Diff for /sql/odbc/parser3odbc.C between versions 1.3 and 1.15

version 1.3, 2001/11/16 12:38:59 version 1.15, 2003/09/29 06:14:16
Line 1 Line 1
 /** @file  /** @file
         Parser ODBC driver.          Parser ODBC 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)
 */  */
 static const char *RCSId="$Id$";   static const char *RCSId="$Id$"; 
   
Line 20  static const char *RCSId="$Id$"; Line 20  static const char *RCSId="$Id$";
   
 #include <AFXDB.H>  #include <AFXDB.H>
   
   // defines
   
   #define MAX_COLS 500
   
 #define MAX_STRING 0x400  #define MAX_STRING 0x400
   #define MAX_NUMBER 40
   
   // new in MSSQL2000, no MFC constants
   #ifndef SQL_NVARCHAR
   #define SQL_NVARCHAR (-9)
   #endif
   #ifndef SQL_NTEXT 
   #define SQL_NTEXT (-10)
   #endif
   #ifndef SQL_SMALLDATETIME
   #define SQL_SMALLDATETIME 11
   #endif
   // create table test (id int, a smalldatetime, b ntext, c nvarchar(100))
   
 #define snprintf _snprintf  #define snprintf _snprintf
 #ifndef strncasecmp  #ifndef strncasecmp
