summaryrefslogtreecommitdiff
path: root/ext/pdo/pdo_dbh.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo/pdo_dbh.c')
-rwxr-xr-xext/pdo/pdo_dbh.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c
new file mode 100755
index 0000000000..a97ce4a644
--- /dev/null
+++ b/ext/pdo/pdo_dbh.c
@@ -0,0 +1,431 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2004 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.0 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_0.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Wez Furlong <wez@php.net> |
+ | Marcus Boerger <helly@php.net> |
+ | Sterling Hughes <sterling@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* The PDO Database Handle Class */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_pdo.h"
+#include "php_pdo_driver.h"
+#include "php_pdo_int.h"
+#include "zend_exceptions.h"
+
+/* {{{ proto object PDO::__construct(string dsn, string username, string passwd [, array driver_opts])
+ */
+static PHP_FUNCTION(dbh_constructor)
+{
+ zval *object = getThis();
+ pdo_dbh_t *dbh = NULL;
+ zend_bool is_persistent = FALSE;
+ char *data_source;
+ long data_source_len;
+ char *driver_name_length;
+ char *colon;
+ char *username, *password;
+ long usernamelen, passwordlen;
+ pdo_driver_t *driver = NULL;
+ zval *driver_options = NULL;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|a!", &data_source, &data_source_len,
+ &username, &usernamelen, &password, &passwordlen, &driver_options)) {
+ ZVAL_NULL(object);
+ return;
+ }
+
+ /* parse the data source name */
+ colon = strchr(data_source, ':');
+
+ if (!colon) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid data source name");
+ ZVAL_NULL(object);
+ return;
+ }
+
+ driver = pdo_find_driver(data_source, colon - data_source);
+
+ if (!driver) {
+ /* NB: don't want to include the data_source in the error message as
+ * it might contain a password */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "could not find driver");
+ ZVAL_NULL(object);
+ return;
+ }
+
+ dbh = pemalloc(sizeof(*dbh), is_persistent);
+
+ if (dbh == NULL) {
+ /* need this check for persistent allocations */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory");
+ }
+
+ memset(dbh, 0, sizeof(*dbh));
+ dbh->is_persistent = is_persistent;
+
+ dbh->data_source_len = strlen(colon + 1);
+ /* when persistent stuff is done, we should check the return values here
+ * too */
+ dbh->data_source = (const char*)pestrdup(colon + 1, is_persistent);
+ dbh->username = pestrdup(username, is_persistent);
+ dbh->password = pestrdup(password, is_persistent);
+
+ if (driver_options) {
+ dbh->auto_commit = pdo_attr_lval(driver_options, PDO_ATTR_AUTOCOMMIT, 1 TSRMLS_CC);
+ } else {
+ dbh->auto_commit = 1;
+ }
+
+ if (driver->db_handle_factory(dbh, driver_options TSRMLS_CC)) {
+ /* all set */
+
+ if (is_persistent) {
+ /* register in the persistent list etc. */
+ ;
+ }
+
+ zend_object_store_set_object(object, dbh TSRMLS_CC);
+ return;
+ }
+
+ /* the connection failed; tidy things up */
+ pefree((char*)dbh->data_source, is_persistent);
+ pefree(dbh, is_persistent);
+
+ /* XXX raise exception */
+ ZVAL_NULL(object);
+}
+/* }}} */
+
+/* {{{ proto object PDO::prepare(string statment)
+ Prepares a statement for execution and returns a statement object */
+static PHP_METHOD(PDO, prepare)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ pdo_stmt_t *stmt;
+ char *statement;
+ long statement_len;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &statement, &statement_len)) {
+ RETURN_FALSE;
+ }
+
+ stmt = ecalloc(1, sizeof(*stmt));
+
+ if (dbh->methods->preparer(dbh, statement, statement_len, stmt TSRMLS_CC)) {
+ /* prepared; create a statement object for PHP land to access it */
+ Z_TYPE_P(return_value) = IS_OBJECT;
+ Z_OBJ_HANDLE_P(return_value) = zend_objects_store_put(stmt, NULL, pdo_dbstmt_free_storage, NULL TSRMLS_CC);
+ Z_OBJ_HT_P(return_value) = &pdo_dbstmt_object_handlers;
+
+ /* give it a reference to me */
+ stmt->database_object_handle = *getThis();
+ zend_objects_store_add_ref(getThis() TSRMLS_CC);
+ stmt->dbh = dbh;
+ return;
+ }
+
+ efree(stmt);
+
+ RETURN_FALSE;
+}
+
+/* {{{ proto bool PDO::beginWork()
+ Initiates a transaction */
+static PHP_METHOD(PDO, beginWork)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (dbh->in_txn) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "There is already an active transaction");
+ RETURN_FALSE;
+ }
+
+ if (!dbh->methods->begin) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver does not support transactions");
+ RETURN_FALSE;
+ }
+
+ if (dbh->methods->begin(dbh TSRMLS_CC)) {
+ dbh->in_txn = 1;
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool PDO::commit()
+ Commit a transaction */
+static PHP_METHOD(PDO, commit)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!dbh->in_txn) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "There is no active transaction");
+ RETURN_FALSE;
+ }
+
+ if (dbh->methods->commit(dbh TSRMLS_CC)) {
+ dbh->in_txn = 0;
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool PDO::rollBack()
+ roll back a transaction */
+static PHP_METHOD(PDO, rollBack)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (!dbh->in_txn) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "There is no active transaction");
+ RETURN_FALSE;
+ }
+
+ if (dbh->methods->rollback(dbh TSRMLS_CC)) {
+ dbh->in_txn = 0;
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool PDO::setAttribute(long attribute, mixed value)
+ Set an attribute */
+static PHP_METHOD(PDO, setAttribute)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ long attr;
+ zval *value = NULL;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
+ RETURN_FALSE;
+ }
+
+ if (!dbh->methods->set_attribute) {
+ goto fail;
+ }
+
+ if (dbh->methods->set_attribute(dbh, attr, value TSRMLS_CC)) {
+ RETURN_TRUE;
+ }
+
+fail:
+ if (attr == PDO_ATTR_AUTOCOMMIT) {
+ /* Feature: if the auto-commit mode cannot be changed, throw an
+ * exception. Until I've added the code for that, raise an
+ * E_ERROR */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "The auto commit mode cannot be changed for this driver");
+ } else if (!dbh->methods->set_attribute) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "This driver doesn't support setting attributes");
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+
+function_entry pdo_dbh_functions[] = {
+ PHP_ME(PDO, prepare, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, beginWork, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, commit, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, rollBack, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, setAttribute, NULL, ZEND_ACC_PUBLIC)
+
+ {NULL, NULL, NULL}
+};
+
+/* {{{ overloaded object handlers for PDO class */
+static zval *dbh_prop_read(zval *object, zval *member, int type TSRMLS_DC)
+{
+ zval *return_value;
+
+ MAKE_STD_ZVAL(return_value);
+ ZVAL_NULL(return_value);
+
+ return return_value;
+}
+
+static void dbh_prop_write(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+ return;
+}
+
+static zval *dbh_read_dim(zval *object, zval *offset, int type TSRMLS_DC)
+{
+ zval *return_value;
+
+ MAKE_STD_ZVAL(return_value);
+ ZVAL_NULL(return_value);
+
+ return return_value;
+}
+
+static void dbh_write_dim(zval *object, zval *offset, zval *value TSRMLS_DC)
+{
+ return;
+}
+
+static int dbh_prop_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
+{
+ return 0;
+}
+
+static int dbh_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
+{
+ return 0;
+}
+
+static void dbh_prop_delete(zval *object, zval *offset TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDO DBH");
+}
+
+static void dbh_dim_delete(zval *object, zval *offset TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete dimensions from a PDO DBH");
+}
+
+static HashTable *dbh_get_properties(zval *object TSRMLS_DC)
+{
+ return NULL;
+}
+
+static union _zend_function *dbh_method_get(zval *object, char *method_name, int method_len TSRMLS_DC)
+{
+ zend_function *fbc;
+ char *lc_method_name;
+
+ lc_method_name = do_alloca(method_len + 1);
+ zend_str_tolower_copy(lc_method_name, method_name, method_len);
+
+ if (zend_hash_find(&pdo_dbh_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
+ free_alloca(lc_method_name);
+ return NULL;
+ }
+
+ free_alloca(lc_method_name);
+ return fbc;
+}
+
+static int dbh_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
+{
+ return FAILURE;
+}
+
+static union _zend_function *dbh_get_ctor(zval *object TSRMLS_DC)
+{
+ static zend_internal_function ctor = {0};
+
+ ctor.type = ZEND_INTERNAL_FUNCTION;
+ ctor.function_name = "__construct";
+ ctor.scope = pdo_dbh_ce;
+ ctor.handler = ZEND_FN(dbh_constructor);
+
+ return (union _zend_function*)&ctor;
+}
+
+static zend_class_entry *dbh_get_ce(zval *object TSRMLS_DC)
+{
+ return pdo_dbh_ce;
+}
+
+static int dbh_get_classname(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
+{
+ *class_name = estrndup("PDO", sizeof("PDO")-1);
+ *class_name_len = sizeof("PDO")-1;
+ return 0;
+}
+
+static int dbh_compare(zval *object1, zval *object2 TSRMLS_DC)
+{
+ return -1;
+}
+
+static zend_object_handlers pdo_dbh_object_handlers = {
+ ZEND_OBJECTS_STORE_HANDLERS,
+ dbh_prop_read,
+ dbh_prop_write,
+ dbh_read_dim,
+ dbh_write_dim,
+ NULL,
+ NULL,
+ NULL,
+ dbh_prop_exists,
+ dbh_prop_delete,
+ dbh_dim_exists,
+ dbh_dim_delete,
+ dbh_get_properties,
+ dbh_method_get,
+ dbh_call_method,
+ dbh_get_ctor,
+ dbh_get_ce,
+ dbh_get_classname,
+ dbh_compare,
+ NULL, /* cast */
+ NULL
+};
+
+static void pdo_dbh_free_storage(void *object TSRMLS_DC)
+{
+ pdo_dbh_t *dbh = (pdo_dbh_t*)object;
+
+ if (!dbh) {
+ return;
+ }
+
+ if (dbh->is_persistent) {
+ /* XXX: don't really free it, just delete the rsrc id */
+ return;
+ }
+
+ dbh->methods->closer(dbh TSRMLS_CC);
+ efree(dbh);
+}
+
+zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+
+ retval.handle = zend_objects_store_put(NULL, NULL, pdo_dbh_free_storage, NULL TSRMLS_CC);
+ retval.handlers = &pdo_dbh_object_handlers;
+
+ return retval;
+}
+
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */