|
|
| version 1.60, 2004/06/18 15:55:52 | version 1.67, 2004/12/23 16:54:52 |
|---|---|
| Line 7 | Line 7 |
| 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] |
| */ | */ |
| static const char *RCSId="$Id$"; | static const char *RCSId="$Id$"; |
| #include "config_includes.h" | #include "config_includes.h" |
| Line 19 static const char *RCSId="$Id$"; | Line 20 static const char *RCSId="$Id$"; |
| #define MAX_IN_LOBS 5 | #define MAX_IN_LOBS 5 |
| #define MAX_LOB_NAME_LENGTH 100 | #define MAX_LOB_NAME_LENGTH 100 |
| #define MAX_OUT_STRING_LENGTH 4000 | #define MAX_OUT_STRING_LENGTH 4000 |
| #define MAX_BINDS 100 | |
| #define EMPTY_CLOB_FUNC_CALL "empty_clob()" | #define EMPTY_CLOB_FUNC_CALL "empty_clob()" |
| Line 44 inline int min(int a, int b){ return a<b | Line 46 inline int min(int a, int b){ return a<b |
| #pragma warning(disable:4611) | #pragma warning(disable:4611) |
| #endif | #endif |
| const sb2 MAGIC_INDICATOR_VALUE_MEANING_NOT_NULL_AND_UNCHANGED=99; | |
| /// @todo small memory leaks here | /// @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; |
| Line 109 static char *lsplit(char **string_ref, c | Line 113 static char *lsplit(char **string_ref, c |
| return result; | return result; |
| } | } |
| static char* rsplit(char* string, char delim) { | |
| if(string) { | |
| char* v=strrchr(string, delim); | |
| if(v) { | |
| *v=0; | |
| return v+1; | |
| } | |
| } | |
| return NULL; | |
| } | |
| #ifndef DOXYGEN | #ifndef DOXYGEN |
| struct Connection { | struct Connection { |
| SQL_Driver_services *services; | SQL_Driver_services *services; |
| Line 122 struct Connection { | Line 137 struct Connection { |
| OCISession *usrhp; | OCISession *usrhp; |
| char* fetch_buffers[MAX_COLS]; | char* fetch_buffers[MAX_COLS]; |
| char* bind_buffers[MAX_BINDS]; | |
| struct Options { | struct Options { |
| bool bLowerCaseColumnNames; | bool bLowerCaseColumnNames; |
| Line 270 public: | Line 286 public: |
| *connection_ref=&connection; | *connection_ref=&connection; |
| char *user=url; | char *user=url; |
| char *service=lsplit(user, '@'); | char *service=rsplit(user, '@'); |
| char *pwd=lsplit(user, ':'); | char *pwd=lsplit(user, ':'); |
| char *options=lsplit(service, '?'); | char *options=lsplit(service, '?'); |
| Line 424 public: | Line 440 public: |
| unsigned long offset, unsigned long limit, | unsigned long offset, unsigned long limit, |
| SQL_Driver_query_event_handlers& handlers) | SQL_Driver_query_event_handlers& handlers) |
| { | { |
| Connection& connection=*static_cast<Connection *>(aconnection); | Connection& connection=*static_cast<Connection *>(aconnection); |
| const char* cstrClientCharset=connection.options.cstrClientCharset; | const char* cstrClientCharset=connection.options.cstrClientCharset; |
| Query_lobs lobs={{0}, 0}; | Query_lobs lobs={{0}, 0}; |
| Line 445 public: | Line 462 public: |
| failed=true; | failed=true; |
| goto cleanup; | goto cleanup; |
| } else { | } else { |
| if(placeholders_count>MAX_BINDS) | |
| fail(connection, "too many bind variables"); | |
| const char *statement=preprocess_statement(connection, astatement, lobs); | const char *statement=preprocess_statement(connection, astatement, lobs); |
| check(connection, "HandleAlloc STMT", OCIHandleAlloc( | check(connection, "HandleAlloc STMT", OCIHandleAlloc( |
| Line 460 public: | Line 480 public: |
| }; | }; |
| int binds_size=sizeof(Bind_info) * placeholders_count; | int binds_size=sizeof(Bind_info) * placeholders_count; |
| // we DO store OCIBind* into ATOMIC gc memory, | |
| // but we do not allocate/free it, that's done automatically from oracle [using environment handles] | |
| // so we don't have to bother with that | |
| Bind_info* binds=static_cast<Bind_info*>(services.malloc_atomic(binds_size)); | Bind_info* binds=static_cast<Bind_info*>(services.malloc_atomic(binds_size)); |
| { | { |
| for(size_t i=0; i<placeholders_count; i++) { | for(size_t i=0; i<placeholders_count; i++) { |
| Placeholder& ph=placeholders[i]; | Placeholder& ph=placeholders[i]; |
| Bind_info& bi=binds[i]; | Bind_info& bi=binds[i]; |
| bi.bind=0; | bi.bind=0; |
| bi.indicator=ph.is_null? -1: 0/*9999*/; | // http://i/docs/oracle/server.804/a58234/basics.htm#422173 |
| bi.indicator=ph.is_null? -1: MAGIC_INDICATOR_VALUE_MEANING_NOT_NULL_AND_UNCHANGED; | |
| size_t value_length; | size_t value_length; |
| Line 486 public: | Line 510 public: |
| value_length=ph.value? strlen(ph.value): 0; | value_length=ph.value? strlen(ph.value): 0; |
| } | } |
| char placeholder_buf[MAX_STRING]; | // clone value for possible output binds |
| sb4 placeh_len=snprintf(placeholder_buf, sizeof(placeholder_buf), ":%s", ph.name); | // note: even empty input can be replaced by huge output |
| check(connection, "bind name", OCIBindByName(stmthp, | char*& value_buf=connection.bind_buffers[i]; // get cached buffer |
| if(!value_buf) // allocate if needed, caching it | |
| value_buf=(char *)services.malloc_atomic(MAX_OUT_STRING_LENGTH+1/*terminator*/); | |
| if(value_length) | |
| memcpy(value_buf, ph.value, value_length+1); | |
| else | |
| value_buf[0]=0; | |
| char name_buf[MAX_STRING]; | |
| sb4 placeh_len=snprintf(name_buf, sizeof(name_buf), ":%s", ph.name); | |
| char check_step_buf[MAX_STRING]; | |
| snprintf(check_step_buf, sizeof(check_step_buf), "bind by name :%s", ph.name); | |
| check(connection, check_step_buf, OCIBindByName(stmthp, | |
| &bi.bind, connection.errhp, | &bi.bind, connection.errhp, |
| (text*)placeholder_buf, placeh_len, | (text*)name_buf, placeh_len, |
| (dvoid *)ph.value, (sword)value_length, SQLT_CHR/*SQLT_STR*/, (dvoid *)&bi.indicator, | (dvoid *)value_buf, (sword)(MAX_OUT_STRING_LENGTH+1), SQLT_STR, (dvoid *)&bi.indicator, |
| (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT)); | (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT)); |
| } | } |
| Line 525 public: | Line 561 public: |
| { | { |
| for(size_t i=0; i<placeholders_count; i++) { | for(size_t i=0; i<placeholders_count; i++) { |
| Placeholder& ph=placeholders[i]; | |
| Bind_info& bi=binds[i]; | Bind_info& bi=binds[i]; |
| if(bi.indicator==MAGIC_INDICATOR_VALUE_MEANING_NOT_NULL_AND_UNCHANGED/*unchanged*/) | |
| if(bi.indicator==9999 /*unchanged*/) | |
| continue; | continue; |
| Placeholder& ph=placeholders[i]; | |
| if(bi.indicator==-1) | if(bi.indicator==-1) |
| ph.is_null=true; | ph.is_null=true; |
| else | else |
| Line 538 public: | Line 573 public: |
| ph.is_null=false; | ph.is_null=false; |
| else | else |
| fail(connection, bi.indicator<0? | fail(connection, bi.indicator<0? |
| "column return buffer overflow, additionally size too big to be returned in 'indicator'" | "output bind buffer overflow, additionally size too big to be returned in 'indicator'" |
| : "column return buffer overflow"); | : "output bind buffer overflow"); |
| ph.were_updated=true; | ph.were_updated=true; |
| const char* bind_buffer=connection.bind_buffers[i]; | |
| if(cstrClientCharset) { | if( size_t value_length=strlen(bind_buffer) ) { |
| if(ph.value) { | char* returned_value=(char*)services.malloc_atomic(value_length+1/*terminator*/); |
| size_t value_length; | memcpy(returned_value, bind_buffer, value_length+1 ); |
| services.transcode(ph.value, strlen(ph.value), | ph.value=returned_value; |
| ph.value, value_length, | |
| if(cstrClientCharset) { | |
| services.transcode(ph.value, value_length, | |
| ph.value, value_length/*<this new value is not used afterwards, actually*/, | |
| cstrClientCharset, | cstrClientCharset, |
| services.request_charset()); | services.request_charset()); |
| } | } |
| } else { | |
| ph.value=0; | |
| } | } |
| } | } |
| } | } |
| Line 682 private: // private funcs | Line 722 private: // private funcs |
| (ub4 *)0, OCI_ATTR_STMT_TYPE, connection.errhp)); | (ub4 *)0, OCI_ATTR_STMT_TYPE, connection.errhp)); |
| */ | */ |
| while(isspace(*statement)) | while(isspace((unsigned char)*statement)) |
| statement++; | statement++; |
| if(strncasecmp(statement, "select", 6)==0) | if(strncasecmp(statement, "select", 6)==0) |
| stmt_type=OCI_STMT_SELECT; | stmt_type=OCI_STMT_SELECT; |