1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
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 : | Marcus Boerger <helly@php.net> |
17 : | Sterling Hughes <sterling@php.net> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : /* $Id: pdo_dbh.c 291096 2009-11-20 18:54:08Z iliaa $ */
22 :
23 : /* The PDO Database Handle Class */
24 :
25 : #ifdef HAVE_CONFIG_H
26 : #include "config.h"
27 : #endif
28 :
29 : #include "php.h"
30 : #include "php_ini.h"
31 : #include "ext/standard/info.h"
32 : #include "php_pdo.h"
33 : #include "php_pdo_driver.h"
34 : #include "php_pdo_int.h"
35 : #include "zend_exceptions.h"
36 : #include "zend_object_handlers.h"
37 : #include "zend_hash.h"
38 :
39 : static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, long attr, zval *value TSRMLS_DC);
40 :
41 : void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp TSRMLS_DC) /* {{{ */
42 519 : {
43 519 : pdo_error_type *pdo_err = &dbh->error_code;
44 519 : char *message = NULL;
45 : const char *msg;
46 :
47 519 : if (dbh->error_mode == PDO_ERRMODE_SILENT) {
48 : #if 0
49 : /* BUG: if user is running in silent mode and hits an error at the driver level
50 : * when they use the PDO methods to call up the error information, they may
51 : * get bogus information */
52 : return;
53 : #endif
54 : }
55 :
56 519 : if (stmt) {
57 471 : pdo_err = &stmt->error_code;
58 : }
59 :
60 519 : strcpy(*pdo_err, sqlstate);
61 :
62 : /* hash sqlstate to error messages */
63 519 : msg = pdo_sqlstate_state_to_description(*pdo_err);
64 519 : if (!msg) {
65 0 : msg = "<<Unknown error>>";
66 : }
67 :
68 519 : if (supp) {
69 519 : spprintf(&message, 0, "SQLSTATE[%s]: %s: %s", *pdo_err, msg, supp);
70 : } else {
71 0 : spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
72 : }
73 :
74 519 : if (dbh->error_mode != PDO_ERRMODE_EXCEPTION) {
75 519 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
76 : } else {
77 : zval *ex, *info;
78 0 : zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception();
79 :
80 0 : MAKE_STD_ZVAL(ex);
81 0 : object_init_ex(ex, pdo_ex);
82 :
83 0 : zend_update_property_string(def_ex, ex, "message", sizeof("message")-1, message TSRMLS_CC);
84 0 : zend_update_property_string(def_ex, ex, "code", sizeof("code")-1, *pdo_err TSRMLS_CC);
85 :
86 0 : MAKE_STD_ZVAL(info);
87 0 : array_init(info);
88 :
89 0 : add_next_index_string(info, *pdo_err, 1);
90 0 : add_next_index_long(info, 0);
91 :
92 0 : zend_update_property(pdo_ex, ex, "errorInfo", sizeof("errorInfo")-1, info TSRMLS_CC);
93 0 : zval_ptr_dtor(&info);
94 :
95 0 : zend_throw_exception_object(ex TSRMLS_CC);
96 : }
97 :
98 519 : if (message) {
99 519 : efree(message);
100 : }
101 519 : }
102 : /* }}} */
103 :
104 : void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
105 2301 : {
106 2301 : pdo_error_type *pdo_err = &dbh->error_code;
107 2301 : const char *msg = "<<Unknown>>";
108 2301 : char *supp = NULL;
109 2301 : long native_code = 0;
110 2301 : char *message = NULL;
111 2301 : zval *info = NULL;
112 :
113 2301 : if (dbh == NULL || dbh->error_mode == PDO_ERRMODE_SILENT) {
114 1853 : return;
115 : }
116 :
117 448 : if (stmt) {
118 378 : pdo_err = &stmt->error_code;
119 : }
120 :
121 : /* hash sqlstate to error messages */
122 448 : msg = pdo_sqlstate_state_to_description(*pdo_err);
123 448 : if (!msg) {
124 9 : msg = "<<Unknown error>>";
125 : }
126 :
127 448 : if (dbh->methods->fetch_err) {
128 448 : MAKE_STD_ZVAL(info);
129 448 : array_init(info);
130 :
131 448 : add_next_index_string(info, *pdo_err, 1);
132 :
133 448 : if (dbh->methods->fetch_err(dbh, stmt, info TSRMLS_CC)) {
134 : zval **item;
135 :
136 448 : if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 1, (void**)&item)) {
137 177 : native_code = Z_LVAL_PP(item);
138 : }
139 :
140 448 : if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 2, (void**)&item)) {
141 173 : supp = estrndup(Z_STRVAL_PP(item), Z_STRLEN_PP(item));
142 : }
143 : }
144 : }
145 :
146 448 : if (supp) {
147 173 : spprintf(&message, 0, "SQLSTATE[%s]: %s: %ld %s", *pdo_err, msg, native_code, supp);
148 : } else {
149 275 : spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
150 : }
151 :
152 448 : if (dbh->error_mode == PDO_ERRMODE_WARNING) {
153 421 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
154 27 : } else if (EG(exception) == NULL) {
155 : zval *ex;
156 27 : zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception();
157 :
158 27 : MAKE_STD_ZVAL(ex);
159 27 : object_init_ex(ex, pdo_ex);
160 :
161 27 : zend_update_property_string(def_ex, ex, "message", sizeof("message")-1, message TSRMLS_CC);
162 27 : zend_update_property_string(def_ex, ex, "code", sizeof("code")-1, *pdo_err TSRMLS_CC);
163 :
164 27 : if (info) {
165 27 : zend_update_property(pdo_ex, ex, "errorInfo", sizeof("errorInfo")-1, info TSRMLS_CC);
166 : }
167 :
168 27 : zend_throw_exception_object(ex TSRMLS_CC);
169 : }
170 :
171 448 : if (info) {
172 448 : zval_ptr_dtor(&info);
173 : }
174 :
175 448 : if (message) {
176 448 : efree(message);
177 : }
178 :
179 448 : if (supp) {
180 173 : efree(supp);
181 : }
182 : }
183 : /* }}} */
184 :
185 : static char *dsn_from_uri(char *uri, char *buf, size_t buflen TSRMLS_DC) /* {{{ */
186 2 : {
187 : php_stream *stream;
188 2 : char *dsn = NULL;
189 :
190 2 : stream = php_stream_open_wrapper(uri, "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
191 2 : if (stream) {
192 0 : dsn = php_stream_get_line(stream, ZSTR(buf), buflen, NULL);
193 0 : php_stream_close(stream);
194 : }
195 2 : return dsn;
196 : }
197 : /* }}} */
198 :
199 : /* {{{ proto void PDO::__construct(string dsn, string username, string passwd [, array options])
200 : */
201 : static PHP_METHOD(PDO, dbh_constructor)
202 1005 : {
203 1005 : zval *object = getThis();
204 1005 : pdo_dbh_t *dbh = NULL;
205 1005 : zend_bool is_persistent = FALSE;
206 : char *data_source;
207 : int data_source_len;
208 : char *colon;
209 1005 : char *username=NULL, *password=NULL;
210 : int usernamelen, passwordlen;
211 1005 : pdo_driver_t *driver = NULL;
212 1005 : zval *options = NULL;
213 : char alt_dsn[512];
214 1005 : int call_factory = 1;
215 :
216 1005 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!a!", &data_source, &data_source_len,
217 : &username, &usernamelen, &password, &passwordlen, &options)) {
218 2 : ZVAL_NULL(object);
219 2 : return;
220 : }
221 :
222 : /* parse the data source name */
223 1003 : colon = strchr(data_source, ':');
224 :
225 1003 : if (!colon) {
226 : /* let's see if this string has a matching dsn in the php.ini */
227 35 : char *ini_dsn = NULL;
228 :
229 35 : snprintf(alt_dsn, sizeof(alt_dsn), "pdo.dsn.%s", data_source);
230 35 : if (FAILURE == cfg_get_string(alt_dsn, &ini_dsn)) {
231 35 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name");
232 35 : ZVAL_NULL(object);
233 35 : return;
234 : }
235 :
236 0 : data_source = ini_dsn;
237 0 : colon = strchr(data_source, ':');
238 :
239 0 : if (!colon) {
240 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via INI: %s)", alt_dsn);
241 0 : ZVAL_NULL(object);
242 0 : return;
243 : }
244 : }
245 :
246 968 : if (!strncmp(data_source, "uri:", sizeof("uri:")-1)) {
247 : /* the specified URI holds connection details */
248 2 : data_source = dsn_from_uri(data_source + sizeof("uri:")-1, alt_dsn, sizeof(alt_dsn) TSRMLS_CC);
249 2 : if (!data_source) {
250 2 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source URI");
251 2 : ZVAL_NULL(object);
252 2 : return;
253 : }
254 0 : colon = strchr(data_source, ':');
255 0 : if (!colon) {
256 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via URI)");
257 0 : ZVAL_NULL(object);
258 0 : return;
259 : }
260 : }
261 :
262 966 : driver = pdo_find_driver(data_source, colon - data_source);
263 :
264 966 : if (!driver) {
265 : /* NB: don't want to include the data_source in the error message as
266 : * it might contain a password */
267 1 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "could not find driver");
268 1 : ZVAL_NULL(object);
269 1 : return;
270 : }
271 :
272 965 : dbh = (pdo_dbh_t *) zend_object_store_get_object(object TSRMLS_CC);
273 :
274 : /* is this supposed to be a persistent connection ? */
275 965 : if (options) {
276 : zval **v;
277 57 : int plen = 0;
278 57 : char *hashkey = NULL;
279 : zend_rsrc_list_entry *le;
280 57 : pdo_dbh_t *pdbh = NULL;
281 :
282 57 : if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_PERSISTENT, (void**)&v)) {
283 32 : if (Z_TYPE_PP(v) == IS_STRING && !is_numeric_string(Z_STRVAL_PP(v), Z_STRLEN_PP(v), NULL, NULL, 0) && Z_STRLEN_PP(v) > 0) {
284 : /* user specified key */
285 0 : plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s:%s", data_source,
286 : username ? username : "",
287 : password ? password : "",
288 : Z_STRVAL_PP(v));
289 0 : is_persistent = 1;
290 : } else {
291 32 : convert_to_long_ex(v);
292 32 : is_persistent = Z_LVAL_PP(v) ? 1 : 0;
293 32 : plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s", data_source,
294 : username ? username : "",
295 : password ? password : "");
296 : }
297 : }
298 :
299 57 : if (is_persistent) {
300 : /* let's see if we have one cached.... */
301 31 : if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, plen+1, (void*)&le)) {
302 27 : if (Z_TYPE_P(le) == php_pdo_list_entry()) {
303 27 : pdbh = (pdo_dbh_t*)le->ptr;
304 :
305 : /* is the connection still alive ? */
306 27 : if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh TSRMLS_CC)) {
307 : /* nope... need to kill it */
308 0 : pdbh = NULL;
309 : }
310 : }
311 : }
312 :
313 31 : if (pdbh) {
314 27 : call_factory = 0;
315 : } else {
316 : /* need a brand new pdbh */
317 4 : pdbh = pecalloc(1, sizeof(*pdbh), 1);
318 :
319 4 : if (!pdbh) {
320 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle");
321 : /* NOTREACHED */
322 : }
323 :
324 4 : pdbh->is_persistent = 1;
325 4 : if (!(pdbh->persistent_id = pemalloc(plen + 1, 1))) {
326 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle");
327 : }
328 4 : memcpy((char *)pdbh->persistent_id, hashkey, plen+1);
329 4 : pdbh->persistent_id_len = plen+1;
330 4 : pdbh->refcount = 1;
331 4 : pdbh->properties = NULL;
332 : }
333 : }
334 :
335 57 : if (pdbh) {
336 : /* let's copy the emalloc bits over from the other handle */
337 31 : if (pdbh->properties) {
338 22 : zend_hash_destroy(dbh->properties);
339 22 : efree(dbh->properties);
340 : } else {
341 9 : pdbh->ce = dbh->ce;
342 9 : pdbh->def_stmt_ce = dbh->def_stmt_ce;
343 9 : pdbh->def_stmt_ctor_args = dbh->def_stmt_ctor_args;
344 9 : pdbh->properties = dbh->properties;
345 : }
346 : /* kill the non-persistent thingamy */
347 31 : efree(dbh);
348 : /* switch over to the persistent one */
349 31 : dbh = pdbh;
350 31 : zend_object_store_set_object(object, dbh TSRMLS_CC);
351 31 : dbh->refcount++;
352 : }
353 :
354 57 : if (hashkey) {
355 32 : efree(hashkey);
356 : }
357 : }
358 :
359 965 : if (call_factory) {
360 938 : dbh->data_source_len = strlen(colon + 1);
361 938 : dbh->data_source = (const char*)pestrdup(colon + 1, is_persistent);
362 938 : dbh->username = username ? pestrdup(username, is_persistent) : NULL;
363 938 : dbh->password = password ? pestrdup(password, is_persistent) : NULL;
364 938 : dbh->default_fetch_type = PDO_FETCH_BOTH;
365 : }
366 :
367 965 : dbh->auto_commit = pdo_attr_lval(options, PDO_ATTR_AUTOCOMMIT, 1 TSRMLS_CC);
368 :
369 965 : if (!dbh->data_source || (username && !dbh->username) || (password && !dbh->password)) {
370 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory");
371 : }
372 :
373 965 : if (!call_factory) {
374 : /* we got a persistent guy from our cache */
375 27 : goto options;
376 : }
377 :
378 938 : if (driver->db_handle_factory(dbh, options TSRMLS_CC)) {
379 : /* all set */
380 :
381 927 : if (is_persistent) {
382 : zend_rsrc_list_entry le;
383 :
384 : /* register in the persistent list etc. */
385 : /* we should also need to replace the object store entry,
386 : since it was created with emalloc */
387 :
388 4 : le.type = php_pdo_list_entry();
389 4 : le.ptr = dbh;
390 :
391 4 : if (FAILURE == zend_hash_update(&EG(persistent_list),
392 : (char*)dbh->persistent_id, dbh->persistent_id_len, (void*)&le,
393 : sizeof(le), NULL)) {
394 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to register persistent entry");
395 : }
396 : }
397 :
398 927 : dbh->driver = driver;
399 954 : options:
400 954 : if (options) {
401 : zval **attr_value;
402 : zstr str_key;
403 : ulong long_key;
404 :
405 55 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(options));
406 167 : while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(options), (void**)&attr_value)
407 : && HASH_KEY_IS_LONG == zend_hash_get_current_key(Z_ARRVAL_P(options),
408 : &str_key, &long_key, 0)) {
409 :
410 57 : pdo_dbh_attribute_set(dbh, long_key, *attr_value TSRMLS_CC);
411 57 : zend_hash_move_forward(Z_ARRVAL_P(options));
412 : }
413 : }
414 :
415 954 : return;
416 : }
417 :
418 : /* the connection failed; things will tidy up in free_storage */
419 : /* XXX raise exception */
420 11 : ZVAL_NULL(object);
421 : }
422 : /* }}} */
423 :
424 : static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */
425 2061 : {
426 2061 : if (ctor_args) {
427 10 : if (Z_TYPE_P(ctor_args) != IS_ARRAY) {
428 0 : pdo_raise_impl_error(dbh, NULL, "HY000", "constructor arguments must be passed as an array" TSRMLS_CC);
429 0 : return NULL;
430 : }
431 10 : if (!dbstmt_ce->constructor) {
432 0 : pdo_raise_impl_error(dbh, NULL, "HY000", "user-supplied statement does not accept constructor arguments" TSRMLS_CC);
433 0 : return NULL;
434 : }
435 : }
436 :
437 2061 : Z_TYPE_P(object) = IS_OBJECT;
438 2061 : object_init_ex(object, dbstmt_ce);
439 2060 : Z_SET_REFCOUNT_P(object, 1);
440 2060 : Z_SET_ISREF_P(object);
441 :
442 2060 : return object;
443 : } /* }}} */
444 :
445 : static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */
446 1966 : {
447 : zval *query_string;
448 : zval z_key;
449 :
450 1966 : MAKE_STD_ZVAL(query_string);
451 1966 : ZVAL_RT_STRINGL(query_string, stmt->query_string, stmt->query_stringlen, 1);
452 1966 : ZVAL_ASCII_STRINGL(&z_key, "queryString", sizeof("queryString")-1, 0);
453 1966 : std_object_handlers.write_property(object, &z_key, query_string TSRMLS_CC);
454 1966 : zval_ptr_dtor(&query_string);
455 1966 : zval_dtor(&z_key);
456 :
457 1966 : if (dbstmt_ce->constructor) {
458 : zend_fcall_info fci;
459 : zend_fcall_info_cache fcc;
460 : zval *retval;
461 :
462 9 : fci.size = sizeof(zend_fcall_info);
463 9 : fci.function_table = &dbstmt_ce->function_table;
464 9 : fci.function_name = NULL;
465 9 : fci.object_ptr = object;
466 9 : fci.symbol_table = NULL;
467 9 : fci.retval_ptr_ptr = &retval;
468 9 : if (ctor_args) {
469 9 : HashTable *ht = Z_ARRVAL_P(ctor_args);
470 : Bucket *p;
471 :
472 9 : fci.param_count = 0;
473 9 : fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
474 9 : p = ht->pListHead;
475 27 : while (p != NULL) {
476 9 : fci.params[fci.param_count++] = (zval**)p->pData;
477 9 : p = p->pListNext;
478 : }
479 : } else {
480 0 : fci.param_count = 0;
481 0 : fci.params = NULL;
482 : }
483 9 : fci.no_separation = 1;
484 :
485 9 : fcc.initialized = 1;
486 9 : fcc.function_handler = dbstmt_ce->constructor;
487 9 : fcc.calling_scope = EG(scope);
488 9 : fcc.called_scope = Z_OBJCE_P(object);
489 9 : fcc.object_ptr = object;
490 :
491 9 : if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
492 0 : zval_dtor(object);
493 0 : ZVAL_NULL(object);
494 0 : object = NULL; /* marks failure */
495 : } else {
496 9 : zval_ptr_dtor(&retval);
497 : }
498 :
499 9 : if (fci.params) {
500 9 : efree(fci.params);
501 : }
502 : }
503 1966 : }
504 : /* }}} */
505 :
506 : /* {{{ proto object PDO::prepare(string statment [, array options])
507 : Prepares a statement for execution and returns a statement object */
508 : static PHP_METHOD(PDO, prepare)
509 1441 : {
510 1441 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
511 : pdo_stmt_t *stmt;
512 : char *statement;
513 : int statement_len;
514 1441 : zval *options = NULL, **opt, **item, *ctor_args;
515 : zend_class_entry *dbstmt_ce, **pce;
516 :
517 1441 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &statement,
518 : &statement_len, &options)) {
519 0 : RETURN_FALSE;
520 : }
521 :
522 1441 : PDO_DBH_CLEAR_ERR();
523 1441 : PDO_CONSTRUCT_CHECK;
524 :
525 1441 : if (ZEND_NUM_ARGS() > 1 && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS, (void**)&opt)) {
526 21 : if (Z_TYPE_PP(opt) != IS_ARRAY || zend_hash_index_find(Z_ARRVAL_PP(opt), 0, (void**)&item) == FAILURE
527 : || PDO_ZVAL_PP_IS_TEXT(item)
528 : || zend_u_lookup_class(Z_TYPE_PP(item), Z_UNIVAL_PP(item), Z_UNILEN_PP(item), &pce TSRMLS_CC) == FAILURE
529 : ) {
530 21 : pdo_raise_impl_error(dbh, NULL, "HY000",
531 : "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
532 : "the classname must be a string specifying an existing class"
533 : TSRMLS_CC);
534 21 : PDO_HANDLE_DBH_ERR();
535 21 : RETURN_FALSE;
536 : }
537 0 : dbstmt_ce = *pce;
538 0 : if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce TSRMLS_CC)) {
539 0 : pdo_raise_impl_error(dbh, NULL, "HY000",
540 : "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC);
541 0 : PDO_HANDLE_DBH_ERR();
542 0 : RETURN_FALSE;
543 : }
544 0 : if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
545 0 : pdo_raise_impl_error(dbh, NULL, "HY000",
546 : "user-supplied statement class cannot have a public constructor" TSRMLS_CC);
547 0 : PDO_HANDLE_DBH_ERR();
548 0 : RETURN_FALSE;
549 : }
550 0 : if (zend_hash_index_find(Z_ARRVAL_PP(opt), 1, (void**)&item) == SUCCESS) {
551 0 : if (Z_TYPE_PP(item) != IS_ARRAY) {
552 0 : pdo_raise_impl_error(dbh, NULL, "HY000",
553 : "PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
554 : "ctor_args must be an array"
555 : TSRMLS_CC);
556 0 : PDO_HANDLE_DBH_ERR();
557 0 : RETURN_FALSE;
558 : }
559 0 : ctor_args = *item;
560 : } else {
561 0 : ctor_args = NULL;
562 : }
563 : } else {
564 1420 : dbstmt_ce = dbh->def_stmt_ce;
565 1420 : ctor_args = dbh->def_stmt_ctor_args;
566 : }
567 :
568 1420 : if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, ctor_args TSRMLS_CC)) {
569 0 : pdo_raise_impl_error(dbh, NULL, "HY000",
570 : "failed to instantiate user-supplied statement class"
571 : TSRMLS_CC);
572 0 : PDO_HANDLE_DBH_ERR();
573 0 : RETURN_FALSE;
574 : }
575 1420 : stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
576 :
577 : /* unconditionally keep this for later reference */
578 1420 : stmt->query_string = estrndup(statement, statement_len);
579 1420 : stmt->query_stringlen = statement_len;
580 1420 : stmt->default_fetch_type = dbh->default_fetch_type;
581 1420 : stmt->dbh = dbh;
582 : /* give it a reference to me */
583 1420 : zend_objects_store_add_ref(getThis() TSRMLS_CC);
584 1420 : php_pdo_dbh_addref(dbh TSRMLS_CC);
585 1420 : stmt->database_object_handle = *getThis();
586 : /* we haven't created a lazy object yet */
587 1420 : ZVAL_NULL(&stmt->lazy_object_ref);
588 :
589 1420 : if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options TSRMLS_CC)) {
590 1414 : pdo_stmt_construct(stmt, return_value, dbstmt_ce, ctor_args TSRMLS_CC);
591 1414 : return;
592 : }
593 :
594 6 : PDO_HANDLE_DBH_ERR();
595 :
596 : /* kill the object handle for the stmt here */
597 6 : zval_dtor(return_value);
598 :
599 6 : RETURN_FALSE;
600 : }
601 : /* }}} */
602 :
603 : /* {{{ proto bool PDO::beginTransaction()
604 : Initiates a transaction */
605 : static PHP_METHOD(PDO, beginTransaction)
606 43 : {
607 43 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
608 :
609 43 : if (zend_parse_parameters_none() == FAILURE) {
610 0 : return;
611 : }
612 43 : PDO_CONSTRUCT_CHECK;
613 :
614 43 : if (dbh->in_txn) {
615 2 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is already an active transaction");
616 2 : RETURN_FALSE;
617 : }
618 :
619 41 : if (!dbh->methods->begin) {
620 : /* TODO: this should be an exception; see the auto-commit mode
621 : * comments below */
622 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "This driver doesn't support transactions");
623 0 : RETURN_FALSE;
624 : }
625 :
626 41 : if (dbh->methods->begin(dbh TSRMLS_CC)) {
627 41 : dbh->in_txn = 1;
628 41 : RETURN_TRUE;
629 : }
630 :
631 0 : PDO_HANDLE_DBH_ERR();
632 0 : RETURN_FALSE;
633 : }
634 : /* }}} */
635 :
636 : /* {{{ proto bool PDO::commit()
637 : Commit a transaction */
638 : static PHP_METHOD(PDO, commit)
639 16 : {
640 16 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
641 :
642 16 : if (zend_parse_parameters_none() == FAILURE) {
643 0 : return;
644 : }
645 16 : PDO_CONSTRUCT_CHECK;
646 :
647 16 : if (!dbh->in_txn) {
648 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction");
649 0 : RETURN_FALSE;
650 : }
651 :
652 16 : if (dbh->methods->commit(dbh TSRMLS_CC)) {
653 16 : dbh->in_txn = 0;
654 16 : RETURN_TRUE;
655 : }
656 :
657 0 : PDO_HANDLE_DBH_ERR();
658 0 : RETURN_FALSE;
659 : }
660 : /* }}} */
661 :
662 : /* {{{ proto bool PDO::rollBack()
663 : roll back a transaction */
664 : static PHP_METHOD(PDO, rollBack)
665 15 : {
666 15 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
667 :
668 15 : if (zend_parse_parameters_none() == FAILURE) {
669 0 : return;
670 : }
671 15 : PDO_CONSTRUCT_CHECK;
672 :
673 15 : if (!dbh->in_txn) {
674 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction");
675 0 : RETURN_FALSE;
676 : }
677 :
678 15 : if (dbh->methods->rollback(dbh TSRMLS_CC)) {
679 15 : dbh->in_txn = 0;
680 15 : RETURN_TRUE;
681 : }
682 :
683 0 : PDO_HANDLE_DBH_ERR();
684 0 : RETURN_FALSE;
685 : }
686 : /* }}} */
687 :
688 : static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, long attr, zval *value TSRMLS_DC) /* {{{ */
689 2894 : {
690 :
691 : #define PDO_LONG_PARAM_CHECK \
692 : if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING && Z_TYPE_P(value) != IS_BOOL) { \
693 : pdo_raise_impl_error(dbh, NULL, "HY000", "attribute value must be an integer" TSRMLS_CC); \
694 : PDO_HANDLE_DBH_ERR(); \
695 : return FAILURE; \
696 : } \
697 :
698 2894 : switch (attr) {
699 : case PDO_ATTR_ERRMODE:
700 916 : PDO_LONG_PARAM_CHECK;
701 913 : convert_to_long(value);
702 913 : switch (Z_LVAL_P(value)) {
703 : case PDO_ERRMODE_SILENT:
704 : case PDO_ERRMODE_WARNING:
705 : case PDO_ERRMODE_EXCEPTION:
706 912 : dbh->error_mode = Z_LVAL_P(value);
707 912 : return SUCCESS;
708 : default:
709 1 : pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode" TSRMLS_CC);
710 1 : PDO_HANDLE_DBH_ERR();
711 1 : return FAILURE;
712 : }
713 : return FAILURE;
714 :
715 : case PDO_ATTR_CASE:
716 875 : PDO_LONG_PARAM_CHECK;
717 875 : convert_to_long(value);
718 875 : switch (Z_LVAL_P(value)) {
719 : case PDO_CASE_NATURAL:
720 : case PDO_CASE_UPPER:
721 : case PDO_CASE_LOWER:
722 875 : dbh->desired_case = Z_LVAL_P(value);
723 875 : return SUCCESS;
724 : default:
725 0 : pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode" TSRMLS_CC);
726 0 : PDO_HANDLE_DBH_ERR();
727 0 : return FAILURE;
728 : }
729 : return FAILURE;
730 :
731 : case PDO_ATTR_ORACLE_NULLS:
732 6 : PDO_LONG_PARAM_CHECK;
733 3 : convert_to_long(value);
734 3 : dbh->oracle_nulls = Z_LVAL_P(value);
735 3 : return SUCCESS;
736 :
737 : case PDO_ATTR_DEFAULT_FETCH_MODE:
738 16 : if (Z_TYPE_P(value) == IS_ARRAY) {
739 : zval **tmp;
740 0 : if (zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) {
741 0 : if (Z_LVAL_PP(tmp) == PDO_FETCH_INTO || Z_LVAL_PP(tmp) == PDO_FETCH_CLASS) {
742 0 : pdo_raise_impl_error(dbh, NULL, "HY000", "FETCH_INTO and FETCH_CLASS are not yet supported as default fetch modes" TSRMLS_CC);
743 0 : return FAILURE;
744 : }
745 : }
746 : } else {
747 16 : PDO_LONG_PARAM_CHECK;
748 : }
749 :
750 16 : convert_to_long(value);
751 16 : if (Z_LVAL_P(value) == PDO_FETCH_USE_DEFAULT) {
752 0 : pdo_raise_impl_error(dbh, NULL, "HY000", "invalid fetch mode type" TSRMLS_CC);
753 0 : return FAILURE;
754 : }
755 16 : dbh->default_fetch_type = Z_LVAL_P(value);
756 16 : return SUCCESS;
757 :
758 : case PDO_ATTR_STRINGIFY_FETCHES:
759 756 : PDO_LONG_PARAM_CHECK;
760 756 : convert_to_long(value);
761 756 : dbh->stringify = Z_LVAL_P(value) ? 1 : 0;
762 756 : return SUCCESS;
763 :
764 : case PDO_ATTR_STATEMENT_CLASS: {
765 : /* array(string classname, array(mixed ctor_args)) */
766 : zend_class_entry **pce;
767 : zval **item;
768 :
769 18 : if (dbh->is_persistent) {
770 0 : pdo_raise_impl_error(dbh, NULL, "HY000",
771 : "PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances"
772 : TSRMLS_CC);
773 0 : PDO_HANDLE_DBH_ERR();
774 0 : return FAILURE;
775 : }
776 18 : if (Z_TYPE_P(value) != IS_ARRAY
777 : || zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&item) == FAILURE
778 : || !PDO_ZVAL_PP_IS_TEXT(item)
779 : || zend_u_lookup_class(Z_TYPE_PP(item), Z_UNIVAL_PP(item), Z_UNILEN_PP(item), &pce TSRMLS_CC) == FAILURE
780 : ) {
781 3 : pdo_raise_impl_error(dbh, NULL, "HY000",
782 : "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
783 : "the classname must be a string specifying an existing class"
784 : TSRMLS_CC);
785 3 : PDO_HANDLE_DBH_ERR();
786 3 : return FAILURE;
787 : }
788 15 : if (!instanceof_function(*pce, pdo_dbstmt_ce TSRMLS_CC)) {
789 1 : pdo_raise_impl_error(dbh, NULL, "HY000",
790 : "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC);
791 1 : PDO_HANDLE_DBH_ERR();
792 1 : return FAILURE;
793 : }
794 14 : if ((*pce)->constructor && !((*pce)->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
795 1 : pdo_raise_impl_error(dbh, NULL, "HY000",
796 : "user-supplied statement class cannot have a public constructor" TSRMLS_CC);
797 1 : PDO_HANDLE_DBH_ERR();
798 1 : return FAILURE;
799 : }
800 13 : dbh->def_stmt_ce = *pce;
801 13 : if (dbh->def_stmt_ctor_args) {
802 4 : zval_ptr_dtor(&dbh->def_stmt_ctor_args);
803 4 : dbh->def_stmt_ctor_args = NULL;
804 : }
805 13 : if (zend_hash_index_find(Z_ARRVAL_P(value), 1, (void**)&item) == SUCCESS) {
806 12 : if (Z_TYPE_PP(item) != IS_ARRAY) {
807 0 : pdo_raise_impl_error(dbh, NULL, "HY000",
808 : "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
809 : "ctor_args must be an array"
810 : TSRMLS_CC);
811 0 : PDO_HANDLE_DBH_ERR();
812 0 : return FAILURE;
813 : }
814 12 : Z_ADDREF_PP(item);
815 12 : dbh->def_stmt_ctor_args = *item;
816 : }
817 13 : return SUCCESS;
818 : }
819 :
820 : default:
821 : ;
822 : }
823 :
824 307 : if (!dbh->methods->set_attribute) {
825 0 : goto fail;
826 : }
827 :
828 307 : PDO_DBH_CLEAR_ERR();
829 307 : if (dbh->methods->set_attribute(dbh, attr, value TSRMLS_CC)) {
830 261 : return SUCCESS;
831 : }
832 :
833 46 : fail:
834 46 : if (attr == PDO_ATTR_AUTOCOMMIT) {
835 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The auto-commit mode cannot be changed for this driver");
836 46 : } else if (!dbh->methods->set_attribute) {
837 0 : pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes" TSRMLS_CC);
838 : } else {
839 46 : PDO_HANDLE_DBH_ERR();
840 : }
841 46 : return FAILURE;
842 : }
843 : /* }}} */
844 :
845 : /* {{{ proto bool PDO::setAttribute(long attribute, mixed value)
846 : Set an attribute */
847 : static PHP_METHOD(PDO, setAttribute)
848 2838 : {
849 2838 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
850 : long attr;
851 : zval *value;
852 :
853 2838 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &attr, &value)) {
854 1 : RETURN_FALSE;
855 : }
856 :
857 2837 : PDO_CONSTRUCT_CHECK;
858 :
859 2837 : if (pdo_dbh_attribute_set(dbh, attr, value TSRMLS_CC) != FAILURE) {
860 2819 : RETURN_TRUE;
861 : }
862 18 : RETURN_FALSE;
863 : }
864 : /* }}} */
865 :
866 : /* {{{ proto mixed PDO::getAttribute(long attribute)
867 : Get an attribute */
868 : static PHP_METHOD(PDO, getAttribute)
869 140 : {
870 140 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
871 : long attr;
872 :
873 140 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
874 0 : RETURN_FALSE;
875 : }
876 :
877 140 : PDO_DBH_CLEAR_ERR();
878 140 : PDO_CONSTRUCT_CHECK;
879 :
880 : /* handle generic PDO-level atributes */
881 140 : switch (attr) {
882 : case PDO_ATTR_PERSISTENT:
883 1 : RETURN_BOOL(dbh->is_persistent);
884 :
885 : case PDO_ATTR_CASE:
886 4 : RETURN_LONG(dbh->desired_case);
887 :
888 : case PDO_ATTR_ORACLE_NULLS:
889 0 : RETURN_LONG(dbh->oracle_nulls);
890 :
891 : case PDO_ATTR_ERRMODE:
892 0 : RETURN_LONG(dbh->error_mode);
893 :
894 : case PDO_ATTR_DRIVER_NAME:
895 31 : RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len, 1);
896 :
897 : case PDO_ATTR_STATEMENT_CLASS:
898 14 : array_init(return_value);
899 14 : add_next_index_unicode(return_value, dbh->def_stmt_ce->name.u, 1);
900 14 : if (dbh->def_stmt_ctor_args) {
901 7 : Z_ADDREF_P(dbh->def_stmt_ctor_args);
902 7 : add_next_index_zval(return_value, dbh->def_stmt_ctor_args);
903 : }
904 14 : return;
905 : case PDO_ATTR_DEFAULT_FETCH_MODE:
906 0 : RETURN_LONG(dbh->default_fetch_type);
907 :
908 : }
909 :
910 90 : if (!dbh->methods->get_attribute) {
911 0 : pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support getting attributes" TSRMLS_CC);
912 0 : RETURN_FALSE;
913 : }
914 :
915 90 : switch (dbh->methods->get_attribute(dbh, attr, return_value TSRMLS_CC)) {
916 : case -1:
917 0 : PDO_HANDLE_DBH_ERR();
918 0 : RETURN_FALSE;
919 :
920 : case 0:
921 15 : pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support that attribute" TSRMLS_CC);
922 15 : RETURN_FALSE;
923 :
924 : default:
925 75 : return;
926 : }
927 : }
928 : /* }}} */
929 :
930 : /* {{{ proto long PDO::exec(string query)
931 : Execute a query that does not return a row set, returning the number of affected rows */
932 : static PHP_METHOD(PDO, exec)
933 3610 : {
934 3610 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
935 : char *statement;
936 : int statement_len;
937 : long ret;
938 :
939 3610 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &statement, &statement_len)) {
940 0 : RETURN_FALSE;
941 : }
942 :
943 3610 : if (!statement_len) {
944 0 : pdo_raise_impl_error(dbh, NULL, "HY000", "trying to execute an empty query" TSRMLS_CC);
945 0 : RETURN_FALSE;
946 : }
947 3610 : PDO_DBH_CLEAR_ERR();
948 3610 : PDO_CONSTRUCT_CHECK;
949 3610 : ret = dbh->methods->doer(dbh, statement, statement_len TSRMLS_CC);
950 3610 : if(ret == -1) {
951 1865 : PDO_HANDLE_DBH_ERR();
952 1865 : RETURN_FALSE;
953 : } else {
954 1745 : RETURN_LONG(ret);
955 : }
956 : }
957 : /* }}} */
958 :
959 :
960 : /* {{{ proto string PDO::lastInsertId([string seqname])
961 : Returns the id of the last row that we affected on this connection. Some databases require a sequence or table name to be passed in. Not always meaningful. */
962 : static PHP_METHOD(PDO, lastInsertId)
963 13 : {
964 13 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
965 13 : char *name = NULL;
966 : int namelen;
967 :
968 13 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &namelen)) {
969 0 : RETURN_FALSE;
970 : }
971 :
972 13 : PDO_DBH_CLEAR_ERR();
973 13 : PDO_CONSTRUCT_CHECK;
974 13 : if (!dbh->methods->last_id) {
975 0 : pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()" TSRMLS_CC);
976 0 : RETURN_FALSE;
977 : } else {
978 13 : Z_STRVAL_P(return_value) = dbh->methods->last_id(dbh, name, &Z_STRLEN_P(return_value) TSRMLS_CC);
979 13 : if (!Z_STRVAL_P(return_value)) {
980 0 : PDO_HANDLE_DBH_ERR();
981 0 : RETURN_FALSE;
982 : } else {
983 13 : Z_TYPE_P(return_value) = IS_STRING;
984 : }
985 : }
986 : }
987 : /* }}} */
988 :
989 : /* {{{ proto string PDO::errorCode()
990 : Fetch the error code associated with the last operation on the database handle */
991 : static PHP_METHOD(PDO, errorCode)
992 98 : {
993 98 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
994 :
995 98 : if (zend_parse_parameters_none() == FAILURE) {
996 0 : return;
997 : }
998 98 : PDO_CONSTRUCT_CHECK;
999 :
1000 98 : if (dbh->query_stmt) {
1001 11 : RETURN_STRING(dbh->query_stmt->error_code, 1);
1002 : }
1003 :
1004 87 : if (dbh->error_code[0] == '\0') {
1005 4 : RETURN_NULL();
1006 : }
1007 :
1008 : // Fallback to default documented value
1009 83 : RETURN_STRING(dbh->error_code, 1);
1010 : }
1011 : /* }}} */
1012 :
1013 : /* {{{ proto int PDO::errorInfo()
1014 : Fetch extended error information associated with the last operation on the database handle */
1015 : static PHP_METHOD(PDO, errorInfo)
1016 35 : {
1017 : int error_count;
1018 35 : int error_count_diff = 0;
1019 35 : int error_expected_count = 3;
1020 :
1021 35 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
1022 :
1023 35 : if (zend_parse_parameters_none() == FAILURE) {
1024 0 : return;
1025 : }
1026 :
1027 35 : PDO_CONSTRUCT_CHECK;
1028 :
1029 35 : array_init(return_value);
1030 :
1031 35 : if (dbh->query_stmt) {
1032 8 : add_next_index_ascii_string(return_value, dbh->query_stmt->error_code, 1);
1033 : } else {
1034 27 : add_next_index_ascii_string(return_value, dbh->error_code, 1);
1035 : }
1036 :
1037 35 : if (dbh->methods->fetch_err) {
1038 35 : dbh->methods->fetch_err(dbh, dbh->query_stmt, return_value TSRMLS_CC);
1039 : }
1040 :
1041 : /**
1042 : * In order to be consistent, we have to make sure we add the good amount
1043 : * of null elements depending on the current number of elements. We make
1044 : * a simple difference and add the needed elements to reach the expected
1045 : * count.
1046 : */
1047 35 : error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1048 :
1049 35 : if (error_expected_count > error_count) {
1050 : int current_index;
1051 :
1052 13 : error_count_diff = error_expected_count - error_count;
1053 39 : for (current_index = 0; current_index < error_count_diff; current_index++) {
1054 26 : add_next_index_null(return_value);
1055 : }
1056 : }
1057 : }
1058 : /* }}} */
1059 :
1060 : /* {{{ proto object PDO::query(string sql [, PDOStatement::setFetchMode() args])
1061 : Prepare and execute $sql; returns the statement object for iteration */
1062 : static PHP_METHOD(PDO, query)
1063 647 : {
1064 647 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
1065 : pdo_stmt_t *stmt;
1066 : char *statement;
1067 : int statement_len;
1068 :
1069 : /* Return a meaningful error when no parameters were passed */
1070 647 : if (!ZEND_NUM_ARGS()) {
1071 6 : zend_parse_parameters(0 TSRMLS_CC, "z|z", NULL, NULL);
1072 6 : RETURN_FALSE;
1073 : }
1074 :
1075 641 : if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &statement,
1076 : &statement_len)) {
1077 0 : RETURN_FALSE;
1078 : }
1079 :
1080 641 : PDO_DBH_CLEAR_ERR();
1081 641 : PDO_CONSTRUCT_CHECK;
1082 :
1083 641 : if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC)) {
1084 0 : pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class" TSRMLS_CC);
1085 0 : return;
1086 : }
1087 640 : stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
1088 :
1089 : /* unconditionally keep this for later reference */
1090 640 : stmt->query_string = estrndup(statement, statement_len);
1091 640 : stmt->query_stringlen = statement_len;
1092 :
1093 640 : stmt->default_fetch_type = dbh->default_fetch_type;
1094 640 : stmt->active_query_string = stmt->query_string;
1095 640 : stmt->active_query_stringlen = statement_len;
1096 640 : stmt->dbh = dbh;
1097 : /* give it a reference to me */
1098 640 : zend_objects_store_add_ref(getThis() TSRMLS_CC);
1099 640 : php_pdo_dbh_addref(dbh TSRMLS_CC);
1100 640 : stmt->database_object_handle = *getThis();
1101 : /* we haven't created a lazy object yet */
1102 640 : ZVAL_NULL(&stmt->lazy_object_ref);
1103 :
1104 640 : if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL TSRMLS_CC)) {
1105 631 : PDO_STMT_CLEAR_ERR();
1106 631 : if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
1107 :
1108 : /* now execute the statement */
1109 571 : PDO_STMT_CLEAR_ERR();
1110 571 : if (stmt->methods->executer(stmt TSRMLS_CC)) {
1111 552 : int ret = 1;
1112 552 : if (!stmt->executed) {
1113 552 : if (stmt->dbh->alloc_own_columns) {
1114 552 : ret = pdo_stmt_describe_columns(stmt TSRMLS_CC);
1115 : }
1116 552 : stmt->executed = 1;
1117 : }
1118 552 : if (ret) {
1119 552 : pdo_stmt_construct(stmt, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC);
1120 552 : return;
1121 : }
1122 : }
1123 : }
1124 : /* something broke */
1125 79 : dbh->query_stmt = stmt;
1126 79 : dbh->query_stmt_zval = *return_value;
1127 79 : PDO_HANDLE_STMT_ERR();
1128 : } else {
1129 9 : PDO_HANDLE_DBH_ERR();
1130 9 : zval_dtor(return_value);
1131 : }
1132 :
1133 88 : RETURN_FALSE;
1134 : }
1135 : /* }}} */
1136 :
1137 : /* {{{ proto string PDO::quote(string string [, int paramtype])
1138 : quotes string for use in a query. The optional paramtype acts as a hint for drivers that have alternate quoting styles. The default value is PDO_PARAM_STR */
1139 : static PHP_METHOD(PDO, quote)
1140 17 : {
1141 17 : pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
1142 : char *str;
1143 : int str_len;
1144 17 : long paramtype = PDO_PARAM_STR;
1145 : char *qstr;
1146 : int qlen;
1147 :
1148 17 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, ¶mtype)) {
1149 0 : RETURN_FALSE;
1150 : }
1151 :
1152 17 : PDO_DBH_CLEAR_ERR();
1153 17 : PDO_CONSTRUCT_CHECK;
1154 17 : if (!dbh->methods->quoter) {
1155 0 : pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting" TSRMLS_CC);
1156 0 : RETURN_FALSE;
1157 : }
1158 :
1159 17 : if (dbh->methods->quoter(dbh, str, str_len, &qstr, &qlen, paramtype TSRMLS_CC)) {
1160 17 : RETURN_STRINGL(qstr, qlen, 0);
1161 : }
1162 0 : PDO_HANDLE_DBH_ERR();
1163 0 : RETURN_FALSE;
1164 : }
1165 : /* }}} */
1166 :
1167 : /* {{{ proto int PDO::__wakeup()
1168 : Prevents use of a PDO instance that has been unserialized */
1169 : static PHP_METHOD(PDO, __wakeup)
1170 0 : {
1171 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances");
1172 0 : }
1173 : /* }}} */
1174 :
1175 : /* {{{ proto int PDO::__sleep()
1176 : Prevents serialization of a PDO instance */
1177 : static PHP_METHOD(PDO, __sleep)
1178 6 : {
1179 6 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances");
1180 6 : }
1181 : /* }}} */
1182 :
1183 : /* {{{ proto array PDO::getAvailableDrivers()
1184 : Return array of available PDO drivers */
1185 : static PHP_METHOD(PDO, getAvailableDrivers)
1186 0 : {
1187 : HashPosition pos;
1188 : pdo_driver_t **pdriver;
1189 :
1190 0 : if (zend_parse_parameters_none() == FAILURE) {
1191 0 : return;
1192 : }
1193 :
1194 0 : array_init(return_value);
1195 :
1196 0 : zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
1197 0 : while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
1198 0 : add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1);
1199 0 : zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
1200 : }
1201 : }
1202 : /* }}} */
1203 :
1204 : /* {{{ arginfo */
1205 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 3)
1206 : ZEND_ARG_INFO(0, dsn)
1207 : ZEND_ARG_INFO(0, username)
1208 : ZEND_ARG_INFO(0, passwd)
1209 : ZEND_ARG_INFO(0, options) /* array */
1210 : ZEND_END_ARG_INFO()
1211 :
1212 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_prepare, 0, 0, 1)
1213 : ZEND_ARG_INFO(0, statment)
1214 : ZEND_ARG_INFO(0, options) /* array */
1215 : ZEND_END_ARG_INFO()
1216 :
1217 : ZEND_BEGIN_ARG_INFO(arginfo_pdo_setattribute, 0)
1218 : ZEND_ARG_INFO(0, attribute)
1219 : ZEND_ARG_INFO(0, value)
1220 : ZEND_END_ARG_INFO()
1221 :
1222 : ZEND_BEGIN_ARG_INFO(arginfo_pdo_getattribute, 0)
1223 : ZEND_ARG_INFO(0, attribute)
1224 : ZEND_END_ARG_INFO()
1225 :
1226 : ZEND_BEGIN_ARG_INFO(arginfo_pdo_exec, 0)
1227 : ZEND_ARG_INFO(0, query)
1228 : ZEND_END_ARG_INFO()
1229 :
1230 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_lastinsertid, 0, 0, 0)
1231 : ZEND_ARG_INFO(0, seqname)
1232 : ZEND_END_ARG_INFO()
1233 :
1234 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quote, 0, 0, 1)
1235 : ZEND_ARG_INFO(0, string)
1236 : ZEND_ARG_INFO(0, paramtype)
1237 : ZEND_END_ARG_INFO()
1238 :
1239 : ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0)
1240 : ZEND_END_ARG_INFO()
1241 : /* }}} */
1242 :
1243 : const zend_function_entry pdo_dbh_functions[] = {
1244 : ZEND_MALIAS(PDO, __construct, dbh_constructor, arginfo_pdo___construct, ZEND_ACC_PUBLIC)
1245 : PHP_ME(PDO, prepare, arginfo_pdo_prepare, ZEND_ACC_PUBLIC)
1246 : PHP_ME(PDO, beginTransaction, arginfo_pdo__void, ZEND_ACC_PUBLIC)
1247 : PHP_ME(PDO, commit, arginfo_pdo__void, ZEND_ACC_PUBLIC)
1248 : PHP_ME(PDO, rollBack, arginfo_pdo__void, ZEND_ACC_PUBLIC)
1249 : PHP_ME(PDO, setAttribute, arginfo_pdo_setattribute, ZEND_ACC_PUBLIC)
1250 : PHP_ME(PDO, exec, arginfo_pdo_exec, ZEND_ACC_PUBLIC)
1251 : PHP_ME(PDO, query, NULL, ZEND_ACC_PUBLIC)
1252 : PHP_ME(PDO, lastInsertId, arginfo_pdo_lastinsertid, ZEND_ACC_PUBLIC)
1253 : PHP_ME(PDO, errorCode, arginfo_pdo__void, ZEND_ACC_PUBLIC)
1254 : PHP_ME(PDO, errorInfo, arginfo_pdo__void, ZEND_ACC_PUBLIC)
1255 : PHP_ME(PDO, getAttribute, arginfo_pdo_getattribute, ZEND_ACC_PUBLIC)
1256 : PHP_ME(PDO, quote, arginfo_pdo_quote, ZEND_ACC_PUBLIC)
1257 : PHP_ME(PDO, __wakeup, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1258 : PHP_ME(PDO, __sleep, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1259 : PHP_ME(PDO, getAvailableDrivers, arginfo_pdo__void, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1260 : {NULL, NULL, NULL}
1261 : };
1262 :
1263 : /* {{{ overloaded object handlers for PDO class */
1264 : int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
1265 3 : {
1266 : const zend_function_entry *funcs;
1267 : zend_function func;
1268 3 : zend_internal_function *ifunc = (zend_internal_function*)&func;
1269 : char *lc_name;
1270 :
1271 3 : if (!dbh || !dbh->methods || !dbh->methods->get_driver_methods) {
1272 0 : return 0;
1273 : }
1274 3 : funcs = dbh->methods->get_driver_methods(dbh, kind TSRMLS_CC);
1275 3 : if (!funcs) {
1276 0 : return 0;
1277 : }
1278 :
1279 3 : if (!(dbh->cls_methods[kind] = pemalloc(sizeof(HashTable), dbh->is_persistent))) {
1280 0 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO methods.");
1281 : }
1282 3 : zend_hash_init_ex(dbh->cls_methods[kind], 8, NULL, NULL, dbh->is_persistent, 0);
1283 :
1284 13 : while (funcs->fname) {
1285 7 : int namelen = strlen(funcs->fname)+1;
1286 :
1287 7 : ifunc->type = ZEND_INTERNAL_FUNCTION;
1288 7 : ifunc->handler = funcs->handler;
1289 7 : ifunc->function_name.u = malloc(UBYTES(namelen));
1290 7 : u_charsToUChars(funcs->fname, ifunc->function_name.u, namelen);
1291 7 : ifunc->scope = dbh->ce;
1292 7 : ifunc->prototype = NULL;
1293 7 : if (funcs->arg_info) {
1294 0 : ifunc->arg_info = (zend_arg_info*)funcs->arg_info + 1;
1295 0 : ifunc->num_args = funcs->num_args;
1296 0 : if (funcs->arg_info[0].required_num_args == -1) {
1297 0 : ifunc->required_num_args = funcs->num_args;
1298 : } else {
1299 0 : ifunc->required_num_args = funcs->arg_info[0].required_num_args;
1300 : }
1301 0 : ifunc->pass_rest_by_reference = funcs->arg_info[0].pass_by_reference;
1302 0 : ifunc->return_reference = funcs->arg_info[0].return_reference;
1303 : } else {
1304 7 : ifunc->arg_info = NULL;
1305 7 : ifunc->num_args = 0;
1306 7 : ifunc->required_num_args = 0;
1307 7 : ifunc->pass_rest_by_reference = 0;
1308 7 : ifunc->return_reference = 0;
1309 : }
1310 7 : if (funcs->flags) {
1311 7 : ifunc->fn_flags = funcs->flags;
1312 : } else {
1313 0 : ifunc->fn_flags = ZEND_ACC_PUBLIC;
1314 : }
1315 7 : lc_name = emalloc(namelen+1);
1316 7 : zend_str_tolower_copy(lc_name, funcs->fname, namelen);
1317 7 : zend_ascii_hash_add(dbh->cls_methods[kind], lc_name, namelen+1, &func, sizeof(zend_function), NULL);
1318 7 : efree(lc_name);
1319 7 : funcs++;
1320 : }
1321 :
1322 3 : return 1;
1323 : }
1324 :
1325 : static union _zend_function *dbh_method_get(
1326 : #if PHP_API_VERSION >= 20041225
1327 : zval **object_pp,
1328 : #else
1329 : zval *object,
1330 : #endif
1331 : zstr method_name,
1332 : int method_len TSRMLS_DC)
1333 8984 : {
1334 8984 : zend_function *fbc = NULL;
1335 : zstr lc_method_name;
1336 : #if PHP_API_VERSION >= 20041225
1337 8984 : zval *object = *object_pp;
1338 : #endif
1339 8984 : pdo_dbh_t *dbh = zend_object_store_get_object(object TSRMLS_CC);
1340 8984 : zend_uchar ztype = IS_UNICODE;
1341 :
1342 8984 : lc_method_name = zend_u_str_tolower_dup(ztype, method_name, method_len);
1343 :
1344 8984 : if ((fbc = std_object_handlers.get_method(object_pp, method_name, method_len TSRMLS_CC)) == NULL) {
1345 : /* not a pre-defined method, nor a user-defined method; check
1346 : * the driver specific methods */
1347 3 : if (!dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1348 3 : if (!pdo_hash_methods(dbh,
1349 : PDO_DBH_DRIVER_METHOD_KIND_DBH TSRMLS_CC)
1350 : || !dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1351 : goto out;
1352 : }
1353 : }
1354 :
1355 3 : if (zend_u_hash_find(dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH],
1356 : ztype, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
1357 3 : if (!fbc) {
1358 3 : fbc = NULL;
1359 : }
1360 : }
1361 : }
1362 :
1363 8977 : out:
1364 8977 : pdo_zstr_efree(lc_method_name);
1365 8977 : return fbc;
1366 : }
1367 :
1368 : static int dbh_compare(zval *object1, zval *object2 TSRMLS_DC)
1369 0 : {
1370 0 : return -1;
1371 : }
1372 :
1373 : static zend_object_handlers pdo_dbh_object_handlers;
1374 :
1375 : void pdo_dbh_init(TSRMLS_D)
1376 17007 : {
1377 : zend_class_entry ce;
1378 :
1379 17007 : INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
1380 17007 : pdo_dbh_ce = zend_register_internal_class(&ce TSRMLS_CC);
1381 17007 : pdo_dbh_ce->create_object = pdo_dbh_new;
1382 :
1383 17007 : memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1384 17007 : pdo_dbh_object_handlers.get_method = dbh_method_get;
1385 17007 : pdo_dbh_object_handlers.compare_objects = dbh_compare;
1386 :
1387 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_BOOL", (long)PDO_PARAM_BOOL);
1388 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_NULL", (long)PDO_PARAM_NULL);
1389 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_INT", (long)PDO_PARAM_INT);
1390 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR", (long)PDO_PARAM_STR);
1391 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB", (long)PDO_PARAM_LOB);
1392 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT", (long)PDO_PARAM_STMT);
1393 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT", (long)PDO_PARAM_INPUT_OUTPUT);
1394 :
1395 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_ALLOC", (long)PDO_PARAM_EVT_ALLOC);
1396 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FREE", (long)PDO_PARAM_EVT_FREE);
1397 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_PRE", (long)PDO_PARAM_EVT_EXEC_PRE);
1398 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_POST", (long)PDO_PARAM_EVT_EXEC_POST);
1399 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_PRE", (long)PDO_PARAM_EVT_FETCH_PRE);
1400 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_POST", (long)PDO_PARAM_EVT_FETCH_POST);
1401 17007 : REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_NORMALIZE", (long)PDO_PARAM_EVT_NORMALIZE);
1402 :
1403 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (long)PDO_FETCH_LAZY);
1404 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC",(long)PDO_FETCH_ASSOC);
1405 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM", (long)PDO_FETCH_NUM);
1406 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH", (long)PDO_FETCH_BOTH);
1407 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ", (long)PDO_FETCH_OBJ);
1408 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND",(long)PDO_FETCH_BOUND);
1409 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN",(long)PDO_FETCH_COLUMN);
1410 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASS",(long)PDO_FETCH_CLASS);
1411 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_INTO", (long)PDO_FETCH_INTO);
1412 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_FUNC", (long)PDO_FETCH_FUNC);
1413 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_GROUP",(long)PDO_FETCH_GROUP);
1414 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_UNIQUE",(long)PDO_FETCH_UNIQUE);
1415 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_KEY_PAIR",(long)PDO_FETCH_KEY_PAIR);
1416 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASSTYPE",(long)PDO_FETCH_CLASSTYPE);
1417 : #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
1418 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_SERIALIZE",(long)PDO_FETCH_SERIALIZE);
1419 : #endif
1420 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_PROPS_LATE",(long)PDO_FETCH_PROPS_LATE);
1421 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_NAMED",(long)PDO_FETCH_NAMED);
1422 :
1423 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_AUTOCOMMIT", (long)PDO_ATTR_AUTOCOMMIT);
1424 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_PREFETCH", (long)PDO_ATTR_PREFETCH);
1425 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_TIMEOUT", (long)PDO_ATTR_TIMEOUT);
1426 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_ERRMODE", (long)PDO_ATTR_ERRMODE);
1427 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_VERSION", (long)PDO_ATTR_SERVER_VERSION);
1428 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_CLIENT_VERSION", (long)PDO_ATTR_CLIENT_VERSION);
1429 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_INFO", (long)PDO_ATTR_SERVER_INFO);
1430 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_CONNECTION_STATUS", (long)PDO_ATTR_CONNECTION_STATUS);
1431 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_CASE", (long)PDO_ATTR_CASE);
1432 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR_NAME", (long)PDO_ATTR_CURSOR_NAME);
1433 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR", (long)PDO_ATTR_CURSOR);
1434 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_ORACLE_NULLS", (long)PDO_ATTR_ORACLE_NULLS);
1435 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_PERSISTENT", (long)PDO_ATTR_PERSISTENT);
1436 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_STATEMENT_CLASS", (long)PDO_ATTR_STATEMENT_CLASS);
1437 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_TABLE_NAMES", (long)PDO_ATTR_FETCH_TABLE_NAMES);
1438 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_CATALOG_NAMES", (long)PDO_ATTR_FETCH_CATALOG_NAMES);
1439 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_DRIVER_NAME", (long)PDO_ATTR_DRIVER_NAME);
1440 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_STRINGIFY_FETCHES",(long)PDO_ATTR_STRINGIFY_FETCHES);
1441 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN",(long)PDO_ATTR_MAX_COLUMN_LEN);
1442 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES",(long)PDO_ATTR_EMULATE_PREPARES);
1443 17007 : REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE",(long)PDO_ATTR_DEFAULT_FETCH_MODE);
1444 :
1445 17007 : REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT", (long)PDO_ERRMODE_SILENT);
1446 17007 : REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING", (long)PDO_ERRMODE_WARNING);
1447 17007 : REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION", (long)PDO_ERRMODE_EXCEPTION);
1448 :
1449 17007 : REGISTER_PDO_CLASS_CONST_LONG("CASE_NATURAL", (long)PDO_CASE_NATURAL);
1450 17007 : REGISTER_PDO_CLASS_CONST_LONG("CASE_LOWER", (long)PDO_CASE_LOWER);
1451 17007 : REGISTER_PDO_CLASS_CONST_LONG("CASE_UPPER", (long)PDO_CASE_UPPER);
1452 :
1453 17007 : REGISTER_PDO_CLASS_CONST_LONG("NULL_NATURAL", (long)PDO_NULL_NATURAL);
1454 17007 : REGISTER_PDO_CLASS_CONST_LONG("NULL_EMPTY_STRING", (long)PDO_NULL_EMPTY_STRING);
1455 17007 : REGISTER_PDO_CLASS_CONST_LONG("NULL_TO_STRING", (long)PDO_NULL_TO_STRING);
1456 :
1457 17007 : REGISTER_PDO_CLASS_CONST_STRING("ERR_NONE", PDO_ERR_NONE);
1458 :
1459 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_NEXT", (long)PDO_FETCH_ORI_NEXT);
1460 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_PRIOR", (long)PDO_FETCH_ORI_PRIOR);
1461 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_FIRST", (long)PDO_FETCH_ORI_FIRST);
1462 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_LAST", (long)PDO_FETCH_ORI_LAST);
1463 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_ABS", (long)PDO_FETCH_ORI_ABS);
1464 17007 : REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_REL", (long)PDO_FETCH_ORI_REL);
1465 :
1466 17007 : REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY", (long)PDO_CURSOR_FWDONLY);
1467 17007 : REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL", (long)PDO_CURSOR_SCROLL);
1468 :
1469 : #if 0
1470 : REGISTER_PDO_CLASS_CONST_LONG("ERR_CANT_MAP", (long)PDO_ERR_CANT_MAP);
1471 : REGISTER_PDO_CLASS_CONST_LONG("ERR_SYNTAX", (long)PDO_ERR_SYNTAX);
1472 : REGISTER_PDO_CLASS_CONST_LONG("ERR_CONSTRAINT", (long)PDO_ERR_CONSTRAINT);
1473 : REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_FOUND", (long)PDO_ERR_NOT_FOUND);
1474 : REGISTER_PDO_CLASS_CONST_LONG("ERR_ALREADY_EXISTS", (long)PDO_ERR_ALREADY_EXISTS);
1475 : REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_IMPLEMENTED", (long)PDO_ERR_NOT_IMPLEMENTED);
1476 : REGISTER_PDO_CLASS_CONST_LONG("ERR_MISMATCH", (long)PDO_ERR_MISMATCH);
1477 : REGISTER_PDO_CLASS_CONST_LONG("ERR_TRUNCATED", (long)PDO_ERR_TRUNCATED);
1478 : REGISTER_PDO_CLASS_CONST_LONG("ERR_DISCONNECTED", (long)PDO_ERR_DISCONNECTED);
1479 : REGISTER_PDO_CLASS_CONST_LONG("ERR_NO_PERM", (long)PDO_ERR_NO_PERM);
1480 : #endif
1481 :
1482 17007 : }
1483 :
1484 : static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC)
1485 3058 : {
1486 : int i;
1487 :
1488 3058 : if (--dbh->refcount)
1489 2087 : return;
1490 :
1491 971 : if (dbh->query_stmt) {
1492 33 : zval_dtor(&dbh->query_stmt_zval);
1493 33 : dbh->query_stmt = NULL;
1494 : }
1495 :
1496 971 : if (dbh->methods) {
1497 930 : dbh->methods->closer(dbh TSRMLS_CC);
1498 : }
1499 :
1500 971 : if (dbh->data_source) {
1501 931 : pefree((char *)dbh->data_source, dbh->is_persistent);
1502 : }
1503 971 : if (dbh->username) {
1504 607 : pefree(dbh->username, dbh->is_persistent);
1505 : }
1506 971 : if (dbh->password) {
1507 607 : pefree(dbh->password, dbh->is_persistent);
1508 : }
1509 :
1510 971 : if (dbh->persistent_id) {
1511 4 : pefree((char *)dbh->persistent_id, dbh->is_persistent);
1512 : }
1513 :
1514 971 : if (dbh->def_stmt_ctor_args) {
1515 8 : zval_ptr_dtor(&dbh->def_stmt_ctor_args);
1516 : }
1517 :
1518 2913 : for (i = 0; i < PDO_DBH_DRIVER_METHOD_KIND__MAX; i++) {
1519 1942 : if (dbh->cls_methods[i]) {
1520 3 : zend_hash_destroy(dbh->cls_methods[i]);
1521 3 : pefree(dbh->cls_methods[i], dbh->is_persistent);
1522 : }
1523 : }
1524 :
1525 971 : pefree(dbh, dbh->is_persistent);
1526 : }
1527 :
1528 : PDO_API void php_pdo_dbh_addref(pdo_dbh_t *dbh TSRMLS_DC)
1529 2060 : {
1530 2060 : dbh->refcount++;
1531 2060 : }
1532 :
1533 : PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh TSRMLS_DC)
1534 2051 : {
1535 2051 : dbh_free(dbh TSRMLS_CC);
1536 2051 : }
1537 :
1538 : static void pdo_dbh_free_storage(pdo_dbh_t *dbh TSRMLS_DC)
1539 1003 : {
1540 1003 : if (dbh->in_txn && dbh->methods && dbh->methods->rollback) {
1541 93 : dbh->methods->rollback(dbh TSRMLS_CC);
1542 93 : dbh->in_txn = 0;
1543 : }
1544 :
1545 1003 : if (dbh->properties) {
1546 981 : zend_hash_destroy(dbh->properties);
1547 981 : efree(dbh->properties);
1548 981 : dbh->properties = NULL;
1549 : }
1550 :
1551 1003 : if (dbh->is_persistent && dbh->methods && dbh->methods->persistent_shutdown) {
1552 4 : dbh->methods->persistent_shutdown(dbh TSRMLS_CC);
1553 : }
1554 1003 : dbh_free(dbh TSRMLS_CC);
1555 1003 : }
1556 :
1557 : zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC)
1558 1005 : {
1559 : zend_object_value retval;
1560 : pdo_dbh_t *dbh;
1561 : zval *tmp;
1562 :
1563 1005 : dbh = emalloc(sizeof(*dbh));
1564 1005 : memset(dbh, 0, sizeof(*dbh));
1565 1005 : dbh->ce = ce;
1566 1005 : dbh->refcount = 1;
1567 1005 : ALLOC_HASHTABLE(dbh->properties);
1568 1005 : zend_hash_init(dbh->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
1569 1005 : zend_hash_copy(dbh->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
1570 1005 : dbh->def_stmt_ce = pdo_dbstmt_ce;
1571 :
1572 1005 : retval.handle = zend_objects_store_put(dbh, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbh_free_storage, NULL TSRMLS_CC);
1573 1005 : retval.handlers = &pdo_dbh_object_handlers;
1574 :
1575 1005 : return retval;
1576 : }
1577 :
1578 : /* }}} */
1579 :
1580 : ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor)
1581 4 : {
1582 4 : if (rsrc->ptr) {
1583 4 : pdo_dbh_t *dbh = (pdo_dbh_t*)rsrc->ptr;
1584 4 : dbh_free(dbh TSRMLS_CC);
1585 4 : rsrc->ptr = NULL;
1586 : }
1587 4 : }
1588 :
1589 : /*
1590 : * Local variables:
1591 : * tab-width: 4
1592 : * c-basic-offset: 4
1593 : * End:
1594 : * vim600: noet sw=4 ts=4 fdm=marker
1595 : * vim<600: noet sw=4 ts=4
1596 : */
|