Annotation of sql/odbc/parser3odbc.C, revision 1.1
1.1 ! parser 1: /** @file
! 2: Parser ODBC driver.
! 3:
! 4: Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
! 5:
! 6: Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
! 7: */
! 8: static const char *RCSId="$Id: parser3odbc.C,v 1.5 2001/09/05 09:22:45 parser Exp $";
! 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>
! 17:
! 18: #include "pa_sql_driver.h"
! 19:
! 20: #include <AFXDB.H>
! 21:
! 22: #define MAX_STRING 0x400
! 23:
! 24: #define snprintf _snprintf
! 25: #ifndef strncasecmp
! 26: # define strncasecmp _strnicmp
! 27: #endif
! 28:
! 29: static char *lsplit(char *string, char delim) {
! 30: if(string) {
! 31: char *v=strchr(string, delim);
! 32: if(v) {
! 33: *v=0;
! 34: return v+1;
! 35: }
! 36: }
! 37: return 0;
! 38: }
! 39:
! 40: /**
! 41: ODBC server driver
! 42: */
! 43: class ODBC_Driver : public SQL_Driver {
! 44: public:
! 45:
! 46: ODBC_Driver() : SQL_Driver() {
! 47: }
! 48:
! 49: /// get api version
! 50: int api_version() { return SQL_DRIVER_API_VERSION; }
! 51: const char *initialize(const char *dlopen_file_spec) { return 0; }
! 52: /** connect
! 53: @param used_only_in_connect_url
! 54: format: @b DSN=dsn;UID=user;PWD=password (ODBC connect string)
! 55: WARNING: must be used only to connect, for buffer doesn't live long
! 56: */
! 57: void connect(
! 58: char *used_only_in_connect_url,
! 59: SQL_Driver_services& services,
! 60: void **connection ///< output: CDatabase *
! 61: ) {
! 62: // _asm int 3;
! 63: CDatabase *db;
! 64: TRY {
! 65: db=new CDatabase();
! 66: db->OpenEx(used_only_in_connect_url, CDatabase::noOdbcDialog);
! 67: db->BeginTrans();
! 68: }
! 69: CATCH_ALL (e) {
! 70: _throw(services, e);
! 71: db=0; // calm, compiler
! 72: }
! 73: END_CATCH_ALL
! 74:
! 75: *(CDatabase **)connection=db;
! 76: }
! 77: void disconnect(void *connection) {
! 78: CDatabase *db=static_cast<CDatabase *>(connection);
! 79: TRY
! 80: delete db;
! 81: CATCH_ALL (e) {
! 82: // nothing
! 83: }
! 84: END_CATCH_ALL
! 85: }
! 86: void commit(SQL_Driver_services& services, void *connection) {
! 87: CDatabase *db=static_cast<CDatabase *>(connection);
! 88: TRY
! 89: db->CommitTrans();
! 90: db->BeginTrans();
! 91: CATCH_ALL (e) {
! 92: _throw(services, e);
! 93: }
! 94: END_CATCH_ALL
! 95: }
! 96: void rollback(SQL_Driver_services& services, void *connection) {
! 97: CDatabase *db=static_cast<CDatabase *>(connection);
! 98: TRY
! 99: db->Rollback();
! 100: db->BeginTrans();
! 101: CATCH_ALL (e) {
! 102: _throw(services, e);
! 103: }
! 104: END_CATCH_ALL
! 105: }
! 106:
! 107: bool ping(SQL_Driver_services&, void *connection) {
! 108: return true;
! 109: }
! 110:
! 111: unsigned int quote(
! 112: SQL_Driver_services&, void *connection,
! 113: char *to, const char *from, unsigned int length) {
! 114: /*
! 115: You must allocate the to buffer to be at least length*2+1 bytes long.
! 116: (In the worse case, each character may need to be encoded as using two bytes,
! 117: and you need room for the terminating null byte.)
! 118:
! 119: it's already UNTAINT_TIMES_BIGGER
! 120: */
! 121: // ' -> ''
! 122: unsigned int result=length;
! 123: while(length--) {
! 124: if(*from=='\'')
! 125: *to++='\'';
! 126: *to++=*from++;
! 127: }
! 128: return result;
! 129: }
! 130: void query(
! 131: SQL_Driver_services& services, void *connection,
! 132: const char *statement, unsigned long offset, unsigned long limit,
! 133: SQL_Driver_query_event_handlers& handlers) {
! 134:
! 135: CDatabase *db=static_cast<CDatabase *>(connection);
! 136:
! 137: while(isspace(*statement))
! 138: statement++;
! 139:
! 140: TRY {
! 141: if(strncasecmp(statement, "select", 6)==0) {
! 142: CRecordset rs(db);
! 143: rs.Open(
! 144: CRecordset::forwardOnly,
! 145: statement,
! 146: CRecordset::executeDirect
! 147: );
! 148:
! 149: int column_count=rs.GetODBCFieldCount();
! 150: if(!column_count)
! 151: services._throw("result contains no columns");
! 152:
! 153: for(int i=0; i<column_count; i++){
! 154: CString string;
! 155: CODBCFieldInfo fieldinfo;
! 156: rs.GetODBCFieldInfo(i, fieldinfo);
! 157: size_t size=fieldinfo.m_strName.GetLength();
! 158: void *ptr=0;
! 159: if(size) {
! 160: ptr=services.malloc(size);
! 161: memcpy(ptr, (char *)LPCTSTR(fieldinfo.m_strName), size);
! 162: }
! 163: handlers.add_column(ptr, size);
! 164: }
! 165:
! 166: handlers.before_rows();
! 167:
! 168: unsigned long row=0;
! 169: while(!rs.IsEOF() && (!limit||(row<offset+limit))) {
! 170: if(row>=offset) {
! 171: handlers.add_row();
! 172: for(int i=0; i<column_count; i++) {
! 173: CString string;
! 174: rs.GetFieldValue(i, string);
! 175: size_t size=string.GetLength();
! 176: void *ptr=0;
! 177: if(size) {
! 178: ptr=services.malloc(size);
! 179: memcpy(ptr, (char *)LPCTSTR(string), size);
! 180: }
! 181: handlers.add_row_cell(ptr, size);
! 182: }
! 183: }
! 184: rs.MoveNext(); row++;
! 185: }
! 186:
! 187: rs.Close();
! 188: } else {
! 189: db->ExecuteSQL(statement);
! 190: }
! 191: }
! 192: CATCH_ALL (e) {
! 193: _throw(services, e);
! 194: }
! 195: END_CATCH_ALL
! 196: }
! 197:
! 198: void _throw(SQL_Driver_services& services, CException *e) {
! 199: char szCause[MAX_STRING]; szCause[0]=0;
! 200: e->GetErrorMessage(szCause, MAX_STRING);
! 201: char msg[MAX_STRING];
! 202: snprintf(msg, MAX_STRING, "%s: %s",
! 203: e->GetRuntimeClass()->m_lpszClassName,
! 204: *szCause?szCause:"unknown");
! 205: services._throw(msg);
! 206: }
! 207:
! 208: };
! 209:
! 210: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
! 211: return new ODBC_Driver();
! 212: }
E-mail: