Diff for /sql/oracle/parser3oracle.C between versions 1.19 and 1.52

version 1.19, 2002/02/08 08:32:41 version 1.52, 2004/03/04 09:10:13
Line 1 Line 1
 /** @file  /** @file
         Parser Oracle driver.          Parser Oracle driver.
   
         Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)          Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com)
   
         Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
Line 38  inline int max(int a, int b) { return a> Line 38  inline int max(int a, int b) { return a>
 inline int min(int a, int b){ return a<b?a:b; }  inline int min(int a, int b){ return a<b?a:b; }
 #endif  #endif
   
 /// @test setenv version memory. maybe key/value needs ::malloc?  #if _MSC_VER
   // interaction between '_setjmp' and C++ object destruction is non-portable
   // but we forced to do that under HPUX
   #pragma warning(disable:4611)   
   #endif
   
   /// @todo small memory leaks here
 static int pa_setenv(const char *name, const char *value, bool do_append) {  static int pa_setenv(const char *name, const char *value, bool do_append) {
         const char *prev_value=0;          const char *prev_value=0;
         if(do_append)          if(do_append)
Line 68  static int pa_setenv(const char *name, c Line 74  static int pa_setenv(const char *name, c
 #else   #else 
         //#ifdef HAVE_SETENV          //#ifdef HAVE_SETENV
         if(value) {          if(value) {
                 char *buf;  
                 if(prev_value) {                  if(prev_value) {
                         // MEM_LEAK_HERE                          // MEM_LEAK_HERE
                         buf=(char *)::malloc(strlen(prev_value)                          char *buf=(char *)::malloc(strlen(prev_value)
                                 +strlen(value)                                  +strlen(value)
                                 +1);                                  +1);
                         strcpy(buf, prev_value);                          strcpy(buf, prev_value);
                         strcat(buf, value);                          strcat(buf, value);
                 } else                          value=buf;
                         buf=value;                  }
   
                 return setenv(name, buf, 1/*overwrite*/);                   return setenv(name, value, 1/*overwrite*/); 
         } else {          } else {
                 unsetenv(name);                  unsetenv(name);
                 return 0;                  return 0;
Line 105  static char *lsplit(char **string_ref, c Line 110  static char *lsplit(char **string_ref, c
     return result;      return result;
 }  }
   
 static const char *options2env(char *options) {  
         while(options) {  
                 if(char *key=lsplit(&options, '&')) {  
                         if(*key) {  
                                 if(char *value=lsplit(key, '=')) {  
                                         bool do_append=key[strlen(key)-1]=='+'; // PATH+=  
                                         if(do_append)  
                                                 key[strlen(key)-1]=0; // remove trailing +  
                                         if(strncmp(key, "ORACLE_", 7)==0  // ORACLE_HOME & co  
                                                 || strncmp(key, "ORA_", 4)==0 // ORA_ENCRYPT_LOGIN & co  
                                                 || strncmp(key, "NLS_", 4)==0 // NLS_LANG & co  
                                                 || do_append  
                                                 ) {  
                                                 if(pa_setenv(key, value, do_append)!=0)  
                                                         return "problem changing process environment" /*key*/;  
                                         } else  
                                                 return "unknown option (option must start with ORACLE_, ORA_ or NLS_)" /*key*/;  
                                 } else   
                                         return "option without =value" /*key*/;  
                         }  
                 }  
         }  
         return 0;  
 }  
   
 #ifndef DOXYGEN  #ifndef DOXYGEN
 struct OracleSQL_connection_struct {  struct Connection {
           SQL_Driver_services *services;
   
         jmp_buf mark; char error[MAX_STRING];          jmp_buf mark; char error[MAX_STRING];
           SQL_Error sql_error;
         OCIEnv *envhp;          OCIEnv *envhp;
         OCIServer *srvhp;          OCIServer *srvhp;
         OCIError *errhp;          OCIError *errhp;
         OCISvcCtx *svchp;          OCISvcCtx *svchp;
         OCISession *usrhp;          OCISession *usrhp;
   
           char* fetch_buffers[MAX_COLS];
   
           struct Options {
                   bool bLowerCaseColumnNames;
                   const char* cstrClientCharset;
           } options;
 };  };
   
 struct OracleSQL_query_lobs {  struct OracleSQL_query_lobs {
Line 150  struct OracleSQL_query_lobs { Line 140  struct OracleSQL_query_lobs {
                 int count;                  int count;
         };          };
         struct cbf_context_struct {          struct cbf_context_struct {
                 SQL_Driver_services *services;                  Connection *connection;
                 OracleSQL_connection_struct *cs;  
                 return_rows *rows;                  return_rows *rows;
         };          };
         struct Item {          struct Item {
Line 166  struct OracleSQL_query_lobs { Line 155  struct OracleSQL_query_lobs {
 #endif  #endif
   
 // forwards  // forwards
 void check(  void check(Connection& connection, const char *step, sword status);
                    SQL_Driver_services& services, OracleSQL_connection_struct &cs,   void check(Connection& connection, bool error);
                    const char *step, sword status);  
 static sb4 cbf_no_data(  static sb4 cbf_no_data(
                                            dvoid *ctxp,                                              dvoid *ctxp, 
                                            OCIBind *bindp,                                              OCIBind *bindp, 
Line 185  static sb4 cbf_get_data(dvoid *ctxp, Line 173  static sb4 cbf_get_data(dvoid *ctxp,
                                                 ub1 *piecep,                                                   ub1 *piecep, 
                                                 dvoid **indpp,                                                   dvoid **indpp, 
                                                 ub2 **rcodepp);                                                  ub2 **rcodepp);
 void tolower(char *out, const char *in, size_t size);  static void tolower(char *out, const char *in, size_t size);
   static void toupper(char *out, const char *in, size_t size);
   
   static const char *options2env(char *s, Connection::Options* options) {
           while(s) {
                   if(char *key=lsplit(&s, '&')) {
                           if(*key) {
                                   if(char *value=lsplit(key, '=')) {
                                           if( strcmp( key, "ClientCharset" ) == 0 ) {
                                                   if(options) {
                                                           toupper(value, value, strlen(value));
                                                           options->cstrClientCharset = value;
                                                   }
                                                   continue;
                                           }
   
                                           if( strcmp( key, "LowerCaseColumnNames" ) == 0 ) {
                                                   if(options)
                                                           options->bLowerCaseColumnNames = atoi(value)!=0;
                                                   continue;
                                           }
   
                                           bool do_append=key[strlen(key)-1]=='+'; // PATH+=
                                           if(do_append)
                                                   key[strlen(key)-1]=0; // remove trailing +
                                           if(strncmp(key, "ORACLE_", 7)==0  // ORACLE_HOME & co
                                                   || strncmp(key, "ORA_", 4)==0 // ORA_ENCRYPT_LOGIN & co
                                                   || strncmp(key, "NLS_", 4)==0 // NLS_LANG & co
                                                   || do_append
                                                   ) {
                                                   if(pa_setenv(key, value, do_append)!=0)
                                                           return "problem changing process environment" /*key*/;
                                           } else
                                                   return "unknown option" /*key*/;
                                   } else 
                                           return "option without =value" /*key*/;
                           }
                   }
           }
           return 0;
   }
   
 /**  /**
         OracleSQL server driver          OracleSQL server driver
         @test NLS_LANG=AMERICAN_AMERICA.CL8MSWIN1251  
 */  */
 class OracleSQL_Driver : public SQL_Driver {  class OracleSQL_Driver : public SQL_Driver {
 public:  public:
Line 208  public: Line 235  public:
                 const char *error=dlopen_file_spec?                  const char *error=dlopen_file_spec?
                         dlink(dlopen_file_spec):"client library column is empty";                          dlink(dlopen_file_spec):"client library column is empty";
                 if(!error) {                  if(!error) {
                         error=options2env(options);                          error=options2env(options, 0);
   
                         if(!error)                          if(!error)
                                 OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0,                                   OCIInitialize((ub4)OCI_THREADED/*| OCI_OBJECT*/, (dvoid *)0, 
Line 234  public: Line 261  public:
         void connect(          void connect(
                 char *used_only_in_connect_url,                   char *used_only_in_connect_url, 
                 SQL_Driver_services& services,                   SQL_Driver_services& services, 
                 void **connection ///< output: OracleSQL_connection_struct *                  void **connection_ref ///< output: Connection *
                 ) {                  ) {
                 // connections are cross-request, do not use services._alloc [linked with request]                  Connection& connection=*(Connection  *)services.malloc(sizeof(Connection));
                 OracleSQL_connection_struct &cs=                  connection.services=&services;
                         *(OracleSQL_connection_struct  *)::calloc(sizeof(OracleSQL_connection_struct), 1);                  connection.options.bLowerCaseColumnNames = true;
                   *connection_ref=&connection;
   
                 char *user=used_only_in_connect_url;                  char *user=used_only_in_connect_url;
                 char *service=lsplit(user, '@');                  char *service=lsplit(user, '@');
Line 248  public: Line 276  public:
                 if(!(user && pwd && service))                  if(!(user && pwd && service))
                         services._throw("mailformed connect part, must be 'user:pass@service'");                          services._throw("mailformed connect part, must be 'user:pass@service'");
   
                 if(const char *error=options2env(options))                  if(const char *error=options2env(options, &connection.options))
                         services._throw(error);                          services._throw(error);
   
                 if(setjmp(cs.mark))                  if(setjmp(connection.mark))
                         services._throw(cs.error);                          services._throw(connection.error);
   
                 // Allocate and initialize OCIError handle, attempt #1                  // Allocate and initialize OCIError handle, attempt #1
                 /*                  /*
Line 270  public: Line 298  public:
                         think, this is some sort of backward compatibility wonder.                          think, this is some sort of backward compatibility wonder.
                         leaving as it is, and without check()                          leaving as it is, and without check()
                 */                  */
                 OCIHandleAlloc((dvoid *)NULL, (dvoid **) &cs.envhp, (ub4)OCI_HTYPE_ENV, 0, 0);                  OCIHandleAlloc((dvoid *)NULL, (dvoid **) &connection.envhp, (ub4)OCI_HTYPE_ENV, 0, 0);
                 // Initialize an environment handle, attempt #2                  // Initialize an environment handle, attempt #2
                 check(services, cs, "EnvInit", OCIEnvInit(                  check(connection, "EnvInit", OCIEnvInit(
                         &cs.envhp, (ub4)OCI_DEFAULT, 0, 0));                                      &connection.envhp, (ub4)OCI_DEFAULT, 0, 0));            
                 // Allocate and initialize OCIError handle                  // Allocate and initialize OCIError handle
                 check(services, cs, "HandleAlloc errhp", OCIHandleAlloc(                   check(connection, "HandleAlloc errhp", OCIHandleAlloc( 
                         (dvoid *)cs.envhp, (dvoid **) &cs.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0));                          (dvoid *)connection.envhp, (dvoid **) &connection.errhp, (ub4)OCI_HTYPE_ERROR, 0, 0));
                 // Allocate and initialize OCIServer handle                  // Allocate and initialize OCIServer handle
                 check(services, cs, "HandleAlloc srvhp", OCIHandleAlloc(                   check(connection, "HandleAlloc srvhp", OCIHandleAlloc( 
                         (dvoid *)cs.envhp, (dvoid **) &cs.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0));                                   (dvoid *)connection.envhp, (dvoid **) &connection.srvhp, (ub4)OCI_HTYPE_SERVER, 0, 0));         
                 // Attach to a 'service'; initialize server context handle                    // Attach to a 'service'; initialize server context handle  
                 check(services, cs, "ServerAttach", OCIServerAttach(                   check(connection, "ServerAttach", OCIServerAttach( 
                         cs.srvhp, cs.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT));                          connection.srvhp, connection.errhp, (text *)service, (sb4)strlen(service), (ub4)OCI_DEFAULT));
                 // Allocate and initialize OCISvcCtx handle                  // Allocate and initialize OCISvcCtx handle
                 check(services, cs, "HandleAlloc svchp", OCIHandleAlloc(                   check(connection, "HandleAlloc svchp", OCIHandleAlloc( 
                         (dvoid *)cs.envhp, (dvoid **) &cs.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0));                                   (dvoid *)connection.envhp, (dvoid **) &connection.svchp, (ub4)OCI_HTYPE_SVCCTX, 0, 0));         
                 // set attribute server context in the service context                  // set attribute server context in the service context
                 check(services, cs, "AttrSet server-service", OCIAttrSet(                   check(connection, "AttrSet server-service", OCIAttrSet( 
                         (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX,                           (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX, 
                         (dvoid *)cs.srvhp, (ub4)0,                           (dvoid *)connection.srvhp, (ub4)0, 
                         (ub4)OCI_ATTR_SERVER, (OCIError *)cs.errhp));                                     (ub4)OCI_ATTR_SERVER, (OCIError *)connection.errhp));           
                 // allocate a user context handle                  // allocate a user context handle
                 check(services, cs, "HandleAlloc usrhp", OCIHandleAlloc(                  check(connection, "HandleAlloc usrhp", OCIHandleAlloc(
                         (dvoid *)cs.envhp, (dvoid **)&cs.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0));                          (dvoid *)connection.envhp, (dvoid **)&connection.usrhp, (ub4)OCI_HTYPE_SESSION, 0, 0));
                 // set 'user' name                  // set 'user' name
                 check(services, cs, "AttrSet user-session", OCIAttrSet(                  check(connection, "AttrSet user-session", OCIAttrSet(
                         (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION,                           (dvoid *)connection.usrhp, (ub4)OCI_HTYPE_SESSION, 
                         (dvoid *)user, (ub4)strlen(user),                           (dvoid *)user, (ub4)strlen(user), 
                         OCI_ATTR_USERNAME, cs.errhp));                                    OCI_ATTR_USERNAME, connection.errhp));          
                 // set 'pwd' password                  // set 'pwd' password
                 check(services, cs, "AttrSet pwd-session", OCIAttrSet(                  check(connection, "AttrSet pwd-session", OCIAttrSet(
                         (dvoid *)cs.usrhp, (ub4)OCI_HTYPE_SESSION,                           (dvoid *)connection.usrhp, (ub4)OCI_HTYPE_SESSION, 
                         (dvoid *)pwd, (ub4)strlen(pwd),                           (dvoid *)pwd, (ub4)strlen(pwd), 
                         OCI_ATTR_PASSWORD, cs.errhp));                          OCI_ATTR_PASSWORD, connection.errhp));
                 // Authenticate a user                    // Authenticate a user  
                 check(services, cs, "SessionBegin", OCISessionBegin(                  check(connection, "SessionBegin", OCISessionBegin(
                         cs.svchp, cs.errhp, cs.usrhp,                           connection.svchp, connection.errhp, connection.usrhp, 
                         OCI_CRED_RDBMS, OCI_DEFAULT));                          OCI_CRED_RDBMS, OCI_DEFAULT));
                 // remember connection in session                  // remember connection in session
                 check(services, cs, "AttrSet service-session", OCIAttrSet(                  check(connection, "AttrSet service-session", OCIAttrSet(
                         (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX,                           (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX, 
                         (dvoid *)cs.usrhp, (ub4)0,                           (dvoid *)connection.usrhp, (ub4)0, 
                         OCI_ATTR_SESSION, cs.errhp));                          OCI_ATTR_SESSION, connection.errhp));
   
                 // return created connection  
                 *(OracleSQL_connection_struct **)connection=&cs;  
         }          }
         void disconnect(void *connection) {          void disconnect(void *aconnection) {
             OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;              Connection& connection=*static_cast<Connection *>(aconnection);
   
                   // free fetch buffers
                   for(int i=0; i<MAX_COLS; i++) {
                           if(void* fetch_buffer=connection.fetch_buffers[i])
                                   ::free(fetch_buffer);
                           else
                                   break;
                   }                       
   
                 // Terminate a user session                  // Terminate a user session
                 OCISessionEnd(                  OCISessionEnd(
                         cs.svchp, cs.errhp, cs.usrhp, (ub4)OCI_DEFAULT);                          connection.svchp, connection.errhp, connection.usrhp, (ub4)OCI_DEFAULT);
                 // Detach from a server; uninitialize server context handle                  // Detach from a server; uninitialize server context handle
                 OCIServerDetach(                  OCIServerDetach(
                         cs.srvhp, cs.errhp, (ub4)OCI_DEFAULT);                          connection.srvhp, connection.errhp, (ub4)OCI_DEFAULT);
                 // Free a previously allocated handles                  // Free a previously allocated handles
                 /*                   /* 
                 oci will free them up as belonging to env                  oci will free them up as belonging to env
                 OCIHandleFree(                  OCIHandleFree(
                         (dvoid *)cs.srvhp, (ub4)OCI_HTYPE_SERVER);                          (dvoid *)connection.srvhp, (ub4)OCI_HTYPE_SERVER);
                 OCIHandleFree(                  OCIHandleFree(
                         (dvoid *)cs.svchp, (ub4)OCI_HTYPE_SVCCTX);                          (dvoid *)connection.svchp, (ub4)OCI_HTYPE_SVCCTX);
                 OCIHandleFree(                  OCIHandleFree(
                         (dvoid *)cs.errhp, (ub4)OCI_HTYPE_ERROR);                          (dvoid *)connection.errhp, (ub4)OCI_HTYPE_ERROR);
                 */                  */
                 OCIHandleFree(                  OCIHandleFree(
                         (dvoid *)cs.envhp, (ub4)OCI_HTYPE_ENV);                          (dvoid *)connection.envhp, (ub4)OCI_HTYPE_ENV);
   
                 // connections are cross-request, do not use services._alloc [linked with request]                  // connections are cross-request, do not use services._alloc [linked with request]
                 ::free(&cs);                  ::free(&connection);
         }          }
         void commit(SQL_Driver_services& services, void *connection) {          void commit(void *aconnection) {
             OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;              Connection& connection=*static_cast<Connection *>(aconnection);
                 if(setjmp(cs.mark))                  if(setjmp(connection.mark))
                         services._throw(cs.error);                          connection.services->_throw(connection.error);
   
                 check(services, cs, "commit", OCITransCommit(cs.svchp, cs.errhp, 0));                  check(connection, "commit", OCITransCommit(connection.svchp, connection.errhp, 0));
         }          }
         void rollback(SQL_Driver_services& services, void *connection) {          void rollback(void *aconnection) {
             OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;              Connection& connection=*static_cast<Connection *>(aconnection);
                 if(setjmp(cs.mark))                  if(setjmp(connection.mark))
                         services._throw(cs.error);                          connection.services->_throw(connection.error);
   
                 check(services, cs, "rollback", OCITransRollback(cs.svchp, cs.errhp, 0));                  // sometimes rollback is done in context when this yields error which masks previous error
                   // consider consequent errors not very important to report, reporting first one
                   /*check(connection, "rollback", */OCITransRollback(connection.svchp, connection.errhp, 0)/*)*/;
         }          }
   
         bool ping(SQL_Driver_services&, void *connection) {          bool ping(void* /*connection*/) {
                 // maybe OCIServerVersion?                  // maybe OCIServerVersion?
                 // select 0 from dual                  // select 0 from dual
                 return true;                  return true;
         }          }
   
         unsigned int quote(          const char* quote(void *aconnection,
                 SQL_Driver_services&, void *,                   const char *from, unsigned int length) 
                 char *to, const char *from, unsigned int length) {          {
                 if(to) { // store mode                  Connection& connection=*static_cast<Connection *>(aconnection);
                         unsigned int result=length;                  char *result=(char*)connection.services->malloc_atomic(length*2+1);
                         while(length--) {                  char *to=result;
                                 switch(*from) {                  while(length--) {
                                 case '\'': // "'" -> "''"                          switch(*from) {
                                         *to++='\''; result++;                          case '\'': // "'" -> "''"
                                         break;                                  *to++='\'';
                                 }                                  break;
                                 *to++=*from++;  
                         }                          }
                         return result;                          *to++=*from++;
                 } else // estimate mode                  }
                         return length*2;                  *to=0;
                   return result;
         }          }
         void query(          void query(void *aconnection, 
                 SQL_Driver_services& services, void *connection,   
                 const char *astatement, unsigned long offset, unsigned long limit,                   const char *astatement, unsigned long offset, unsigned long limit, 
                 SQL_Driver_query_event_handlers& handlers) {                  SQL_Driver_query_event_handlers& handlers) 
                           {
                 OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;                  Connection& connection=*static_cast<Connection *>(aconnection);
                 OracleSQL_query_lobs lobs={{0}, 0};                  OracleSQL_query_lobs lobs={{0}, 0};
                 OCIStmt *stmthp=0;                  OCIStmt *stmthp=0;
   
                   SQL_Driver_services& services=*connection.services;
   
                   // transcode from $request:charset to connect-string?client_charset
                   size_t transcoded_statement_size;
                   if(const char* cstrClientCharset=connection.options.cstrClientCharset)
                           services.transcode(astatement, strlen(astatement),
                                   astatement, transcoded_statement_size,
                                   services.request_charset(),
                                   cstrClientCharset);
   
                 bool failed=false;                  bool failed=false;
                 if(setjmp(cs.mark)) {                  if(setjmp(connection.mark)) {
                         failed=true;                          failed=true;
                         goto cleanup;                          goto cleanup;
                 } else {                  } else {
                         const char *statement=preprocess_statement(services, cs,                           const char *statement=preprocess_statement(connection, astatement, lobs);
                                 astatement, lobs);  
   
                         check(services, cs, "HandleAlloc STMT", OCIHandleAlloc(                           check(connection, "HandleAlloc STMT", OCIHandleAlloc( 
                                 (dvoid *)cs.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0));                                  (dvoid *)connection.envhp, (dvoid **) &stmthp, (ub4)OCI_HTYPE_STMT, 0, 0));
                         check(services, cs, "syntax",                           check(connection, "syntax", 
                                 OCIStmtPrepare(stmthp, cs.errhp, (unsigned char *)statement,                                   OCIStmtPrepare(stmthp, connection.errhp, (unsigned char *)statement, 
                                 (ub4)strlen((char *)statement),                                   (ub4)strlen((char *)statement), 
                                 (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT));                                  (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT));
                         {                          {
                                 for(int i=0; i<lobs.count; i++) {                                  for(int i=0; i<lobs.count; i++) {
                                         check(services, cs, "alloc output var desc", OCIDescriptorAlloc(                                          check(connection, "alloc output var desc", OCIDescriptorAlloc(
                                                 (dvoid *)cs.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0));                                                  (dvoid *)connection.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0));
   
                                         check(services, cs, "bind output", OCIBindByPos(stmthp,                                           check(connection, "bind output", OCIBindByPos(stmthp, 
                                                 &lobs.items[i].bind, cs.errhp,                                                   &lobs.items[i].bind, connection.errhp, 
                                                 (ub4)1+i,                                                   (ub4)1+i, 
                                                 (dvoid *)&lobs.items[i].locator,                                                   (dvoid *)&lobs.items[i].locator, 
                                                 (sword)sizeof (lobs.items[i].locator), SQLT_CLOB, (dvoid *)0,                                                   (sword)sizeof (lobs.items[i].locator), SQLT_CLOB, (dvoid *)0, 
                                                 (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DATA_AT_EXEC));                                                  (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DATA_AT_EXEC));
   
                                         lobs.items[i].rows.count=0;                                          lobs.items[i].rows.count=0;
                                         OracleSQL_query_lobs::cbf_context_struct cbf_context={                                          OracleSQL_query_lobs::cbf_context_struct cbf_context={&connection, &lobs.items[i].rows};
                                                 &services, &cs, &lobs.items[i].rows};                                          check(connection, "bind dynamic", OCIBindDynamic(
                                         check(services, cs, "bind dynamic", OCIBindDynamic(                                                  lobs.items[i].bind, connection.errhp, 
                                                 lobs.items[i].bind, cs.errhp,   
                                                 (dvoid *) &cbf_context, cbf_no_data,                                                   (dvoid *) &cbf_context, cbf_no_data, 
                                                 (dvoid *) &cbf_context, cbf_get_data));                                                  (dvoid *) &cbf_context, cbf_get_data));
                                 }                                  }
                         }                          }
   
                         execute_prepared(services, cs,                           execute_prepared(connection, 
                                 statement, stmthp, lobs,                                   statement, stmthp, lobs, 
                                 offset, limit, handlers);                                  offset, limit, handlers);
                 }                  }
Line 444  cleanup: // no check call after this poi Line 487  cleanup: // no check call after this poi
                 if(stmthp)                  if(stmthp)
                         OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT);                          OCIHandleFree((dvoid *)stmthp, (ub4)OCI_HTYPE_STMT);
   
                 if(failed)                  if(failed) {
                         services._throw(cs.error);                          if(connection.sql_error.defined())
                                   services._throw(connection.sql_error);
                           services._throw(connection.error);
                   }
         }          }
   
 private: // private funcs  private: // private funcs
   
         const char *preprocess_statement(SQL_Driver_services& services, OracleSQL_connection_struct &cs,           const char *preprocess_statement(Connection& connection, 
                 const char *astatement, OracleSQL_query_lobs &lobs) {                  const char *astatement, OracleSQL_query_lobs &lobs) {
                 size_t statement_size=strlen(astatement);                  size_t statement_size=strlen(astatement);
                   SQL_Driver_services& services=*connection.services;
   
                 char *result=(char *)services.malloc(statement_size                  char *result=(char *)services.malloc_atomic(statement_size
                         +MAX_STRING // in case of short 'strings'                          +MAX_STRING // in case of short 'strings'
                         +11/* returning */+6/* into */+(MAX_LOB_NAME_LENGTH+2/*:, */)*2/*ret into*/*MAX_IN_LOBS                          +11/* returning */+6/* into */+(MAX_LOB_NAME_LENGTH+2/*:, */)*2/*ret into*/*MAX_IN_LOBS
                         +1);                          +1);
Line 467  private: // private funcs Line 514  private: // private funcs
                                 o[0]=='/' &&                                  o[0]=='/' &&
                                 o[1]=='*' &&                                   o[1]=='*' && 
                                 o[2]=='*') { // name start                                  o[2]=='*') { // name start
                                   const char* saved_o=o;
                                 o+=3;                                  o+=3;
                                 const char *name_begin=o;                                  const char *name_begin=o;
                                 while(*o)                                  while(*o)
Line 475  private: // private funcs Line 523  private: // private funcs
                                                 o[1]=='*' &&                                                  o[1]=='*' &&
                                                 o[2]=='/' &&                                                  o[2]=='/' &&
                                                 o[3]=='\'') { // name end                                                  o[3]=='\'') { // name end
                                                   saved_o=0; // found, marking that
                                                 const char *name_end=o;                                                  const char *name_end=o;
                                                 o+=4;                                                  o+=4;
                                                 OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++];                                                  OracleSQL_query_lobs::Item &item=lobs.items[lobs.count++];
                                                 item.name_ptr=name_begin; item.name_size=name_end-name_begin;                                                  item.name_ptr=name_begin; item.name_size=name_end-name_begin;
                                                 item.data_ptr=(char *)services.malloc(statement_size/*max*/); item.data_size=0;                                                  item.data_ptr=(char *)services.malloc_atomic(statement_size/*max*/); item.data_size=0;
   
                                                 const char *start=o;                                                  const char *start=o;
                                                 bool escaped=false;                                                  bool escaped=false;
Line 506  private: // private funcs Line 555  private: // private funcs
                                                 break;                                                  break;
                                         } else                                          } else
                                                 o++; // /**skip**/'xxx'                                                  o++; // /**skip**/'xxx'
                                   if(saved_o) {
                                           o=saved_o;
                                           *n++=*o++;
                                   }
                         } else                          } else
                                 *n++=*o++;                                  *n++=*o++;
                 }                  }
Line 518  private: // private funcs Line 571  private: // private funcs
                                 if(i)                                  if(i)
                                         *n++=',';                                          *n++=',';
                                 n+=sprintf(n, "%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);                                  n+=sprintf(n, "%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
                                 /*memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size);  
                                 n+=lobs.items[i].name_size;*/  
                         }                          }
                         n+=sprintf(n, " into ");                          n+=sprintf(n, " into ");
                         for(i=0; i<lobs.count; i++) {                          for(i=0; i<lobs.count; i++) {
                                 if(i)                                  if(i)
                                         *n++='x';                                          *n++=',';
                                 n+=sprintf(n, ":%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);                                  n+=sprintf(n, ":%.*s", lobs.items[i].name_size, lobs.items[i].name_ptr);
                                 /**n++=':';  
                                 memcpy(n, lobs.items[i].name_ptr, lobs.items[i].name_size);  
                                 n+=lobs.items[i].name_size;*/  
                         }                          }
                 }                  }
   
Line 536  private: // private funcs Line 584  private: // private funcs
         }          }
   
         void execute_prepared(          void execute_prepared(
                 SQL_Driver_services& services, OracleSQL_connection_struct &cs,                   Connection& connection, 
                 const char *statement, OCIStmt *stmthp, OracleSQL_query_lobs &lobs,                   const char *statement, OCIStmt *stmthp, OracleSQL_query_lobs &lobs, 
                 unsigned long offset, unsigned long limit,                   unsigned long offset, unsigned long limit, 
                 SQL_Driver_query_event_handlers& handlers) {                  SQL_Driver_query_event_handlers& handlers) {
Line 545  private: // private funcs Line 593  private: // private funcs
         /*          /*
                 //gpfs on sun. paf 000818                  //gpfs on sun. paf 000818
                 //Zanyway, this is needed before.                   //Zanyway, this is needed before. 
                 check(services, cs, "get stmt type", OCIAttrGet(                  check(connection, "get stmt type", OCIAttrGet(
                         (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (ub1 *)&stmt_type,                           (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, (ub1 *)&stmt_type, 
                         (ub4 *)0, OCI_ATTR_STMT_TYPE, cs.errhp));                          (ub4 *)0, OCI_ATTR_STMT_TYPE, connection.errhp));
         */          */
   
                 while(isspace(*statement))                   while(isspace(*statement)) 
Line 559  private: // private funcs Line 607  private: // private funcs
                 else if(strncasecmp(statement, "update", 6)==0)                  else if(strncasecmp(statement, "update", 6)==0)
                         stmt_type=OCI_STMT_UPDATE;                          stmt_type=OCI_STMT_UPDATE;
   
                 sword status=OCIStmtExecute(cs.svchp, stmthp, cs.errhp,                   sword status=OCIStmtExecute(connection.svchp, stmthp, connection.errhp, 
                         (ub4)stmt_type==OCI_STMT_SELECT?0:1, (ub4)0,                           (ub4)stmt_type==OCI_STMT_SELECT?0:1, (ub4)0, 
                         (OCISnapshot *)NULL,                           (OCISnapshot *)NULL, 
                         (OCISnapshot *)NULL, (ub4)OCI_DEFAULT);                          (OCISnapshot *)NULL, (ub4)OCI_DEFAULT);
   
                 if(status!=OCI_NO_DATA)                  if(status!=OCI_NO_DATA)
                         check(services, cs, "execute", status);                          check(connection, "execute", status);
   
                 {                  {
                         for(int i=0; i<lobs.count; i++)                           for(int i=0; i<lobs.count; i++) 
Line 573  private: // private funcs Line 621  private: // private funcs
                                         OracleSQL_query_lobs::return_rows *rows=&lobs.items[i].rows;                                          OracleSQL_query_lobs::return_rows *rows=&lobs.items[i].rows;
                                         for(int r=0; r<rows->count; r++) {                                          for(int r=0; r<rows->count; r++) {
                                                 OCILobLocator *locator=rows->row[r].locator;                                                  OCILobLocator *locator=rows->row[r].locator;
                                                 check(services, cs, "lobwrite", OCILobWrite (                                                  check(connection, "lobwrite", OCILobWrite (
                                                         cs.svchp, cs.errhp,                                                           connection.svchp, connection.errhp, 
                                                         locator, &bytes_to_write, 1,                                                           locator, &bytes_to_write, 1, 
                                                         (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE,                                                           (dvoid *)lobs.items[i].data_ptr, (ub4)bytes_to_write, OCI_ONE_PIECE, 
                                                         (dvoid *)0, 0, (ub2)0,                                                           (dvoid *)0, 0, (ub2)0, 
Line 585  private: // private funcs Line 633  private: // private funcs
                                   
                 switch(stmt_type) {                  switch(stmt_type) {
                 case OCI_STMT_SELECT:                  case OCI_STMT_SELECT:
                         fetch_table(services, cs,                          fetch_table(connection,
                                 stmthp, offset, limit,                                   stmthp, offset, limit, 
                                 handlers);                                  handlers);
                         break;                          break;
Line 598  private: // private funcs Line 646  private: // private funcs
                 }                  }
         }          }
   
         void fetch_table(SQL_Driver_services& services, OracleSQL_connection_struct &cs,           void fetch_table(Connection& connection, 
                 OCIStmt *stmthp, unsigned long offset, unsigned long limit,                   OCIStmt *stmthp, unsigned long offset, unsigned long limit, 
                 SQL_Driver_query_event_handlers& handlers) {                  SQL_Driver_query_event_handlers& handlers) 
           {
                   SQL_Driver_services& services=*connection.services;
   
                 ub4 prefetch_rows=100;                  ub4 prefetch_rows=100;
                 check(services, cs, "AttrSet prefetch-rows", OCIAttrSet(                   check(connection, "AttrSet prefetch-rows", OCIAttrSet( 
                         (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT,                           (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, 
                         (dvoid *)&prefetch_rows, (ub4)0,                           (dvoid *)&prefetch_rows, (ub4)0, 
                         (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)cs.errhp));                          (ub4)OCI_ATTR_PREFETCH_ROWS, (OCIError *)connection.errhp));
   
                 ub4 prefetch_mem_size=100*1024;                  ub4 prefetch_mem_size=100*0x400;
                 check(services, cs, "AttrSet prefetch-memory", OCIAttrSet(                   check(connection, "AttrSet prefetch-memory", OCIAttrSet( 
                         (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT,                           (dvoid *)stmthp, (ub4)OCI_HTYPE_STMT, 
                         (dvoid *)&prefetch_mem_size, (ub4)0,                           (dvoid *)&prefetch_mem_size, (ub4)0, 
                         (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)cs.errhp));                          (ub4)OCI_ATTR_PREFETCH_MEMORY, (OCIError *)connection.errhp));
   
                 OCIParam          *mypard;                  OCIParam          *mypard;
                 ub2                    dtype;                  ub2                    dtype;
                 text                  *col_name;                  const char*           col_name;
   
                 struct {                  struct Col {
                         ub2 type;                          ub2 type;
                         char *str;                          char *str;
                         OCILobLocator *var;                          OCILobLocator *var;
Line 628  private: // private funcs Line 678  private: // private funcs
                 int column_count=0;                  int column_count=0;
   
                 bool failed=false;                  bool failed=false;
                 jmp_buf saved_mark; memcpy(saved_mark, cs.mark, sizeof(jmp_buf));                  jmp_buf saved_mark; memcpy(saved_mark, connection.mark, sizeof(jmp_buf));
                 if(setjmp(cs.mark)) {                  if(setjmp(connection.mark)) {
                         failed=true;                          failed=true;
                         goto cleanup;                          goto cleanup;
                 } else {                  } else {
                         // idea of preincrementing is that at error time all handles would free up                          // idea of preincrementing is that at error time all handles would free up
                         while(++column_count<=MAX_COLS) {                          while(++column_count<=MAX_COLS) {
                                 /* get next descriptor, if there is one */                                  /* get next descriptor, if there is one */
                                 if(OCIParamGet(stmthp, OCI_HTYPE_STMT, cs.errhp, (void **)&mypard,                                   if(OCIParamGet(stmthp, OCI_HTYPE_STMT, connection.errhp, (void **)&mypard, 
                                         (ub4) column_count)!=OCI_SUCCESS) {                                          (ub4) column_count)!=OCI_SUCCESS) {
                                         --column_count;                                          --column_count;
                                         break;                                          break;
                                 }                                  }
                                                                   
                                 /* Retrieve the data type attribute */                                  /* Retrieve the data type attribute */
                                 check(services, cs, "get type", OCIAttrGet(                                  check(connection, "get type", OCIAttrGet(
                                         (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM,                                           (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, 
                                         (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE,                                           (dvoid*) &dtype, (ub4 *)0, (ub4)OCI_ATTR_DATA_TYPE, 
                                         (OCIError *)cs.errhp));                                          (OCIError *)connection.errhp));
                                                                   
                                 /* Retrieve the column name attribute */                                  /* Retrieve the column name attribute */
                                 ub4 col_name_len;                                  ub4 col_name_len;
                                 check(services, cs, "get name", OCIAttrGet(                                  check(connection, "get name", OCIAttrGet(
                                         (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM,                                           (dvoid*) mypard, (ub4)OCI_DTYPE_PARAM, 
                                         (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME,                                           (dvoid**) &col_name, (ub4 *) &col_name_len, (ub4)OCI_ATTR_NAME, 
                                         (OCIError *)cs.errhp));                                          (OCIError *)connection.errhp));
                                                                   // transcode to $request:charset from connect-string?client_charset
                                   if(const char* cstrClientCharset=connection.options.cstrClientCharset) {
                                           services.transcode(col_name, col_name_len,
                                                   col_name, col_name_len,
                                                   cstrClientCharset,
                                                   services.request_charset());
                                   }
   
                                   Col& col=cols[column_count-1];
                                 {                                  {
                                         size_t size=(size_t)col_name_len;                                          size_t length=(size_t)col_name_len;
                                         char *ptr=(char *)services.malloc(size);                                          char *ptr=(char *)services.malloc_atomic(length+1);
                                         tolower(ptr, (char *)col_name, size);                                          if( connection.options.bLowerCaseColumnNames ) 
                                         handlers.add_column(ptr, size);                                                  tolower(ptr, col_name, length);
                                           else
                                                   memcpy(ptr, col_name, length);                                          
                                           ptr[length]=0;
                                           check(connection, handlers.add_column(connection.sql_error, ptr, length));
                                 }                                  }
                                                                   
                                 ub2 coerce_type=dtype;                                  ub2 coerce_type=dtype;
Line 669  private: // private funcs Line 731  private: // private funcs
                                 switch(dtype) {                                  switch(dtype) {
                                 case SQLT_CLOB:                                   case SQLT_CLOB: 
                                         {                                          {
                                                 check(services, cs, "alloc output var desc", OCIDescriptorAlloc(                                                  check(connection, "alloc output var desc", OCIDescriptorAlloc(
                                                         (dvoid *)cs.envhp, (dvoid **)(ptr=&cols[column_count-1].var),                                                           (dvoid *)connection.envhp, (dvoid **)(ptr=&col.var), 
                                                         (ub4)OCI_DTYPE_LOB,                                                           (ub4)OCI_DTYPE_LOB, 
                                                         0, (dvoid **)0));                                                          0, (dvoid **)0));
                                                                                                   
Line 679  private: // private funcs Line 741  private: // private funcs
                                         }                                          }
                                 default:                                  default:
                                         coerce_type=SQLT_STR;                                          coerce_type=SQLT_STR;
                                         ptr=cols[column_count-1].str=(char *)services.malloc(MAX_OUT_STRING_LENGTH+1);                                          char*& buf=connection.fetch_buffers[column_count-1];
                                           ptr=buf; // get cached buffer
                                           if(!ptr) // allocate if needed, caching it
                                                   ptr=buf=(char *)::/*see disconnect*/malloc(MAX_OUT_STRING_LENGTH+1/*terminator*/);
                                           col.str=(char*)ptr;
                                         size=MAX_OUT_STRING_LENGTH;                                          size=MAX_OUT_STRING_LENGTH;
                                         break;                                          break;
                                 }                                  }
                                                                   
                                 cols[column_count-1].type=coerce_type;                                  col.type=coerce_type;
                                                                   
                                 check(services, cs, "DefineByPos", OCIDefineByPos(                                  // http://i/docs/oracle/server.804/a58234/oci_func.htm#449680
                                         stmthp, &cols[column_count-1].def, cs.errhp,                                   //   this call implicitly allocates the define handle
                                   // http://sunsite.eunnet.net/documentation/oracle.8.0.4/server.804/a58234/basics.htm
                                   //   when a statement handle is freed, any bind and define handles associated with it 
                                   //   are also freed
                                   col.def=0; check(connection, "DefineByPos", OCIDefineByPos(
                                           stmthp, &col.def, connection.errhp, 
                                         column_count, (ub1 *) ptr, size,                                           column_count, (ub1 *) ptr, size, 
                                         coerce_type, (dvoid *) &cols[column_count-1].indicator,                                           coerce_type, (dvoid *) &col.indicator, 
                                         (ub2 *)0, (ub2 *)0, OCI_DEFAULT));                                          (ub2 *)0, (ub2 *)0, OCI_DEFAULT));
                         }                          }
                                                   
                         handlers.before_rows();                          check(connection, handlers.before_rows(connection.sql_error));
                                                   
                         for(unsigned long row=0; !limit||row<limit+offset; row++) {                          for(unsigned long row=0; !limit||row<offset+limit; row++) {
                                 sword status=OCIStmtFetch(stmthp, cs.errhp, (ub4)1,  (ub4)OCI_FETCH_NEXT,                                   sword status=OCIStmtFetch(stmthp, connection.errhp, (ub4)1,  (ub4)OCI_FETCH_NEXT, 
                                         (ub4)OCI_DEFAULT);                                          (ub4)OCI_DEFAULT);
                                 if(status==OCI_NO_DATA)                                  if(status==OCI_NO_DATA)
                                         break;                                          break;
                                 check(services, cs, "fetch", status);                                  check(connection, "fetch", status);
   
                                 if(row>=offset) {                                  if(row>=offset) {
                                         handlers.add_row();                                          check(connection, handlers.add_row(connection.sql_error));
                                         for(int i=0; i<column_count; i++) {                                          for(int i=0; i<column_count; i++) {
                                                 size_t size=0;                                                  size_t length=0;
                                                 void *ptr=0;                                                  char* strm=0;
                                                 if(!cols[i].indicator) // not NULL                                                  if(!cols[i].indicator) // not NULL
                                                         switch(cols[i].type) {                                                          switch(cols[i].type) {
                                                         case SQLT_CLOB:                                                           case SQLT_CLOB: 
                                                                 {                                                                  {
                                                                         ub4   amtp=4096000000UL;  
                                                                         ub4   offset=1;                                                                          ub4   offset=1;
                                                                         ub4   loblen=0;  
                                                                         OCILobLocator *var=(OCILobLocator *)cols[i].var;                                                                          OCILobLocator *var=(OCILobLocator *)cols[i].var;
                                                                         OCILobGetLength(cs.svchp, cs.errhp, var, &loblen);                                                                          size_t read_size=0;
                                                                         if(loblen) {                                                                          strm=(char*)services.malloc_atomic(1/*for terminator*/); // set type of memory block
                                                                                 size=(size_t)loblen;                                                                          do {
                                                                                 ptr=services.malloc(size);                                                                                  char buf[MAX_STRING*10];
                                                                                 check(services, cs, "lobread", OCILobRead(cs.svchp, cs.errhp,                                                                                   ub4   amtp=0/*to be read in stream mode*/;
                                                                                         var, &amtp, offset, (dvoid *) ptr,                                                                                   // http://i/docs/oracle/server.804/a58234/oci_func.htm#427818
                                                                                         loblen, (dvoid *)0,                                                                                   status=OCILobRead(connection.svchp, connection.errhp, 
                                                                                         0,                                                                                           var, &amtp, offset, (dvoid *)buf, 
                                                                                         (ub2)0, (ub1) SQLCS_IMPLICIT));                                                                                          sizeof(buf), 
                                                                         }                                                                                          (dvoid *)0, 0, 
                                                                                           (ub2)0, (ub1)SQLCS_IMPLICIT);
                                           if(status!=OCI_SUCCESS && status!=OCI_NEED_DATA)
                                                                                           check(connection, "lobread", status);
   
                                                                                   strm=(char*)services.realloc(strm, read_size+amtp+1/*for termintator*/);
                                                                                   memcpy(strm+read_size, buf, amtp);
                                                                                   read_size+=amtp;
                                                                                   offset+=amtp;
                                                                           } while(status==OCI_NEED_DATA);
   
                                                                           length=(size_t)read_size;
                                                                           strm[length]=0;
                                                                         break;                                                                          break;
                                                                 }                                                                  }
                                                         default:                                                          default:
                                                                 if(const char *str=cols[i].str) {                                                                  if(const char *value=cols[i].str) {
                                                                         size=strlen(str);                                                                          length=strlen(value);
                                                                         ptr=services.malloc(size);                                                                          strm=(char*)services.malloc_atomic(length+1);
                                                                         memcpy(ptr, str, size);                                                                          memcpy(strm, value, length+1);
                                                                 } else {                                                                  } else {
                                                                         size=0;                                                                          length=0;
                                                                         ptr=0;                                                                          strm=0;
                                                                 }                                                                  }
                                                                 break;                                                                  break;
                                                         }                                                          }
                                                 handlers.add_row_cell(ptr, size);  
                                                   const char* str=strm;
                                                   if(str && length)
                                                   {
                                                           // transcode to $request:charset from connect-string?client_charset
                                                           if(const char* cstrClientCharset=connection.options.cstrClientCharset) {
                                                                   const char* dest;
                                                                   size_t dest_length;
                                                                   services.transcode(str, length,
                                                                           dest, dest_length,
                                                                           cstrClientCharset,
                                                                           services.request_charset());
                                                                   str=dest;
                                                                   length=dest_length;
                                                           }
                                                   }
   
                                                   check(connection, handlers.add_row_cell(connection.sql_error, str, length));
                                         }                                          }
                                 }                                  }
                         }                          }
Line 762  cleanup: // no check call after this poi Line 860  cleanup: // no check call after this poi
   
 private: // conn client library funcs  private: // conn client library funcs
                   
         friend void check(          friend void check(Connection& connection, const char *step, sword status);
                 SQL_Driver_services& services, OracleSQL_connection_struct &cs,   
                 const char *step, sword status);  
         friend sb4 cbf_get_data(dvoid *ctxp,           friend sb4 cbf_get_data(dvoid *ctxp, 
                 OCIBind *bindp,                   OCIBind *bindp, 
                 ub4 iter, ub4 index,                   ub4 iter, ub4 index, 
Line 874  private: // conn client library funcs li Line 970  private: // conn client library funcs li
   
         const char *dlink(const char *dlopen_file_spec) {          const char *dlink(const char *dlopen_file_spec) {
                 if(lt_dlinit())                  if(lt_dlinit())
   
                         return lt_dlerror();                          return lt_dlerror();
   
   
   
         lt_dlhandle handle=lt_dlopen(dlopen_file_spec);          lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
   
                 //return "hren31";  
   
         if(!handle)          if(!handle)
                         return lt_dlerror(); //"can not open the dynamic link module";                          return lt_dlerror(); //"can not open the dynamic link module";
   
Line 914  private: // conn client library funcs li Line 1003  private: // conn client library funcs li
   
 } *OracleSQL_driver;  } *OracleSQL_driver;
   
 void check(  void check(Connection& connection, const char *step, sword status) {
         SQL_Driver_services& services, OracleSQL_connection_struct &cs,   
         const char *step, sword status) {  
   
         const char *msg;          const char *msg;
         char reason[MAX_STRING/2];          char reason[MAX_STRING/2];
   
         switch (status) {          switch (status) {
         case OCI_SUCCESS:          case OCI_SUCCESS: // hurrah
                 return; // hurrah          case OCI_SUCCESS_WITH_INFO:             // ignoring. example: count(column) when column contains NULLs, 
                                                                                                                   // count() not counting them and gives that status
                   return;
         case OCI_ERROR:          case OCI_ERROR:
                 {                  {
                 sb4 errcode;                          sb4 errcode;
                 if(OracleSQL_driver->OCIErrorGet((dvoid *)cs.errhp, (ub4)1, (text *)NULL, &errcode,                           if(OracleSQL_driver->OCIErrorGet((dvoid *)connection.errhp, (ub4)1, (text *)NULL, &errcode, 
                         (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS)                                  (text *)reason, (ub4)sizeof(reason), OCI_HTYPE_ERROR)==OCI_SUCCESS) {
                         msg=reason;                                  msg=reason;
                 else  
                         msg="[can not get error description]";                                  // transcode to $request:charset from connect-string?client_charset
                 break;                                  if(const char* cstrClientCharset=connection.options.cstrClientCharset) {
                                           if(msg) {
                                                   if(size_t msg_length=strlen(msg)) {
                                                           connection.services->transcode(msg, msg_length,
                                                                   msg, msg_length,
                                                                   cstrClientCharset,
                                                                   connection.services->request_charset());
                                                   }
                                           }
                                   }
                           } else
                                   msg="[can not get error description]";
                           break;
                 }                  }
         case OCI_SUCCESS_WITH_INFO:  
                 msg="SUCCESS_WITH_INFO"; break;  
         case OCI_NEED_DATA:          case OCI_NEED_DATA:
                 msg="NEED_DATA"; break;                  msg="NEED_DATA"; break;
         case OCI_NO_DATA:          case OCI_NO_DATA:
Line 950  void check( Line 1049  void check(
                 msg="unknown"; break;                  msg="unknown"; break;
         }          }
   
         snprintf(cs.error, sizeof(cs.error), "%s (%s, %d)",           snprintf(connection.error, sizeof(connection.error), "%s (%s, %d)", 
                 msg, step, (int)status);                  msg, step, (int)status);
         longjmp(cs.mark, 1);          longjmp(connection.mark, 1);
 }  }
   
   void check(Connection& connection, bool error) {
           if(error)
                   longjmp(connection.mark, 1);
   }
   
 /* ----------------------------------------------------------------- */  /* ----------------------------------------------------------------- */
 /* Intbind callback that does not do any data input.                 */  /* Intbind callback that does not do any data input.                 */
 /* ----------------------------------------------------------------- */  /* ----------------------------------------------------------------- */
 static sb4 cbf_no_data(  static sb4 cbf_no_data(
                                 dvoid *ctxp,                                   dvoid* /*ctxp*/, 
                                 OCIBind *bindp,                                   OCIBind* /*bindp*/, 
                                 ub4 iter, ub4 index,                                   ub4 /*iter*/, ub4 /*index*/, 
                                 dvoid **bufpp,                                   dvoid **bufpp, 
                                 ub4 *alenpp,                                   ub4 *alenpp, 
                                 ub1 *piecep,                                   ub1 *piecep, 
Line 981  static sb4 cbf_no_data( Line 1084  static sb4 cbf_no_data(
 /* ----------------------------------------------------------------- */  /* ----------------------------------------------------------------- */
 static sb4 cbf_get_data(dvoid *ctxp,   static sb4 cbf_get_data(dvoid *ctxp, 
                                  OCIBind *bindp,                                    OCIBind *bindp, 
                                  ub4 iter, ub4 index,                                    ub4 /*iter*/, ub4 index, 
                                  dvoid **bufpp,                                    dvoid **bufpp, 
                                  ub4 **alenp,                                    ub4 **alenp, 
                                  ub1 *piecep,                                    ub1 *piecep, 
Line 992  static sb4 cbf_get_data(dvoid *ctxp, Line 1095  static sb4 cbf_get_data(dvoid *ctxp,
   
         if(index==0) {          if(index==0) {
                 static ub4  rows;                  static ub4  rows;
                 check(*context.services, *context.cs, "AttrGet cbf_get_data ROWS_RETURNED",                   check(*context.connection, "AttrGet cbf_get_data ROWS_RETURNED", 
                         OracleSQL_driver->OCIAttrGet(                          OracleSQL_driver->OCIAttrGet(
                                 (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows,                                   (CONST dvoid *) bindp, OCI_HTYPE_BIND, (dvoid *)&rows, 
                                 (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.cs->errhp)) ;                                  (ub4 *)sizeof(ub2), OCI_ATTR_ROWS_RETURNED, context.connection->errhp)) ;
                 context.rows->count=(ub2)rows;                  context.rows->count=(ub2)rows;
                 context.rows->row=(OracleSQL_query_lobs::return_rows::return_row *)                  context.rows->row=(OracleSQL_query_lobs::return_rows::return_row *)
                         context.services->malloc(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows);                          context.connection->services->malloc_atomic(sizeof(OracleSQL_query_lobs::return_rows::return_row)*rows);
         }          }
   
         OracleSQL_query_lobs::return_rows::return_row &var=context.rows->row[index];          OracleSQL_query_lobs::return_rows::return_row &var=context.rows->row[index];
   
         check(*context.services, *context.cs, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc(          check(*context.connection, "alloc output var desc dynamic", OracleSQL_driver->OCIDescriptorAlloc(
                 (dvoid *) context.cs->envhp, (dvoid **)&var.locator,                   (dvoid *) context.connection->envhp, (dvoid **)&var.locator, 
                 (ub4)OCI_DTYPE_LOB,                   (ub4)OCI_DTYPE_LOB, 
                 0, (dvoid **)0));                  0, (dvoid **)0));
   
Line 1017  static sb4 cbf_get_data(dvoid *ctxp, Line 1120  static sb4 cbf_get_data(dvoid *ctxp,
         return OCI_CONTINUE;          return OCI_CONTINUE;
 }  }
   
 void tolower(char *out, const char *in, size_t size) {  static void tolower(char *out, const char *in, size_t size) {
         while(size--)          while(size--)
                 *out++=tolower(*in++);                  *out++=(char)tolower(*in++);
 }  }
   static void toupper(char *out, const char *in, size_t size) {
           while(size--)
                   *out++=(char)toupper(*in++);
   }
   
   
 extern "C" SQL_Driver *SQL_DRIVER_CREATE() {  extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
         //_asm int 3;  
         return OracleSQL_driver=new OracleSQL_Driver();          return OracleSQL_driver=new OracleSQL_Driver();
 }  }

Removed from v.1.19  
changed lines
  Added in v.1.52


E-mail: