Diff for /sql/oracle/parser3oracle.C between versions 1.10 and 1.58

version 1.10, 2001/11/14 09:30:30 version 1.58, 2004/05/25 07:00:09
Line 1 Line 1
 /** @file  /** @file
         Parser Oracle driver.          Parser Oracle driver.
   
         Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)          Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com)
   
         Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x]          2001.07.30 using Oracle 8.1.6 [@test tested with Oracle 7.x.x]
 */  */
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, value, 1/*overwrite*/); 
                 return setenv(name, buf, 1/*overwrite*/);   
         } else {          } else {
                 unsetenv(name);                  unsetenv(name);
                 return 0;                  return 0;
Line 105  static char *lsplit(char **string_ref, c Line 109  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 149  struct OracleSQL_query_lobs { Line 138  struct OracleSQL_query_lobs {
                 } *row;                  } *row;
                 int count;                  int count;
         };          };
         struct cbf_context_struct {  
                 SQL_Driver_services *services;  
                 OracleSQL_connection_struct *cs;  
                 return_rows *rows;  
         };  
         struct Item {          struct Item {
                 const char *name_ptr; size_t name_size;                  const char *name_ptr; size_t name_size;
                 char *data_ptr; size_t data_size;                  char *data_ptr; size_t data_size;
                 OCILobLocator *locator;                  OCILobLocator *locator;
                 OCIBind *bind;                  OCIBind *bind;
                 return_rows rows;                  return_rows rows;
                   Connection *connection;
         } items[MAX_IN_LOBS];          } items[MAX_IN_LOBS];
         int count;          int count;
 };  };
 #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 169  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_str(char *out, const char *in, size_t size);
   static void toupper_str(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_str(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 231  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 222  public: Line 245  public:
         }          }
   
         /**     connect          /**     connect
                 @param used_only_in_connect_url                  @param url
                         format: @b user:pass@service?                          format: @b user:pass@service?
                            ORACLE_HOME=/u01/app/oracle/product/8.1.5&                             ORACLE_HOME=/u01/app/oracle/product/8.1.5&
                            ORA_NLS33=/u01/app/oracle/product/8.1.5/ocommon/nls/admin/data&                             ORA_NLS33=/u01/app/oracle/product/8.1.5/ocommon/nls/admin/data&
Line 230  public: Line 253  public:
                            ORA_ENCRYPT_LOGIN=TRUE                             ORA_ENCRYPT_LOGIN=TRUE
   
                 @todo environment manupulation doesnt look thread safe                  @todo environment manupulation doesnt look thread safe
                   @todo allocate 'aused_only_in_connect_url' on gc heap, so it can be manipulated directly
         */          */
         void connect(          void connect(
                 char *used_only_in_connect_url,                   char *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]                  // connections are cross-request, do not use services._alloc [linked with request]
                 OracleSQL_connection_struct &cs=                  Connection& connection=*(Connection  *)services.malloc(sizeof(Connection));
                         *(OracleSQL_connection_struct  *)::calloc(sizeof(OracleSQL_connection_struct), 1);                  connection.services=&services;
                   connection.options.bLowerCaseColumnNames = true;
                   *connection_ref=&connection;
   
                 char *user=used_only_in_connect_url;                  char *user=url;
                 char *service=lsplit(user, '@');                  char *service=lsplit(user, '@');
                 char *pwd=lsplit(user, ':');                  char *pwd=lsplit(user, ':');
                 char *options=lsplit(service, '?');                  char *options=lsplit(service, '?');
Line 248  public: Line 275  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 297  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;  
         }          }
         /// @test remove return          void disconnect(void *aconnection) {
         void disconnect(void *connection) {              Connection& connection=*static_cast<Connection *>(aconnection);
   
                 return;  
   
                   // free fetch buffers. leave that to GC [no such services func. yet?]
                   /*
                   for(int i=0; i<MAX_COLS; i++) {
                           if(void* fetch_buffer=connection.fetch_buffers[i])
                                   connection.services->free(fetch_buffer);
                           else
                                   break;
                   }
                   */
   
             OracleSQL_connection_struct &cs=*(OracleSQL_connection_struct *)connection;  
                 // 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]                  // free connection. leave that to GC [no such services func. yet?]
                 ::free(&cs);                  // connection.services->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) {          {
                 /*                  Connection& connection=*static_cast<Connection *>(aconnection);
                         it's already UNTAINT_TIMES_BIGGER                  char *result=(char*)connection.services->malloc_atomic(length*2+1);
                 */                  char *to=result;
                 unsigned int result=length;  
                 while(length--) {                  while(length--) {
                         switch(*from) {                          switch(*from) {
                         case '\'': // "'" -> "''"                          case '\'': // "'" -> "''"
                                 *to++='\'';                                  *to++='\'';
                                 break;                                  break;
                         case '\\': // "\" -> "\\"  
                                 *to++='\'';  
                                 break;  
                         }                          }
                         *to++=*from++;                          *to++=*from++;
                 }                  }
                   *to=0;
                 return result;                  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);
                   const char* cstrClientCharset=connection.options.cstrClientCharset;
                 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
                   if(cstrClientCharset) {
                           size_t transcoded_statement_size;
                           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(                                          OracleSQL_query_lobs::Item &item=lobs.items[i];
                                                 (dvoid *)cs.envhp, (dvoid **)&lobs.items[i].locator, (ub4)OCI_DTYPE_LOB, 0, 0));                                          check(connection, "alloc output var desc", OCIDescriptorAlloc(
                                                   (dvoid *)connection.envhp, (dvoid **)&item.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,                                                   &item.bind, connection.errhp, 
                                                 (ub4)1+i,                                                   (ub4)1+i, 
                                                 (dvoid *)&lobs.items[i].locator,                                                   (dvoid *)&item.locator, 
                                                 (sword)sizeof (lobs.items[i].locator), SQLT_CLOB, (dvoid *)0,                                                   (sword)sizeof (item.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;                                          item.rows.count=0;
                                         OracleSQL_query_lobs::cbf_context_struct cbf_context={                                          item.connection=&connection;
                                                 &services, &cs, &lobs.items[i].rows};                                          check(connection, "bind dynamic", OCIBindDynamic(
                                         check(services, cs, "bind dynamic", OCIBindDynamic(                                                  item.bind, connection.errhp, 
                                                 lobs.items[i].bind, cs.errhp,                                                   (dvoid *) &item, cbf_no_data, 
                                                 (dvoid *) &cbf_context, cbf_no_data,                                                   (dvoid *) &item, 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 452  cleanup: // no check call after this poi Line 491  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 475  private: // private funcs Line 518  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 483  private: // private funcs Line 527  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;
                                                 while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) {                                                  while(*o && !(o[0]=='\'' && o[1]!='\'' && !escaped)) {
                                                         escaped=*o=='\\' || (o[0]=='\'' && o[1]=='\'');                                                          escaped=o[0]=='\'' && o[1]=='\'';
                                                         if(escaped) {                                                          if(escaped) {
                                                                 // write pending, skip "\" or "'"                                                                  // write pending, skip "\" or "'"
                                                                 if(size_t size=o-start) {                                                                  if(size_t size=o-start) {
Line 514  private: // private funcs Line 559  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 526  private: // private funcs Line 575  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 544  private: // private funcs Line 588  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 553  private: // private funcs Line 597  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)) 
                           statement++;
                 if(strncasecmp(statement, "select", 6)==0)                   if(strncasecmp(statement, "select", 6)==0) 
                         stmt_type=OCI_STMT_SELECT;                          stmt_type=OCI_STMT_SELECT;
                 else if(strncasecmp(statement, "insert", 6)==0)                  else if(strncasecmp(statement, "insert", 6)==0)
Line 564  private: // private funcs Line 611  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 578  private: // private funcs Line 625  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 590  private: // private funcs Line 637  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 603  private: // private funcs Line 650  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) 
 /*          {
                   const char* cstrClientCharset=connection.options.cstrClientCharset;
                   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 634  private: // private funcs Line 683  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(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_str(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 675  private: // private funcs Line 736  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 685  private: // private funcs Line 746  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 *)services.malloc_atomic(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(cstrClientCharset)
                                                                   services.transcode(str, length,
                                                                           str, length,
                                                                           cstrClientCharset,
                                                                           services.request_charset());
                                                   }
   
                                                   check(connection, handlers.add_row_cell(connection.sql_error, str, length));
                                         }                                          }
                                 }                                  }
                         }                          }
Line 768  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 880  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 920  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 956  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 987  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, 
                                  dvoid **indpp,                                    dvoid **indpp, 
                                  ub2 **rcodepp) {                                   ub2 **rcodepp) {
         OracleSQL_query_lobs::cbf_context_struct &context=          OracleSQL_query_lobs::Item& context=*static_cast<OracleSQL_query_lobs::Item*>(ctxp);
                 *(OracleSQL_query_lobs::cbf_context_struct *)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 1023  static sb4 cbf_get_data(dvoid *ctxp, Line 1119  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_str(char *out, const char *in, size_t size) {
         while(size--)          while(size--)
                 *out++=tolower(*in++);                  *out++=(char)tolower(*in++);
 }  }
   static void toupper_str(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.10  
changed lines
  Added in v.1.58


E-mail: