|
|
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.5 ! parser 8: static const char *RCSId="$Id: parser3odbc.C,v 1.4 2001/09/05 08:57:43 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>
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: }
1.3 parser 77: void disconnect(void *connection) {
1.1 parser 78: CDatabase *db=static_cast<CDatabase *>(connection);
79: TRY
80: delete db;
81: CATCH_ALL (e) {
1.3 parser 82: // nothing
1.1 parser 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: */
1.2 parser 121: // ' -> ''
122: unsigned int result=length;
123: while(length--) {
124: if(*from=='\'')
125: *to++='\'';
126: *to++=*from++;
127: }
128: return result;
1.1 parser 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: }
1.2 parser 184: rs.MoveNext(); row++;
1.1 parser 185: }
186:
187: rs.Close();
188: } else {
1.2 parser 189: db->ExecuteSQL(statement);
1.1 parser 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:
1.5 ! parser 210: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
1.1 parser 211: return new ODBC_Driver();
212: }