|
|
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: */
1.3 ! paf 8: static const char *RCSId="$Id: parser3odbc.C,v 1.2 2001/10/29 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);
172: size_t size=string.GetLength();
173: void *ptr=0;
174: if(size) {
175: ptr=services.malloc(size);
176: memcpy(ptr, (char *)LPCTSTR(string), size);
177: }
178: handlers.add_row_cell(ptr, size);
179: }
180: }
181: rs.MoveNext(); row++;
182: }
183:
184: rs.Close();
185: } else {
186: db->ExecuteSQL(statement);
187: }
188: }
189: CATCH_ALL (e) {
190: _throw(services, e);
191: }
192: END_CATCH_ALL
193: }
194:
195: void _throw(SQL_Driver_services& services, CException *e) {
196: char szCause[MAX_STRING]; szCause[0]=0;
197: e->GetErrorMessage(szCause, MAX_STRING);
198: char msg[MAX_STRING];
199: snprintf(msg, MAX_STRING, "%s: %s",
200: e->GetRuntimeClass()->m_lpszClassName,
201: *szCause?szCause:"unknown");
202: services._throw(msg);
203: }
204:
205: };
206:
207: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
208: return new ODBC_Driver();
209: }