/* * This script demonstrates the use of the threaded ODBC interface to insert * data into a database based on a timer. */ require ("Application"); require ("ODBCThreadSupport"); class DatabaseLogger Application { /* User-defined values, may be changed as needed. */ DSN = "SQLHawk"; user = ""; password = ""; tablename = "tbl_BaseValues"; // Base name for the disk cache file cachefile = "c:\\TEMP\\testcache.txt"; //A class that represents the table we are logging to. tableclass; //an instance of the ODBCThread class that does all the work with the Database. thread; } /* This method will be called every time the connection is established to the database. * If there is something we only want to perform on the first connection, we can test * is_first_connect to perform the code only once. */ method DatabaseLogger.onConnect() { princ ("Connection succeeded\n"); if (.thread.is_first_connect) { // Start the sequence defined by the AddInitStage calls in the constructor .thread.BeginAsyncInit(); } } /* If we get a connection attempt failure, or the connection fails after having been * connected, this method is called. */ method DatabaseLogger.onConnectFail() { princ ("Connection closed: ", SQLResult.Description, "\n"); } /* Map the table in the set of table definitions that matches the name in .tablename * into a Gamma class. This lets us easily convert between class instances and rows * in the table. */ method DatabaseLogger.mapTable(name, tabledefinitions) { .tableclass = .thread.ClassFromTable(name, tabledefinitions); } /* This is where you would set up the timer or event handler functions to write to the table. * I am just calling the functioning that calls the stored procedure without setting up any events. */ method DatabaseLogger.startLogging() { .callQuery(); } // call the query method DatabaseLogger.callQuery() { local query = format("select * from tablename where CASTNUM=33463 AND LADELNUM=8"); local result = .thread.ExecDirect(STORE_AND_FORWARD, query, `(@self).queryComplete()); } /* Print out the return of the Stored Procedure * This method will be called when the Stored Procedure fires */ method DatabaseLogger.queryComplete () { princ(SQLResult.Result.rows, "\n"); princ(SQLResult.Result.rows[0][0], "\n"); princ(SQLResult.Result.rows[0][1], "\n"); princ("Stored Procedure fired successfully.\n"); } /* Write the 'main line' of the program here. */ method DatabaseLogger.constructor () { // Create and configure the database connection object .thread = new ODBCThread(); .thread.Configure(.DSN, .user, .password, STORE_AND_FORWARD //| STORE_ALWAYS //| NO_STORE_TO_SECONDARY //| ALLOW_CACHE_RESTART //| NO_FLUSH_ON_WRITE , .cachefile, 5000000); .thread.MaxTransactions = 2000; // Query the table and map it to a class for eash insertion. We want to run an asynchronous event // within the asynchronous initialization stage, so to do that we specify the special method // cbInitStage as the callback function of our asynchronous event (GetTableInfo). We deal with // the return from the GetTableInfo in the onSuccess argument of the init stage. .thread.AddInitTableInfo("", "", .tablename, "TABLE,VIEW", `(@self).mapTable(@.tablename, SQLTables), nil); // Do not start writing data to the table until we have successfully created and mapped // the table to a class. If we wanted to start writing data immediately, then we would // create the table class beforehand instead of querying the database for the table // definition. Then, even if the database were unavailable we could still cache to the // local disk until the database was ready. .thread.AddInitStage(nil, `(@self).startLogging(), nil); // Set up the callback functions for various events from the database thread .thread.OnConnectionSucceeded = `(@self).onConnect(); .thread.OnConnectionFailed = `(@self).onConnectFail(); .thread.OnFileSystemError = `princ("File System Error: ", SQLResult.Description, ": ", strerror(SQLResult.ReturnCode), "\n"); .thread.OnODBCError = `princ("ODBC Error: ", SQLResult, "\n"); .thread.OnExecuteStored = nil; // Now that everything is configured, start the thread and begin connecting. All of the // logic now will be driven through the onConnect callback and then through the init // stages. .thread.Start(); } /* Any code to be run when the program gets shut down. */ method DatabaseLogger.destructor () { if (.thread) destroy(.thread); } /* Start the program by instantiating the class. */ ApplicationSingleton (DatabaseLogger);