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