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