Line 109  public: Line 126  public:
                 return true;                  return true;
         }          }
   
         unsigned int quote(          const char* quote(
                 SQL_Driver_services&, void *connection,                  SQL_Driver_services& services, void *connection,
                 char *to, const char *from, unsigned int length) {                  const char *from, unsigned int length) {
                 if(to) { // store mode                  char *result=(char*)services.malloc_atomic(length*2+1);
                         unsigned int result=length;                  char *to=result;
                         while(length--) {                  while(length--) {
                                 if(*from=='\'') { // ' -> ''                          if(*from=='\'') { // ' -> ''
                                         *to++='\''; result++;                                  *to++='\'';
                                 }  
                                 *to++=*from++;  
                         }                          }
                         return result;                          *to++=*from++;
                 } else // estimate mode                  }
                         return length*2;                  *to=0;
                   return result;
         }          }
         void query(          void query(
                 SQL_Driver_services& services, void *connection,                   SQL_Driver_services& services, void *connection, 
Line 135  public: Line 151  public:
                         statement++;                          statement++;
                                   
                 TRY {                  TRY {
                         if(strncasecmp(statement, "select", 6)==0) {                          // mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\adosql.chm::/adoprg02_4g33.htm
                           // Server cursors are created only for statements that begin with: 
                           // SELECT
                           // EXEC[ute] procedure_name
                           // call procedure_name
                           // mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\odbcsql.chm::/od_6_035_5dnp.htm
                           // The ODBC CALL escape sequence for calling a procedure is:
                           // {[?=]call procedure_name[([parameter][,[parameter]]...)]}
                           if(strncasecmp(statement, "select", 6)==0
                                   || strncasecmp(statement, "EXEC", 4)==0
                                   || strncasecmp(statement, "call", 4)==0
                                   || strncasecmp(statement, "{", 1)==0) {
                                 CRecordset rs(db);                                   CRecordset rs(db); 
                                 rs.Open(                                  TRY {
                                         CRecordset::forwardOnly,                                           rs.Open(
                                         statement,                                                  CRecordset::forwardOnly, 
                                         CRecordset::executeDirect                                                     statement,
                                         );                                                  CRecordset::executeDirect   
                                                   );
                                   } CATCH_ALL (e) {
                                           // could not fetch a table
                                           TRY {
                                                   // then try resultless query
                                                   db->ExecuteSQL(statement);
                                                   // OK then
                                                   return;
                                           } CATCH_ALL (e2) {
                                                   // still nothing good
                                                   _throw(services, e); // throw ORIGINAL exception
                                           } END_CATCH_ALL
                                   } END_CATCH_ALL
   
                                 int column_count=rs.GetODBCFieldCount();                                  int column_count=rs.GetODBCFieldCount();
                                 if(!column_count)                                  if(!column_count)
                                         services._throw("result contains no columns");                                          services._throw("result contains no columns");
   
                                   SWORD column_types[MAX_COLS];
                                   if(column_count>MAX_COLS)
                                           column_count=MAX_COLS;
   
                                   SQL_Error sql_error;
   #define CHECK(afailed) if(afailed) services._throw(sql_error)
   
                                 for(int i=0; i<column_count; i++){                                  for(int i=0; i<column_count; i++){
                                         CString string;                                          CString string;
                                         CODBCFieldInfo fieldinfo;                                          CODBCFieldInfo fieldinfo;
                                         rs.GetODBCFieldInfo(i, fieldinfo);                                          rs.GetODBCFieldInfo(i, fieldinfo);
                                           column_types[i]=fieldinfo.m_nSQLType;
                                         size_t size=fieldinfo.m_strName.GetLength();                                          size_t size=fieldinfo.m_strName.GetLength();
                                         void *ptr=0;                                          char *str=0;
                                         if(size) {                                          if(size) {
                                                 ptr=services.malloc(size);                                                  str=(char*)services.malloc_atomic(size+1);
                                                 memcpy(ptr, (char *)LPCTSTR(fieldinfo.m_strName), size);                                                  memcpy(str, (char *)LPCTSTR(fieldinfo.m_strName), size+1);
                                         }                                          }
                                         handlers.add_column(ptr, size);                                          CHECK(handlers.add_column(sql_error, str, size));
                                 }                                  }
   
                                 handlers.before_rows();                                  CHECK(handlers.before_rows(sql_error));
   
                                 unsigned long row=0;                                  unsigned long row=0;
                                   CDBVariant v;
                                   CString s;
                                 while(!rs.IsEOF() && (!limit||(row<offset+limit))) {                                  while(!rs.IsEOF() && (!limit||(row<offset+limit))) {
                                         if(row>=offset) {                                          if(row>=offset) {
                                                 handlers.add_row();                                                  CHECK(handlers.add_row(sql_error));
                                                 for(int i=0; i<column_count; i++)                                               {                                                  for(int i=0; i<column_count; i++) {
                                                         CString string;                                                          size_t size;
                                                         rs.GetFieldValue(i, string);                                                          char* str;
                                                         size_t size=string.GetLength();                                                          switch(column_types[i]) {
                                                         void *ptr=0;                                                          //case xBOOL:
                                                         if(size) {  //                                                      case SQL_INTEGER: // serg@design.ru did that in parser2. test first!
                                                                 ptr=services.malloc(size);                                                          //case SQL_DATETIME: << default: handles that more properly (?)
                                                                 memcpy(ptr, (char *)LPCTSTR(string), size);                                                          case SQL_BINARY: 
                                                           case SQL_VARBINARY:
                                                           case SQL_LONGVARBINARY:
                                                           case SQL_SMALLDATETIME:
                                                                   rs.GetFieldValue(i, v);
                                                                   getFromDBVariant(services, v, str, size);
                                                                   break;
                                                           default:
                                                                   rs.GetFieldValue(i, s);
                                                                   getFromString(services, s, str, size);
                                                                   break;
                                                         }                                                          }
                                                         handlers.add_row_cell(ptr, size);                                                          CHECK(handlers.add_row_cell(sql_error, str, size));
                                                 }                                                  }
                                         }                                          }
                                         rs.MoveNext();  row++;                                          rs.MoveNext();  row++;
Line 185  public: Line 245  public:
                         } else {                          } else {
                                 db->ExecuteSQL(statement);                                  db->ExecuteSQL(statement);
                         }                          }
                 }                   } CATCH_ALL (e) {
                 CATCH_ALL (e) {  
                         _throw(services, e);                          _throw(services, e);
                   } END_CATCH_ALL
           }
   
           void getFromDBVariant(SQL_Driver_services& services, CDBVariant& v, char*& str, size_t& size) {
                   switch(v.m_dwType) {
                   case DBVT_BINARY: /* << would cause problems with current String implementation
                                     now falling into NULL case, effectively ignoring such columns [not failing]
                           {
                                   if(size=v.m_pbinary->m_dwDataLength) {
                                           str=services.malloc_atomic(size+1);
                                           memcpy(ptr, ::GlobalLock(v.m_pbinary->m_hData), size);
                                           ::GlobalUnlock(v.m_pbinary->m_hData);
                                   } else 
                                           str=0;
                                   break;
                           }*/ 
                   case DBVT_NULL: // No union member is valid for access. 
                           str=0;
                           size=0;
                           break;
   /*              case DBVT_BOOL:
                           ptr=v.m_boolVal?"1":"0";
                           size=1;
                           break;*/
   /*                                                      case DBVT_UCHAR:
                           size=strlen(ptr=v.m_chVal);
                           break;
                   case DBVT_SHORT:
                           char buf[MAX_NUMBER];
                           size=snprintf(HEAPIZE buf, "%d", v.m_iVal);
                           break;*/
   /*              case DBVT_LONG: 
                           {
                                   char local_buf[MAX_NUMBER];
                                   size=snprintf(local_buf, MAX_NUMBER, "%ld", v.m_lVal);
                                   ptr=services.malloc_atomic(size);
                                   memcpy(ptr, local_buf, size);
                                   break;
                           }*/
                   /*case DBVT_SINGLE:
                           m_fltVal 
                           break;
           case DBVT_DOUBLE m_dblVal 
           case DBVT_STRING m_pstring */
                   case DBVT_DATE:
                           {
                                   char local_buf[MAX_STRING];
                                   size=snprintf(local_buf, MAX_STRING, 
                                           "%04d-%02d-%02d %02d:%02d:%02d.%03d",
                                           v.m_pdate->year, 
                                           v.m_pdate->month,
                                           v.m_pdate->day,
                                           v.m_pdate->hour,
                                           v.m_pdate->minute,
                                           v.m_pdate->second,
                                           v.m_pdate->fraction);
                                   str=(char*)services.malloc_atomic(size+1);
                                   memcpy(str, local_buf, size+1);
                                   break;
                           }
                   default:
                           char msg[MAX_STRING];
                           snprintf(msg, MAX_STRING, "unknown column return variant type (%d)",
                                   v.m_dwType);
                           services._throw(msg);
                   }
           }
   
           void getFromString(SQL_Driver_services& services, CString& s, char*& astr, size_t& size) {
                   if(s.IsEmpty()) {
                           astr=0;
                           size=0;
                   } else {
                           const char *cstr=LPCTSTR(s);
                           size=strlen(cstr); //string.GetLength() works wrong with non-string types: 
                           astr=(char*)services.malloc_atomic(size+1);
                           memcpy(astr, cstr, size+1);
                 }                  }
                 END_CATCH_ALL  
         }          }
   
         void _throw(SQL_Driver_services& services, CException *e) {          void _throw(SQL_Driver_services& services, CException *e) {

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


E-mail: