ROOT logo
// @(#)root/odbc:$Id$
// Author: Sergey Linev   6/02/2006

/*************************************************************************
 * Copyright (C) 1995-2006, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TODBCServer.h"

#include "TODBCRow.h"
#include "TODBCResult.h"
#include "TODBCStatement.h"
#include "TSQLColumnInfo.h"
#include "TSQLTableInfo.h"
#include "TUrl.h"
#include "TString.h"
#include "TObjString.h"
#include "TList.h"
#include "Riostream.h"


#include <sqlext.h>


ClassImp(TODBCServer)

//______________________________________________________________________________
TODBCServer::TODBCServer(const char *db, const char *uid, const char *pw) :
   TSQLServer()
{
   // Open a connection to a ODBC server. The db arguments can be:
   // 1. Form "odbc://[user[:passwd]@]<host>[:<port>][/<database>][?Driver]",
   //    e.g.: "odbc://pcroot.cern.ch:3306/test?MySQL".
   //    Driver argument specifies ODBC driver, which should be used for
   //    connection. By default, MyODBC driver name is used.
   //    The uid is the username and pw the password that should be used
   //    for the connection.
   //    If uid and pw are not specified (==0), user and passwd arguments from
   //    URL will be used. Works only with MySQL ODBC, probably with PostrSQL
   //    ODBC.
   // 2. Form "odbcd://DRIVER={MyODBC};SERVER=pcroot.cern.ch;DATABASE=test;USER=user;PASSWORD=pass;OPTION=3;PORT=3306;"
   //    This is a form, which is accepted by SQLDriverConnect function of ODBC.
   //    Here some other arguments can be specified, which are not included
   //    in standard URL format.
   // 3. Form "odbcn://MySpecialConfig", where MySpecialConfig is entry,
   //    defined in user DSN (user data source). Here uid and pw should be
   //    always specified.
   //
   //    Configuring unixODBC under Linux: http://www.unixodbc.org/odbcinst.html
   //    Remarks: for variants 1 & 2 it is enough to create/configure
   //    odbcinst.ini file. For variant 3 file odbc.ini should be created.
   //    Path to this files can be specified in environmental variables like
   //      export ODBCINI=/home/my/unixODBC/etc/odbc.ini
   //      export ODBCSYSINI=/home/my/unixODBC/etc
   //
   //    Configuring MySQL ODBC under Windows.
   //    Installing ODBC driver for MySQL is enough to use it under Windows.
   //    Afer odbcd:// variant can be used with DRIVER={MySQL ODBC 3.51 Driver};
   //    To configure User DSN, go into Start menu -> Settings ->
   //    Control panel -> Administrative tools-> Data Sources (ODBC).
   //
   //    To install Oracle ODBC driver for Windows, one should download
   //    and install either complete Oracle client (~500 MB), or so-called
   //    Instant Client Basic and Instant Client ODBC (~20 MB together).
   //    Some remark about Instant Client:
   //       1) Two additional DLLs are required: mfc71.dll & msver71.dll
   //          They can be found either in MS VC++ 7.1 Free Toolkit or
   //          downloaded from other Internet sites
   //       2) ORACLE_HOME environment variable should be specified and point to
   //           location, where Instant Client files are extracted
   //       3) Run odbc_install.exe from account with administrative rights
   //       3) In $ORACLE_HOME/network/admin/ directory appropriate *.ora files
   //          like ldap.ora, sqlnet.ora, tnsnames.ora should be installed.
   //          Contact your Oracle administrator to get these files.
   //    After Oracle ODBC driver is installed, appropriate entry in ODBC drivers
   //    list like "Oracle in instantclient10_2" should appiar. Connection
   //    string example:
   //     "odbcd://DRIVER={Oracle in instantclient10_2};DBQ=db-test;UID=user_name;PWD=user_pass;";

   TString connstr;
   Bool_t simpleconnect = kTRUE;

   SQLRETURN retcode;
   SQLHWND  hwnd;

   fPort = 1; // indicate that we are connected

   if ((strncmp(db, "odbc", 4)!=0) || (strlen(db)<8)) {
      SetError(-1, "db argument should be started from odbc...","TODBCServer");
      goto zombie;
   }

   if (strncmp(db, "odbc://", 7)==0) {
      TUrl url(db);
      if (!url.IsValid()) {
         SetError(-1, Form("not valid URL: %s", db), "TODBCServer");
         goto zombie;
      }
      const char* driver = "MyODBC";
      const char* dbase = url.GetFile();
      if (dbase!=0)
         if (*dbase=='/') dbase++; //skip leading "/" if appears

      if (((uid==0) || (*uid==0)) && (strlen(url.GetUser())>0)) {
         uid = url.GetUser();
         pw = url.GetPasswd();
      }

      if (strlen(url.GetOptions())!=0) driver = url.GetOptions();

      connstr.Form("DRIVER={%s};"
                   "SERVER=%s;"
                   "DATABASE=%s;"
                   "USER=%s;"
                   "PASSWORD=%s;"
                   "OPTION=3;",
                    driver, url.GetHost(), dbase, uid, pw);
      if (url.GetPort()>0)
          connstr += Form("PORT=%d;", url.GetPort());

      fHost = url.GetHost();
      fPort = url.GetPort()>0 ? url.GetPort() : 1;
      fDB = dbase;
      simpleconnect = kFALSE;
   } else
   if (strncmp(db, "odbcd://", 8)==0) {
      connstr = db+8;
      simpleconnect = kFALSE;
   } else
   if (strncmp(db, "odbcn://", 8)==0) {
      connstr = db+8;
      simpleconnect = kTRUE;
   } else {
      SetError(-1, "db argument is invalid", "TODBCServer");
      goto zombie;
   }

   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &fHenv);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;

   /* Set the ODBC version environment attribute */
   retcode = SQLSetEnvAttr(fHenv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;

   /* Allocate connection handle */
   retcode = SQLAllocHandle(SQL_HANDLE_DBC, fHenv, &fHdbc);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;

   /* Set login timeout to 5 seconds. */
   retcode = SQLSetConnectAttr(fHdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER) 5, 0);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;

   char sbuf[2048];

   SQLSMALLINT reslen;
   SQLINTEGER reslen1;

   hwnd = 0;

   if (simpleconnect)
      retcode = SQLConnect(fHdbc, (SQLCHAR*) connstr.Data(), SQL_NTS,
                                  (SQLCHAR*) uid, SQL_NTS,
                                  (SQLCHAR*) pw, SQL_NTS);
   else
      retcode = SQLDriverConnect(fHdbc, hwnd,
                                 (SQLCHAR*) connstr.Data(), SQL_NTS,
                                 (SQLCHAR*) sbuf, sizeof(sbuf), &reslen, SQL_DRIVER_NOPROMPT);

   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;

   fType = "ODBC";
                  
   retcode = SQLGetInfo(fHdbc, SQL_USER_NAME, sbuf, sizeof(sbuf), &reslen);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   fUserId = sbuf;

   retcode = SQLGetInfo(fHdbc, SQL_DBMS_NAME, sbuf, sizeof(sbuf), &reslen);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   fServerInfo = sbuf;
   fType = sbuf;
   
   retcode = SQLGetInfo(fHdbc, SQL_DBMS_VER, sbuf, sizeof(sbuf), &reslen);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   fServerInfo += " ";
   fServerInfo += sbuf;

   // take current catalog - database name
   retcode = SQLGetConnectAttr(fHdbc, SQL_ATTR_CURRENT_CATALOG, sbuf, sizeof(sbuf), &reslen1);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   if (fDB.Length()==0) fDB = sbuf;

   retcode = SQLGetInfo(fHdbc, SQL_SERVER_NAME, sbuf, sizeof(sbuf), &reslen);
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   if (fHost.Length()==0) fHost = sbuf;

/*   
   
   SQLUINTEGER iinfo;
   retcode = SQLGetInfo(fHdbc, SQL_PARAM_ARRAY_ROW_COUNTS, &iinfo, sizeof(iinfo), 0);  
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   Info("Constr", "SQL_PARAM_ARRAY_ROW_COUNTS = %u", iinfo);
   
   retcode = SQLGetInfo(fHdbc, SQL_PARAM_ARRAY_SELECTS, &iinfo, sizeof(iinfo), 0);  
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   Info("Constr", "SQL_PARAM_ARRAY_SELECTS = %u", iinfo);

   retcode = SQLGetInfo(fHdbc, SQL_BATCH_ROW_COUNT, &iinfo, sizeof(iinfo), 0);  
   if (ExtractErrors(retcode, "TODBCServer")) goto zombie;
   Info("Constr", "SQL_BATCH_ROW_COUNT = %u", iinfo);
*/

   return;

zombie:
   fPort = -1;
   fHost = "";
   MakeZombie();
}

//______________________________________________________________________________
TODBCServer::~TODBCServer()
{
   // Close connection to MySQL DB server.

   if (IsConnected())
      Close();
}

//______________________________________________________________________________
TList* TODBCServer::ListData(Bool_t isdrivers)
{
   // Produce TList object with list of available 
   // ODBC drivers (isdrivers = kTRUE) or data sources (isdrivers = kFALSE)

   SQLHENV   henv;
   SQLRETURN retcode;

   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
   if ((retcode!=SQL_SUCCESS) && (retcode!=SQL_SUCCESS_WITH_INFO)) return 0;

   retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
   if ((retcode!=SQL_SUCCESS) && (retcode!=SQL_SUCCESS_WITH_INFO)) return 0;
   
   TList* lst = 0;
   
   char namebuf[2048], optbuf[2048];
   SQLSMALLINT reslen1, reslen2;
   
   do {
      strlcpy(namebuf, "",2048); 
      strlcpy(optbuf, "",2048);
      if (isdrivers)
         retcode = SQLDrivers(henv, (lst==0 ? SQL_FETCH_FIRST : SQL_FETCH_NEXT), 
                     (SQLCHAR*) namebuf, sizeof(namebuf), &reslen1,
                     (SQLCHAR*) optbuf, sizeof(optbuf), &reslen2);
      else
         retcode = SQLDataSources(henv, (lst==0 ? SQL_FETCH_FIRST : SQL_FETCH_NEXT), 
                     (SQLCHAR*) namebuf, sizeof(namebuf), &reslen1,
                     (SQLCHAR*) optbuf, sizeof(optbuf), &reslen2);
                     
      if (retcode==SQL_NO_DATA) break;
      if ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO)) {
         if (lst==0) { 
            lst = new TList; 
            lst->SetOwner(kTRUE);
         } 
         for (int n=0;n<reslen2-1;n++)
            if (optbuf[n]=='\0') optbuf[n] = ';';
         
         lst->Add(new TNamed(namebuf, optbuf));
      } 
   } while ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO));

   SQLFreeHandle(SQL_HANDLE_ENV, henv);
   
   return lst;
   
}


//______________________________________________________________________________
TList* TODBCServer::GetDrivers()
{
   // Produce TList object with list of available ODBC drivers
   // User must delete TList object aftewards
   // Name of driver can be used in connecting to data base in form
   // TSQLServer::Connect("odbcd://DRIVER={<drivername>};DBQ=<dbname>;UID=user;PWD=pass;", 0, 0);

   return ListData(kTRUE);
}

//______________________________________________________________________________
void TODBCServer::PrintDrivers()
{
   // Print list of ODBC drivers in form:
   //   <name> : <options list>
    
   TList* lst = GetDrivers();
   cout << "List of ODBC drivers:" << endl;
   TIter iter(lst);
   TNamed* n = 0;
   while ((n = (TNamed*) iter()) != 0) 
      cout << "  " << n->GetName() << " : " << n->GetTitle() << endl; 
   delete lst;
}

//______________________________________________________________________________
TList* TODBCServer::GetDataSources()
{
   // Produce TList object with list of available ODBC data sources
   // User must delete TList object aftewards
   // Name of data source can be used later for connection:
   // TSQLServer::Connect("odbcn://<data_source_name>", "user", "pass");

   return ListData(kFALSE);
}

//______________________________________________________________________________
void TODBCServer::PrintDataSources()
{
   // Print list of ODBC data sources in form:
   //   <name> : <options list>
    
   TList* lst = GetDataSources();
   cout << "List of ODBC data sources:" << endl;
   TIter iter(lst);
   TNamed* n = 0;
   while ((n = (TNamed*) iter()) != 0) 
      cout << "  " << n->GetName() << " : " << n->GetTitle() << endl; 
   delete lst;
}

//______________________________________________________________________________
Bool_t TODBCServer::ExtractErrors(SQLRETURN retcode, const char* method)
{
   // Extract errors, produced by last ODBC function call

   if ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO)) return kFALSE;

   SQLINTEGER i = 0;
   SQLINTEGER native;
   SQLCHAR state[7];
   SQLCHAR text[256];
   SQLSMALLINT len;

   while (SQLGetDiagRec(SQL_HANDLE_ENV, fHenv, ++i, state, &native, text,
                          sizeof(text), &len ) == SQL_SUCCESS)
      //Error(method, "%s:%ld:%ld:%s\n", state, i, native, text);
      SetError(native, (const char*) text, method);

   i = 0;

   while (SQLGetDiagRec(SQL_HANDLE_DBC, fHdbc, ++i, state, &native, text,
                          sizeof(text), &len ) == SQL_SUCCESS)
//      Error(method, "%s:%ld:%ld:%s\n", state, i, native, text);
      SetError(native, (const char*) text, method);

   return kTRUE;
}

// Reset error and check that server connected
#define CheckConnect(method, res)                       \
   {                                                    \
      ClearError();                                     \
      if (!IsConnected()) {                             \
         SetError(-1,"ODBC driver is not connected",method); \
         return res;                                    \
      }                                                 \
   }

//______________________________________________________________________________
void TODBCServer::Close(Option_t *)
{
   // Close connection to MySQL DB server.

   SQLDisconnect(fHdbc);
   SQLFreeHandle(SQL_HANDLE_DBC, fHdbc);
   SQLFreeHandle(SQL_HANDLE_ENV, fHenv);
   fPort = -1;
}

//______________________________________________________________________________
TSQLResult *TODBCServer::Query(const char *sql)
{
   // Execute SQL command. Result object must be deleted by the user.
   // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
   // The result object must be deleted by the user.

   CheckConnect("Query", 0);

   SQLRETURN    retcode;
   SQLHSTMT     hstmt;

   SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);

   retcode = SQLExecDirect(hstmt, (SQLCHAR*) sql, SQL_NTS);
   if (ExtractErrors(retcode, "Query")) {
      SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
      return 0;
   }

   return new TODBCResult(hstmt);
}

//______________________________________________________________________________
Bool_t TODBCServer::Exec(const char* sql)
{
   // Executes query which does not produce any results set
   // Return kTRUE if successfull

   CheckConnect("Exec", 0);

   SQLRETURN    retcode;
   SQLHSTMT     hstmt;

   SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);

   retcode = SQLExecDirect(hstmt, (SQLCHAR*) sql, SQL_NTS);

   Bool_t res = !ExtractErrors(retcode, "Exec");

   SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

   return res;
}

//______________________________________________________________________________
Int_t TODBCServer::SelectDataBase(const char *db)
{
   // Select a database. Returns 0 if successful, non-zero otherwise.
   // Not all RDBMS support selecting of database (catalog) after connecting
   // Normally user should specify database name at time of connection

   CheckConnect("SelectDataBase", -1);
   
   SQLRETURN retcode = SQLSetConnectAttr(fHdbc, SQL_ATTR_CURRENT_CATALOG, (SQLCHAR*) db, SQL_NTS);
   if (ExtractErrors(retcode, "SelectDataBase")) return -1;
   
   fDB = db;

   return 0;
}

//______________________________________________________________________________
TSQLResult *TODBCServer::GetDataBases(const char *)
{
   // List all available databases. Wild is for wildcarding "t%" list all
   // databases starting with "t".
   // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
   // The result object must be deleted by the user.

   CheckConnect("GetDataBases", 0);

   return 0;
}

//______________________________________________________________________________
TSQLResult *TODBCServer::GetTables(const char*, const char* wild)
{
   // List all tables in the specified database. Wild is for wildcarding
   // "t%" list all tables starting with "t".
   // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
   // The result object must be deleted by the user.

   CheckConnect("GetTables", 0);

   SQLRETURN    retcode;
   SQLHSTMT     hstmt;

   SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);

   SQLCHAR* schemaName = 0;
   SQLSMALLINT schemaNameLength = 0;

/*
   TString schemabuf;
   // schema is used by Oracle to specify to which user belong table
   // therefore, to see correct tables, schema name is set to user name
   if ((fUserId.Length()>0) && (fServerInfo.Contains("Oracle"))) {
      schemabuf = fUserId;
      schemabuf.ToUpper();
      schemaName = (SQLCHAR*) schemabuf.Data();
      schemaNameLength = schemabuf.Length();
   }
*/
   
   SQLCHAR* tableName = 0;
   SQLSMALLINT tableNameLength = 0;

   if ((wild!=0) && (strlen(wild)!=0)) {
      tableName = (SQLCHAR*) wild;
      tableNameLength = strlen(wild);
      SQLSetStmtAttr(hstmt, SQL_ATTR_METADATA_ID, (SQLPOINTER) SQL_FALSE, 0);
   }

   retcode = SQLTables(hstmt, NULL, 0, schemaName, schemaNameLength, tableName, tableNameLength, (SQLCHAR*) "TABLE", 5);
   if (ExtractErrors(retcode, "GetTables")) {
      SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
      return 0;
   }

   return new TODBCResult(hstmt);
}

//______________________________________________________________________________
TList* TODBCServer::GetTablesList(const char* wild)
{
   // Return list of tables in database
   // See TSQLServer::GetTablesList() for details.

   CheckConnect("GetTablesList", 0);

   TSQLResult* res = GetTables(0, wild);
   if (res==0) return 0;

   TList* lst = 0;

   TSQLRow* row = 0;

   while ((row = res->Next())!=0) {
      const char* tablename = row->GetField(2);
      if (tablename!=0) {
//         Info("List","%s %s %s %s %s", tablename, row->GetField(0), row->GetField(1), row->GetField(3), row->GetField(4));
         if (lst==0) {
            lst = new TList;
            lst->SetOwner(kTRUE);
         }
         lst->Add(new TObjString(tablename));
      }
      delete row;
   }

   delete res;

   return lst;
}


//______________________________________________________________________________
TSQLTableInfo* TODBCServer::GetTableInfo(const char* tablename)
{
   // Produces SQL table info
   // Object must be deleted by user

   CheckConnect("GetTableInfo", 0);

   #define STR_LEN 128+1
   #define REM_LEN 254+1

   /* Declare buffers for result set data */

   SQLCHAR       szCatalog[STR_LEN], szSchema[STR_LEN];
   SQLCHAR       szTableName[STR_LEN], szColumnName[STR_LEN];
   SQLCHAR       szTypeName[STR_LEN], szRemarks[REM_LEN];
   SQLCHAR       szColumnDefault[STR_LEN], szIsNullable[STR_LEN];
   SQLLEN        columnSize, bufferLength, charOctetLength, ordinalPosition;
   SQLSMALLINT   dataType, decimalDigits, numPrecRadix, nullable;
   SQLSMALLINT   sqlDataType, datetimeSubtypeCode;
   SQLRETURN     retcode;
   SQLHSTMT      hstmt;

   /* Declare buffers for bytes available to return */

   SQLLEN cbCatalog, cbSchema, cbTableName, cbColumnName;
   SQLLEN cbDataType, cbTypeName, cbColumnSize, cbBufferLength;
   SQLLEN cbDecimalDigits, cbNumPrecRadix, cbNullable, cbRemarks;
   SQLLEN cbColumnDefault, cbSQLDataType, cbDatetimeSubtypeCode, cbCharOctetLength;
   SQLLEN cbOrdinalPosition, cbIsNullable;


   SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);

   retcode = SQLColumns(hstmt, NULL, 0, NULL, 0, (SQLCHAR*) tablename, SQL_NTS, NULL, 0);
   if (ExtractErrors(retcode, "GetTableInfo")) {
      SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
      return 0;
   }

   TList* lst = 0;

   /* Bind columns in result set to buffers */

   SQLBindCol(hstmt, 1, SQL_C_CHAR, szCatalog, STR_LEN,&cbCatalog);
   SQLBindCol(hstmt, 2, SQL_C_CHAR, szSchema, STR_LEN, &cbSchema);
   SQLBindCol(hstmt, 3, SQL_C_CHAR, szTableName, STR_LEN,&cbTableName);
   SQLBindCol(hstmt, 4, SQL_C_CHAR, szColumnName, STR_LEN, &cbColumnName);
   SQLBindCol(hstmt, 5, SQL_C_SSHORT, &dataType, 0, &cbDataType);
   SQLBindCol(hstmt, 6, SQL_C_CHAR, szTypeName, STR_LEN, &cbTypeName);
   SQLBindCol(hstmt, 7, SQL_C_SLONG, &columnSize, 0, &cbColumnSize);
   SQLBindCol(hstmt, 8, SQL_C_SLONG, &bufferLength, 0, &cbBufferLength);
   SQLBindCol(hstmt, 9, SQL_C_SSHORT, &decimalDigits, 0, &cbDecimalDigits);
   SQLBindCol(hstmt, 10, SQL_C_SSHORT, &numPrecRadix, 0, &cbNumPrecRadix);
   SQLBindCol(hstmt, 11, SQL_C_SSHORT, &nullable, 0, &cbNullable);
   SQLBindCol(hstmt, 12, SQL_C_CHAR, szRemarks, REM_LEN, &cbRemarks);
   SQLBindCol(hstmt, 13, SQL_C_CHAR, szColumnDefault, STR_LEN, &cbColumnDefault);
   SQLBindCol(hstmt, 14, SQL_C_SSHORT, &sqlDataType, 0, &cbSQLDataType);
   SQLBindCol(hstmt, 15, SQL_C_SSHORT, &datetimeSubtypeCode, 0, &cbDatetimeSubtypeCode);
   SQLBindCol(hstmt, 16, SQL_C_SLONG, &charOctetLength, 0, &cbCharOctetLength);
   SQLBindCol(hstmt, 17, SQL_C_SLONG, &ordinalPosition, 0, &cbOrdinalPosition);
   SQLBindCol(hstmt, 18, SQL_C_CHAR, szIsNullable, STR_LEN, &cbIsNullable);

   retcode = SQLFetch(hstmt);

   while ((retcode==SQL_SUCCESS) || (retcode==SQL_SUCCESS_WITH_INFO)) {

      Int_t sqltype = kSQL_NONE;

      Int_t data_size = -1;    // size in bytes
      Int_t data_length = -1;  // declaration like VARCHAR(n) or NUMERIC(n)
      Int_t data_scale = -1;   // second argument in declaration
      Int_t data_sign = -1; // no info about sign

      switch (dataType) {
         case SQL_CHAR:
            sqltype = kSQL_CHAR;
            data_size = columnSize;
            data_length = charOctetLength;
            break;
         case SQL_VARCHAR:
         case SQL_LONGVARCHAR:
            sqltype = kSQL_VARCHAR;
            data_size = columnSize;
            data_length = charOctetLength;
            break;
         case SQL_DECIMAL:
         case SQL_NUMERIC:
            sqltype = kSQL_NUMERIC;
            data_size = columnSize; // size of column in database
            data_length = columnSize;
            data_scale = decimalDigits;
            break;
         case SQL_INTEGER:
         case SQL_TINYINT:
         case SQL_BIGINT:
            sqltype = kSQL_INTEGER;
            data_size = columnSize;
            break;
         case SQL_REAL:
         case SQL_FLOAT:
            sqltype = kSQL_FLOAT;
            data_size = columnSize;
            data_sign = 1;
            break;
         case SQL_DOUBLE:
            sqltype = kSQL_DOUBLE;
            data_size = columnSize;
            data_sign = 1;
            break;
         case SQL_BINARY:
         case SQL_VARBINARY:
         case SQL_LONGVARBINARY:
            sqltype = kSQL_BINARY;
            data_size = columnSize;
            break;
         case SQL_TYPE_TIMESTAMP:
            sqltype = kSQL_TIMESTAMP;
            data_size = columnSize;
            break;
      }

      if (lst==0) lst = new TList;

      lst->Add(new TSQLColumnInfo((const char*) szColumnName,
                                  (const char*) szTypeName,
                                  nullable!=0,
                                  sqltype,
                                  data_size,
                                  data_length,
                                  data_scale,
                                  data_sign));

      retcode = SQLFetch(hstmt);
   }

   SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

   return new TSQLTableInfo(tablename, lst);
}

//______________________________________________________________________________
TSQLResult *TODBCServer::GetColumns(const char*, const char *table, const char*)
{
   // List all columns in specified table in the specified database.
   // Wild is for wildcarding "t%" list all columns starting with "t".
   // Returns a pointer to a TSQLResult object if successful, 0 otherwise.
   // The result object must be deleted by the user.

   CheckConnect("GetColumns", 0);

   SQLRETURN    retcode;
   SQLHSTMT     hstmt;

   SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);

   retcode = SQLColumns(hstmt, NULL, 0, NULL, 0, (SQLCHAR*) table, SQL_NTS, NULL, 0);
   if (ExtractErrors(retcode, "GetColumns")) {
      SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
      return 0;
   }

   return new TODBCResult(hstmt);
}

//______________________________________________________________________________
Int_t TODBCServer::GetMaxIdentifierLength()
{
   // returns maximum allowed length of identifier (table name, column name, index name)

   CheckConnect("GetMaxIdentifierLength", 20);

   SQLUINTEGER info = 0;
   SQLRETURN retcode;

   retcode = SQLGetInfo(fHdbc, SQL_MAX_IDENTIFIER_LEN, (SQLPOINTER)&info, sizeof(info), NULL);

   if (ExtractErrors(retcode, "GetMaxIdentifierLength")) return 20;

   return info;
}

//______________________________________________________________________________
Int_t TODBCServer::CreateDataBase(const char*)
{
   // Create a database. Returns 0 if successful, non-zero otherwise.

   CheckConnect("CreateDataBase", -1);

   return -1;
}

//______________________________________________________________________________
Int_t TODBCServer::DropDataBase(const char*)
{
   // Drop (i.e. delete) a database. Returns 0 if successful, non-zero
   // otherwise.

   CheckConnect("DropDataBase", -1);

   return -1;
}

//______________________________________________________________________________
Int_t TODBCServer::Reload()
{
   // Reload permission tables. Returns 0 if successful, non-zero
   // otherwise. User must have reload permissions.

   CheckConnect("Reload", -1);

   return -1;
}

//______________________________________________________________________________
Int_t TODBCServer::Shutdown()
{
   // Shutdown the database server. Returns 0 if successful, non-zero
   // otherwise. User must have shutdown permissions.

   CheckConnect("Shutdown", -1);

   return -1;
}

//______________________________________________________________________________
const char *TODBCServer::ServerInfo()
{
   // Return server info.

   CheckConnect("ServerInfo", 0);

   return fServerInfo;
}

//______________________________________________________________________________
TSQLStatement *TODBCServer::Statement(const char *sql, Int_t bufsize)
{
   // Creates ODBC statement for provided query.
   // See TSQLStatement class for more details.

   CheckConnect("Statement", 0);

   if (!sql || !*sql) {
      SetError(-1, "no query string specified", "Statement");
      return 0;
   }

//   SQLUINTEGER info = 0;
//   SQLGetInfo(fHdbc, SQL_PARAM_ARRAY_ROW_COUNTS, (SQLPOINTER)&info, sizeof(info), NULL);
//   if (info==SQL_PARC_BATCH) Info("Statement","info==SQL_PARC_BATCH"); else
//   if (info==SQL_PARC_NO_BATCH) Info("Statement","info==SQL_PARC_NO_BATCH"); else
//    Info("Statement","info==%u", info);


   SQLRETURN    retcode;
   SQLHSTMT     hstmt;

   retcode = SQLAllocHandle(SQL_HANDLE_STMT, fHdbc, &hstmt);
   if (ExtractErrors(retcode, "Statement")) return 0;

   retcode = SQLPrepare(hstmt, (SQLCHAR*) sql, SQL_NTS);
   if (ExtractErrors(retcode, "Statement")) {
      SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
      return 0;
   }

   return new TODBCStatement(hstmt, bufsize, fErrorOut);
}

//______________________________________________________________________________
Bool_t TODBCServer::StartTransaction()
{
   // Starts transaction.
   // Check for transaction support.
   // Switch off autocommitment mode.

   CheckConnect("StartTransaction", kFALSE);

   SQLUINTEGER info = 0;
   SQLRETURN retcode;

   retcode = SQLGetInfo(fHdbc, SQL_TXN_CAPABLE, (SQLPOINTER)&info, sizeof(info), NULL);
   if (ExtractErrors(retcode, "StartTransaction")) return kFALSE;

   if (info==0) {
      SetError(-1,"Transactions not supported","StartTransaction");
      return kFALSE;
   }

   if (!Commit()) return kFALSE;

   retcode = SQLSetConnectAttr(fHdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF, 0);
   if (ExtractErrors(retcode, "StartTransaction")) return kFALSE;

   return kTRUE;
}

//______________________________________________________________________________
Bool_t TODBCServer::EndTransaction(Bool_t commit)
{
   // Complete current transaction (commit = kTRUE) or rollback
   // Switches on autocommit mode of ODBC driver

   const char* method = commit ? "Commit" : "Rollback";

   CheckConnect(method, kFALSE);

   SQLRETURN retcode = SQLEndTran(SQL_HANDLE_DBC, fHdbc, commit ? SQL_COMMIT : SQL_ROLLBACK);
   if (ExtractErrors(retcode, method)) return kFALSE;

   retcode = SQLSetConnectAttr(fHdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_ON, 0);

   return kTRUE;
}

//______________________________________________________________________________
Bool_t TODBCServer::Commit()
{
   // Commit transaction

   return EndTransaction(kTRUE);
}

//______________________________________________________________________________
Bool_t TODBCServer::Rollback()
{
   // Rollback transaction

   return EndTransaction(kFALSE);
}
 TODBCServer.cxx:1
 TODBCServer.cxx:2
 TODBCServer.cxx:3
 TODBCServer.cxx:4
 TODBCServer.cxx:5
 TODBCServer.cxx:6
 TODBCServer.cxx:7
 TODBCServer.cxx:8
 TODBCServer.cxx:9
 TODBCServer.cxx:10
 TODBCServer.cxx:11
 TODBCServer.cxx:12
 TODBCServer.cxx:13
 TODBCServer.cxx:14
 TODBCServer.cxx:15
 TODBCServer.cxx:16
 TODBCServer.cxx:17
 TODBCServer.cxx:18
 TODBCServer.cxx:19
 TODBCServer.cxx:20
 TODBCServer.cxx:21
 TODBCServer.cxx:22
 TODBCServer.cxx:23
 TODBCServer.cxx:24
 TODBCServer.cxx:25
 TODBCServer.cxx:26
 TODBCServer.cxx:27
 TODBCServer.cxx:28
 TODBCServer.cxx:29
 TODBCServer.cxx:30
 TODBCServer.cxx:31
 TODBCServer.cxx:32
 TODBCServer.cxx:33
 TODBCServer.cxx:34
 TODBCServer.cxx:35
 TODBCServer.cxx:36
 TODBCServer.cxx:37
 TODBCServer.cxx:38
 TODBCServer.cxx:39
 TODBCServer.cxx:40
 TODBCServer.cxx:41
 TODBCServer.cxx:42
 TODBCServer.cxx:43
 TODBCServer.cxx:44
 TODBCServer.cxx:45
 TODBCServer.cxx:46
 TODBCServer.cxx:47
 TODBCServer.cxx:48
 TODBCServer.cxx:49
 TODBCServer.cxx:50
 TODBCServer.cxx:51
 TODBCServer.cxx:52
 TODBCServer.cxx:53
 TODBCServer.cxx:54
 TODBCServer.cxx:55
 TODBCServer.cxx:56
 TODBCServer.cxx:57
 TODBCServer.cxx:58
 TODBCServer.cxx:59
 TODBCServer.cxx:60
 TODBCServer.cxx:61
 TODBCServer.cxx:62
 TODBCServer.cxx:63
 TODBCServer.cxx:64
 TODBCServer.cxx:65
 TODBCServer.cxx:66
 TODBCServer.cxx:67
 TODBCServer.cxx:68
 TODBCServer.cxx:69
 TODBCServer.cxx:70
 TODBCServer.cxx:71
 TODBCServer.cxx:72
 TODBCServer.cxx:73
 TODBCServer.cxx:74
 TODBCServer.cxx:75
 TODBCServer.cxx:76
 TODBCServer.cxx:77
 TODBCServer.cxx:78
 TODBCServer.cxx:79
 TODBCServer.cxx:80
 TODBCServer.cxx:81
 TODBCServer.cxx:82
 TODBCServer.cxx:83
 TODBCServer.cxx:84
 TODBCServer.cxx:85
 TODBCServer.cxx:86
 TODBCServer.cxx:87
 TODBCServer.cxx:88
 TODBCServer.cxx:89
 TODBCServer.cxx:90
 TODBCServer.cxx:91
 TODBCServer.cxx:92
 TODBCServer.cxx:93
 TODBCServer.cxx:94
 TODBCServer.cxx:95
 TODBCServer.cxx:96
 TODBCServer.cxx:97
 TODBCServer.cxx:98
 TODBCServer.cxx:99
 TODBCServer.cxx:100
 TODBCServer.cxx:101
 TODBCServer.cxx:102
 TODBCServer.cxx:103
 TODBCServer.cxx:104
 TODBCServer.cxx:105
 TODBCServer.cxx:106
 TODBCServer.cxx:107
 TODBCServer.cxx:108
 TODBCServer.cxx:109
 TODBCServer.cxx:110
 TODBCServer.cxx:111
 TODBCServer.cxx:112
 TODBCServer.cxx:113
 TODBCServer.cxx:114
 TODBCServer.cxx:115
 TODBCServer.cxx:116
 TODBCServer.cxx:117
 TODBCServer.cxx:118
 TODBCServer.cxx:119
 TODBCServer.cxx:120
 TODBCServer.cxx:121
 TODBCServer.cxx:122
 TODBCServer.cxx:123
 TODBCServer.cxx:124
 TODBCServer.cxx:125
 TODBCServer.cxx:126
 TODBCServer.cxx:127
 TODBCServer.cxx:128
 TODBCServer.cxx:129
 TODBCServer.cxx:130
 TODBCServer.cxx:131
 TODBCServer.cxx:132
 TODBCServer.cxx:133
 TODBCServer.cxx:134
 TODBCServer.cxx:135
 TODBCServer.cxx:136
 TODBCServer.cxx:137
 TODBCServer.cxx:138
 TODBCServer.cxx:139
 TODBCServer.cxx:140
 TODBCServer.cxx:141
 TODBCServer.cxx:142
 TODBCServer.cxx:143
 TODBCServer.cxx:144
 TODBCServer.cxx:145
 TODBCServer.cxx:146
 TODBCServer.cxx:147
 TODBCServer.cxx:148
 TODBCServer.cxx:149
 TODBCServer.cxx:150
 TODBCServer.cxx:151
 TODBCServer.cxx:152
 TODBCServer.cxx:153
 TODBCServer.cxx:154
 TODBCServer.cxx:155
 TODBCServer.cxx:156
 TODBCServer.cxx:157
 TODBCServer.cxx:158
 TODBCServer.cxx:159
 TODBCServer.cxx:160
 TODBCServer.cxx:161
 TODBCServer.cxx:162
 TODBCServer.cxx:163
 TODBCServer.cxx:164
 TODBCServer.cxx:165
 TODBCServer.cxx:166
 TODBCServer.cxx:167
 TODBCServer.cxx:168
 TODBCServer.cxx:169
 TODBCServer.cxx:170
 TODBCServer.cxx:171
 TODBCServer.cxx:172
 TODBCServer.cxx:173
 TODBCServer.cxx:174
 TODBCServer.cxx:175
 TODBCServer.cxx:176
 TODBCServer.cxx:177
 TODBCServer.cxx:178
 TODBCServer.cxx:179
 TODBCServer.cxx:180
 TODBCServer.cxx:181
 TODBCServer.cxx:182
 TODBCServer.cxx:183
 TODBCServer.cxx:184
 TODBCServer.cxx:185
 TODBCServer.cxx:186
 TODBCServer.cxx:187
 TODBCServer.cxx:188
 TODBCServer.cxx:189
 TODBCServer.cxx:190
 TODBCServer.cxx:191
 TODBCServer.cxx:192
 TODBCServer.cxx:193
 TODBCServer.cxx:194
 TODBCServer.cxx:195
 TODBCServer.cxx:196
 TODBCServer.cxx:197
 TODBCServer.cxx:198
 TODBCServer.cxx:199
 TODBCServer.cxx:200
 TODBCServer.cxx:201
 TODBCServer.cxx:202
 TODBCServer.cxx:203
 TODBCServer.cxx:204
 TODBCServer.cxx:205
 TODBCServer.cxx:206
 TODBCServer.cxx:207
 TODBCServer.cxx:208
 TODBCServer.cxx:209
 TODBCServer.cxx:210
 TODBCServer.cxx:211
 TODBCServer.cxx:212
 TODBCServer.cxx:213
 TODBCServer.cxx:214
 TODBCServer.cxx:215
 TODBCServer.cxx:216
 TODBCServer.cxx:217
 TODBCServer.cxx:218
 TODBCServer.cxx:219
 TODBCServer.cxx:220
 TODBCServer.cxx:221
 TODBCServer.cxx:222
 TODBCServer.cxx:223
 TODBCServer.cxx:224
 TODBCServer.cxx:225
 TODBCServer.cxx:226
 TODBCServer.cxx:227
 TODBCServer.cxx:228
 TODBCServer.cxx:229
 TODBCServer.cxx:230
 TODBCServer.cxx:231
 TODBCServer.cxx:232
 TODBCServer.cxx:233
 TODBCServer.cxx:234
 TODBCServer.cxx:235
 TODBCServer.cxx:236
 TODBCServer.cxx:237
 TODBCServer.cxx:238
 TODBCServer.cxx:239
 TODBCServer.cxx:240
 TODBCServer.cxx:241
 TODBCServer.cxx:242
 TODBCServer.cxx:243
 TODBCServer.cxx:244
 TODBCServer.cxx:245
 TODBCServer.cxx:246
 TODBCServer.cxx:247
 TODBCServer.cxx:248
 TODBCServer.cxx:249
 TODBCServer.cxx:250
 TODBCServer.cxx:251
 TODBCServer.cxx:252
 TODBCServer.cxx:253
 TODBCServer.cxx:254
 TODBCServer.cxx:255
 TODBCServer.cxx:256
 TODBCServer.cxx:257
 TODBCServer.cxx:258
 TODBCServer.cxx:259
 TODBCServer.cxx:260
 TODBCServer.cxx:261
 TODBCServer.cxx:262
 TODBCServer.cxx:263
 TODBCServer.cxx:264
 TODBCServer.cxx:265
 TODBCServer.cxx:266
 TODBCServer.cxx:267
 TODBCServer.cxx:268
 TODBCServer.cxx:269
 TODBCServer.cxx:270
 TODBCServer.cxx:271
 TODBCServer.cxx:272
 TODBCServer.cxx:273
 TODBCServer.cxx:274
 TODBCServer.cxx:275
 TODBCServer.cxx:276
 TODBCServer.cxx:277
 TODBCServer.cxx:278
 TODBCServer.cxx:279
 TODBCServer.cxx:280
 TODBCServer.cxx:281
 TODBCServer.cxx:282
 TODBCServer.cxx:283
 TODBCServer.cxx:284
 TODBCServer.cxx:285
 TODBCServer.cxx:286
 TODBCServer.cxx:287
 TODBCServer.cxx:288
 TODBCServer.cxx:289
 TODBCServer.cxx:290
 TODBCServer.cxx:291
 TODBCServer.cxx:292
 TODBCServer.cxx:293
 TODBCServer.cxx:294
 TODBCServer.cxx:295
 TODBCServer.cxx:296
 TODBCServer.cxx:297
 TODBCServer.cxx:298
 TODBCServer.cxx:299
 TODBCServer.cxx:300
 TODBCServer.cxx:301
 TODBCServer.cxx:302
 TODBCServer.cxx:303
 TODBCServer.cxx:304
 TODBCServer.cxx:305
 TODBCServer.cxx:306
 TODBCServer.cxx:307
 TODBCServer.cxx:308
 TODBCServer.cxx:309
 TODBCServer.cxx:310
 TODBCServer.cxx:311
 TODBCServer.cxx:312
 TODBCServer.cxx:313
 TODBCServer.cxx:314
 TODBCServer.cxx:315
 TODBCServer.cxx:316
 TODBCServer.cxx:317
 TODBCServer.cxx:318
 TODBCServer.cxx:319
 TODBCServer.cxx:320
 TODBCServer.cxx:321
 TODBCServer.cxx:322
 TODBCServer.cxx:323
 TODBCServer.cxx:324
 TODBCServer.cxx:325
 TODBCServer.cxx:326
 TODBCServer.cxx:327
 TODBCServer.cxx:328
 TODBCServer.cxx:329
 TODBCServer.cxx:330
 TODBCServer.cxx:331
 TODBCServer.cxx:332
 TODBCServer.cxx:333
 TODBCServer.cxx:334
 TODBCServer.cxx:335
 TODBCServer.cxx:336
 TODBCServer.cxx:337
 TODBCServer.cxx:338
 TODBCServer.cxx:339
 TODBCServer.cxx:340
 TODBCServer.cxx:341
 TODBCServer.cxx:342
 TODBCServer.cxx:343
 TODBCServer.cxx:344
 TODBCServer.cxx:345
 TODBCServer.cxx:346
 TODBCServer.cxx:347
 TODBCServer.cxx:348
 TODBCServer.cxx:349
 TODBCServer.cxx:350
 TODBCServer.cxx:351
 TODBCServer.cxx:352
 TODBCServer.cxx:353
 TODBCServer.cxx:354
 TODBCServer.cxx:355
 TODBCServer.cxx:356
 TODBCServer.cxx:357
 TODBCServer.cxx:358
 TODBCServer.cxx:359
 TODBCServer.cxx:360
 TODBCServer.cxx:361
 TODBCServer.cxx:362
 TODBCServer.cxx:363
 TODBCServer.cxx:364
 TODBCServer.cxx:365
 TODBCServer.cxx:366
 TODBCServer.cxx:367
 TODBCServer.cxx:368
 TODBCServer.cxx:369
 TODBCServer.cxx:370
 TODBCServer.cxx:371
 TODBCServer.cxx:372
 TODBCServer.cxx:373
 TODBCServer.cxx:374
 TODBCServer.cxx:375
 TODBCServer.cxx:376
 TODBCServer.cxx:377
 TODBCServer.cxx:378
 TODBCServer.cxx:379
 TODBCServer.cxx:380
 TODBCServer.cxx:381
 TODBCServer.cxx:382
 TODBCServer.cxx:383
 TODBCServer.cxx:384
 TODBCServer.cxx:385
 TODBCServer.cxx:386
 TODBCServer.cxx:387
 TODBCServer.cxx:388
 TODBCServer.cxx:389
 TODBCServer.cxx:390
 TODBCServer.cxx:391
 TODBCServer.cxx:392
 TODBCServer.cxx:393
 TODBCServer.cxx:394
 TODBCServer.cxx:395
 TODBCServer.cxx:396
 TODBCServer.cxx:397
 TODBCServer.cxx:398
 TODBCServer.cxx:399
 TODBCServer.cxx:400
 TODBCServer.cxx:401
 TODBCServer.cxx:402
 TODBCServer.cxx:403
 TODBCServer.cxx:404
 TODBCServer.cxx:405
 TODBCServer.cxx:406
 TODBCServer.cxx:407
 TODBCServer.cxx:408
 TODBCServer.cxx:409
 TODBCServer.cxx:410
 TODBCServer.cxx:411
 TODBCServer.cxx:412
 TODBCServer.cxx:413
 TODBCServer.cxx:414
 TODBCServer.cxx:415
 TODBCServer.cxx:416
 TODBCServer.cxx:417
 TODBCServer.cxx:418
 TODBCServer.cxx:419
 TODBCServer.cxx:420
 TODBCServer.cxx:421
 TODBCServer.cxx:422
 TODBCServer.cxx:423
 TODBCServer.cxx:424
 TODBCServer.cxx:425
 TODBCServer.cxx:426
 TODBCServer.cxx:427
 TODBCServer.cxx:428
 TODBCServer.cxx:429
 TODBCServer.cxx:430
 TODBCServer.cxx:431
 TODBCServer.cxx:432
 TODBCServer.cxx:433
 TODBCServer.cxx:434
 TODBCServer.cxx:435
 TODBCServer.cxx:436
 TODBCServer.cxx:437
 TODBCServer.cxx:438
 TODBCServer.cxx:439
 TODBCServer.cxx:440
 TODBCServer.cxx:441
 TODBCServer.cxx:442
 TODBCServer.cxx:443
 TODBCServer.cxx:444
 TODBCServer.cxx:445
 TODBCServer.cxx:446
 TODBCServer.cxx:447
 TODBCServer.cxx:448
 TODBCServer.cxx:449
 TODBCServer.cxx:450
 TODBCServer.cxx:451
 TODBCServer.cxx:452
 TODBCServer.cxx:453
 TODBCServer.cxx:454
 TODBCServer.cxx:455
 TODBCServer.cxx:456
 TODBCServer.cxx:457
 TODBCServer.cxx:458
 TODBCServer.cxx:459
 TODBCServer.cxx:460
 TODBCServer.cxx:461
 TODBCServer.cxx:462
 TODBCServer.cxx:463
 TODBCServer.cxx:464
 TODBCServer.cxx:465
 TODBCServer.cxx:466
 TODBCServer.cxx:467
 TODBCServer.cxx:468
 TODBCServer.cxx:469
 TODBCServer.cxx:470
 TODBCServer.cxx:471
 TODBCServer.cxx:472
 TODBCServer.cxx:473
 TODBCServer.cxx:474
 TODBCServer.cxx:475
 TODBCServer.cxx:476
 TODBCServer.cxx:477
 TODBCServer.cxx:478
 TODBCServer.cxx:479
 TODBCServer.cxx:480
 TODBCServer.cxx:481
 TODBCServer.cxx:482
 TODBCServer.cxx:483
 TODBCServer.cxx:484
 TODBCServer.cxx:485
 TODBCServer.cxx:486
 TODBCServer.cxx:487
 TODBCServer.cxx:488
 TODBCServer.cxx:489
 TODBCServer.cxx:490
 TODBCServer.cxx:491
 TODBCServer.cxx:492
 TODBCServer.cxx:493
 TODBCServer.cxx:494
 TODBCServer.cxx:495
 TODBCServer.cxx:496
 TODBCServer.cxx:497
 TODBCServer.cxx:498
 TODBCServer.cxx:499
 TODBCServer.cxx:500
 TODBCServer.cxx:501
 TODBCServer.cxx:502
 TODBCServer.cxx:503
 TODBCServer.cxx:504
 TODBCServer.cxx:505
 TODBCServer.cxx:506
 TODBCServer.cxx:507
 TODBCServer.cxx:508
 TODBCServer.cxx:509
 TODBCServer.cxx:510
 TODBCServer.cxx:511
 TODBCServer.cxx:512
 TODBCServer.cxx:513
 TODBCServer.cxx:514
 TODBCServer.cxx:515
 TODBCServer.cxx:516
 TODBCServer.cxx:517
 TODBCServer.cxx:518
 TODBCServer.cxx:519
 TODBCServer.cxx:520
 TODBCServer.cxx:521
 TODBCServer.cxx:522
 TODBCServer.cxx:523
 TODBCServer.cxx:524
 TODBCServer.cxx:525
 TODBCServer.cxx:526
 TODBCServer.cxx:527
 TODBCServer.cxx:528
 TODBCServer.cxx:529
 TODBCServer.cxx:530
 TODBCServer.cxx:531
 TODBCServer.cxx:532
 TODBCServer.cxx:533
 TODBCServer.cxx:534
 TODBCServer.cxx:535
 TODBCServer.cxx:536
 TODBCServer.cxx:537
 TODBCServer.cxx:538
 TODBCServer.cxx:539
 TODBCServer.cxx:540
 TODBCServer.cxx:541
 TODBCServer.cxx:542
 TODBCServer.cxx:543
 TODBCServer.cxx:544
 TODBCServer.cxx:545
 TODBCServer.cxx:546
 TODBCServer.cxx:547
 TODBCServer.cxx:548
 TODBCServer.cxx:549
 TODBCServer.cxx:550
 TODBCServer.cxx:551
 TODBCServer.cxx:552
 TODBCServer.cxx:553
 TODBCServer.cxx:554
 TODBCServer.cxx:555
 TODBCServer.cxx:556
 TODBCServer.cxx:557
 TODBCServer.cxx:558
 TODBCServer.cxx:559
 TODBCServer.cxx:560
 TODBCServer.cxx:561
 TODBCServer.cxx:562
 TODBCServer.cxx:563
 TODBCServer.cxx:564
 TODBCServer.cxx:565
 TODBCServer.cxx:566
 TODBCServer.cxx:567
 TODBCServer.cxx:568
 TODBCServer.cxx:569
 TODBCServer.cxx:570
 TODBCServer.cxx:571
 TODBCServer.cxx:572
 TODBCServer.cxx:573
 TODBCServer.cxx:574
 TODBCServer.cxx:575
 TODBCServer.cxx:576
 TODBCServer.cxx:577
 TODBCServer.cxx:578
 TODBCServer.cxx:579
 TODBCServer.cxx:580
 TODBCServer.cxx:581
 TODBCServer.cxx:582
 TODBCServer.cxx:583
 TODBCServer.cxx:584
 TODBCServer.cxx:585
 TODBCServer.cxx:586
 TODBCServer.cxx:587
 TODBCServer.cxx:588
 TODBCServer.cxx:589
 TODBCServer.cxx:590
 TODBCServer.cxx:591
 TODBCServer.cxx:592
 TODBCServer.cxx:593
 TODBCServer.cxx:594
 TODBCServer.cxx:595
 TODBCServer.cxx:596
 TODBCServer.cxx:597
 TODBCServer.cxx:598
 TODBCServer.cxx:599
 TODBCServer.cxx:600
 TODBCServer.cxx:601
 TODBCServer.cxx:602
 TODBCServer.cxx:603
 TODBCServer.cxx:604
 TODBCServer.cxx:605
 TODBCServer.cxx:606
 TODBCServer.cxx:607
 TODBCServer.cxx:608
 TODBCServer.cxx:609
 TODBCServer.cxx:610
 TODBCServer.cxx:611
 TODBCServer.cxx:612
 TODBCServer.cxx:613
 TODBCServer.cxx:614
 TODBCServer.cxx:615
 TODBCServer.cxx:616
 TODBCServer.cxx:617
 TODBCServer.cxx:618
 TODBCServer.cxx:619
 TODBCServer.cxx:620
 TODBCServer.cxx:621
 TODBCServer.cxx:622
 TODBCServer.cxx:623
 TODBCServer.cxx:624
 TODBCServer.cxx:625
 TODBCServer.cxx:626
 TODBCServer.cxx:627
 TODBCServer.cxx:628
 TODBCServer.cxx:629
 TODBCServer.cxx:630
 TODBCServer.cxx:631
 TODBCServer.cxx:632
 TODBCServer.cxx:633
 TODBCServer.cxx:634
 TODBCServer.cxx:635
 TODBCServer.cxx:636
 TODBCServer.cxx:637
 TODBCServer.cxx:638
 TODBCServer.cxx:639
 TODBCServer.cxx:640
 TODBCServer.cxx:641
 TODBCServer.cxx:642
 TODBCServer.cxx:643
 TODBCServer.cxx:644
 TODBCServer.cxx:645
 TODBCServer.cxx:646
 TODBCServer.cxx:647
 TODBCServer.cxx:648
 TODBCServer.cxx:649
 TODBCServer.cxx:650
 TODBCServer.cxx:651
 TODBCServer.cxx:652
 TODBCServer.cxx:653
 TODBCServer.cxx:654
 TODBCServer.cxx:655
 TODBCServer.cxx:656
 TODBCServer.cxx:657
 TODBCServer.cxx:658
 TODBCServer.cxx:659
 TODBCServer.cxx:660
 TODBCServer.cxx:661
 TODBCServer.cxx:662
 TODBCServer.cxx:663
 TODBCServer.cxx:664
 TODBCServer.cxx:665
 TODBCServer.cxx:666
 TODBCServer.cxx:667
 TODBCServer.cxx:668
 TODBCServer.cxx:669
 TODBCServer.cxx:670
 TODBCServer.cxx:671
 TODBCServer.cxx:672
 TODBCServer.cxx:673
 TODBCServer.cxx:674
 TODBCServer.cxx:675
 TODBCServer.cxx:676
 TODBCServer.cxx:677
 TODBCServer.cxx:678
 TODBCServer.cxx:679
 TODBCServer.cxx:680
 TODBCServer.cxx:681
 TODBCServer.cxx:682
 TODBCServer.cxx:683
 TODBCServer.cxx:684
 TODBCServer.cxx:685
 TODBCServer.cxx:686
 TODBCServer.cxx:687
 TODBCServer.cxx:688
 TODBCServer.cxx:689
 TODBCServer.cxx:690
 TODBCServer.cxx:691
 TODBCServer.cxx:692
 TODBCServer.cxx:693
 TODBCServer.cxx:694
 TODBCServer.cxx:695
 TODBCServer.cxx:696
 TODBCServer.cxx:697
 TODBCServer.cxx:698
 TODBCServer.cxx:699
 TODBCServer.cxx:700
 TODBCServer.cxx:701
 TODBCServer.cxx:702
 TODBCServer.cxx:703
 TODBCServer.cxx:704
 TODBCServer.cxx:705
 TODBCServer.cxx:706
 TODBCServer.cxx:707
 TODBCServer.cxx:708
 TODBCServer.cxx:709
 TODBCServer.cxx:710
 TODBCServer.cxx:711
 TODBCServer.cxx:712
 TODBCServer.cxx:713
 TODBCServer.cxx:714
 TODBCServer.cxx:715
 TODBCServer.cxx:716
 TODBCServer.cxx:717
 TODBCServer.cxx:718
 TODBCServer.cxx:719
 TODBCServer.cxx:720
 TODBCServer.cxx:721
 TODBCServer.cxx:722
 TODBCServer.cxx:723
 TODBCServer.cxx:724
 TODBCServer.cxx:725
 TODBCServer.cxx:726
 TODBCServer.cxx:727
 TODBCServer.cxx:728
 TODBCServer.cxx:729
 TODBCServer.cxx:730
 TODBCServer.cxx:731
 TODBCServer.cxx:732
 TODBCServer.cxx:733
 TODBCServer.cxx:734
 TODBCServer.cxx:735
 TODBCServer.cxx:736
 TODBCServer.cxx:737
 TODBCServer.cxx:738
 TODBCServer.cxx:739
 TODBCServer.cxx:740
 TODBCServer.cxx:741
 TODBCServer.cxx:742
 TODBCServer.cxx:743
 TODBCServer.cxx:744
 TODBCServer.cxx:745
 TODBCServer.cxx:746
 TODBCServer.cxx:747
 TODBCServer.cxx:748
 TODBCServer.cxx:749
 TODBCServer.cxx:750
 TODBCServer.cxx:751
 TODBCServer.cxx:752
 TODBCServer.cxx:753
 TODBCServer.cxx:754
 TODBCServer.cxx:755
 TODBCServer.cxx:756
 TODBCServer.cxx:757
 TODBCServer.cxx:758
 TODBCServer.cxx:759
 TODBCServer.cxx:760
 TODBCServer.cxx:761
 TODBCServer.cxx:762
 TODBCServer.cxx:763
 TODBCServer.cxx:764
 TODBCServer.cxx:765
 TODBCServer.cxx:766
 TODBCServer.cxx:767
 TODBCServer.cxx:768
 TODBCServer.cxx:769
 TODBCServer.cxx:770
 TODBCServer.cxx:771
 TODBCServer.cxx:772
 TODBCServer.cxx:773
 TODBCServer.cxx:774
 TODBCServer.cxx:775
 TODBCServer.cxx:776
 TODBCServer.cxx:777
 TODBCServer.cxx:778
 TODBCServer.cxx:779
 TODBCServer.cxx:780
 TODBCServer.cxx:781
 TODBCServer.cxx:782
 TODBCServer.cxx:783
 TODBCServer.cxx:784
 TODBCServer.cxx:785
 TODBCServer.cxx:786
 TODBCServer.cxx:787
 TODBCServer.cxx:788
 TODBCServer.cxx:789
 TODBCServer.cxx:790
 TODBCServer.cxx:791
 TODBCServer.cxx:792
 TODBCServer.cxx:793
 TODBCServer.cxx:794
 TODBCServer.cxx:795
 TODBCServer.cxx:796
 TODBCServer.cxx:797
 TODBCServer.cxx:798
 TODBCServer.cxx:799
 TODBCServer.cxx:800
 TODBCServer.cxx:801
 TODBCServer.cxx:802
 TODBCServer.cxx:803
 TODBCServer.cxx:804
 TODBCServer.cxx:805
 TODBCServer.cxx:806
 TODBCServer.cxx:807
 TODBCServer.cxx:808
 TODBCServer.cxx:809
 TODBCServer.cxx:810
 TODBCServer.cxx:811
 TODBCServer.cxx:812
 TODBCServer.cxx:813
 TODBCServer.cxx:814
 TODBCServer.cxx:815
 TODBCServer.cxx:816
 TODBCServer.cxx:817
 TODBCServer.cxx:818
 TODBCServer.cxx:819
 TODBCServer.cxx:820
 TODBCServer.cxx:821
 TODBCServer.cxx:822
 TODBCServer.cxx:823
 TODBCServer.cxx:824
 TODBCServer.cxx:825
 TODBCServer.cxx:826
 TODBCServer.cxx:827
 TODBCServer.cxx:828
 TODBCServer.cxx:829
 TODBCServer.cxx:830
 TODBCServer.cxx:831
 TODBCServer.cxx:832
 TODBCServer.cxx:833
 TODBCServer.cxx:834
 TODBCServer.cxx:835
 TODBCServer.cxx:836
 TODBCServer.cxx:837
 TODBCServer.cxx:838
 TODBCServer.cxx:839
 TODBCServer.cxx:840
 TODBCServer.cxx:841
 TODBCServer.cxx:842
 TODBCServer.cxx:843
 TODBCServer.cxx:844
 TODBCServer.cxx:845
 TODBCServer.cxx:846
 TODBCServer.cxx:847
 TODBCServer.cxx:848
 TODBCServer.cxx:849
 TODBCServer.cxx:850
 TODBCServer.cxx:851
 TODBCServer.cxx:852
 TODBCServer.cxx:853
 TODBCServer.cxx:854
 TODBCServer.cxx:855
 TODBCServer.cxx:856
 TODBCServer.cxx:857
 TODBCServer.cxx:858
 TODBCServer.cxx:859
 TODBCServer.cxx:860
 TODBCServer.cxx:861
 TODBCServer.cxx:862
 TODBCServer.cxx:863
 TODBCServer.cxx:864
 TODBCServer.cxx:865
 TODBCServer.cxx:866
 TODBCServer.cxx:867
 TODBCServer.cxx:868
 TODBCServer.cxx:869
 TODBCServer.cxx:870
 TODBCServer.cxx:871
 TODBCServer.cxx:872
 TODBCServer.cxx:873