|
|
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.2 ! paf 8: static const char *RCSId="$Id: parser3odbc.C,v 1.1.1.1 2001/09/21 15:42:21 parser 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; }
52: const char *initialize(const char *dlopen_file_spec) { return 0; }
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) {
115: /*
116: You must allocate the to buffer to be at least length*2+1 bytes long.
117: (In the worse case, each character may need to be encoded as using two bytes,
118: and you need room for the terminating null byte.)
119:
120: it's already UNTAINT_TIMES_BIGGER
121: */
122: // ' -> ''
123: unsigned int result=length;
124: while(length--) {
125: if(*from=='\'')
126: *to++='\'';
127: *to++=*from++;
128: }
129: return result;
130: }
131: void query(
132: SQL_Driver_services& services, void *connection,
133: const char *statement, unsigned long offset, unsigned long limit,
134: SQL_Driver_query_event_handlers& handlers) {
135:
136: CDatabase *db=static_cast<CDatabase *>(connection);
137:
138: while(isspace(*statement))
139: statement++;
140:
141: TRY {
142: if(strncasecmp(statement, "select", 6)==0) {
143: CRecordset rs(db);
144: rs.Open(
145: CRecordset::forwardOnly,
146: statement,
147: CRecordset::executeDirect
148: );
149:
150: int column_count=rs.GetODBCFieldCount();
151: if(!column_count)
152: services._throw("result contains no columns");
153:
154: for(int i=0; i<column_count; i++){
155: CString string;
156: CODBCFieldInfo fieldinfo;
157: rs.GetODBCFieldInfo(i, fieldinfo);
158: size_t size=fieldinfo.m_strName.GetLength();
159: void *ptr=0;
160: if(size) {
161: ptr=services.malloc(size);
162: memcpy(ptr, (char *)LPCTSTR(fieldinfo.m_strName), size);
163: }
164: handlers.add_column(ptr, size);
165: }
166:
167: handlers.before_rows();
168:
169: unsigned long row=0;
170: while(!rs.IsEOF() && (!limit||(row<offset+limit))) {
171: if(row>=offset) {
172: handlers.add_row();
173: for(int i=0; i<column_count; i++) {
174: CString string;
175: rs.GetFieldValue(i, string);
176: size_t size=string.GetLength();
177: void *ptr=0;
178: if(size) {
179: ptr=services.malloc(size);
180: memcpy(ptr, (char *)LPCTSTR(string), size);
181: }
182: handlers.add_row_cell(ptr, size);
183: }
184: }
185: rs.MoveNext(); row++;
186: }
187:
188: rs.Close();
189: } else {
190: db->ExecuteSQL(statement);
191: }
192: }
193: CATCH_ALL (e) {
194: _throw(services, e);
195: }
196: END_CATCH_ALL
197: }
198:
199: void _throw(SQL_Driver_services& services, CException *e) {
200: char szCause[MAX_STRING]; szCause[0]=0;
201: e->GetErrorMessage(szCause, MAX_STRING);
202: char msg[MAX_STRING];
203: snprintf(msg, MAX_STRING, "%s: %s",
204: e->GetRuntimeClass()->m_lpszClassName,
205: *szCause?szCause:"unknown");
206: services._throw(msg);
207: }
208:
209: };
210:
211: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
212: return new ODBC_Driver();
213: }