Annotation of sql/odbc/parser3odbc.C, revision 1.7

1.1       parser      1: /** @file
                      2:        Parser ODBC driver.
                      3: 
1.5       paf         4:        Copyright(c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
1.1       parser      5: 
1.5       paf         6:        Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1       parser      7: */
1.7     ! paf         8: static const char *RCSId="$Id: parser3odbc.C,v 1.6 2002/03/05 15:04:59 paf Exp $"; 
1.1       parser      9: 
                     10: #ifndef _MSC_VER
                     11: #      error compile ISAPI module with MSVC [no urge for now to make it autoconf-ed (PAF)]
                     12: #endif
                     13: 
                     14: #include <string.h>
                     15: #include <stdio.h>
                     16: #include <stdlib.h>
1.2       paf        17: #include <setjmp.h>
1.1       parser     18: 
                     19: #include "pa_sql_driver.h"
                     20: 
                     21: #include <AFXDB.H>
                     22: 
                     23: #define MAX_STRING 0x400
1.7     ! paf        24: #define MAX_NUMBER 40
        !            25: 
        !            26: // MSSQL2000
        !            27: #ifndef SQL_NVARCHAR
        !            28: #define SQL_NVARCHAR (-9)
        !            29: #endif
        !            30: #ifndef SQL_NTEXT 
        !            31: #define SQL_NTEXT (-10)
        !            32: #endif
        !            33: #ifndef SQL_SMALLDATETIME
        !            34: #define SQL_SMALLDATETIME 11
        !            35: #endif
        !            36: // create table test (id int, a smalldatetime, b ntext, c nvarchar(100))
1.1       parser     37: 
                     38: #define snprintf _snprintf
                     39: #ifndef strncasecmp
                     40: #      define strncasecmp _strnicmp
                     41: #endif
                     42: 
                     43: static char *lsplit(char *string, char delim) {
                     44:     if(string) {
                     45:                char *v=strchr(string, delim);
                     46:                if(v) {
                     47:                        *v=0;
                     48:                        return v+1;
                     49:                }
                     50:     }
                     51:     return 0;
                     52: }
                     53: 
                     54: /**
                     55:        ODBC server driver
                     56: */
                     57: class ODBC_Driver : public SQL_Driver {
                     58: public:
                     59: 
                     60:        ODBC_Driver() : SQL_Driver() {
                     61:        }
                     62: 
                     63:        /// get api version
                     64:        int api_version() { return SQL_DRIVER_API_VERSION; }
1.3       paf        65:        const char *initialize(char *dlopen_file_spec) { return 0; }
1.1       parser     66:        /**     connect
                     67:                @param used_only_in_connect_url
                     68:                        format: @b DSN=dsn;UID=user;PWD=password (ODBC connect string)
                     69:                        WARNING: must be used only to connect, for buffer doesn't live long
                     70:        */
                     71:        void connect(
                     72:                char *used_only_in_connect_url, 
                     73:                SQL_Driver_services& services, 
                     74:                void **connection ///< output: CDatabase *
                     75:                ) {
                     76:        //      _asm int 3;
                     77:                CDatabase *db;
                     78:                TRY {
                     79:                        db=new CDatabase();
                     80:                        db->OpenEx(used_only_in_connect_url, CDatabase::noOdbcDialog);
                     81:                        db->BeginTrans();
                     82:                } 
                     83:                CATCH_ALL (e) {
                     84:                        _throw(services, e);
                     85:                        db=0; // calm, compiler
                     86:                }
                     87:                END_CATCH_ALL
                     88: 
                     89:                *(CDatabase **)connection=db;
                     90:        }
                     91:        void disconnect(void *connection) {
                     92:                CDatabase *db=static_cast<CDatabase *>(connection);
                     93:                TRY
                     94:                        delete db;
                     95:                CATCH_ALL (e) {
                     96:                        // nothing
                     97:                }
                     98:                END_CATCH_ALL
                     99:        }
                    100:        void commit(SQL_Driver_services& services, void *connection) {
                    101:                CDatabase *db=static_cast<CDatabase *>(connection);
                    102:                TRY
                    103:                        db->CommitTrans();
                    104:                        db->BeginTrans();
                    105:                CATCH_ALL (e) {
                    106:                        _throw(services, e);
                    107:                }
                    108:                END_CATCH_ALL
                    109:        }
                    110:        void rollback(SQL_Driver_services& services, void *connection) {
                    111:                CDatabase *db=static_cast<CDatabase *>(connection);
                    112:                TRY
                    113:                        db->Rollback();
                    114:                        db->BeginTrans();
                    115:                CATCH_ALL (e) {
                    116:                        _throw(services, e);
                    117:                }
                    118:                END_CATCH_ALL
                    119:        }
                    120: 
                    121:        bool ping(SQL_Driver_services&, void *connection) {
                    122:                return true;
                    123:        }
                    124: 
                    125:        unsigned int quote(
                    126:                SQL_Driver_services&, void *connection,
                    127:                char *to, const char *from, unsigned int length) {
1.3       paf       128:                if(to) { // store mode
                    129:                        unsigned int result=length;
                    130:                        while(length--) {
                    131:                                if(*from=='\'') { // ' -> ''
                    132:                                        *to++='\''; result++;
                    133:                                }
                    134:                                *to++=*from++;
                    135:                        }
                    136:                        return result;
                    137:                } else // estimate mode
                    138:                        return length*2;
1.1       parser    139:        }
                    140:        void query(
                    141:                SQL_Driver_services& services, void *connection, 
                    142:                const char *statement, unsigned long offset, unsigned long limit,
                    143:                SQL_Driver_query_event_handlers& handlers) {
                    144: 
                    145:                CDatabase *db=static_cast<CDatabase *>(connection);
                    146: 
                    147:                while(isspace(*statement)) 
                    148:                        statement++;
                    149:                
                    150:                TRY {
                    151:                        if(strncasecmp(statement, "select", 6)==0) {
                    152:                                CRecordset rs(db); 
                    153:                                rs.Open(
                    154:                                        CRecordset::forwardOnly, 
                    155:                                        statement,
                    156:                                        CRecordset::executeDirect   
                    157:                                        );
                    158: 
                    159:                                int column_count=rs.GetODBCFieldCount();
                    160:                                if(!column_count)
                    161:                                        services._throw("result contains no columns");
                    162: 
                    163:                                for(int i=0; i<column_count; i++){
                    164:                                        CString string;
                    165:                                        CODBCFieldInfo fieldinfo;
                    166:                                        rs.GetODBCFieldInfo(i, fieldinfo);
                    167:                                        size_t size=fieldinfo.m_strName.GetLength();
                    168:                                        void *ptr=0;
                    169:                                        if(size) {
                    170:                                                ptr=services.malloc(size);
                    171:                                                memcpy(ptr, (char *)LPCTSTR(fieldinfo.m_strName), size);
                    172:                                        }
                    173:                                        handlers.add_column(ptr, size);
                    174:                                }
                    175: 
                    176:                                handlers.before_rows();
                    177: 
                    178:                                unsigned long row=0;
                    179:                                while(!rs.IsEOF() && (!limit||(row<offset+limit))) {
                    180:                                        if(row>=offset) {
                    181:                                                handlers.add_row();
                    182:                                                for(int i=0; i<column_count; i++)                                               {
1.7     ! paf       183:                                                        CODBCFieldInfo fieldinfo;
        !           184:                                                        rs.GetODBCFieldInfo(i, fieldinfo);
1.6       paf       185:                                                        size_t size;
                    186:                                                        void *ptr;
1.7     ! paf       187:                                                        switch(fieldinfo.m_nSQLType) {
        !           188:                                                        //case xBOOL:
        !           189: //                                                     case SQL_INTEGER: // serg@design.ru did that in parser2. test first!
        !           190:                                                        //case SQL_DATETIME:
        !           191:                                                        case SQL_SMALLDATETIME:
        !           192:                                                                {
        !           193:                                                                        CDBVariant v;
        !           194:                                                                        rs.GetFieldValue(i, v);
        !           195:                                                                        getFromDBVariant(services, v, ptr, size);
        !           196:                                                                        break;
        !           197:                                                                }
        !           198:                                                        default:
        !           199:                                                                {
        !           200:                                                                        CString s;
        !           201:                                                                        rs.GetFieldValue(i, s);
        !           202:                                                                        getFromString(services, s, ptr, size);
        !           203:                                                                        break;
        !           204:                                                                }
1.1       parser    205:                                                        }
                    206:                                                        handlers.add_row_cell(ptr, size);
                    207:                                                }
                    208:                                        }
                    209:                                        rs.MoveNext();  row++;
                    210:                                }
                    211:                                
                    212:                                rs.Close();
                    213:                        } else {
                    214:                                db->ExecuteSQL(statement);
                    215:                        }
                    216:                } 
                    217:                CATCH_ALL (e) {
                    218:                        _throw(services, e);
                    219:                }
                    220:                END_CATCH_ALL
1.7     ! paf       221:        }
        !           222: 
        !           223:        void getFromDBVariant(SQL_Driver_services& services, CDBVariant& v, void *& ptr, size_t& size) {
        !           224:                switch(v.m_dwType) {
        !           225:                case DBVT_NULL: // No union member is valid for access. 
        !           226:                        ptr=0;
        !           227:                        size=0;
        !           228:                        break;
        !           229: /*             case DBVT_BOOL:
        !           230:                        ptr=v.m_boolVal?"1":"0";
        !           231:                        size=1;
        !           232:                        break;*/
        !           233: /*                                                     case DBVT_UCHAR:
        !           234:                        size=strlen(ptr=v.m_chVal);
        !           235:                        break;
        !           236:                case DBVT_SHORT:
        !           237:                        char buf[MAX_NUMBER];
        !           238:                        size=snprintf(HEAPIZE buf, "%d", v.m_iVal);
        !           239:                        break;*/
        !           240: /*             case DBVT_LONG: 
        !           241:                        {
        !           242:                                char local_buf[MAX_NUMBER];
        !           243:                                size=snprintf(local_buf, MAX_NUMBER, "%ld", v.m_lVal);
        !           244:                                ptr=services.malloc(size);
        !           245:                                memcpy(ptr, local_buf, size);
        !           246:                                break;
        !           247:                        }*/
        !           248:                /*case DBVT_SINGLE:
        !           249:                        m_fltVal 
        !           250:                        break;
        !           251:        case DBVT_DOUBLE m_dblVal 
        !           252:        case DBVT_STRING m_pstring 
        !           253:        case DBVT_BINARY m_pbinary */
        !           254:                case DBVT_DATE:
        !           255:                        {
        !           256:                                char local_buf[MAX_STRING];
        !           257:                                size=snprintf(local_buf, MAX_STRING, 
        !           258:                                        "%04d-%02d-%02d %02d:%02d:%02d.%03d",
        !           259:                                        v.m_pdate->year, 
        !           260:                                        v.m_pdate->month,
        !           261:                                        v.m_pdate->day,
        !           262:                                        v.m_pdate->hour,
        !           263:                                        v.m_pdate->minute,
        !           264:                                        v.m_pdate->second,
        !           265:                                        v.m_pdate->fraction);
        !           266:                                ptr=services.malloc(size);
        !           267:                                memcpy(ptr, local_buf, size);
        !           268:                                break;
        !           269:                        }
        !           270:                default:
        !           271:                        char msg[MAX_STRING];
        !           272:                        snprintf(msg, MAX_STRING, "unknown column return variant type (%d)",
        !           273:                                v.m_dwType);
        !           274:                        services._throw(msg);
        !           275:                }
        !           276:        }
        !           277: 
        !           278:        void getFromString(SQL_Driver_services& services, CString& s, void *& ptr, size_t& size) {
        !           279:                if(s.IsEmpty()) {
        !           280:                        ptr=0;
        !           281:                        size=0;
        !           282:                } else {
        !           283:                        const char *cstr=LPCTSTR(s);
        !           284:                        size=strlen(cstr); //string.GetLength() works wrong with non-string types: 
        !           285:                        ptr=services.malloc(size);
        !           286:                        memcpy(ptr, cstr, size);
        !           287:                }
1.1       parser    288:        }
                    289: 
                    290:        void _throw(SQL_Driver_services& services, CException *e) {
                    291:                char szCause[MAX_STRING]; szCause[0]=0;
                    292:                e->GetErrorMessage(szCause, MAX_STRING);
                    293:                char msg[MAX_STRING];
                    294:                snprintf(msg, MAX_STRING, "%s: %s",
                    295:                        e->GetRuntimeClass()->m_lpszClassName,
                    296:                        *szCause?szCause:"unknown");
                    297:                services._throw(msg);
                    298:        }
                    299: 
                    300: };
                    301: 
                    302: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
                    303:        return new ODBC_Driver();
                    304: }

E-mail: