Diff for /sql/sqlite/parser3sqlite.C between versions 1.3 and 1.4

version 1.3, 2007/12/27 14:24:21 version 1.4, 2008/06/24 17:46:57
Line 17 Line 17
 #define MAX_STRING 0x400  #define MAX_STRING 0x400
 #define MAX_NUMBER 20  #define MAX_NUMBER 20
   
   #define SQLITE_DEFAULT_CHARSET "UTF-8"
   
 #if _MSC_VER  #if _MSC_VER
 #       define snprintf _snprintf  #       define snprintf _snprintf
 #       define strcasecmp _stricmp  #       define strcasecmp _stricmp
 #endif  #endif
   
 static void MBox(const char *message, const char *title){  
 //      MessageBox(0, (LPCSTR)message, (LPCSTR)title, MB_OK);  
 }  
   
 static char *lsplit(char *string, char delim) {  static char *lsplit(char *string, char delim) {
     if(string) {      if(string) {
                 char *v=strchr(string, delim);                  char *v=strchr(string, delim);
Line 70  public: Line 68  public:
   
         /// get api version          /// get api version
         int api_version() { return SQL_DRIVER_API_VERSION; }          int api_version() { return SQL_DRIVER_API_VERSION; }
   
         /// initialize driver by loading sql dynamic link library          /// initialize driver by loading sql dynamic link library
         const char *initialize(char *dlopen_file_spec) {          const char *initialize(char *dlopen_file_spec) {
                 return dlopen_file_spec?                  return dlopen_file_spec?
                         dlink(dlopen_file_spec):"client library column is empty";                          dlink(dlopen_file_spec):"client library column is empty";
         }          }
   
         /**     connect          /**     connect
                 @param url                  @param url
                         format: @b database                          format: @b [localhost/]dbfile?
                         SQLite options - database file name                          ClientCharset=UTF-8&
                           autocommit=1
         */          */
         void connect(          void connect(
                 char *url,                           char *url, 
                 SQL_Driver_services& services,                           SQL_Driver_services& services, 
                 void **connection_ref ///< output: Connection*                          void **connection_ref ///< output: Connection*
                 ) {                  ){
   
                 int rc;                  int rc;
   
 //              char *cstrBackwardCompAskServerToTranscode=0;                  Connection& connection=*(Connection *)services.malloc(sizeof(Connection));
   
                 Connection& connection=*(Connection  *)services.malloc(sizeof(Connection));  
                 connection.services=&services;                  connection.services=&services;
                   connection.cstrClientCharset=SQLITE_DEFAULT_CHARSET;    
                   connection.autocommit=true;
   
                 rc = sqlite3_open(url, &connection.handle);                  char *db = url;
                   char *options = lsplit(db, '?');
   
                   char *db_path=(char*)services.malloc(strlen((char*)services.request_document_root()) + strlen(db) + 2); 
                   db_path=strncat(db_path, (char*)services.request_document_root(), MAX_STRING);
                   db_path+="/";
                   db_path=strncat(db_path, db, MAX_STRING);
   
                   while(options) {
                           if(char *key=lsplit(&options, '&')) {
                                   if(*key) {
                                           if(char *value=lsplit(key, '=')) {
                                                   if(strcmp(key, "ClientCharset" )==0) { // transcoding with parser
                                                           toupper_str(value, value, strlen(value));
                                                           connection.cstrClientCharset=value;
                                                           continue;
                                                   } else if(strcasecmp(key, "autocommit")==0) {
                                                           if(atoi(value)==0)
                                                                   connection.autocommit=false;
                                                           continue;
                                                   } else
                                                           services._throw("unknown connect option" /*key*/);
                                           } else 
                                                   services._throw("connect option without =value" /*key*/);
                                   }
                           }
                   }
   
                   // transcode database_name from $request:charset to UTF-8
                   size_t transcoded_db_path_size;
                   const char* sdb = db_path;
                   services.transcode(sdb, strlen(db_path),
                           sdb, transcoded_db_path_size,
                           services.request_charset(),
                           SQLITE_DEFAULT_CHARSET);
                   
                   rc = sqlite3_open(db_path, &connection.handle);
   
                 if( SQLITE_OK != rc ){                  if( SQLITE_OK != rc ){
                         services._throw(sqlite3_errmsg(connection.handle));                          const char* errmsg = sqlite3_errmsg(connection.handle);
                           _throw(connection, errmsg);
                         sqlite3_close(connection.handle);                          sqlite3_close(connection.handle);
                 }                  }
   
                 connection.cstrClientCharset=0;   
                 connection.autocommit=true;   // значит что все INSERTы и UPDATEы коммитятся автоматически будучи запущенными отдельным запросом  
                 *connection_ref=&connection;                  *connection_ref=&connection;
                   
                   if(!connection.autocommit)
                           exec(connection, "SET AUTOCOMMIT=0");
                           
         }          }
   
         void exec(Connection& connection, const char* statement) {          void exec(Connection& connection, const char* statement) {
   
                 char *zErr;                  char *zErr;
                 int rc;                  int rc;
                   rc=sqlite3_exec(connection.handle, statement, 0, 0, &zErr);
                 rc = sqlite3_exec(connection.handle, statement, 0, 0, &zErr);                  if(rc!=SQLITE_OK){
                           _throw(connection, zErr);
                 MBox(statement, "exec_stat");                          sqlite3_free(zErr); // error? can't free memory after throw
   
                 if( SQLITE_OK!=rc ){  
                         MBox(zErr, "exec_error");  
                         connection.services->_throw(zErr);  
                         sqlite3_free(zErr);  
                 }                  }
   
         }          }
   
         void disconnect(void *aconnection) {          void disconnect(void *aconnection) {
                 Connection& connection=*static_cast<Connection*>(aconnection);                  Connection& connection=*static_cast<Connection*>(aconnection);
   
                 sqlite3_close(connection.handle);                  sqlite3_close(connection.handle);
                 connection.handle=0;                  connection.handle=0;
   
                 MBox("disconnect", "disconnect");  
   
         }          }
   
         void commit(void *aconnection) {          void commit(void *aconnection) {
                 //_asm int 3;  
                 Connection& connection=*static_cast<Connection*>(aconnection);                  Connection& connection=*static_cast<Connection*>(aconnection);
                 MBox("commit", "commit");  
   
                 if(!connection.autocommit)                  if(!connection.autocommit)
                         exec(connection, "commit");                          exec(connection, "COMMIT");
         }          }
   
         void rollback(void *aconnection) {          void rollback(void *aconnection) {
                 Connection& connection=*static_cast<Connection*>(aconnection);                  Connection& connection=*static_cast<Connection*>(aconnection);
   
                 MBox("rollback", "rollback");  
   
                 if(!connection.autocommit)                  if(!connection.autocommit)
                         exec(connection, "rollback");                          exec(connection, "ROLLBACK");
         }          }
   
         bool ping(void *aconnection) {          bool ping(void *aconnection) {
                 Connection& connection=*static_cast<Connection*>(aconnection);                  return true;  // not needed
   
                 return true;  // пинг не требуется, т.к. сервер не сокетный :)  
         }          }
   
         const char* quote(void *aconnection, const char *from, unsigned int length) {          const char* quote(void *aconnection, const char *from, unsigned int length) {
                 Connection& connection=*static_cast<Connection*>(aconnection);                  Connection& connection=*static_cast<Connection*>(aconnection);
                 /*                  /*
                         3.23.22b  
                         You must allocate the to buffer to be at least length*2+1 bytes long.                           You must allocate the to buffer to be at least length*2+1 bytes long. 
                         (In the worse case, each character may need to be encoded as using two bytes,                           In the worse case, each character may need to be encoded as using two bytes, 
                         and you need room for the terminating null byte.)                          and you need room for the terminating null byte.
                 */                  */
                 char *result=(char*)connection.services->malloc_atomic(length*2+1);                  char *result=(char*)connection.services->malloc_atomic(length*2+1);
                 MBox(from, "quote");  
                 char *to=result;                  char *to=result;
                 while(length--) {                  while(length--) {
                         if(*from=='\'') { // ' -> ''                          if(*from=='\'') { // ' -> ''
                                 *to++='\'';                                  *to++='\'';
                           } else if(*from=='\"') { // " -> ""
                                   *to++='\"';
                         }                          }
                         *to++=*from++;                          *to++=*from++;
                 }                  }
                 *to=0;                  *to=0;
 //              mysql_escape_string(result, from, length);  
                 return result;                  return result;
         }          }
   
         void query(void *aconnection,           void query(void *aconnection, 
                 const char *astatement,                   const char *astatement, 
                 size_t placeholders_count, Placeholder* placeholders,                   size_t placeholders_count, Placeholder* placeholders, 
Line 187  public: Line 210  public:
                 const char* cstrClientCharset=connection.cstrClientCharset;                  const char* cstrClientCharset=connection.cstrClientCharset;
   
                 if(placeholders_count>0)                  if(placeholders_count>0)
                         services._throw("bind variables not supported (yet)");                          _throw(connection, "bind variables not supported yet");
      
                   // transcode from $request:charset to ClientCharset
                   if(cstrClientCharset) {
                           size_t transcoded_statement_size;
                           services.transcode(astatement, strlen(astatement),
                                   astatement, transcoded_statement_size,
                                   services.request_charset(),
                                   cstrClientCharset);
                   }
                   
                 const char *statement;                  const char *statement;
                 // вот этот блок добавляет в запрос LIMIT N, M если задано. SQLite поддерживает эти параметры  
                 if(offset || limit) {                  if(offset || limit) {
                         size_t statement_size=strlen(astatement);                          size_t statement_size=strlen(astatement);
                         char *statement_limited=(char *)services.malloc_atomic(                          char *statement_limited=(char *)services.malloc_atomic(
Line 207  public: Line 238  public:
                         statement=astatement;                          statement=astatement;
   
   
 //              char *zErr;  
                 const char *pzTail;                  const char *pzTail;
                 sqlite3_stmt *SQL;                  sqlite3_stmt *SQL;
                 int rc;                  int rc;
Line 217  public: Line 247  public:
   
                 do{ // cycling through SQL commands                  do{ // cycling through SQL commands
   
 //                      MBox(statement, "statement");  
                         rc = sqlite3_prepare(connection.handle, statement, -1, &SQL, &pzTail);                          rc = sqlite3_prepare(connection.handle, statement, -1, &SQL, &pzTail);
                         MBox(pzTail, "tail");  
   
                         if( SQLITE_OK!=rc ){                          if(rc!=SQLITE_OK){
                                 MBox(sqlite3_errmsg(connection.handle), "query_error");                                  _throw(connection, sqlite3_errmsg(connection.handle));
                                 services._throw(sqlite3_errmsg(connection.handle));                                  sqlite3_free(pzTail); // error? can't free memory after throw
 //                              sqlite3_free(zErr);  
                         }                          }
                                                   
   
Line 242  public: Line 269  public:
   
                                         char* strm=(char*)services.malloc_atomic(length+1);                                          char* strm=(char*)services.malloc_atomic(length+1);
                                         memcpy(strm, column_name, length+1);                                          memcpy(strm, column_name, length+1);
                                           const char* str = strm;
                                           // transcode to $request:charset from connect-string?ClientCharset
                                           if(cstrClientCharset) {
                                                   services.transcode(str, length,
                                                           str, length,
                                                           cstrClientCharset,
                                                           services.request_charset());
                                           }
                                                           
                                         CHECK(handlers.add_column(sql_error, (const char*)strm, length));                                          CHECK(handlers.add_column(sql_error, (const char*)strm, length));
                                 }                                  }
                                 CHECK(handlers.before_rows(sql_error));                                  CHECK(handlers.before_rows(sql_error));
Line 267  public: Line 302  public:
                                                         // но switch я всё-таки сделал - так, на будущее                                                          // но switch я всё-таки сделал - так, на будущее
                                                         switch(column_type) {                                                          switch(column_type) {
                                                                 case SQLITE_TEXT:                                                                  case SQLITE_TEXT:
                                                                         str = sqlite3_column_text(SQL, i);                                                                          str=(const unsigned char*)sqlite3_column_text(SQL, i);
                                                                         length = strlen((const char*)str);                                                                          length=strlen(str);
                                                                         break;                                                                          break;
                                                                 case SQLITE_INTEGER:                                                                  case SQLITE_INTEGER:
                                                                         str = sqlite3_column_text(SQL, i);                                                                          str=(const unsigned char*)sqlite3_column_text(SQL, i);
                                                                         length = strlen((const char*)str);                                                                          length=strlen(str);
                                                                         break;                                                                          break;
                                                                 case SQLITE_NULL:                                                                  case SQLITE_NULL:
                                                                         str = NULL;                                                                          str=NULL;
                                                                         length = 0;                                                                          length=0;
                                                                         break;                                                                          break;
                                                                 default:                                                                  default:
                                                                         str = sqlite3_column_text(SQL, i);                                                                          str=(const unsigned char*)sqlite3_column_text(SQL, i);
                                                                         length = strlen((const char*)str);                                                                          length=strlen(str);
                                                                         break;                                                                          break;
                                                         }                                                          }
   
                                                         //MBox((const char*)str, "query_in_step");                                                          if(length){
                                                                   char* strm=(char*)services.malloc_atomic(length+1);
                                                         char* strm=(char*)services.malloc_atomic(length+1);                                                                  memcpy(strm, str, length+1);
                                                         memcpy(strm, str, length+1);                                                                  str = strm;
   
                                                         CHECK(handlers.add_row_cell(sql_error, (const char*)strm, length));                                                                  // transcode to $request:charset from connect-string?ClientCharset
                                                                   if(cstrClientCharset) {
                                                                           services.transcode(str, length,
                                                                                   str, length,
                                                                                   cstrClientCharset,
                                                                                   services.request_charset());
                                                                   }
                                                           } else
                                                                   str = 0;
                                                           
                                                           CHECK(handlers.add_row_cell(sql_error, str, length));
   
                                                 }                                                  }
                                         }                                          }
Line 298  public: Line 343  public:
                         }  // if column                          }  // if column
   
                         if( rc == SQLITE_ERROR || rc == SQLITE_MISUSE ){                          if( rc == SQLITE_ERROR || rc == SQLITE_MISUSE ){
                                 services._throw(sqlite3_errmsg(connection.handle));                                  _throw(connection, sqlite3_errmsg(connection.handle));
                         }                          }
   
         cleanup:          cleanup:
Line 307  public: Line 352  public:
                 } while (strlen(pzTail) > 0);                  } while (strlen(pzTail) > 0);
   
                 if(failed)                  if(failed)
                         services._throw(sql_error);                          _throw(connection, sql_error);
         }          }
   
   private:
           void _throw(Connection& connection, const char* aerr_msg) {
                           size_t err_length=strlen(aerr_msg);
                           if(err_length && connection.cstrClientCharset) {
                                   connection.services->transcode(aerr_msg, err_length,
                                           aerr_msg, err_length,
                                           connection.cstrClientCharset,
                                           connection.services->request_charset());
                           }
                           connection.services->_throw(aerr_msg);
           }
   
   
 private: // sqlite client library funcs  private: // sqlite client library funcs
   
         typedef int (*t_sqlite3_open)(const char *filename, sqlite3 **ppDb); t_sqlite3_open sqlite3_open;          typedef int (*t_sqlite3_open)(const char *filename, sqlite3 **ppDb); t_sqlite3_open sqlite3_open;

Removed from v.1.3  
changed lines
  Added in v.1.4


E-mail: