Annotation of embedaddon/php/ext/pdo_dblib/dblib_driver.c, revision 1.1.1.5
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.5 ! misho 5: | Copyright (c) 1997-2014 The PHP Group |
1.1 misho 6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Author: Wez Furlong <wez@php.net> |
16: | Frank M. Kromann <frank@kromann.info> |
17: +----------------------------------------------------------------------+
18: */
19:
1.1.1.2 misho 20: /* $Id$ */
1.1 misho 21:
22: #ifdef HAVE_CONFIG_H
23: # include "config.h"
24: #endif
25:
26: #include "php.h"
27: #include "php_ini.h"
28: #include "ext/standard/info.h"
29: #include "pdo/php_pdo.h"
30: #include "pdo/php_pdo_driver.h"
31: #include "php_pdo_dblib.h"
32: #include "php_pdo_dblib_int.h"
33: #include "zend_exceptions.h"
34:
1.1.1.3 misho 35: /* Cache of the server supported datatypes, initialized in handle_factory */
36: zval* pdo_dblib_datatypes;
37:
1.1 misho 38: static int dblib_fetch_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
39: {
40: pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
41: pdo_dblib_err *einfo = &H->err;
42: pdo_dblib_stmt *S = NULL;
43: char *message;
44: char *msg;
45:
46: if (stmt) {
47: S = (pdo_dblib_stmt*)stmt->driver_data;
48: einfo = &S->err;
49: }
50:
51: if (einfo->dberr == SYBESMSG && einfo->lastmsg) {
52: msg = einfo->lastmsg;
53: } else if (einfo->dberr == SYBESMSG && DBLIB_G(err).lastmsg) {
54: msg = DBLIB_G(err).lastmsg;
55: DBLIB_G(err).lastmsg = NULL;
56: } else {
57: msg = einfo->dberrstr;
58: }
59:
60: spprintf(&message, 0, "%s [%d] (severity %d) [%s]",
61: msg, einfo->dberr, einfo->severity, stmt ? stmt->active_query_string : "");
62:
63: add_next_index_long(info, einfo->dberr);
64: add_next_index_string(info, message, 0);
65: add_next_index_long(info, einfo->oserr);
66: add_next_index_long(info, einfo->severity);
67: if (einfo->oserrstr) {
68: add_next_index_string(info, einfo->oserrstr, 1);
69: }
70:
71: return 1;
72: }
73:
74:
75: static int dblib_handle_closer(pdo_dbh_t *dbh TSRMLS_DC)
76: {
77: pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
78:
79: if (H) {
80: if (H->link) {
81: dbclose(H->link);
82: H->link = NULL;
83: }
84: if (H->login) {
85: dbfreelogin(H->login);
86: H->login = NULL;
87: }
88: pefree(H, dbh->is_persistent);
89: dbh->driver_data = NULL;
90: }
91: return 0;
92: }
93:
94: static int dblib_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
95: {
96: pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
97: pdo_dblib_stmt *S = ecalloc(1, sizeof(*S));
98:
99: S->H = H;
100: stmt->driver_data = S;
101: stmt->methods = &dblib_stmt_methods;
102: stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
103: S->err.sqlstate = stmt->error_code;
104:
105: return 1;
106: }
107:
108: static long dblib_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
109: {
110: pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
111: RETCODE ret, resret;
112:
113: dbsetuserdata(H->link, (BYTE*)&H->err);
114:
115: if (FAIL == dbcmd(H->link, sql)) {
116: return -1;
117: }
118:
119: if (FAIL == dbsqlexec(H->link)) {
120: return -1;
121: }
122:
123: resret = dbresults(H->link);
124:
125: if (resret == FAIL) {
126: return -1;
127: }
128:
129: ret = dbnextrow(H->link);
130: if (ret == FAIL) {
131: return -1;
132: }
133:
134: if (dbnumcols(H->link) <= 0) {
135: return DBCOUNT(H->link);
136: }
137:
138: /* throw away any rows it might have returned */
139: dbcanquery(H->link);
140:
141: return DBCOUNT(H->link);
142: }
143:
144: static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
145: {
146: pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
147: char *q;
148: int l = 1;
149:
150: *quoted = q = safe_emalloc(2, unquotedlen, 3);
151: *q++ = '\'';
152:
153: while (unquotedlen--) {
154: if (*unquoted == '\'') {
155: *q++ = '\'';
156: *q++ = '\'';
157: l += 2;
158: } else {
159: *q++ = *unquoted;
160: ++l;
161: }
162: unquoted++;
163: }
164:
165: *q++ = '\'';
166: *q++ = '\0';
167: *quotedlen = l+1;
168:
169: return 1;
170: }
171:
1.1.1.2 misho 172: static int pdo_dblib_transaction_cmd(const char *cmd, pdo_dbh_t *dbh TSRMLS_DC)
173: {
174: pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
175: RETCODE ret;
176:
177: if (FAIL == dbcmd(H->link, cmd)) {
178: return 0;
179: }
180:
181: if (FAIL == dbsqlexec(H->link)) {
182: return 0;
183: }
184:
185: return 1;
186: }
187:
188: static int dblib_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
189: {
190: return pdo_dblib_transaction_cmd("BEGIN TRANSACTION", dbh TSRMLS_CC);
191: }
192:
193: static int dblib_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
194: {
195: return pdo_dblib_transaction_cmd("COMMIT TRANSACTION", dbh TSRMLS_CC);
196: }
197:
198: static int dblib_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
199: {
200: return pdo_dblib_transaction_cmd("ROLLBACK TRANSACTION", dbh TSRMLS_CC);
201: }
202:
203: char *dblib_handle_last_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
204: {
205: pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
206:
207: RETCODE ret;
208: char *id = NULL;
209:
210: /*
211: * Would use scope_identity() but it's not implemented on Sybase
212: */
213:
214: if (FAIL == dbcmd(H->link, "SELECT @@IDENTITY")) {
215: return NULL;
216: }
217:
218: if (FAIL == dbsqlexec(H->link)) {
219: return NULL;
220: }
221:
222: ret = dbresults(H->link);
223: if (ret == FAIL || ret == NO_MORE_RESULTS) {
224: dbcancel(H->link);
225: return NULL;
226: }
227:
228: ret = dbnextrow(H->link);
229:
230: if (ret == FAIL || ret == NO_MORE_ROWS) {
231: dbcancel(H->link);
232: return NULL;
233: }
234:
235: if (dbdatlen(H->link, 1) == 0) {
236: dbcancel(H->link);
237: return NULL;
238: }
239:
240: id = emalloc(32);
241: *len = dbconvert(NULL, (dbcoltype(H->link, 1)) , (dbdata(H->link, 1)) , (dbdatlen(H->link, 1)), SQLCHAR, id, (DBINT)-1);
242:
243: dbcancel(H->link);
244: return id;
245: }
246:
1.1 misho 247: static struct pdo_dbh_methods dblib_methods = {
248: dblib_handle_closer,
249: dblib_handle_preparer,
250: dblib_handle_doer,
251: dblib_handle_quoter,
1.1.1.2 misho 252: dblib_handle_begin, /* begin */
253: dblib_handle_commit, /* commit */
254: dblib_handle_rollback, /* rollback */
255: NULL, /*set attr */
256: dblib_handle_last_id, /* last insert id */
1.1 misho 257: dblib_fetch_error, /* fetch error */
258: NULL, /* get attr */
259: NULL, /* check liveness */
1.1.1.2 misho 260: NULL, /* get driver methods */
261: NULL, /* request shutdown */
262: NULL /* in transaction */
1.1 misho 263: };
264:
265: static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
266: {
267: pdo_dblib_db_handle *H;
1.1.1.3 misho 268: int i, nvars, nvers, ret = 0;
269: int *val;
270:
271: const pdo_dblib_keyval tdsver[] = {
272: {"4.2",DBVERSION_42}
273: ,{"4.6",DBVERSION_46}
274: ,{"5.0",DBVERSION_70} /* FIXME: This does not work with Sybase, but environ will */
275: ,{"6.0",DBVERSION_70}
276: ,{"7.0",DBVERSION_70}
1.1.1.4 misho 277: #ifdef DBVERSION_71
1.1.1.3 misho 278: ,{"7.1",DBVERSION_71}
1.1.1.4 misho 279: #endif
280: #ifdef DBVERSION_72
1.1.1.3 misho 281: ,{"7.2",DBVERSION_72}
282: ,{"8.0",DBVERSION_72}
1.1.1.4 misho 283: #endif
1.1.1.3 misho 284: ,{"10.0",DBVERSION_100}
285: ,{"auto",0} /* Only works with FreeTDS. Other drivers will bork */
286:
287: };
288:
289: nvers = sizeof(tdsver)/sizeof(tdsver[0]);
290:
1.1 misho 291: struct pdo_data_src_parser vars[] = {
1.1.1.3 misho 292: { "charset", NULL, 0 }
293: ,{ "appname", "PHP " PDO_DBLIB_FLAVOUR, 0 }
294: ,{ "host", "127.0.0.1", 0 }
295: ,{ "dbname", NULL, 0 }
296: ,{ "secure", NULL, 0 } /* DBSETLSECURE */
297: ,{ "version", NULL, 0 } /* DBSETLVERSION */
1.1 misho 298: };
1.1.1.3 misho 299:
300: nvars = sizeof(vars)/sizeof(vars[0]);
301:
302: php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, nvars);
1.1 misho 303:
304: H = pecalloc(1, sizeof(*H), dbh->is_persistent);
305: H->login = dblogin();
306: H->err.sqlstate = dbh->error_code;
307:
308: if (!H->login) {
309: goto cleanup;
310: }
311:
1.1.1.3 misho 312: DBERRHANDLE(H->login, (EHANDLEFUNC) error_handler);
313: DBMSGHANDLE(H->login, (MHANDLEFUNC) msg_handler);
314:
315: if(vars[5].optval) {
316: for(i=0;i<nvers;i++) {
317: if(strcmp(vars[5].optval,tdsver[i].key) == 0) {
318: if(FAIL==dbsetlversion(H->login, tdsver[i].value)) {
319: pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Failed to set version specified in connection string." TSRMLS_CC);
320: goto cleanup;
321: }
322: break;
323: }
324: }
325:
326: if (i==nvers) {
327: printf("Invalid version '%s'\n", vars[5].optval);
328: pdo_raise_impl_error(dbh, NULL, "HY000", "PDO_DBLIB: Invalid version specified in connection string." TSRMLS_CC);
329: goto cleanup; /* unknown version specified */
330: }
331: }
332:
1.1 misho 333: if (dbh->username) {
1.1.1.3 misho 334: if(FAIL == DBSETLUSER(H->login, dbh->username)) {
335: goto cleanup;
336: }
1.1 misho 337: }
1.1.1.3 misho 338:
1.1 misho 339: if (dbh->password) {
1.1.1.3 misho 340: if(FAIL == DBSETLPWD(H->login, dbh->password)) {
341: goto cleanup;
342: }
1.1 misho 343: }
344:
345: #if !PHP_DBLIB_IS_MSSQL
346: if (vars[0].optval) {
347: DBSETLCHARSET(H->login, vars[0].optval);
348: }
349: #endif
350:
351: DBSETLAPP(H->login, vars[1].optval);
352:
1.1.1.5 ! misho 353: /* DBSETLDBNAME is only available in FreeTDS 0.92 or above */
1.1.1.4 misho 354: #ifdef DBSETLDBNAME
355: if (vars[3].optval) {
1.1.1.5 ! misho 356: if(FAIL == DBSETLDBNAME(H->login, vars[3].optval)) goto cleanup;
1.1.1.4 misho 357: }
358: #endif
359:
1.1 misho 360: H->link = dbopen(H->login, vars[2].optval);
361:
1.1.1.3 misho 362: if (!H->link) {
1.1 misho 363: goto cleanup;
364: }
365:
1.1.1.5 ! misho 366: /*
! 367: * FreeTDS < 0.92 does not support the DBSETLDBNAME option
! 368: * Send use database here after login (Will not work with SQL Azure)
! 369: */
! 370: #ifndef DBSETLDBNAME
! 371: if (vars[3].optval) {
! 372: if(FAIL == dbuse(H->link, vars[3].optval)) goto cleanup;
! 373: }
! 374: #endif
! 375:
! 376: #if PHP_DBLIB_IS_MSSQL
1.1 misho 377: /* dblib do not return more than this length from text/image */
378: DBSETOPT(H->link, DBTEXTLIMIT, "2147483647");
1.1.1.5 ! misho 379: #endif
1.1.1.2 misho 380:
1.1 misho 381: /* limit text/image from network */
382: DBSETOPT(H->link, DBTEXTSIZE, "2147483647");
383:
1.1.1.2 misho 384: /* allow double quoted indentifiers */
1.1.1.3 misho 385: DBSETOPT(H->link, DBQUOTEDIDENT, "1");
1.1.1.2 misho 386:
1.1 misho 387: ret = 1;
388: dbh->max_escaped_char_length = 2;
389: dbh->alloc_own_columns = 1;
390:
391: cleanup:
1.1.1.3 misho 392: for (i = 0; i < nvars; i++) {
1.1 misho 393: if (vars[i].freeme) {
394: efree(vars[i].optval);
395: }
396: }
397:
398: dbh->methods = &dblib_methods;
399: dbh->driver_data = H;
400:
401: if (!ret) {
402: zend_throw_exception_ex(php_pdo_get_exception(), DBLIB_G(err).dberr TSRMLS_CC,
403: "SQLSTATE[%s] %s (severity %d)",
404: DBLIB_G(err).sqlstate,
405: DBLIB_G(err).dberrstr,
406: DBLIB_G(err).severity);
407: }
408:
409: return ret;
410: }
411:
412: pdo_driver_t pdo_dblib_driver = {
413: #if PDO_DBLIB_IS_MSSQL
414: PDO_DRIVER_HEADER(mssql),
415: #elif defined(PHP_WIN32)
1.1.1.2 misho 416: #define PDO_DBLIB_IS_SYBASE
1.1 misho 417: PDO_DRIVER_HEADER(sybase),
418: #else
419: PDO_DRIVER_HEADER(dblib),
420: #endif
421: pdo_dblib_handle_factory
422: };
423:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>