summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/enchant/CREDITS2
-rwxr-xr-xext/enchant/config.m436
-rw-r--r--ext/enchant/config.w3213
-rw-r--r--ext/enchant/docs/examples/example1.php25
-rwxr-xr-xext/enchant/enchant.c774
-rwxr-xr-xext/enchant/package.xml146
-rw-r--r--ext/enchant/php_enchant.h83
-rw-r--r--ext/enchant/tests/broker_describe.phpt28
-rw-r--r--ext/enchant/tests/broker_free.phpt21
-rw-r--r--ext/enchant/tests/broker_init.phpt15
-rw-r--r--ext/enchant/tests/broker_request_dict.phpt31
-rw-r--r--ext/enchant/tests/hindi_correct.txt1
-rw-r--r--ext/enchant/tests/hindi_incorrect.txt1
-rw-r--r--ext/fileinfo/CREDITS2
-rw-r--r--ext/fileinfo/EXPERIMENTAL0
-rw-r--r--ext/fileinfo/config.m462
-rw-r--r--ext/fileinfo/fileinfo.c437
-rw-r--r--ext/fileinfo/fileinfo.php29
-rw-r--r--ext/fileinfo/package.xml43
-rw-r--r--ext/fileinfo/php_fileinfo.h61
-rwxr-xr-xext/pdo/CREDITS2
-rw-r--r--ext/pdo/Makefile.frag26
-rwxr-xr-xext/pdo/README56
-rwxr-xr-xext/pdo/TODO97
-rwxr-xr-xext/pdo/config.m468
-rwxr-xr-xext/pdo/config.w3210
-rwxr-xr-xext/pdo/package.xml119
-rwxr-xr-xext/pdo/pdo.c399
-rwxr-xr-xext/pdo/pdo.php62
-rwxr-xr-xext/pdo/pdo_dbh.c1443
-rw-r--r--ext/pdo/pdo_sql_parser.c712
-rw-r--r--ext/pdo/pdo_sql_parser.re487
-rw-r--r--ext/pdo/pdo_sqlstate.c340
-rwxr-xr-xext/pdo/pdo_stmt.c2499
-rwxr-xr-xext/pdo/php_pdo.h91
-rwxr-xr-xext/pdo/php_pdo_driver.h663
-rwxr-xr-xext/pdo/php_pdo_int.h84
-rwxr-xr-xext/pdo_mysql/CREDITS3
-rwxr-xr-xext/pdo_mysql/config.m4134
-rw-r--r--ext/pdo_mysql/config.w3215
-rw-r--r--ext/pdo_mysql/get_error_codes.php27
-rwxr-xr-xext/pdo_mysql/mysql_driver.c573
-rwxr-xr-xext/pdo_mysql/mysql_statement.c642
-rw-r--r--ext/pdo_mysql/package2.xml93
-rwxr-xr-xext/pdo_mysql/pdo_mysql.c116
-rwxr-xr-xext/pdo_mysql/php_pdo_mysql.h53
-rwxr-xr-xext/pdo_mysql/php_pdo_mysql_int.h90
-rw-r--r--ext/pdo_mysql/php_pdo_mysql_sqlstate.h388
-rw-r--r--ext/pdo_mysql/tests/bug_33689.phpt50
-rw-r--r--ext/pdo_mysql/tests/common.phpt28
-rw-r--r--ext/pdo_mysql/tests/config.inc19
-rw-r--r--ext/pdo_mysql/tests/pecl_bug_5200.phpt30
-rw-r--r--ext/pdo_mysql/tests/pecl_bug_5780.phpt41
-rw-r--r--ext/pdo_mysql/tests/pecl_bug_5802.phpt52
-rw-r--r--ext/pdo_mysql/tests/show_tables.phpt20
-rw-r--r--ext/pdo_pgsql/CREDITS2
-rw-r--r--ext/pdo_pgsql/config.m4131
-rw-r--r--ext/pdo_pgsql/config.w3222
-rw-r--r--ext/pdo_pgsql/package2.xml87
-rw-r--r--ext/pdo_pgsql/pdo_pgsql.c139
-rw-r--r--ext/pdo_pgsql/pgsql_driver.c711
-rw-r--r--ext/pdo_pgsql/pgsql_statement.c664
-rw-r--r--ext/pdo_pgsql/php_pdo_pgsql.h55
-rw-r--r--ext/pdo_pgsql/php_pdo_pgsql_int.h114
-rw-r--r--ext/sqlite/tests/bug26911.phpt10
-rwxr-xr-xext/sqlite/tests/sqlite_018.phpt13
-rwxr-xr-xext/sqlite/tests/sqlite_019.phpt46
-rwxr-xr-xext/sqlite/tests/sqlite_022.phpt98
-rw-r--r--ext/tidy/CREDITS2
-rw-r--r--ext/tidy/README122
-rw-r--r--ext/tidy/TODO3
-rw-r--r--ext/tidy/config.m435
-rw-r--r--ext/tidy/examples/cleanhtml.php38
-rw-r--r--ext/tidy/examples/dumpit.php93
-rw-r--r--ext/tidy/examples/urlgrab.php60
-rw-r--r--ext/tidy/package.xml64
-rw-r--r--ext/tidy/php_tidy.h238
-rw-r--r--ext/tidy/tests/001.phpt24
-rw-r--r--ext/tidy/tests/002.phpt22
-rw-r--r--ext/tidy/tests/003.phpt25
-rw-r--r--ext/tidy/tests/004.phpt21
-rw-r--r--ext/tidy/tests/005.html1
-rw-r--r--ext/tidy/tests/005.phpt23
-rw-r--r--ext/tidy/tests/006.phpt21
-rw-r--r--ext/tidy/tests/007.phpt36
-rw-r--r--ext/tidy/tidy.c1689
86 files changed, 13267 insertions, 2684 deletions
diff --git a/ext/enchant/CREDITS b/ext/enchant/CREDITS
new file mode 100644
index 0000000000..481febbfc2
--- /dev/null
+++ b/ext/enchant/CREDITS
@@ -0,0 +1,2 @@
+enchant
+Pierre-Alain Joye, Ilia Alshanetsky
diff --git a/ext/enchant/config.m4 b/ext/enchant/config.m4
new file mode 100755
index 0000000000..b59cd8fb3c
--- /dev/null
+++ b/ext/enchant/config.m4
@@ -0,0 +1,36 @@
+dnl
+dnl $Id$
+dnl
+
+PHP_ARG_WITH(enchant,for ENCHANT support,
+[ --with-enchant[=DIR] Include enchant support.
+ GNU Aspell version 1.1.3 or higher required.])
+
+if test "$PHP_ENCHANT" != "no"; then
+ PHP_NEW_EXTENSION(enchant, enchant.c, $ext_shared)
+ if test "$PHP_ENCHANT" != "yes"; then
+ ENCHANT_SEARCH_DIRS=$PHP_ENCHANT
+ else
+ ENCHANT_SEARCH_DIRS="/usr/local /usr"
+ fi
+ for i in $ENCHANT_SEARCH_DIRS; do
+ if test -f $i/include/enchant/enchant.h; then
+ ENCHANT_DIR=$i
+ ENCHANT_INCDIR=$i/include/enchant
+ elif test -f $i/include/enchant.h; then
+ ENCHANT_DIR=$i
+ ENCHANT_INCDIR=$i/include
+ fi
+ done
+
+ if test -z "$ENCHANT_DIR"; then
+ AC_MSG_ERROR(Cannot find enchant)
+ fi
+
+ ENCHANT_LIBDIR=$ENCHANT_DIR/lib
+
+ AC_DEFINE(HAVE_ENCHANT,1,[ ])
+ PHP_SUBST(ENCHANT_SHARED_LIBADD)
+ PHP_ADD_LIBRARY_WITH_PATH(enchant, $ENCHANT_LIBDIR, ENCHANT_SHARED_LIBADD)
+ PHP_ADD_INCLUDE($ENCHANT_INCDIR)
+fi
diff --git a/ext/enchant/config.w32 b/ext/enchant/config.w32
new file mode 100644
index 0000000000..f9ba6beafc
--- /dev/null
+++ b/ext/enchant/config.w32
@@ -0,0 +1,13 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_ENABLE("enchant", "Enchant Support", "no");
+
+if (PHP_ENCHANT == "yes") {
+ if (CHECK_HEADER_ADD_INCLUDE("enchant.h", "CFLAGS_ENCHANT", PHP_ENCHANT)) {
+ EXTENSION("enchant", "enchant.c");
+ AC_DEFINE('HAVE_ENCHANT', 1, 'Have Enchant support', false);
+ } else {
+ WARNING('Could not find enchant.h; skipping');
+ }
+}
diff --git a/ext/enchant/docs/examples/example1.php b/ext/enchant/docs/examples/example1.php
new file mode 100644
index 0000000000..9d503f74e6
--- /dev/null
+++ b/ext/enchant/docs/examples/example1.php
@@ -0,0 +1,25 @@
+<?php
+$tag = 'en_US';
+$r = enchant_broker_init();
+$bprovides = enchant_broker_describe($r);
+echo "Current broker provides the following backend(s):\n";
+print_r($bprovides);
+
+
+if (enchant_broker_dict_exists($r,$tag)) {
+ $d = enchant_broker_request_dict($r, $tag);
+ $dprovides = enchant_dict_describe($d);
+ echo "dictionary $tag provides:\n";
+ $spellerrors = enchant_dict_check($d, "soong");
+ print_r($dprovides);
+ echo "found $spellerrors spell errors\n";
+ if ($spellerrors) {
+ $suggs = enchant_dict_suggest($d, "soong");
+ echo "Suggestions for 'soong':";
+ print_r($suggs);
+ }
+ enchant_broker_free_dict($d);
+} else {
+}
+enchant_broker_free($r);
+?>
diff --git a/ext/enchant/enchant.c b/ext/enchant/enchant.c
new file mode 100755
index 0000000000..f47a2b34e3
--- /dev/null
+++ b/ext/enchant/enchant.c
@@ -0,0 +1,774 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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 at through the world-wide-web at |
+ | 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: Pierre-Alain Joye <paj@pearfr.org> |
+ | Ilia Alshanetsky <ilia@prohost.org> |
+ +----------------------------------------------------------------------+
+
+ $Id$
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <enchant.h>
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_enchant.h"
+
+
+typedef EnchantBroker * EnchantBrokerPtr;
+typedef struct _broker_struct enchant_broker;
+typedef struct _dict_struct enchant_dict;
+
+typedef enchant_broker * enchant_brokerPtr;
+typedef enchant_dict * enchant_dictPtr;
+
+typedef struct _broker_struct {
+ EnchantBroker *pbroker;
+ enchant_dict **dict;
+ unsigned int dictcnt;
+ long rsrc_id;
+} _enchant_broker;
+
+typedef struct _dict_struct {
+ unsigned int id;
+ EnchantDict *pdict;
+ enchant_broker *pbroker;
+ long rsrc_id;
+ enchant_dict *next;
+ enchant_dict *prev;
+} _enchant_dict;
+
+
+/* True global resources - no need for thread safety here */
+static int le_enchant_broker;
+static int le_enchant_dict;
+
+/* If you declare any globals in php_enchant.h uncomment this:*/
+/*ZEND_DECLARE_MODULE_GLOBALS(enchant)*/
+
+/* {{{ enchant_functions[]
+ *
+ * Every user visible function must have an entry in enchant_functions[].
+ */
+function_entry enchant_functions[] = {
+ PHP_FE(enchant_broker_init, NULL)
+ PHP_FE(enchant_broker_free, NULL)
+ PHP_FE(enchant_broker_get_error, NULL)
+ PHP_FE(enchant_broker_list_dicts, NULL)
+ PHP_FE(enchant_broker_request_dict, NULL)
+ PHP_FE(enchant_broker_request_pwl_dict, NULL)
+ PHP_FE(enchant_broker_free_dict, NULL)
+ PHP_FE(enchant_broker_dict_exists, NULL)
+ PHP_FE(enchant_broker_set_ordering, NULL)
+ PHP_FE(enchant_broker_describe, NULL)
+ PHP_FE(enchant_dict_check, NULL)
+ PHP_FE(enchant_dict_suggest, NULL)
+ PHP_FE(enchant_dict_add_to_personal, NULL)
+ PHP_FE(enchant_dict_add_to_session, NULL)
+ PHP_FE(enchant_dict_is_in_session, NULL)
+ PHP_FE(enchant_dict_store_replacement, NULL)
+ PHP_FE(enchant_dict_get_error, NULL)
+ PHP_FE(enchant_dict_describe, NULL)
+ PHP_FE(enchant_dict_quick_check, third_arg_force_ref)
+
+ {NULL, NULL, NULL} /* Must be the last line in enchant_functions[] */
+};
+/* }}} */
+
+/* {{{ enchant_module_entry
+ */
+zend_module_entry enchant_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+ STANDARD_MODULE_HEADER,
+#endif
+ "enchant",
+ enchant_functions,
+ PHP_MINIT(enchant),
+ PHP_MSHUTDOWN(enchant),
+ NULL, /* Replace with NULL if there's nothing to do at request start */
+ NULL, /* Replace with NULL if there's nothing to do at request end */
+ PHP_MINFO(enchant),
+#if ZEND_MODULE_API_NO >= 20010901
+ PHP_ENCHANT_VERSION,
+#endif
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_ENCHANT
+ZEND_GET_MODULE(enchant)
+#endif
+
+static void
+enumerate_providers_fn (const char * const name,
+ const char * const desc,
+ const char * const file,
+ void * ud) /* {{{ */
+{
+ zval *zdesc = (zval *) ud;
+ zval *tmp_array;
+
+ MAKE_STD_ZVAL(tmp_array);
+ array_init(tmp_array);
+
+ add_assoc_string(tmp_array, "name", (char *)name, 1);
+ add_assoc_string(tmp_array, "desc", (char *)desc, 1);
+ add_assoc_string(tmp_array, "file", (char *)file, 1);
+
+ if (Z_TYPE_P(zdesc)!=IS_ARRAY) {
+ array_init(zdesc);
+ }
+
+ add_next_index_zval(zdesc, tmp_array);
+}
+/* }}} */
+
+static void
+describe_dict_fn (const char * const lang,
+ const char * const name,
+ const char * const desc,
+ const char * const file,
+ void * ud) /* {{{ */
+{
+ zval *zdesc = (zval *) ud;
+ array_init(zdesc);
+ add_assoc_string(zdesc, "lang", (char *)lang, 1);
+ add_assoc_string(zdesc, "name", (char *)name, 1);
+ add_assoc_string(zdesc, "desc", (char *)desc, 1);
+ add_assoc_string(zdesc, "file", (char *)file, 1);
+}
+/* }}} */
+
+static void php_enchant_list_dicts_fn( const char * const lang_tag,
+ const char * const provider_name, const char * const provider_desc,
+ const char * const provider_file, void * ud) /* {{{ */
+{
+ zval *zdesc = (zval *) ud;
+ zval *tmp_array;
+
+ MAKE_STD_ZVAL(tmp_array);
+ array_init(tmp_array);
+ add_assoc_string(tmp_array, "lang_tag", (char *)lang_tag, 1);
+ add_assoc_string(tmp_array, "provider_name", (char *)provider_name, 1);
+ add_assoc_string(tmp_array, "provider_desc", (char *)provider_desc, 1);
+ add_assoc_string(tmp_array, "provider_file", (char *)provider_file, 1);
+
+ if (Z_TYPE_P(zdesc) != IS_ARRAY) {
+ array_init(zdesc);
+ }
+ add_next_index_zval(zdesc, tmp_array);
+
+}
+/* }}} */
+
+static void php_enchant_broker_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+{
+ if (rsrc->ptr) {
+ enchant_broker *broker = (enchant_broker *)rsrc->ptr;
+ if (broker) {
+ if (broker->pbroker) {
+ if (broker->dictcnt && broker->dict) {
+ if (broker->dict) {
+ int total, tofree;
+ tofree = total = broker->dictcnt-1;
+ do {
+ zend_list_delete(broker->dict[total]->rsrc_id);
+ efree(broker->dict[total]);
+ total--;
+ } while (total>=0);
+ }
+ efree(broker->dict);
+ broker->dict = NULL;
+ }
+ enchant_broker_free(broker->pbroker);
+ }
+ efree(broker);
+ }
+ }
+}
+/* }}} */
+
+static void php_enchant_dict_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
+
+{
+ if (rsrc->ptr) {
+ enchant_dict *pdict = (enchant_dict *)rsrc->ptr;
+ if (pdict) {
+ if (pdict->pdict && pdict->pbroker) {
+ enchant_broker_free_dict(pdict->pbroker->pbroker, pdict->pdict);
+ if (pdict->id) {
+ pdict->pbroker->dict[pdict->id-1]->next = NULL;
+ }
+ zend_list_delete(pdict->pbroker->rsrc_id);
+ }
+
+ }
+ }
+}
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(enchant)
+{
+ le_enchant_broker = zend_register_list_destructors_ex(php_enchant_broker_free, NULL, "enchant_broker", module_number);
+ le_enchant_dict = zend_register_list_destructors_ex(php_enchant_dict_free, NULL, "enchant_dict", module_number);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_MSHUTDOWN_FUNCTION(enchant)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+static void __enumerate_providers_fn (const char * const name,
+ const char * const desc,
+ const char * const file,
+ void * ud) /* {{{ */
+{
+ php_info_print_table_row(3, name, desc, file);
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(enchant)
+{
+ EnchantBroker *pbroker;
+
+ pbroker = enchant_broker_init();
+ php_info_print_table_start();
+ php_info_print_table_header(2, "enchant support", "enabled");
+ php_info_print_table_row(2, "Version", PHP_ENCHANT_VERSION);
+ php_info_print_table_row(2, "Revision", "$Revision$");
+ php_info_print_table_end();
+
+ php_info_print_table_start();
+ enchant_broker_describe(pbroker, __enumerate_providers_fn, NULL);
+ php_info_print_table_end();
+ enchant_broker_free(pbroker);
+}
+/* }}} */
+
+#define PHP_ENCHANT_GET_BROKER \
+ ZEND_FETCH_RESOURCE(pbroker, enchant_broker *, &broker, -1, "enchant_broker", le_enchant_broker); \
+ if (!pbroker || !pbroker->pbroker) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "Resource broker invalid"); \
+ RETURN_FALSE; \
+ }
+
+#define PHP_ENCHANT_GET_DICT \
+ ZEND_FETCH_RESOURCE(pdict, enchant_dict *, &dict, -1, "enchant_dict", le_enchant_dict); \
+ if (!pdict || !pdict->pdict) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", "Invalid dictionary resource."); \
+ RETURN_FALSE; \
+ }
+
+/* {{{ proto resource enchant_broker_init()
+ create a new broker object capable of requesting */
+PHP_FUNCTION(enchant_broker_init)
+{
+ enchant_broker *broker;
+ EnchantBroker *pbroker;
+
+ if (ZEND_NUM_ARGS()) {
+ ZEND_WRONG_PARAM_COUNT();
+ }
+
+ pbroker = enchant_broker_init();
+
+ if (pbroker) {
+ broker = (enchant_broker *) emalloc(sizeof(enchant_broker));
+ broker->pbroker = pbroker;
+ broker->dict = NULL;
+ broker->dictcnt = 0;
+ broker->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, broker, le_enchant_broker);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto boolean enchant_broker_free(resource broker)
+ Destroys the broker object and its dictionnaries */
+PHP_FUNCTION(enchant_broker_free)
+{
+ zval *broker;
+ enchant_broker *pbroker;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &broker) == FAILURE) {
+ RETURN_FALSE;
+ }
+ PHP_ENCHANT_GET_BROKER;
+
+ zend_list_delete(Z_RESVAL_P(broker));
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string enchant_broker_get_error(resource broker)
+ Returns the last error of the broker */
+PHP_FUNCTION(enchant_broker_get_error)
+{
+ zval *broker;
+ enchant_broker *pbroker;
+ char *msg;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &broker) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_BROKER;
+
+ msg = enchant_broker_get_error(pbroker->pbroker);
+ if (msg) {
+ RETURN_STRING((char *)msg, 1);
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string enchant_broker_list_dicts(resource broker)
+ Lists the dictionaries available for the given broker */
+PHP_FUNCTION(enchant_broker_list_dicts)
+{
+ zval *broker;
+ enchant_broker *pbroker;
+ EnchantDictDescribeFn describetozval = php_enchant_list_dicts_fn;
+
+ char *msg;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &broker) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_BROKER;
+
+ enchant_broker_list_dicts(pbroker->pbroker, php_enchant_list_dicts_fn, (void *)return_value);
+}
+/* }}} */
+
+/* {{{ proto resource enchant_broker_request_dict(resource broker, string tag)
+ create a new dictionary using tag, the non-empty language tag you wish to request
+ a dictionary for ("en_US", "de_DE", ...) */
+PHP_FUNCTION(enchant_broker_request_dict)
+{
+ zval *broker;
+ enchant_broker *pbroker;
+ enchant_dict *dict;
+ EnchantDict *d;
+ char *tag;
+ int taglen;
+ int pos;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &broker, &tag, &taglen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_BROKER;
+
+ d = enchant_broker_request_dict(pbroker->pbroker, (const char *)tag);
+ if (d) {
+ if (pbroker->dictcnt) {
+ pbroker->dict = (enchant_dict **)erealloc(pbroker->dict, sizeof(enchant_dict *) * pbroker->dictcnt);
+ pos = pbroker->dictcnt++;
+ } else {
+ pbroker->dict = (enchant_dict **)emalloc(sizeof(enchant_dict *));
+ pos = 0;
+ pbroker->dictcnt++;
+ }
+
+ dict = pbroker->dict[pos] = (enchant_dict *)emalloc(sizeof(enchant_dict));
+ dict->id = pos;
+ dict->pbroker = pbroker;
+ dict->pdict = d;
+ dict->prev = pos ? pbroker->dict[pos-1] : NULL;
+ dict->next = NULL;
+ pbroker->dict[pos] = dict;
+
+ if (pos) {
+ pbroker->dict[pos-1]->next = dict;
+ }
+
+ dict->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, dict, le_enchant_dict);
+ zend_list_addref(pbroker->rsrc_id);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto resource enchant_broker_request_pwl_dict(resource broker, string filename)
+ creates a dictionary using a PWL file. A PWL file is personal word file one word per line. It must exist before the call.*/
+PHP_FUNCTION(enchant_broker_request_pwl_dict)
+{
+ zval *broker;
+ enchant_broker *pbroker;
+ enchant_dict *dict;
+ EnchantDict *d;
+ char *pwl;
+ int pwllen;
+ int pos;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &broker, &pwl, &pwllen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if ((PG(safe_mode) && (!php_checkuid(pwl, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(pwl TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_BROKER;
+
+ d = enchant_broker_request_pwl_dict(pbroker->pbroker, (const char *)pwl);
+ if (d) {
+ if (pbroker->dictcnt) {
+ pos = pbroker->dictcnt++;
+ pbroker->dict = (enchant_dict **)erealloc(pbroker->dict, sizeof(enchant_dict *) * pbroker->dictcnt);
+ } else {
+ pbroker->dict = (enchant_dict **)emalloc(sizeof(enchant_dict *));
+ pos = 0;
+ pbroker->dictcnt++;
+ }
+ dict = pbroker->dict[pos] = (enchant_dict *)emalloc(sizeof(enchant_dict));
+ dict->id = pos;
+ dict->pbroker = pbroker;
+ dict->pdict = d;
+ dict->prev = pos?pbroker->dict[pos-1]:NULL;
+ dict->next = NULL;
+ pbroker->dict[pos] = dict;
+ if (pos) {
+ pbroker->dict[pos-1]->next = dict;
+ }
+ dict->rsrc_id = ZEND_REGISTER_RESOURCE(return_value, dict, le_enchant_dict);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto resource enchant_broker_free_dict(resource dict)
+ Free the dictionary resource */
+PHP_FUNCTION(enchant_broker_free_dict)
+{
+ zval *dict;
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &dict) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ zend_list_delete(Z_RESVAL_P(dict));
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool enchant_broker_dict_exists(resource broker, string tag)
+ Wether a dictionary exists or not. Using non-empty tag */
+PHP_FUNCTION(enchant_broker_dict_exists)
+{
+ zval *broker;
+ char *tag;
+ int taglen;
+ enchant_broker * pbroker;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &broker, &tag, &taglen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_BROKER;
+
+ RETURN_BOOL(enchant_broker_dict_exists(pbroker->pbroker, tag));
+}
+/* }}} */
+
+/* {{{ proto bool enchant_broker_set_ordering(resource broker, string tag, string ordering)
+ Declares a preference of dictionaries to use for the language
+ described/referred to by 'tag'. The ordering is a comma delimited
+ list of provider names. As a special exception, the "*" tag can
+ be used as a language tag to declare a default ordering for any
+ language that does not explictly declare an ordering. */
+
+PHP_FUNCTION(enchant_broker_set_ordering)
+{
+ zval *broker;
+ char *pordering;
+ int porderinglen;
+ char *ptag;
+ int ptaglen;
+ enchant_broker * pbroker;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &broker, &ptag, &ptaglen, &pordering, &porderinglen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_BROKER;
+
+ enchant_broker_set_ordering(pbroker->pbroker, ptag, pordering);
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto array enchant_broker_describe(resource broker)
+ Enumerates the Enchant providers and tells you some rudimentary information about them. The same info is provided through phpinfo() */
+PHP_FUNCTION(enchant_broker_describe)
+{
+ EnchantBrokerDescribeFn describetozval = enumerate_providers_fn;
+ zval *broker;
+ enchant_broker * pbroker;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &broker) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_BROKER;
+
+ enchant_broker_describe(pbroker->pbroker, describetozval, (void *)return_value);
+}
+/* }}} */
+
+/* {{{ proto bool enchant_dict_quick_check(resource dict, string word [, array &suggestions])
+ If the word is correctly spelled return true, otherwise return false, if suggestions variable
+ is provided, fill it with spelling alternatives. */
+PHP_FUNCTION(enchant_dict_quick_check)
+{
+ zval *dict, *sugg = NULL;
+ char *word;
+ int wordlen;
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|z/", &dict, &word, &wordlen, &sugg) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (sugg) {
+ zval_dtor(sugg);
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ if (enchant_dict_check(pdict->pdict, word, wordlen) > 0) {
+ if (!sugg && ZEND_NUM_ARGS() == 2) {
+ RETURN_FALSE;
+ }
+
+ int n_sugg;
+ char **suggs;
+
+ array_init(sugg);
+
+ suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, (size_t *) &n_sugg);
+ if (suggs && n_sugg) {
+ int i;
+ for (i = 0; i < n_sugg; i++) {
+ add_next_index_string(sugg, suggs[i], 1);
+ }
+ enchant_dict_free_suggestions(pdict->pdict, suggs);
+ }
+
+
+ RETURN_FALSE;
+ }
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool enchant_dict_check(resource dict, string word)
+ If the word is correctly spelled return true, otherwise return false */
+PHP_FUNCTION(enchant_dict_check)
+{
+ zval *dict;
+ char *word;
+ int wordlen;
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &dict, &word, &wordlen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ RETURN_BOOL(!enchant_dict_check(pdict->pdict, word, wordlen));
+}
+/* }}} */
+
+/* {{{ proto array enchant_dict_suggest(resource dict, string word)
+ Will return a list of values if any of those pre-conditions are not met.*/
+PHP_FUNCTION(enchant_dict_suggest)
+{
+ zval *dict;
+ char *word;
+ int wordlen;
+ char **suggs;
+ enchant_dict *pdict;
+ int n_sugg;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &dict, &word, &wordlen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ suggs = enchant_dict_suggest(pdict->pdict, word, wordlen, (size_t *)&n_sugg);
+ if (suggs && n_sugg) {
+ int i;
+
+ array_init(return_value);
+ for (i = 0; i < n_sugg; i++) {
+ add_next_index_string(return_value, suggs[i], 1);
+ }
+
+ enchant_dict_free_suggestions(pdict->pdict, suggs);
+ }
+}
+/* }}} */
+
+/* {{{ proto void enchant_dict_add_to_personal(resource dict, string word)
+ add 'word' to personal word list */
+PHP_FUNCTION(enchant_dict_add_to_personal)
+{
+ zval *dict;
+ char *word;
+ int wordlen;
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &dict, &word, &wordlen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ enchant_dict_add_to_personal(pdict->pdict, word, wordlen);
+}
+/* }}} */
+
+/* {{{ proto void enchant_dict_add_to_session(resource dict, string word)
+ add 'word' to this spell-checking session */
+PHP_FUNCTION(enchant_dict_add_to_session)
+{
+ zval *dict;
+ char *word;
+ int wordlen;
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &dict, &word, &wordlen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ enchant_dict_add_to_session(pdict->pdict, word, wordlen);
+}
+/* }}} */
+
+/* {{{ proto bool enchant_dict_is_in_session(resource dict, string word)
+ whether or not 'word' exists in this spelling-session */
+PHP_FUNCTION(enchant_dict_is_in_session)
+{
+ zval *dict;
+ char *word;
+ int wordlen;
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &dict, &word, &wordlen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ RETURN_BOOL(enchant_dict_is_in_session(pdict->pdict, word, wordlen));
+}
+/* }}} */
+
+/* {{{ proto void enchant_dict_store_replacement(resource dict, string mis, string cor)
+ add a correction for 'mis' using 'cor'.
+ Notes that you replaced @mis with @cor, so it's possibly more likely
+ that future occurrences of @mis will be replaced with @cor. So it might
+ bump @cor up in the suggestion list.*/
+PHP_FUNCTION(enchant_dict_store_replacement)
+{
+ zval *dict;
+ char *mis, *cor;
+ int mislen, corlen;
+
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &dict, &mis, &mislen, &cor, &corlen) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ enchant_dict_store_replacement(pdict->pdict, mis, mislen, cor, corlen);
+}
+/* }}} */
+
+/* {{{ proto string enchant_dict_get_error(resource dict)
+ Returns the last error of the current spelling-session */
+PHP_FUNCTION(enchant_dict_get_error)
+{
+ zval *dict;
+ enchant_dict *pdict;
+ char *msg;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &dict) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ msg = enchant_dict_get_error(pdict->pdict);
+ if (msg) {
+ RETURN_STRING((char *)msg, 1);
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto array enchant_dict_describe(resource dict)
+ Describes an individual dictionary 'dict' */
+PHP_FUNCTION(enchant_dict_describe)
+{
+ zval *dict;
+ enchant_dict *pdict;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &dict) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ PHP_ENCHANT_GET_DICT;
+
+ enchant_dict_describe(pdict->pdict, describe_dict_fn, (void *)return_value);
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/enchant/package.xml b/ext/enchant/package.xml
new file mode 100755
index 0000000000..e3cd7d901b
--- /dev/null
+++ b/ext/enchant/package.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.4.8" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+ <name>enchant</name>
+ <channel>pecl.php.net</channel>
+ <summary>libenchant binder, support near all spelling tools</summary>
+ <description>Enchant is a binder for libenchant. Libenchant provides a common
+API for many spell libraries:
+- aspell/pspell (intended to replace ispell)
+- hspell (hebrew)
+- ispell
+- myspell/hunspell (OpenOffice project, mozilla)
+- uspell (primarily Yiddish, Hebrew, and Eastern European languages)
+A plugin system allows to add custom spell support.
+see www.abisource.com/enchant/
+ </description>
+ <lead>
+ <name>Pierre-Alain Joye</name>
+ <user>pajoye</user>
+ <email>paj@pearfr.org</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Ilia Alshanetsky</name>
+ <user>iliaa</user>
+ <email>ilia@php.net</email>
+ <active>yes</active>
+ </lead>
+ <date>2006-03-21</date>
+ <version>
+ <release>1.0.1</release>
+ <api>1.1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>- add enchant_broker_list_dicts to get a list of available dictionaries
+- fix compilation warnings
+- add examples
+- add tests</notes>
+ <contents>
+ <dir name="/">
+ <dir name="docs">
+ <dir name="examples">
+ <file name="example1.php" role="doc"/>
+ </dir>
+<!-- //docs/examples -->
+ </dir>
+<!-- //docs -->
+ <file name="config.m4" role="src"/>
+ <file name="config.w32" role="src"/>
+ <file name="CREDITS" role="doc"/>
+ <file name="enchant.c" role="src"/>
+ <file name="php_enchant.h" role="src"/>
+ <dir name="tests">
+ <file name="broker_describe.phpt" role="test"/>
+ <file name="broker_free.phpt" role="test"/>
+ <file name="broker_init.phpt" role="test"/>
+ <file name="broker_request_dict.phpt" role="test"/>
+ <file name="hindi_correct.txt" role="test"/>
+ <file name="hindi_incorrect.txt" role="test"/>
+ </dir>
+ </dir>
+<!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5</min>
+ </php>
+ <pearinstaller>
+ <min>1.4.0b1</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <providesextension>enchant</providesextension>
+ <extsrcrelease>
+ <configureoption default="shared" name="with-enchant" prompt="libenchant prefix?"/>
+ </extsrcrelease>
+ <changelog>
+ <release>
+ <date>2004-08-11</date>
+ <version>
+ <release>1.0</release>
+ <api>1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>- Fixed leak inside MINFO function.
+- Fixed crash inside enchant_dict_suggest() when there are no suggestions.
+- Added missing safe_mode/open_basedir check inside enchant_broker_request_pwl_dict().
+- Fixed various function prototypes.
+- Fixed possible leak in suggestions result.
+ </notes>
+ </release>
+ <release>
+ <version>
+ <release>0.2.1</release>
+ <api>0.2.1</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <date>2004-03-11</date>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>- Fix possible leak in suggestions result
+- Move to beta status
+ </notes>
+ </release>
+ <release>
+ <version>
+ <release>0.2.0</release>
+ <api>0.2.0</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2006-03-21</date>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>- Add Ilia Alshanetsky as maintainer
+- Cleanup sources codes (ilia)
+- Add enchant_dict_quick_check (ilia)
+ </notes>
+ </release>
+ <release>
+ <version>
+ <release>0.1</release>
+ <api>0.1</api>
+ </version>
+ <stability>
+ <release>alpha</release>
+ <api>alpha</api>
+ </stability>
+ <date>2003-03-08</date>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>Initial release
+ </notes>
+ </release>
+ </changelog>
+</package>
diff --git a/ext/enchant/php_enchant.h b/ext/enchant/php_enchant.h
new file mode 100644
index 0000000000..893a4c8809
--- /dev/null
+++ b/ext/enchant/php_enchant.h
@@ -0,0 +1,83 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 4 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2003 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 at through the world-wide-web at |
+ | 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: Pierre-Alain Joye <paj@pearfr.org> |
+ +----------------------------------------------------------------------+
+
+ $Id$
+*/
+
+#ifndef PHP_ENCHANT_H
+#define PHP_ENCHANT_H
+
+extern zend_module_entry enchant_module_entry;
+#define phpext_enchant_ptr &enchant_module_entry
+
+#define PHP_ENCHANT_VERSION "1.0.2-dev"
+
+#ifdef PHP_WIN32
+#define PHP_ENCHANT_API __declspec(dllexport)
+#else
+#define PHP_ENCHANT_API
+#endif
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+static void php_enchant_broker_free(zend_rsrc_list_entry *rsrc TSRMLS_DC);
+static void php_enchant_dict_free(zend_rsrc_list_entry *rsrc TSRMLS_DC);
+
+PHP_MINIT_FUNCTION(enchant);
+PHP_MSHUTDOWN_FUNCTION(enchant);
+PHP_MINFO_FUNCTION(enchant);
+
+PHP_FUNCTION(enchant_broker_init);
+PHP_FUNCTION(enchant_broker_free);
+PHP_FUNCTION(enchant_broker_get_error);
+PHP_FUNCTION(enchant_broker_list_dicts);
+PHP_FUNCTION(enchant_broker_request_dict);
+PHP_FUNCTION(enchant_broker_request_pwl_dict);
+PHP_FUNCTION(enchant_broker_free_dict);
+PHP_FUNCTION(enchant_broker_dict_exists);
+PHP_FUNCTION(enchant_broker_set_ordering);
+PHP_FUNCTION(enchant_broker_describe);
+
+PHP_FUNCTION(enchant_dict_check);
+PHP_FUNCTION(enchant_dict_suggest);
+PHP_FUNCTION(enchant_dict_add_to_personal);
+PHP_FUNCTION(enchant_dict_add_to_session);
+PHP_FUNCTION(enchant_dict_is_in_session);
+PHP_FUNCTION(enchant_dict_store_replacement);
+PHP_FUNCTION(enchant_dict_get_error);
+PHP_FUNCTION(enchant_dict_describe);
+PHP_FUNCTION(enchant_dict_quick_check);
+
+#ifdef ZTS
+#define ENCHANT_G(v) TSRMG(enchant_globals_id, zend_enchant_globals *, v)
+#else
+#define ENCHANT_G(v) (enchant_globals.v)
+#endif
+
+#endif /* PHP_ENCHANT_H */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * indent-tabs-mode: t
+ * End:
+ */
+
diff --git a/ext/enchant/tests/broker_describe.phpt b/ext/enchant/tests/broker_describe.phpt
new file mode 100644
index 0000000000..4c03f6f4dd
--- /dev/null
+++ b/ext/enchant/tests/broker_describe.phpt
@@ -0,0 +1,28 @@
+--TEST--
+enchant_broker_describe() function
+--SKIPIF--
+<?php
+if(!extension_loaded('enchant')) die('skip, enchant not loader');
+
+ ?>
+--FILE--
+<?php
+$broker = enchant_broker_init();
+
+if(!$broker) exit("failed, broker_init failure\n");
+
+$provides = enchant_broker_describe($broker);
+
+if (is_array($provides)) {
+ foreach ($provides as $backend) {
+ if (!(isset($backend['name']) && isset($backend['desc']) && isset($backend['file']))) {
+ exit("failed\n");
+ }
+ }
+ exit("OK\n");
+} else {
+ echo "failed";
+}
+?>
+--EXPECTF--
+OK
diff --git a/ext/enchant/tests/broker_free.phpt b/ext/enchant/tests/broker_free.phpt
new file mode 100644
index 0000000000..d00c22a974
--- /dev/null
+++ b/ext/enchant/tests/broker_free.phpt
@@ -0,0 +1,21 @@
+--TEST--
+enchant_broker_free() function
+--SKIPIF--
+<?php
+if(!extension_loaded('enchant')) die('skip, enchant not loader');
+
+ ?>
+--FILE--
+<?php
+$broker = enchant_broker_init();
+if (is_resource($broker)) {
+ echo "OK\n";
+ enchant_broker_free($broker);
+} else {
+ exit("init failed\n");
+}
+echo "OK\n";
+?>
+--EXPECT--
+OK
+OK
diff --git a/ext/enchant/tests/broker_init.phpt b/ext/enchant/tests/broker_init.phpt
new file mode 100644
index 0000000000..359a653359
--- /dev/null
+++ b/ext/enchant/tests/broker_init.phpt
@@ -0,0 +1,15 @@
+--TEST--
+enchant_broker_init() function
+--SKIPIF--
+<?php
+if(!extension_loaded('enchant')) die('skip, enchant not loader');
+
+ ?>
+--FILE--
+<?php
+$broker = enchant_broker_init();
+echo is_resource($broker) ? "OK" : "Failure";
+echo "\n";
+?>
+--EXPECT--
+OK
diff --git a/ext/enchant/tests/broker_request_dict.phpt b/ext/enchant/tests/broker_request_dict.phpt
new file mode 100644
index 0000000000..5744da6747
--- /dev/null
+++ b/ext/enchant/tests/broker_request_dict.phpt
@@ -0,0 +1,31 @@
+--TEST--
+enchant_broker_request_dict() function
+--SKIPIF--
+<?php
+if(!extension_loaded('enchant')) die('skip, enchant not loader');
+?>
+--FILE--
+<?php
+$broker = enchant_broker_init();
+if (!is_resource($broker)) {
+ exit("init failed\n");
+}
+
+$dicts = enchant_broker_list_dicts($broker);
+if (is_array($dicts)) {
+ if (count($dicts)) {
+ $dict = enchant_broker_request_dict($broker, $dicts[0]['lang_tag']);
+ if (is_resource($dict)) {
+ echo "OK\n";
+ } else {
+ echo "fail to request " . $dicts[0]['lang_tag'];
+ }
+ }
+} else {
+ exit("list dicts failed\n");
+}
+echo "OK\n";
+?>
+--EXPECT--
+OK
+OK
diff --git a/ext/enchant/tests/hindi_correct.txt b/ext/enchant/tests/hindi_correct.txt
new file mode 100644
index 0000000000..cced6b86fa
--- /dev/null
+++ b/ext/enchant/tests/hindi_correct.txt
@@ -0,0 +1 @@
+इस पृष्ठ में एक लिंक बनाने के लिये इस प्रतीक को खीचें व छोड़ें
diff --git a/ext/enchant/tests/hindi_incorrect.txt b/ext/enchant/tests/hindi_incorrect.txt
new file mode 100644
index 0000000000..1f7353c958
--- /dev/null
+++ b/ext/enchant/tests/hindi_incorrect.txt
@@ -0,0 +1 @@
+इस पृष्ठ में एक लिंक बनाने के लिये इस प्रतीक को खच व छड
diff --git a/ext/fileinfo/CREDITS b/ext/fileinfo/CREDITS
new file mode 100644
index 0000000000..6251d1b110
--- /dev/null
+++ b/ext/fileinfo/CREDITS
@@ -0,0 +1,2 @@
+fileinfo
+Ilia Alshanetsky
diff --git a/ext/fileinfo/EXPERIMENTAL b/ext/fileinfo/EXPERIMENTAL
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/ext/fileinfo/EXPERIMENTAL
diff --git a/ext/fileinfo/config.m4 b/ext/fileinfo/config.m4
new file mode 100644
index 0000000000..f1c15c006b
--- /dev/null
+++ b/ext/fileinfo/config.m4
@@ -0,0 +1,62 @@
+dnl $Id$
+dnl config.m4 for extension fileinfo
+
+PHP_ARG_WITH(fileinfo, for fileinfo support,
+[ --with-fileinfo=DIR Include fileinfo support])
+
+if test "$PHP_FILEINFO" != "no"; then
+ SEARCH_PATH="/usr/local /usr /usr/share/file"
+ if test -r $PHP_FILEINFO/include/magic.h || test -r $PHP_FILEINFO/magic.h; then
+ FILEINFO_DIR=$PHP_FILEINFO
+ else
+ AC_MSG_CHECKING([for magic files in default path])
+ for i in $SEARCH_PATH ; do
+ if test -r $i/include/magic.h || test -r $i/magic.h; then
+ FILEINFO_DIR=$i
+ AC_MSG_RESULT(found in $i)
+ break
+ fi
+ done
+ fi
+
+ if test -z "$FILEINFO_DIR"; then
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([Please reinstall the libmagic distribution])
+ fi
+
+ if test -r "$FILEINFO_DIR/include/magic.h"; then
+ PHP_ADD_INCLUDE($FILEINFO_DIR/include)
+ else
+ PHP_ADD_INCLUDE($FILEINFO_DIR)
+ fi
+
+ LIBNAME=magic
+ LIBSYMBOL=magic_open
+
+ PHP_CHECK_FUNC(dl, dlopen)
+ PHP_CHECK_FUNC(gzgets, z)
+ PHP_CHECK_FUNC(round, m)
+
+ PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
+ [
+ PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $FILEINFO_DIR/lib, FILEINFO_SHARED_LIBADD)
+ AC_DEFINE(HAVE_FILEINFOLIB,1,[ ])
+ ],[
+ AC_MSG_ERROR([wrong magic lib version or lib not found])
+ ],[
+ -L$FILEINFO_DIR/lib
+ ])
+
+ MAGIC_MIME_LOCATIONS="/usr/local/share/file/magic /usr/share/file/magic /usr/share/misc/file/magic /etc/magic /usr/share/misc"
+ for i in $MAGIC_MIME_LOCATIONS; do
+ if test -f $i; then
+ PHP_DEFAULT_MAGIC_FILE=$i
+ break
+ fi
+ done
+ AC_DEFINE_UNQUOTED(PHP_DEFAULT_MAGIC_FILE,"$PHP_DEFAULT_MAGIC_FILE",[magic file path])
+
+ PHP_SUBST(FILEINFO_SHARED_LIBADD)
+
+ PHP_NEW_EXTENSION(fileinfo, fileinfo.c, $ext_shared)
+fi
diff --git a/ext/fileinfo/fileinfo.c b/ext/fileinfo/fileinfo.c
new file mode 100644
index 0000000000..04fe848d84
--- /dev/null
+++ b/ext/fileinfo/fileinfo.c
@@ -0,0 +1,437 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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: Ilia Alshanetsky <ilia@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "php.h"
+
+#include <magic.h>
+/*
+ * HOWMANY specifies the maximum offset libmagic will look at
+ * this is currently hardcoded in the libmagic source but not exported
+ */
+#ifndef HOWMANY
+#define HOWMANY 65536
+#endif
+
+
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/file.h" /* needed for context stuff */
+#include "php_fileinfo.h"
+#include "fopen_wrappers.h" /* needed for is_url */
+
+struct php_fileinfo {
+ long options;
+ struct magic_set *magic;
+};
+
+#ifndef PHP_DEFAULT_MAGIC_FILE
+#define PHP_DEFAULT_MAGIC_FILE NULL
+#endif
+
+#ifdef ZEND_ENGINE_2
+
+static zend_object_handlers finfo_object_handlers;
+zend_class_entry *finfo_class_entry;
+
+struct finfo_object {
+ zend_object zo;
+ struct php_fileinfo *ptr;
+};
+
+#define FILEINFO_DECLARE_INIT_OBJECT(object) \
+ zval *object = getThis();
+
+#define FILEINFO_REGISTER_OBJECT(_object, _ptr) \
+{ \
+ struct finfo_object *obj; \
+ obj = (struct finfo_object*)zend_object_store_get_object(_object TSRMLS_CC); \
+ obj->ptr = _ptr; \
+}
+
+#define FILEINFO_FROM_OBJECT(finfo, object) \
+{ \
+ struct finfo_object *obj = zend_object_store_get_object(object TSRMLS_CC); \
+ finfo = obj->ptr; \
+ if (!finfo) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The invalid fileinfo object."); \
+ RETURN_FALSE; \
+ } \
+}
+
+/* {{{ finfo_objects_dtor
+ */
+static void finfo_objects_dtor(void *object, zend_object_handle handle TSRMLS_DC)
+{
+ struct finfo_object *intern = (struct finfo_object *) object;
+
+ if (intern->ptr) {
+ magic_close(intern->ptr->magic);
+ efree(intern->ptr);
+ }
+
+ efree(intern);
+}
+/* }}} */
+
+/* {{{ finfo_objects_new
+ */
+PHP_FILEINFO_API zend_object_value finfo_objects_new(zend_class_entry *class_type TSRMLS_DC)
+{
+ zend_object_value retval;
+ struct finfo_object *intern;
+
+ intern = ecalloc(1, sizeof(struct finfo_object));
+ intern->zo.ce = class_type;
+ intern->zo.properties = NULL;
+#if ZEND_EXTENSION_API_NO > 220050000
+ intern->zo.guards = NULL;
+#else
+ intern->zo.in_get = 0;
+ intern->zo.in_set = 0;
+#endif
+ intern->ptr = NULL;
+
+ retval.handle = zend_objects_store_put(intern, finfo_objects_dtor, NULL, NULL TSRMLS_CC);
+ retval.handlers = (zend_object_handlers *) &finfo_object_handlers;
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ finfo_class_functions
+ */
+function_entry finfo_class_functions[] = {
+ ZEND_ME_MAPPING(finfo, finfo_open, NULL)
+ ZEND_ME_MAPPING(set_flags, finfo_set_flags,NULL)
+ ZEND_ME_MAPPING(file, finfo_file, NULL)
+ ZEND_ME_MAPPING(buffer, finfo_buffer, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+#else
+
+#define FILEINFO_REGISTER_OBJECT(_object, _ptr) {}
+#define FILEINFO_FROM_OBJECT(socket_id, object) {}
+
+#define FILEINFO_DECLARE_INIT_OBJECT(object)
+#define object 0
+
+#endif
+
+#define FINFO_SET_OPTION(magic, options) \
+ if (magic_setflags(magic, options) == -1) { \
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to set option '%ld' %d:%s", \
+ options, magic_errno(magic), magic_error(magic)); \
+ RETURN_FALSE; \
+ }
+
+/* True global resources - no need for thread safety here */
+static int le_fileinfo;
+
+void finfo_resource_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ if (rsrc->ptr) {
+ struct php_fileinfo *finfo = (struct php_fileinfo *) rsrc->ptr;
+ magic_close(finfo->magic);
+ efree(rsrc->ptr);
+ rsrc->ptr = NULL;
+ }
+}
+
+/* {{{ fileinfo_functions[]
+ */
+function_entry fileinfo_functions[] = {
+ PHP_FE(finfo_open, NULL)
+ PHP_FE(finfo_close, NULL)
+ PHP_FE(finfo_set_flags, NULL)
+ PHP_FE(finfo_file, NULL)
+ PHP_FE(finfo_buffer, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(finfo)
+{
+#ifdef ZEND_ENGINE_2
+ zend_class_entry _finfo_class_entry;
+ INIT_CLASS_ENTRY(_finfo_class_entry, "finfo", finfo_class_functions);
+ _finfo_class_entry.create_object = finfo_objects_new;
+ finfo_class_entry = zend_register_internal_class(&_finfo_class_entry TSRMLS_CC);
+
+ /* copy the standard object handlers to you handler table */
+ memcpy(&finfo_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+#endif /* ZEND_ENGINE_2 */
+
+ le_fileinfo = zend_register_list_destructors_ex(finfo_resource_destructor, NULL, "file_info", module_number);
+
+ REGISTER_LONG_CONSTANT("FILEINFO_NONE", MAGIC_NONE, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILEINFO_SYMLINK", MAGIC_SYMLINK, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILEINFO_MIME", MAGIC_MIME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILEINFO_COMPRESS", MAGIC_COMPRESS, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILEINFO_DEVICES", MAGIC_DEVICES, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILEINFO_CONTINUE", MAGIC_CONTINUE, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILEINFO_PRESERVE_ATIME", MAGIC_PRESERVE_ATIME, CONST_CS|CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("FILEINFO_RAW", MAGIC_RAW, CONST_CS|CONST_PERSISTENT);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ fileinfo_module_entry
+ */
+zend_module_entry fileinfo_module_entry = {
+#if ZEND_MODULE_API_NO >= 20010901
+ STANDARD_MODULE_HEADER,
+#endif
+ "fileinfo",
+ fileinfo_functions,
+ PHP_MINIT(finfo),
+ NULL,
+ NULL,
+ NULL,
+ PHP_MINFO(fileinfo),
+#if ZEND_MODULE_API_NO >= 20010901
+ "0.1", /* Replace with version number for your extension */
+#endif
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_FILEINFO
+ZEND_GET_MODULE(fileinfo)
+#endif
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(fileinfo)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "fileinfo support", "enabled");
+ php_info_print_table_end();
+}
+/* }}} */
+
+/* {{{ proto resource finfo_open([int options [, string arg]])
+ Create a new fileinfo resource. */
+PHP_FUNCTION(finfo_open)
+{
+ long options = MAGIC_NONE;
+ char *file = PHP_DEFAULT_MAGIC_FILE;
+ int file_len = 0;
+ struct php_fileinfo *finfo;
+ FILEINFO_DECLARE_INIT_OBJECT(object)
+ char resolved_path[MAXPATHLEN];
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &options, &file, &file_len) == FAILURE) {
+ RETURN_FALSE;
+ }
+
+ if (file_len) { /* user specified filed, perform open_basedir checks */
+ if (!VCWD_REALPATH(file, resolved_path)) {
+ RETURN_FALSE;
+ }
+ file = resolved_path;
+
+ if ((PG(safe_mode) && (!php_checkuid(file, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(file TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+ }
+
+ finfo = emalloc(sizeof(struct php_fileinfo));
+
+ finfo->options = options;
+ finfo->magic = magic_open(options);
+
+ if (finfo->magic == NULL) {
+ efree(finfo);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid mode '%ld'.", options);
+ RETURN_FALSE;
+ }
+
+ if (magic_load(finfo->magic, file) == -1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to load magic database at '%s'.", file);
+ magic_close(finfo->magic);
+ efree(finfo);
+ RETURN_FALSE;
+ }
+
+ if (object) {
+ FILEINFO_REGISTER_OBJECT(object, finfo);
+ } else {
+ ZEND_REGISTER_RESOURCE(return_value, finfo, le_fileinfo);
+ }
+}
+/* }}} */
+
+/* {{{ proto resource finfo_close(resource finfo)
+ Close fileinfo resource. */
+PHP_FUNCTION(finfo_close)
+{
+ struct php_fileinfo *finfo;
+ zval *zfinfo;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zfinfo) == FAILURE) {
+ RETURN_FALSE;
+ }
+ ZEND_FETCH_RESOURCE(finfo, struct php_fileinfo *, &zfinfo, -1, "file_info", le_fileinfo);
+
+ zend_list_delete(Z_RESVAL_P(zfinfo));
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool finfo_set_flags(resource finfo, int options)
+ Set libmagic configuration options. */
+PHP_FUNCTION(finfo_set_flags)
+{
+ long options;
+ struct php_fileinfo *finfo;
+ zval *zfinfo;
+ FILEINFO_DECLARE_INIT_OBJECT(object)
+
+ if (object) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &options) == FAILURE) {
+ RETURN_FALSE;
+ }
+ FILEINFO_FROM_OBJECT(finfo, object);
+ } else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &zfinfo, &options) == FAILURE) {
+ RETURN_FALSE;
+ }
+ ZEND_FETCH_RESOURCE(finfo, struct php_fileinfo *, &zfinfo, -1, "file_info", le_fileinfo);
+ }
+
+ FINFO_SET_OPTION(finfo->magic, options)
+ finfo->options = options;
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+static void _php_finfo_get_type(INTERNAL_FUNCTION_PARAMETERS, int mode)
+{
+ long options = 0;
+ char *buffer, *tmp, *ret_val;
+ int buffer_len;
+ struct php_fileinfo *finfo;
+ zval *zfinfo, *zcontext = NULL;
+ FILEINFO_DECLARE_INIT_OBJECT(object)
+
+ if (object) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lbz", &buffer, &buffer_len, &options, &zcontext) == FAILURE) {
+ RETURN_FALSE;
+ }
+ FILEINFO_FROM_OBJECT(finfo, object);
+ } else {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs|lbz", &zfinfo, &buffer, &buffer_len, &options, &zcontext) == FAILURE) {
+ RETURN_FALSE;
+ }
+ ZEND_FETCH_RESOURCE(finfo, struct php_fileinfo *, &zfinfo, -1, "file_info", le_fileinfo);
+ }
+
+ /* Set options for the current file/buffer. */
+ if (options) {
+ FINFO_SET_OPTION(finfo->magic, options)
+ }
+
+ if (mode) { /* file */
+ /* determine if the file is a local file or remote URL */
+ char *tmp2;
+ php_stream_wrapper *wrap = php_stream_locate_url_wrapper(buffer, &tmp2, 0 TSRMLS_CC);
+ if (wrap && wrap->is_url) {
+#ifdef ZEND_ENGINE_2
+ php_stream_context *context = php_stream_context_from_zval(zcontext, 0);
+#else
+ php_stream_context *context = NULL;
+#endif
+ php_stream *stream = php_stream_open_wrapper_ex(buffer, "rb",
+ ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, context);
+ if (!stream) {
+ RETURN_FALSE;
+ }
+ buffer_len = php_stream_copy_to_mem(stream, &tmp, HOWMANY, 0);
+ php_stream_close(stream);
+
+ if (buffer_len == 0) {
+ RETURN_FALSE;
+ }
+ } else { /* local file */
+ char resolved_path[MAXPATHLEN];
+ if (!VCWD_REALPATH(buffer, resolved_path)) {
+ RETURN_FALSE;
+ }
+
+ ret_val = (char *) magic_file(finfo->magic, buffer);
+ goto common;
+ }
+ } else { /* buffer */
+ tmp = buffer;
+ }
+
+ ret_val = (char *) magic_buffer(finfo->magic, tmp, buffer_len);
+ if (mode) {
+ efree(tmp);
+ }
+common:
+ /* Restore options */
+ if (options) {
+ FINFO_SET_OPTION(finfo->magic, finfo->options)
+ }
+
+ if (!ret_val) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed identify data %d:%s",
+ magic_errno(finfo->magic), magic_error(finfo->magic));
+ RETURN_FALSE;
+ } else {
+ RETURN_STRING(ret_val, 1);
+ }
+}
+
+/* {{{ proto string finfo_file(resource finfo, char *file_name [, int options [, resource context]])
+ Return information about a file. */
+PHP_FUNCTION(finfo_file)
+{
+ _php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+}
+/* }}} */
+
+/* {{{ proto string finfo_buffer(resource finfo, char *string [, int options])
+ Return infromation about a string buffer. */
+PHP_FUNCTION(finfo_buffer)
+{
+ _php_finfo_get_type(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/fileinfo/fileinfo.php b/ext/fileinfo/fileinfo.php
new file mode 100644
index 0000000000..1ee9efbeb8
--- /dev/null
+++ b/ext/fileinfo/fileinfo.php
@@ -0,0 +1,29 @@
+<?php
+if(!extension_loaded('fileinfo')) {
+ dl('fileinfo.' . PHP_SHLIB_SUFFIX);
+}
+if(!extension_loaded('fileinfo')) {
+ die("fileinfo extension is not avaliable, please compile it.\n");
+}
+
+// normal operation
+$res = finfo_open(FILEINFO_MIME); /* return mime type ala mimetype extension */
+$files = glob("*");
+foreach ($files as $file) {
+ echo finfo_file($res, $file) . "\n";
+}
+finfo_close($res);
+
+// OO mode
+/*
+ * FILEINFO_PRESERVE_ATIME - if possible preserve the original access time
+ * FILEINFO_SYMLINK - follow symlinks
+ * FILEINFO_DEVICES - look at the contents of blocks or character special devices
+ * FILEINFO_COMPRESS - decompress compressed files
+ */
+$fi = new finfo(FILEINFO_PRESERVE_ATIME|FILEINFO_SYMLINK|FILEINFO_DEVICES|FILEINFO_COMPRESS);
+$files = glob("*");
+foreach ($files as $file) {
+ echo $fi->buffer(file_get_contents($file)) . "\n";
+}
+?>
diff --git a/ext/fileinfo/package.xml b/ext/fileinfo/package.xml
new file mode 100644
index 0000000000..fd3fdab384
--- /dev/null
+++ b/ext/fileinfo/package.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE package SYSTEM "../pear/package.dtd">
+<package>
+ <name>Fileinfo</name>
+ <summary>libmagic bindings</summary>
+ <maintainers>
+ <maintainer>
+ <user>iliaa</user>
+ <name>Ilia Alshanetsky</name>
+ <email>ilia@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ </maintainers>
+ <description>
+This extension allows retrieval of information regarding vast majority of file.
+This information may include dimensions, quality, length etc...
+
+Additionally it can also be used to retrieve the mime type for a particular
+file and for text files proper language encoding.
+ </description>
+ <license>PHP</license>
+ <release>
+ <state>stable</state>
+ <version>1.0.2</version>
+ <date>2005-12-05</date>
+ <notes>
+ 1) Allow build against 5.1 and 5.0 versions of PHP
+ </notes>
+ <filelist>
+ <file role="src" name="config.m4"/>
+ <file role="src" name="fileinfo.c"/>
+ <file role="src" name="php_fileinfo.h"/>
+ <file role="doc" name="CREDITS"/>
+ <file role="doc" name="EXPERIMENTAL"/>
+ <file role="doc" name="fileinfo.php"/>
+ </filelist>
+ <deps>
+ </deps>
+ </release>
+</package>
+<!--
+vim:et:ts=1:sw=1
+-->
diff --git a/ext/fileinfo/php_fileinfo.h b/ext/fileinfo/php_fileinfo.h
new file mode 100644
index 0000000000..66c562172d
--- /dev/null
+++ b/ext/fileinfo/php_fileinfo.h
@@ -0,0 +1,61 @@
+/*
+ +----------------------------------------------------------------------+
+ | 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: Ilia Alshanetsky <ilia@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_FILEINFO_H
+#define PHP_FILEINFO_H
+
+extern zend_module_entry fileinfo_module_entry;
+#define phpext_fileinfo_ptr &fileinfo_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_FILEINFO_API __declspec(dllexport)
+#else
+#define PHP_FILEINFO_API
+#endif
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+PHP_MINFO_FUNCTION(fileinfo);
+
+PHP_FUNCTION(finfo_open);
+PHP_FUNCTION(finfo_close);
+PHP_FUNCTION(finfo_set_flags);
+PHP_FUNCTION(finfo_file);
+PHP_FUNCTION(finfo_buffer);
+
+#ifdef ZTS
+#define FILEINFO_G(v) TSRMG(fileinfo_globals_id, zend_fileinfo_globals *, v)
+#else
+#define FILEINFO_G(v) (fileinfo_globals.v)
+#endif
+
+#endif /* PHP_FILEINFO_H */
+
+
+/*
+ * 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
+ */
diff --git a/ext/pdo/CREDITS b/ext/pdo/CREDITS
new file mode 100755
index 0000000000..e650219359
--- /dev/null
+++ b/ext/pdo/CREDITS
@@ -0,0 +1,2 @@
+PHP Data Objects
+Wez Furlong, Marcus Boerger, Sterling Hughes, George Schlossnagle
diff --git a/ext/pdo/Makefile.frag b/ext/pdo/Makefile.frag
new file mode 100644
index 0000000000..283a6e2433
--- /dev/null
+++ b/ext/pdo/Makefile.frag
@@ -0,0 +1,26 @@
+phpincludedir=$(prefix)/include/php
+
+PDO_HEADER_FILES= \
+ php_pdo.h \
+ php_pdo_driver.h
+
+install-pdo-headers:
+ @echo "Installing PDO headers: $(INSTALL_ROOT)$(phpincludedir)/ext/pdo/"
+ @$(mkinstalldirs) $(INSTALL_ROOT)$(phpincludedir)/ext/pdo
+ @for f in $(PDO_HEADER_FILES); do \
+ if test -f "$(top_srcdir)/$$f"; then \
+ $(INSTALL_DATA) $(top_srcdir)/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
+ elif test -f "$(top_builddir)/$$f"; then \
+ $(INSTALL_DATA) $(top_builddir)/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
+ elif test -f "$(top_srcdir)/ext/pdo/$$f"; then \
+ $(INSTALL_DATA) $(top_srcdir)/ext/pdo/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
+ elif test -f "$(top_builddir)/ext/pdo/$$f"; then \
+ $(INSTALL_DATA) $(top_builddir)/ext/pdo/$$f $(INSTALL_ROOT)$(phpincludedir)/ext/pdo; \
+ else \
+ echo "hmmm"; \
+ fi \
+ done;
+
+# mini hack
+install: $(all_targets) $(install_targets) install-pdo-headers
+
diff --git a/ext/pdo/README b/ext/pdo/README
new file mode 100755
index 0000000000..da806b0f30
--- /dev/null
+++ b/ext/pdo/README
@@ -0,0 +1,56 @@
+$Id$
+
+PHP Data Objects
+================
+
+Concept: Data Access Abstraction
+
+Goals:
+
+1/ Be light-weight
+2/ Provide common API for common database operations
+3/ Be performant
+4/ Keep majority of PHP specific stuff in the PDO core (such as persistent
+ resource management); drivers should only have to worry about getting the
+ data and not about PHP internals.
+
+
+Transactions and autocommit
+===========================
+
+When you create a database handle, you *should* specify the autocommit
+behaviour that you require. PDO will default to autocommit on.
+
+$dbh = new PDO("...", $user, $pass, array(PDO_ATTR_AUTOCOMMIT => true));
+
+When auto-commit is on, the driver will implicitly commit each query as it is
+executed. This works fine for most simple tasks but can be significantly
+slower when you are making a large number of udpates.
+
+$dbh = new PDO("...", $user, $pass, array(PDO_ATTR_AUTOCOMMIT => false));
+
+When auto-commit is off, you must then use $dbh->beginTransaction() to
+initiate a transaction. When your work is done, you then call $dbh->commit()
+or $dbh->rollBack() to persist or abort your changes respectively. Not all
+databases support transactions.
+
+You can change the auto-commit mode at run-time:
+
+$dbh->setAttribute(PDO_ATTR_AUTOCOMMIT, false);
+
+Regardless of the error handling mode set on the database handle, if the
+autocommit mode cannot be changed, an exception will be thrown.
+
+Some drivers will allow you to temporarily disable autocommit if you call
+$dbh->beginTransaction(). When you commit() or rollBack() such a transaction,
+the handle will switch back to autocommit mode again. If the mode could not
+be changed, an exception will be raised, as noted above.
+
+When the database handle is closed or destroyed (or at request end for
+persistent handles), the driver will implicitly rollBack(). It is your
+responsibility to call commit() when you are done making changes and
+autocommit is turned off.
+
+vim:tw=78:et
+
+
diff --git a/ext/pdo/TODO b/ext/pdo/TODO
new file mode 100755
index 0000000000..4e46791164
--- /dev/null
+++ b/ext/pdo/TODO
@@ -0,0 +1,97 @@
+$Id$
+
+Roadmap for PDO
+
+Core, version 1.1:
+==================
+
+ - Add PDO::queryParams(), similar to PDO::query(), but accepts
+ an array of parameters as the second argument, pushing the remaining
+ args (which are args to setFetchMode()) up by one.
+
+ - Separate the handle factory call into two phases:
+ - handle creation
+ - connecting
+
+ This would then allow PDO to call setAttribute()
+ for each driver option specified in the constructor.
+ Right now, the handling of driver attributes is a bit sloppy.
+
+ - Add:
+ pdo.max_persistent
+ pdo.persistent_timeout
+ pdo.ping_interval
+
+ with the same meanings as those options from oci8.
+
+ - BLOB/CLOB.
+ Investigate the various APIs to determine if we can
+ transparently map BLOBs and CLOBs as PDO_PARAM_LOB.
+ If the API needs hints from the client side, we need
+ to introduce a PDO_PARAM_CLOB to differentiate between
+ binary and character data.
+
+ - Character set selection.
+ Generalize/standardize this.
+
+ - meta data.
+ Formalize getColumnMeta().
+ Look at retrieving lists of tables and other objects in the db.
+
+ - tracing/logging/debugging
+ Add ini options:
+
+ pdo.trace_file
+ pdo.enable_tracing
+
+ And corresponding attributes, ATTR_TRACE_FILE, ATTR_TRACING_ENABLE,
+ settable at dbh and stmt levels independently. If set at the dbh level,
+ the stmt will inherit its value. If not set explicitly in code, the
+ defaults for the dbh will come from the INI settings.
+
+ ATTR_TRACE_FILE will accept a string or a stream.
+
+ The INI options are useful for administrative tracing/debugging.
+ Trace mode will output very verbose info.
+
+
+General DB API Roundup:
+=========
+ Consider how the following can be implemented in PDO:
+
+ mysqli_change_user(); alters auth credentials on a live connection
+ mysqli_info(); info about rows affected by last query
+ mysqli_master_query(); force query to run on master
+ mysqli_ping(); ping / reconnect
+ mysqli_stat(); one line summary of server status
+
+ oci_password_change()
+
+ Also consider master/slave and/or failover server configuration.
+
+
+Postgres:
+=========
+
+ - Real large object support.
+ - Someone with more pgsql experience can suggest more features
+
+Oracle:
+=======
+
+ - Support for array types and collections.
+
+Userspace PDO Driver:
+=====================
+
+ - Will be hard.
+
+PDO Session module:
+===================
+
+ - Is it worth writing in C?
+ Probably not.
+
+
+vim:se et ts=2 sw=2 tw=78:
+
diff --git a/ext/pdo/config.m4 b/ext/pdo/config.m4
new file mode 100755
index 0000000000..8b6f6fbf39
--- /dev/null
+++ b/ext/pdo/config.m4
@@ -0,0 +1,68 @@
+dnl $Id$
+dnl config.m4 for extension pdo
+dnl vim:se ts=2 sw=2 et:
+
+AC_DEFUN([PHP_PDO_PEAR_CHECK],[
+ pdo_running_under_pear=0
+ case `pwd` in
+ /var/tmp/pear-build-*)
+ pdo_running_under_pear=1
+ ;;
+ esac
+
+ if test "$pdo_running_under_pear$PHP_PEAR_VERSION" = "1"; then
+ # we're running in an environment that smells like pear,
+ # and the PHP_PEAR_VERSION env var is not set. That implies
+ # that we're running under a slightly broken pear installer
+ AC_MSG_ERROR([
+PDO requires that you upgrade your PEAR installer tools. Please
+do so now by running:
+
+ % sudo pear upgrade pear
+
+or by manually downloading and installing PEAR version 1.3.5 or higher.
+
+Once you've upgraded, please re-try your PDO install.
+ ])
+ fi
+])
+
+PHP_ARG_ENABLE(pdo, whether to enable PDO support,
+[ --disable-pdo Disable PHP Data Objects support], yes)
+
+if test "$PHP_PDO" != "no"; then
+
+ PHP_PDO_PEAR_CHECK
+
+ if test "$ext_shared" = "yes" ; then
+ case $host_alias in
+ *darwin*)
+ if test "$pdo_running_under_pear" = "1"; then
+ AC_MSG_ERROR([
+Due to the way that loadable modules work on OSX/Darwin, you need to
+compile the PDO package statically into the PHP core.
+
+Please follow the instructions at: http://netevil.org/node.php?nid=202
+for more detail on this issue.
+ ])
+ fi
+ ext_shared=no
+ ;;
+ esac
+ fi
+ PHP_NEW_EXTENSION(pdo, pdo.c pdo_dbh.c pdo_stmt.c pdo_sql_parser.c pdo_sqlstate.c, $ext_shared)
+ ifdef([PHP_ADD_EXTENSION_DEP],
+ [
+ PHP_ADD_EXTENSION_DEP(pdo, spl, true)
+ ])
+
+ ifdef([PHP_INSTALL_HEADERS],
+ [
+ dnl Sadly, this is a complete NOP for pecl extensions
+ PHP_INSTALL_HEADERS(ext/pdo, [php_pdo.h php_pdo_driver.h])
+ ])
+
+ dnl so we always include the known-good working hack.
+ PHP_ADD_MAKEFILE_FRAGMENT
+fi
+
diff --git a/ext/pdo/config.w32 b/ext/pdo/config.w32
new file mode 100755
index 0000000000..ae8829388e
--- /dev/null
+++ b/ext/pdo/config.w32
@@ -0,0 +1,10 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_ENABLE("pdo", "Enable PHP Data Objects support", "no");
+
+if (PHP_PDO != "no") {
+ EXTENSION('pdo', 'pdo.c pdo_dbh.c pdo_stmt.c pdo_sql_parser.c pdo_sqlstate.c');
+ ADD_EXTENSION_DEP('pdo', 'spl', true);
+}
+
diff --git a/ext/pdo/package.xml b/ext/pdo/package.xml
new file mode 100755
index 0000000000..46c0b3a9ca
--- /dev/null
+++ b/ext/pdo/package.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE package SYSTEM "../pear/package.dtd">
+<package version="1.0">
+ <name>PDO</name>
+ <summary>PHP Data Objects Interface</summary>
+ <maintainers>
+ <maintainer>
+ <user>wez</user>
+ <name>Wez Furlong</name>
+ <email>wez@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ <maintainer>
+ <user>helly</user>
+ <name>Marcus Boerger</name>
+ <email>helly@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ <maintainer>
+ <user>iliaa</user>
+ <name>Ilia Alshanetsky</name>
+ <email>iliaa@php.net</email>
+ <role>lead</role>
+ </maintainer>
+ <maintainer>
+ <user>gschlossnagle</user>
+ <name>George Schlossnagle</name>
+ <email>george@omniti.com</email>
+ <role>lead</role>
+ </maintainer>
+ </maintainers>
+
+ <description>
+ PDO provides a uniform data access interface, sporting advanced features such
+ as prepared statements and bound parameters. PDO drivers are dynamically
+ loadable and may be developed independently from the core, but still accessed
+ using the same API.
+
+ Read the documentation at http://www.php.net/pdo for more information.
+ </description>
+ <license>PHP</license>
+ <release>
+ <state>stable</state>
+ <version>1.0.2</version>
+ <date>2005-11-28</date>
+
+ <notes>
+** NOTE WELL! **
+All the PDO_XXX constants have been renamed to PDO::XXX form for future
+compatibility with PHP namespaces. Sorry for the inconvenience, especially
+after Release Candidate 1.
+
+You need to install a PDO database driver to make use of PDO,
+check http://pecl.php.net/package-search.php?pkg_name=PDO
+for a list of available PDO drivers.
+
+It is highly recommended that you update to PHP 5.1 before using PDO.
+
+If you are running on Windows, you can find a precompiled binary at:
+http://pecl4win.php.net/ext.php/php_pdo.dll
+
+You can find additional PDO drivers at:
+http://pecl4win.php.net
+
+** Changes **
+- Fixed bug #35431 (PDO crashes when using LAZY fetch with fetchAll). (Wez)
+- Fixed bug #35430 (PDO crashes on incorrect FETCH_FUNC use). (Tony)
+
+- Changed PDO_XXX constants to PDO::XXX
+- It is now possible to extend PDO and PDOStatement and override their constructors
+
+- Fixed Bug #35303; PDO::prepare() can cause crashes with invalid parameters
+- Fixed Bug #35135; "new PDOStatement" can cause crashes.
+- Fixed Bug #35293 and PECL Bug #5589; segfault when creating persistent connections
+- Fixed PECL Bug #5010, problem installing headers
+- renamed pdo_drivers() to PDO::getAvailableDrivers()
+- Various fixes when building with SPL
+- PDO::setAttribute(PDO::ATTR_STATEMENT_CLASS) allows you to set your own
+ PDOStatement replacement when extending PDO and PDOStatement
+- Fixed Bug #34687; error information from PDO::query() was not always returned
+- Fixed PECL Bug #5750; uri: DSN was not handled correctly
+- Fixed PECL Bug #5589; segfault when persistent connection attempt fails
+- Fixed Bug #34590; User defined PDOStatement class methods are not callable
+- Fixed Bug #34908; FETCH_INTO segfaults without destination object
+- Fixed PECL Bug #5809; PDOStatement::execute(array(...)) modifies args
+- Fixed PECL Bug #5772; FETCH_FUNC cannot call functions with mixed case names
+
+** Note **
+
+You should uninstall and re-install your individual database drivers whenever
+you upgrade the base PDO package, otherwise you will see an error about PDO API
+numbers when you run your PHP scripts.
+
+ </notes>
+
+ <filelist>
+ <file role="src" name="config.m4"/>
+ <file role="src" name="config.w32"/>
+ <file role="src" name="pdo.c"/>
+ <file role="src" name="pdo_dbh.c"/>
+ <file role="src" name="pdo_stmt.c"/>
+ <file role="src" name="php_pdo.h"/>
+ <file role="src" name="php_pdo_driver.h"/>
+ <file role="src" name="php_pdo_int.h"/>
+ <file role="src" name="pdo_sql_parser.re"/>
+ <file role="src" name="pdo_sql_parser.c"/>
+ <file role="src" name="pdo_sqlstate.c"/>
+ <file role="src" name="Makefile.frag"/>
+
+ <file role="doc" name="README"/>
+ <file role="doc" name="TODO"/>
+ <file role="doc" name="pdo.php"/>
+ <file role="doc" name="CREDITS"/>
+ </filelist>
+ <deps>
+ <dep type="php" rel="ge" version="5.0.3"/>
+ </deps>
+ </release>
+</package>
diff --git a/ext/pdo/pdo.c b/ext/pdo/pdo.c
new file mode 100755
index 0000000000..02a2aa1860
--- /dev/null
+++ b/ext/pdo/pdo.c
@@ -0,0 +1,399 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#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"
+
+static zend_class_entry *spl_ce_RuntimeException;
+
+ZEND_DECLARE_MODULE_GLOBALS(pdo)
+
+/* True global resources - no need for thread safety here */
+
+/* the registry of PDO drivers */
+HashTable pdo_driver_hash;
+
+/* we use persistent resources for the driver connection stuff */
+static int le_ppdo;
+
+int php_pdo_list_entry(void)
+{
+ return le_ppdo;
+}
+
+/* for exceptional circumstances */
+zend_class_entry *pdo_exception_ce;
+
+PDO_API zend_class_entry *php_pdo_get_exception(void)
+{
+ return pdo_exception_ce;
+}
+
+PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC)
+{
+#if can_handle_soft_dependency_on_SPL && defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1))
+ if (!root) {
+ if (!spl_ce_RuntimeException) {
+ zend_class_entry **pce;
+
+ if (zend_hash_find(CG(class_table), "runtimeexception", sizeof("RuntimeException"), (void **) &pce) == SUCCESS) {
+ spl_ce_RuntimeException = *pce;
+ return *pce;
+ }
+ } else {
+ return spl_ce_RuntimeException;
+ }
+ }
+#endif
+#if (PHP_MAJOR_VERSION < 6)
+ return zend_exception_get_default();
+#else
+ return zend_exception_get_default(TSRMLS_C);
+#endif
+}
+
+zend_class_entry *pdo_dbh_ce, *pdo_dbstmt_ce, *pdo_row_ce;
+
+/* proto array pdo_drivers()
+ Return array of available PDO drivers */
+PHP_FUNCTION(pdo_drivers)
+{
+ HashPosition pos;
+ pdo_driver_t **pdriver;
+
+ array_init(return_value);
+
+ zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
+ while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
+ add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1);
+ zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
+ }
+}
+/* }}} */
+
+/* {{{ pdo_functions[] */
+function_entry pdo_functions[] = {
+ PHP_FE(pdo_drivers, NULL)
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ pdo_functions[] */
+#if ZEND_MODULE_API_NO >= 20050922
+static zend_module_dep pdo_deps[] = {
+#ifdef HAVE_SPL
+ ZEND_MOD_REQUIRED("spl")
+#endif
+ {NULL, NULL, NULL}
+};
+#endif
+/* }}} */
+
+/* {{{ pdo_module_entry */
+zend_module_entry pdo_module_entry = {
+#if ZEND_MODULE_API_NO >= 20050922
+ STANDARD_MODULE_HEADER_EX, NULL,
+ pdo_deps,
+#else
+ STANDARD_MODULE_HEADER,
+#endif
+ "PDO",
+ pdo_functions,
+ PHP_MINIT(pdo),
+ PHP_MSHUTDOWN(pdo),
+ PHP_RINIT(pdo),
+ PHP_RSHUTDOWN(pdo),
+ PHP_MINFO(pdo),
+ "1.0.2",
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_PDO
+ZEND_GET_MODULE(pdo)
+#endif
+
+/* {{{ PHP_INI */
+PHP_INI_BEGIN()
+ STD_PHP_INI_ENTRY("pdo.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_pdo_globals, pdo_globals)
+PHP_INI_END()
+/* }}} */
+
+/* {{{ php_pdo_init_globals */
+static void php_pdo_init_globals(zend_pdo_globals *pdo_globals)
+{
+ pdo_globals->global_value = 0;
+}
+/* }}} */
+
+PDO_API int php_pdo_register_driver(pdo_driver_t *driver)
+{
+ if (driver->api_version != PDO_DRIVER_API) {
+ zend_error(E_ERROR, "PDO: driver %s requires PDO API version %ld; this is PDO version %d",
+ driver->driver_name, driver->api_version, PDO_DRIVER_API);
+ return FAILURE;
+ }
+ if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
+ zend_error(E_ERROR, "You MUST load PDO before loading any PDO drivers");
+ return FAILURE; /* NOTREACHED */
+ }
+
+ return zend_hash_add(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len,
+ (void**)&driver, sizeof(driver), NULL);
+}
+
+PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver)
+{
+ if (!zend_hash_exists(&module_registry, "pdo", sizeof("pdo"))) {
+ return;
+ }
+
+ zend_hash_del(&pdo_driver_hash, (char*)driver->driver_name, driver->driver_name_len);
+}
+
+pdo_driver_t *pdo_find_driver(const char *name, int namelen)
+{
+ pdo_driver_t **driver = NULL;
+
+ zend_hash_find(&pdo_driver_hash, (char*)name, namelen, (void**)&driver);
+
+ return driver ? *driver : NULL;
+}
+
+PDO_API int php_pdo_parse_data_source(const char *data_source,
+ unsigned long data_source_len, struct pdo_data_src_parser *parsed,
+ int nparams)
+{
+ int i, j;
+ int valstart = -1;
+ int semi = -1;
+ int optstart = 0;
+ int nlen;
+ int n_matches = 0;
+
+ i = 0;
+ while (i < data_source_len) {
+ /* looking for NAME= */
+
+ if (data_source[i] == '\0') {
+ break;
+ }
+
+ if (data_source[i] != '=') {
+ ++i;
+ continue;
+ }
+
+ valstart = ++i;
+
+ /* now we're looking for VALUE; or just VALUE<NUL> */
+ semi = -1;
+ while (i < data_source_len) {
+ if (data_source[i] == '\0') {
+ semi = i++;
+ break;
+ }
+ if (data_source[i] == ';') {
+ semi = i++;
+ break;
+ }
+ ++i;
+ }
+
+ if (semi == -1) {
+ semi = i;
+ }
+
+ /* find the entry in the array */
+ nlen = valstart - optstart - 1;
+ for (j = 0; j < nparams; j++) {
+ if (0 == strncmp(data_source + optstart, parsed[j].optname, nlen) && parsed[j].optname[nlen] == '\0') {
+ /* got a match */
+ if (parsed[j].freeme) {
+ efree(parsed[j].optval);
+ }
+ parsed[j].optval = estrndup(data_source + valstart, semi - valstart);
+ parsed[j].freeme = 1;
+ ++n_matches;
+ break;
+ }
+ }
+
+ while (i < data_source_len && isspace(data_source[i])) {
+ i++;
+ }
+
+ optstart = i;
+ }
+
+ return n_matches;
+}
+
+static const char digit_vec[] = "0123456789";
+PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC)
+{
+ char buffer[65];
+ char outbuf[65] = "";
+ register char *p;
+ long long_val;
+ char *dst = outbuf;
+
+ if (i64 < 0) {
+ i64 = -i64;
+ *dst++ = '-';
+ }
+
+ if (i64 == 0) {
+ *dst++ = '0';
+ *dst++ = '\0';
+ return estrdup(outbuf);
+ }
+
+ p = &buffer[sizeof(buffer)-1];
+ *p = '\0';
+
+ while ((pdo_uint64_t)i64 > (pdo_uint64_t)LONG_MAX) {
+ pdo_uint64_t quo = (pdo_uint64_t)i64 / (unsigned int)10;
+ unsigned int rem = (unsigned int)(i64 - quo*10U);
+ *--p = digit_vec[rem];
+ i64 = (pdo_int64_t)quo;
+ }
+ long_val = (long)i64;
+ while (long_val != 0) {
+ long quo = long_val / 10;
+ *--p = digit_vec[(unsigned int)(long_val - quo * 10)];
+ long_val = quo;
+ }
+ while ((*dst++ = *p++) != 0)
+ ;
+ *dst = '\0';
+ return estrdup(outbuf);
+}
+
+/* {{{ PHP_MINIT_FUNCTION */
+PHP_MINIT_FUNCTION(pdo)
+{
+ zend_class_entry ce;
+
+ spl_ce_RuntimeException = NULL;
+
+ ZEND_INIT_MODULE_GLOBALS(pdo, php_pdo_init_globals, NULL);
+ REGISTER_INI_ENTRIES();
+
+ if (FAILURE == pdo_sqlstate_init_error_table()) {
+ return FAILURE;
+ }
+
+ zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
+
+ le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
+ "PDO persistent database", module_number);
+
+ INIT_CLASS_ENTRY(ce, "PDOException", NULL);
+
+ pdo_exception_ce = zend_register_internal_class_ex(&ce, php_pdo_get_exception_base(0 TSRMLS_CC), NULL TSRMLS_CC);
+
+ zend_declare_property_null(pdo_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
+
+ pdo_dbh_init(TSRMLS_C);
+ pdo_stmt_init(TSRMLS_C);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION */
+PHP_MSHUTDOWN_FUNCTION(pdo)
+{
+ UNREGISTER_INI_ENTRIES();
+ zend_hash_destroy(&pdo_driver_hash);
+ pdo_sqlstate_fini_error_table();
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RINIT_FUNCTION */
+PHP_RINIT_FUNCTION(pdo)
+{
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION */
+PHP_RSHUTDOWN_FUNCTION(pdo)
+{
+ /* TODO: visit persistent handles: for each persistent statement handle,
+ * remove bound parameter associations */
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION */
+PHP_MINFO_FUNCTION(pdo)
+{
+ HashPosition pos;
+ char *drivers = NULL, *ldrivers = estrdup("");
+ pdo_driver_t **pdriver;
+
+ php_info_print_table_start();
+ php_info_print_table_header(2, "PDO support", "enabled");
+
+ zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
+ while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
+ spprintf(&drivers, 0, "%s, %s", ldrivers, (*pdriver)->driver_name);
+ zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
+ efree(ldrivers);
+ ldrivers = drivers;
+ }
+
+ php_info_print_table_row(2, "PDO drivers", drivers ? drivers+2 : "");
+
+ if (drivers) {
+ efree(drivers);
+ }
+
+ php_info_print_table_end();
+
+#if 0
+ DISPLAY_INI_ENTRIES();
+#endif
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/pdo/pdo.php b/ext/pdo/pdo.php
new file mode 100755
index 0000000000..1008f7bd04
--- /dev/null
+++ b/ext/pdo/pdo.php
@@ -0,0 +1,62 @@
+<?php
+dl('pdo.so');
+dl('pdo_sqlite.so');
+
+//$x = new PDO("oci:dbname=hostname", 'php', 'php');
+$x = new PDO("sqlite::memory:");
+
+$x->query("create table test(name string, value string)");
+debug_zval_dump($x);
+
+$stmt = $x->prepare("INSERT INTO test (NAME, VALUE) VALUES (:name, :value)");
+
+$stmt->bindParam(":name", $the_name, PDO_PARAM_STR, 32);
+$stmt->bindParam(":value", $the_value, PDO_PARAM_STR, 32);
+
+for ($i = 0; $i < 4; $i++) {
+ $the_name = "foo" . rand();
+ $the_value = "bar" . rand();
+
+ if (!$stmt->execute()) {
+ break;
+ }
+}
+
+$stmt = null;
+
+echo "DEFAULT:\n";
+foreach ($x->query("select NAME, VALUE from test") as $row) {
+ print_r($row);
+}
+
+echo "OBJ:\n";
+
+class Foo {
+ public $NAME = "Don't change me";
+}
+
+$foo = new foo;
+
+foreach ($x->query("select NAME, VALUE from test", PDO_FETCH_COLUMN, 1) as $row) {
+ debug_zval_dump($row);
+}
+
+echo "Done\n";
+exit;
+
+$stmt = $x->prepare("select NAME, VALUE from test where value like ?");
+$the_name = 'bar%';
+$stmt->execute(array($the_name)) or die("failed to execute!");
+$stmt->bindColumn('VALUE', $value);
+
+while ($row = $stmt->fetch()) {
+ echo "name=$row[NAME] value=$row[VALUE]\n";
+ echo "value is $value\n";
+ echo "\n";
+}
+
+echo "Let's try an update\n";
+
+echo "All done\n";
+
+?>
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c
new file mode 100755
index 0000000000..23c852553a
--- /dev/null
+++ b/ext/pdo/pdo_dbh.c
@@ -0,0 +1,1443 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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"
+#include "zend_object_handlers.h"
+#include "zend_hash.h"
+
+void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp TSRMLS_DC)
+{
+ pdo_error_type *pdo_err = &dbh->error_code;
+ char *message = NULL;
+ const char *msg;
+ zval *info = NULL;
+
+ if (dbh->error_mode == PDO_ERRMODE_SILENT) {
+#if 0
+ /* BUG: if user is running in silent mode and hits an error at the driver level
+ * when they use the PDO methods to call up the error information, they may
+ * get bogus information */
+ return;
+#endif
+ }
+
+ if (stmt) {
+ pdo_err = &stmt->error_code;
+ }
+
+ strcpy(*pdo_err, sqlstate);
+
+ /* hash sqlstate to error messages */
+ msg = pdo_sqlstate_state_to_description(*pdo_err);
+ if (!msg) {
+ msg = "<<Unknown error>>";
+ }
+
+ MAKE_STD_ZVAL(info);
+ array_init(info);
+
+ add_next_index_string(info, *pdo_err, 1);
+ add_next_index_long(info, 0);
+
+ if (supp) {
+ spprintf(&message, 0, "SQLSTATE[%s]: %s: %s", *pdo_err, msg, supp);
+ } else {
+ spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
+ }
+
+ if (dbh->error_mode != PDO_ERRMODE_EXCEPTION) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
+
+ if (info) {
+ zval_ptr_dtor(&info);
+ }
+ } else {
+ zval *ex;
+ zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception();
+
+ MAKE_STD_ZVAL(ex);
+ object_init_ex(ex, pdo_ex);
+
+ zend_update_property_string(def_ex, ex, "message", sizeof("message")-1, message TSRMLS_CC);
+ zend_update_property_string(def_ex, ex, "code", sizeof("code")-1, *pdo_err TSRMLS_CC);
+
+ if (info) {
+ zend_update_property(pdo_ex, ex, "errorInfo", sizeof("errorInfo")-1, info TSRMLS_CC);
+ zval_ptr_dtor(&info);
+ }
+
+ zend_throw_exception_object(ex TSRMLS_CC);
+ }
+
+ if (message) {
+ efree(message);
+ }
+}
+
+void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC)
+{
+ pdo_error_type *pdo_err = &dbh->error_code;
+ const char *msg = "<<Unknown>>";
+ char *supp = NULL;
+ long native_code = 0;
+ char *message = NULL;
+ zval *info = NULL;
+
+ if (dbh->error_mode == PDO_ERRMODE_SILENT) {
+ return;
+ }
+
+ if (stmt) {
+ pdo_err = &stmt->error_code;
+ }
+
+ /* hash sqlstate to error messages */
+ msg = pdo_sqlstate_state_to_description(*pdo_err);
+ if (!msg) {
+ msg = "<<Unknown error>>";
+ }
+
+ if (dbh->methods->fetch_err) {
+
+ MAKE_STD_ZVAL(info);
+ array_init(info);
+
+ add_next_index_string(info, *pdo_err, 1);
+
+ if (dbh->methods->fetch_err(dbh, stmt, info TSRMLS_CC)) {
+ zval **item;
+
+ if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 1, (void**)&item)) {
+ native_code = Z_LVAL_PP(item);
+ }
+
+ if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(info), 2, (void**)&item)) {
+ supp = estrndup(Z_STRVAL_PP(item), Z_STRLEN_PP(item));
+ }
+ }
+
+ zval_ptr_dtor(&info);
+ info = NULL;
+ }
+
+ if (supp) {
+ spprintf(&message, 0, "SQLSTATE[%s]: %s: %ld %s", *pdo_err, msg, native_code, supp);
+ } else {
+ spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
+ }
+
+ if (dbh->error_mode == PDO_ERRMODE_WARNING) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
+
+ if (info) {
+ zval_ptr_dtor(&info);
+ }
+ } else if (EG(exception) == NULL) {
+ zval *ex;
+ zend_class_entry *def_ex = php_pdo_get_exception_base(1 TSRMLS_CC), *pdo_ex = php_pdo_get_exception();
+
+ MAKE_STD_ZVAL(ex);
+ object_init_ex(ex, pdo_ex);
+
+ zend_update_property_string(def_ex, ex, "message", sizeof("message")-1, message TSRMLS_CC);
+ zend_update_property_string(def_ex, ex, "code", sizeof("code")-1, *pdo_err TSRMLS_CC);
+
+ if (info) {
+ zend_update_property(pdo_ex, ex, "errorInfo", sizeof("errorInfo")-1, info TSRMLS_CC);
+ zval_ptr_dtor(&info);
+ }
+
+ zend_throw_exception_object(ex TSRMLS_CC);
+ }
+
+ if (message) {
+ efree(message);
+ }
+
+ if (supp) {
+ efree(supp);
+ }
+}
+
+static char *dsn_from_uri(char *uri, char *buf, size_t buflen TSRMLS_DC)
+{
+ php_stream *stream;
+ char *dsn = NULL;
+
+ stream = php_stream_open_wrapper(uri, "rb", ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL);
+ if (stream) {
+ dsn = php_stream_get_line(stream, buf, buflen, NULL);
+ php_stream_close(stream);
+ }
+ return dsn;
+}
+
+/* {{{ proto object PDO::__construct(string dsn, string username, string passwd [, array options])
+ */
+static PHP_METHOD(PDO, dbh_constructor)
+{
+ zval *object = getThis();
+ pdo_dbh_t *dbh = NULL;
+ zend_bool is_persistent = FALSE;
+ char *data_source;
+ int data_source_len;
+ char *colon;
+ char *username=NULL, *password=NULL;
+ int usernamelen, passwordlen;
+ pdo_driver_t *driver = NULL;
+ zval *options = NULL;
+ char alt_dsn[512];
+ int call_factory = 1;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!a!", &data_source, &data_source_len,
+ &username, &usernamelen, &password, &passwordlen, &options)) {
+ ZVAL_NULL(object);
+ return;
+ }
+
+ /* parse the data source name */
+ colon = strchr(data_source, ':');
+
+ if (!colon) {
+ /* let's see if this string has a matching dsn in the php.ini */
+ char *ini_dsn = NULL;
+
+ snprintf(alt_dsn, sizeof(alt_dsn), "pdo.dsn.%s", data_source);
+ if (FAILURE == cfg_get_string(alt_dsn, &ini_dsn)) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name");
+ ZVAL_NULL(object);
+ return;
+ }
+
+ data_source = ini_dsn;
+ colon = strchr(data_source, ':');
+
+ if (!colon) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via INI: %s)", alt_dsn);
+ ZVAL_NULL(object);
+ return;
+ }
+ }
+
+ if (!strncmp(data_source, "uri:", sizeof("uri:")-1)) {
+ /* the specified URI holds connection details */
+ data_source = dsn_from_uri(data_source + sizeof("uri:")-1, alt_dsn, sizeof(alt_dsn) TSRMLS_CC);
+ if (!data_source) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source URI");
+ ZVAL_NULL(object);
+ return;
+ }
+ colon = strchr(data_source, ':');
+ if (!colon) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "invalid data source name (via URI)");
+ 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 */
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "could not find driver");
+ ZVAL_NULL(object);
+ return;
+ }
+
+ dbh = (pdo_dbh_t *) zend_object_store_get_object(object TSRMLS_CC);
+
+ /* is this supposed to be a persistent connection ? */
+ if (options) {
+ zval **v;
+ int plen;
+ char *hashkey = NULL;
+ list_entry *le;
+ pdo_dbh_t *pdbh = NULL;
+
+ if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_PERSISTENT, (void**)&v)) {
+ if (Z_TYPE_PP(v) == IS_STRING) {
+ /* user specified key */
+ plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s:%s", data_source,
+ username ? username : "",
+ password ? password : "",
+ Z_STRVAL_PP(v));
+ is_persistent = 1;
+ } else {
+ convert_to_long_ex(v);
+ is_persistent = Z_LVAL_PP(v) ? 1 : 0;
+ plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s", data_source,
+ username ? username : "",
+ password ? password : "");
+ }
+ }
+
+ if (is_persistent) {
+ /* let's see if we have one cached.... */
+ if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, plen+1, (void*)&le)) {
+ if (Z_TYPE_P(le) == php_pdo_list_entry()) {
+ pdbh = (pdo_dbh_t*)le->ptr;
+
+ /* is the connection still alive ? */
+ if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh TSRMLS_CC)) {
+ /* nope... need to kill it */
+ pdbh = NULL;
+ }
+ }
+ }
+
+ if (pdbh) {
+ call_factory = 0;
+ } else {
+ /* need a brand new pdbh */
+ pdbh = pecalloc(1, sizeof(*pdbh), 1);
+
+ if (!pdbh) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle");
+ /* NOTREACHED */
+ }
+
+ pdbh->is_persistent = 1;
+ if (!(pdbh->persistent_id = pemalloc(plen + 1, 1))) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO handle");
+ }
+ memcpy((char *)pdbh->persistent_id, hashkey, plen+1);
+ pdbh->persistent_id_len = plen+1;
+ pdbh->refcount = 1;
+ }
+ }
+
+ if (pdbh) {
+ /* let's copy the emalloc bits over from the other handle */
+ pdbh->ce = dbh->ce;
+ pdbh->def_stmt_ce = dbh->def_stmt_ce;
+ pdbh->def_stmt_ctor_args = dbh->def_stmt_ctor_args;
+ pdbh->properties = dbh->properties;
+ /* kill the non-persistent thingamy */
+ efree(dbh);
+ /* switch over to the persistent one */
+ dbh = pdbh;
+ zend_object_store_set_object(object, dbh TSRMLS_CC);
+ dbh->refcount++;
+ }
+
+ if (hashkey) {
+ efree(hashkey);
+ }
+ }
+
+ dbh->data_source_len = strlen(colon + 1);
+ dbh->data_source = (const char*)pestrdup(colon + 1, is_persistent);
+ dbh->username = username ? pestrdup(username, is_persistent) : NULL;
+ dbh->password = password ? pestrdup(password, is_persistent) : NULL;
+
+ dbh->auto_commit = pdo_attr_lval(options, PDO_ATTR_AUTOCOMMIT, 1 TSRMLS_CC);
+
+ if (!dbh->data_source || (username && !dbh->username) || (password && !dbh->password)) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory");
+ }
+
+ if (!call_factory) {
+ /* we got a persistent guy from our cache */
+ return;
+ }
+
+ if (driver->db_handle_factory(dbh, options TSRMLS_CC)) {
+ /* all set */
+
+ if (is_persistent) {
+ list_entry le;
+
+ /* register in the persistent list etc. */
+ /* we should also need to replace the object store entry,
+ since it was created with emalloc */
+
+ le.type = php_pdo_list_entry();
+ le.ptr = dbh;
+
+ if (FAILURE == zend_hash_update(&EG(persistent_list),
+ (char*)dbh->persistent_id, dbh->persistent_id_len, (void*)&le,
+ sizeof(le), NULL)) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to register persistent entry");
+ }
+ }
+
+ dbh->driver = driver;
+ return;
+ }
+
+ /* the connection failed; things will tidy up in free_storage */
+ /* XXX raise exception */
+ ZVAL_NULL(object);
+}
+/* }}} */
+
+static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */
+{
+ if (ctor_args) {
+ if (Z_TYPE_P(ctor_args) != IS_ARRAY) {
+ pdo_raise_impl_error(dbh, NULL, "HY000", "constructor arguments must be passed as an array" TSRMLS_CC);
+ return NULL;
+ }
+ if (!dbstmt_ce->constructor) {
+ pdo_raise_impl_error(dbh, NULL, "HY000", "user-supplied statement does not accept constructor arguments" TSRMLS_CC);
+ return NULL;
+ }
+ }
+
+ Z_TYPE_P(object) = IS_OBJECT;
+ object_init_ex(object, dbstmt_ce);
+ object->refcount = 1;
+ object->is_ref = 1;
+
+ return object;
+} /* }}} */
+
+static void pdo_stmt_construct(pdo_stmt_t *stmt, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args TSRMLS_DC) /* {{{ */
+{
+ zval *query_string;
+ zval z_key;
+
+ MAKE_STD_ZVAL(query_string);
+ ZVAL_STRINGL(query_string, stmt->query_string, stmt->query_stringlen, 1);
+ ZVAL_STRINGL(&z_key, "queryString", sizeof("queryString")-1, 0);
+ std_object_handlers.write_property(object, &z_key, query_string TSRMLS_CC);
+ zval_ptr_dtor(&query_string);
+
+ if (dbstmt_ce->constructor) {
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval *retval;
+
+ fci.size = sizeof(zend_fcall_info);
+ fci.function_table = &dbstmt_ce->function_table;
+ fci.function_name = NULL;
+ fci.object_pp = &object;
+ fci.symbol_table = NULL;
+ fci.retval_ptr_ptr = &retval;
+ if (ctor_args) {
+ HashTable *ht = Z_ARRVAL_P(ctor_args);
+ Bucket *p;
+
+ fci.param_count = 0;
+ fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0);
+ p = ht->pListHead;
+ while (p != NULL) {
+ fci.params[fci.param_count++] = (zval**)p->pData;
+ p = p->pListNext;
+ }
+ } else {
+ fci.param_count = 0;
+ fci.params = NULL;
+ }
+ fci.no_separation = 1;
+
+ fcc.initialized = 1;
+ fcc.function_handler = dbstmt_ce->constructor;
+ fcc.calling_scope = EG(scope);
+ fcc.object_pp = &object;
+
+ if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
+ zval_dtor(object);
+ ZVAL_NULL(object);
+ object = NULL; /* marks failure */
+ } else {
+ zval_ptr_dtor(&retval);
+ }
+
+ if (fci.params) {
+ efree(fci.params);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto object PDO::prepare(string statment [, array options])
+ 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;
+ int statement_len;
+ zval *options = NULL, **opt, **item, *ctor_args;
+ zend_class_entry *dbstmt_ce, **pce;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &statement,
+ &statement_len, &options)) {
+ RETURN_FALSE;
+ }
+
+ PDO_DBH_CLEAR_ERR();
+ PDO_CONSTRUCT_CHECK;
+
+ if (ZEND_NUM_ARGS() > 1 && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS, (void**)&opt)) {
+ if (Z_TYPE_PP(opt) != IS_ARRAY || zend_hash_index_find(Z_ARRVAL_PP(opt), 0, (void**)&item) == FAILURE
+ || Z_TYPE_PP(item) != IS_STRING
+ || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_PP(item), &pce TSRMLS_CC) == FAILURE
+ ) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
+ "the classname must be a string specifying an existing class"
+ TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ dbstmt_ce = *pce;
+ if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce TSRMLS_CC)) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "user-supplied statement class cannot have a public constructor" TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ if (zend_hash_index_find(Z_ARRVAL_PP(opt), 1, (void**)&item) == SUCCESS) {
+ if (Z_TYPE_PP(item) != IS_ARRAY) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
+ "ctor_args must be an array"
+ TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ ctor_args = *item;
+ } else {
+ ctor_args = NULL;
+ }
+ } else {
+ dbstmt_ce = dbh->def_stmt_ce;
+ ctor_args = dbh->def_stmt_ctor_args;
+ }
+
+ if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, ctor_args TSRMLS_CC)) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "failed to instantiate user-supplied statement class"
+ TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
+
+ /* unconditionally keep this for later reference */
+ stmt->query_string = estrndup(statement, statement_len);
+ stmt->query_stringlen = statement_len;
+ stmt->default_fetch_type = PDO_FETCH_BOTH;
+ stmt->dbh = dbh;
+ /* give it a reference to me */
+ zend_objects_store_add_ref(getThis() TSRMLS_CC);
+ stmt->database_object_handle = *getThis();
+ /* we haven't created a lazy object yet */
+ ZVAL_NULL(&stmt->lazy_object_ref);
+
+ if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options TSRMLS_CC)) {
+ pdo_stmt_construct(stmt, return_value, dbstmt_ce, ctor_args TSRMLS_CC);
+ return;
+ }
+
+ PDO_HANDLE_DBH_ERR();
+
+ /* kill the object handle for the stmt here */
+ zval_dtor(return_value);
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool PDO::beginTransaction()
+ Initiates a transaction */
+static PHP_METHOD(PDO, beginTransaction)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ PDO_CONSTRUCT_CHECK;
+
+ if (dbh->in_txn) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is already an active transaction");
+ RETURN_FALSE;
+ }
+
+ if (!dbh->methods->begin) {
+ /* TODO: this should be an exception; see the auto-commit mode
+ * comments below */
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "This driver doesn't support transactions");
+ RETURN_FALSE;
+ }
+
+ if (dbh->methods->begin(dbh TSRMLS_CC)) {
+ dbh->in_txn = 1;
+ RETURN_TRUE;
+ }
+
+ PDO_HANDLE_DBH_ERR();
+ 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);
+
+ PDO_CONSTRUCT_CHECK;
+
+ if (!dbh->in_txn) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction");
+ RETURN_FALSE;
+ }
+
+ if (dbh->methods->commit(dbh TSRMLS_CC)) {
+ dbh->in_txn = 0;
+ RETURN_TRUE;
+ }
+
+ PDO_HANDLE_DBH_ERR();
+ 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);
+
+ PDO_CONSTRUCT_CHECK;
+
+ if (!dbh->in_txn) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "There is no active transaction");
+ RETURN_FALSE;
+ }
+
+ if (dbh->methods->rollback(dbh TSRMLS_CC)) {
+ dbh->in_txn = 0;
+ RETURN_TRUE;
+ }
+
+ PDO_HANDLE_DBH_ERR();
+ 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;
+ }
+
+ PDO_CONSTRUCT_CHECK;
+
+ switch (attr) {
+ case PDO_ATTR_ERRMODE:
+ convert_to_long(value);
+ switch (Z_LVAL_P(value)) {
+ case PDO_ERRMODE_SILENT:
+ case PDO_ERRMODE_WARNING:
+ case PDO_ERRMODE_EXCEPTION:
+ dbh->error_mode = Z_LVAL_P(value);
+ RETURN_TRUE;
+ default:
+ pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode" TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ RETURN_FALSE;
+
+ case PDO_ATTR_CASE:
+ convert_to_long(value);
+ switch (Z_LVAL_P(value)) {
+ case PDO_CASE_NATURAL:
+ case PDO_CASE_UPPER:
+ case PDO_CASE_LOWER:
+ dbh->desired_case = Z_LVAL_P(value);
+ RETURN_TRUE;
+ default:
+ pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode" TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ RETURN_FALSE;
+
+ case PDO_ATTR_ORACLE_NULLS:
+ convert_to_long(value);
+ dbh->oracle_nulls = Z_LVAL_P(value);
+ RETURN_TRUE;
+
+ case PDO_ATTR_STRINGIFY_FETCHES:
+ convert_to_long(value);
+ dbh->stringify = Z_LVAL_P(value) ? 1 : 0;
+ RETURN_TRUE;
+
+ case PDO_ATTR_STATEMENT_CLASS: {
+ /* array(string classname, array(mixed ctor_args)) */
+ zend_class_entry **pce;
+ zval **item;
+
+ if (dbh->is_persistent) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances"
+ TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ if (Z_TYPE_P(value) != IS_ARRAY
+ || zend_hash_index_find(Z_ARRVAL_P(value), 0, (void**)&item) == FAILURE
+ || Z_TYPE_PP(item) != IS_STRING
+ || zend_lookup_class(Z_STRVAL_PP(item), Z_STRLEN_PP(item), &pce TSRMLS_CC) == FAILURE
+ ) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
+ "the classname must be a string specifying an existing class"
+ TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ if (!instanceof_function(*pce, pdo_dbstmt_ce TSRMLS_CC)) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "user-supplied statement class must be derived from PDOStatement" TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ if ((*pce)->constructor && !((*pce)->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "user-supplied statement class cannot have a public constructor" TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ dbh->def_stmt_ce = *pce;
+ if (dbh->def_stmt_ctor_args) {
+ zval_ptr_dtor(&dbh->def_stmt_ctor_args);
+ dbh->def_stmt_ctor_args = NULL;
+ }
+ if (zend_hash_index_find(Z_ARRVAL_P(value), 1, (void**)&item) == SUCCESS) {
+ if (Z_TYPE_PP(item) != IS_ARRAY) {
+ pdo_raise_impl_error(dbh, NULL, "HY000",
+ "PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
+ "ctor_args must be an array"
+ TSRMLS_CC);
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ }
+ (*item)->refcount++;
+ dbh->def_stmt_ctor_args = *item;
+ }
+ RETURN_TRUE;
+ }
+
+ default:
+ ;
+ }
+
+ if (!dbh->methods->set_attribute) {
+ goto fail;
+ }
+
+ PDO_DBH_CLEAR_ERR();
+ if (dbh->methods->set_attribute(dbh, attr, value TSRMLS_CC)) {
+ RETURN_TRUE;
+ }
+
+fail:
+ if (attr == PDO_ATTR_AUTOCOMMIT) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "The auto-commit mode cannot be changed for this driver");
+ } else if (!dbh->methods->set_attribute) {
+ pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes" TSRMLS_CC);
+ } else {
+ PDO_HANDLE_DBH_ERR();
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto mixed PDO::getAttribute(long attribute)
+ Get an attribute */
+static PHP_METHOD(PDO, getAttribute)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ long attr;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
+ RETURN_FALSE;
+ }
+
+ PDO_DBH_CLEAR_ERR();
+ PDO_CONSTRUCT_CHECK;
+
+ /* handle generic PDO-level atributes */
+ switch (attr) {
+ case PDO_ATTR_PERSISTENT:
+ RETURN_BOOL(dbh->is_persistent);
+
+ case PDO_ATTR_CASE:
+ RETURN_LONG(dbh->desired_case);
+
+ case PDO_ATTR_ORACLE_NULLS:
+ RETURN_LONG(dbh->oracle_nulls);
+
+ case PDO_ATTR_ERRMODE:
+ RETURN_LONG(dbh->error_mode);
+
+ case PDO_ATTR_DRIVER_NAME:
+ RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len, 1);
+
+ case PDO_ATTR_STATEMENT_CLASS:
+ array_init(return_value);
+ add_next_index_string(return_value, dbh->def_stmt_ce->name, 1);
+ if (dbh->def_stmt_ctor_args) {
+ dbh->def_stmt_ctor_args->refcount++;
+ add_next_index_zval(return_value, dbh->def_stmt_ctor_args);
+ }
+ return;
+ }
+
+ if (!dbh->methods->get_attribute) {
+ pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support getting attributes" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ switch (dbh->methods->get_attribute(dbh, attr, return_value TSRMLS_CC)) {
+ case -1:
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+
+ case 0:
+ pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support that attribute" TSRMLS_CC);
+ RETURN_FALSE;
+
+ default:
+ return;
+ }
+}
+/* }}} */
+
+/* {{{ proto long PDO::exec(string query)
+ Execute a query that does not return a row set, returning the number of affected rows */
+static PHP_METHOD(PDO, exec)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *statement;
+ int statement_len;
+ long ret;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &statement, &statement_len)) {
+ RETURN_FALSE;
+ }
+
+ if (!statement_len) {
+ RETURN_FALSE;
+ }
+ PDO_DBH_CLEAR_ERR();
+ PDO_CONSTRUCT_CHECK;
+ ret = dbh->methods->doer(dbh, statement, statement_len TSRMLS_CC);
+ if(ret == -1) {
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ } else {
+ RETURN_LONG(ret);
+ }
+}
+/* }}} */
+
+
+/* {{{ proto string PDO::lastInsertId([string seqname])
+ 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. */
+static PHP_METHOD(PDO, lastInsertId)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *name = NULL;
+ int namelen;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &name, &namelen)) {
+ RETURN_FALSE;
+ }
+
+ PDO_DBH_CLEAR_ERR();
+ PDO_CONSTRUCT_CHECK;
+ if (!dbh->methods->last_id) {
+ pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()" TSRMLS_CC);
+ RETURN_FALSE;
+ } else {
+ Z_STRVAL_P(return_value) = dbh->methods->last_id(dbh, name, &Z_STRLEN_P(return_value) TSRMLS_CC);
+ if (!Z_STRVAL_P(return_value)) {
+ PDO_HANDLE_DBH_ERR();
+ RETURN_FALSE;
+ } else {
+ Z_TYPE_P(return_value) = IS_STRING;
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto string PDO::errorCode()
+ Fetch the error code associated with the last operation on the database handle */
+static PHP_METHOD(PDO, errorCode)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (ZEND_NUM_ARGS()) {
+ RETURN_FALSE;
+ }
+ PDO_CONSTRUCT_CHECK;
+
+ if (dbh->query_stmt) {
+ RETURN_STRING(dbh->query_stmt->error_code, 1);
+ }
+
+ RETURN_STRING(dbh->error_code, 1);
+}
+/* }}} */
+
+/* {{{ proto int PDO::errorInfo()
+ Fetch extended error information associated with the last operation on the database handle */
+static PHP_METHOD(PDO, errorInfo)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+
+ if (ZEND_NUM_ARGS()) {
+ RETURN_FALSE;
+ }
+ PDO_CONSTRUCT_CHECK;
+
+ array_init(return_value);
+
+ if (dbh->query_stmt) {
+ add_next_index_string(return_value, dbh->query_stmt->error_code, 1);
+ } else {
+ add_next_index_string(return_value, dbh->error_code, 1);
+ }
+ if (dbh->methods->fetch_err) {
+ dbh->methods->fetch_err(dbh, dbh->query_stmt, return_value TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ proto object PDO::query(string sql [, PDOStatement::setFetchMode() args])
+ Prepare and execute $sql; returns the statement object for iteration */
+static PHP_METHOD(PDO, query)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ pdo_stmt_t *stmt;
+ char *statement;
+ int statement_len;
+
+ if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s", &statement,
+ &statement_len)) {
+ RETURN_FALSE;
+ }
+
+ PDO_DBH_CLEAR_ERR();
+ PDO_CONSTRUCT_CHECK;
+
+ if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC)) {
+ pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class" TSRMLS_CC);
+ return;
+ }
+ stmt = (pdo_stmt_t*)zend_object_store_get_object(return_value TSRMLS_CC);
+
+ /* unconditionally keep this for later reference */
+ stmt->query_string = estrndup(statement, statement_len);
+ stmt->query_stringlen = statement_len;
+ stmt->default_fetch_type = PDO_FETCH_BOTH;
+ stmt->active_query_string = stmt->query_string;
+ stmt->active_query_stringlen = statement_len;
+ stmt->dbh = dbh;
+ /* give it a reference to me */
+ zend_objects_store_add_ref(getThis() TSRMLS_CC);
+ stmt->database_object_handle = *getThis();
+ /* we haven't created a lazy object yet */
+ ZVAL_NULL(&stmt->lazy_object_ref);
+
+ if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL TSRMLS_CC)) {
+ if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
+ /* now execute the statement */
+ PDO_STMT_CLEAR_ERR();
+ if (stmt->methods->executer(stmt TSRMLS_CC)) {
+ int ret = 1;
+ if (!stmt->executed) {
+ if (stmt->dbh->alloc_own_columns) {
+ ret = pdo_stmt_describe_columns(stmt TSRMLS_CC);
+ }
+ stmt->executed = 1;
+ }
+ if (ret) {
+ pdo_stmt_construct(stmt, return_value, dbh->def_stmt_ce, dbh->def_stmt_ctor_args TSRMLS_CC);
+ return;
+ }
+ }
+ }
+ /* something broke */
+ dbh->query_stmt = stmt;
+ dbh->query_stmt_zval = *return_value;
+ PDO_HANDLE_STMT_ERR();
+ } else {
+ PDO_HANDLE_DBH_ERR();
+ zval_dtor(return_value);
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string PDO::quote(string string [, int paramtype])
+ 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 */
+static PHP_METHOD(PDO, quote)
+{
+ pdo_dbh_t *dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ char *str;
+ int str_len;
+ long paramtype = PDO_PARAM_STR;
+ char *qstr;
+ int qlen;
+
+ if (FAILURE == zend_parse_parameters(1 TSRMLS_CC, "s|l", &str, &str_len,
+ &paramtype)) {
+ RETURN_FALSE;
+ }
+
+ PDO_DBH_CLEAR_ERR();
+ PDO_CONSTRUCT_CHECK;
+ if (!dbh->methods->quoter) {
+ pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (dbh->methods->quoter(dbh, str, str_len, &qstr, &qlen, paramtype TSRMLS_CC)) {
+ RETURN_STRINGL(qstr, qlen, 0);
+ }
+ PDO_HANDLE_DBH_ERR();
+}
+/* }}} */
+
+/* {{{ proto int PDO::__wakeup()
+ Prevents use of a PDO instance that has been unserialized */
+static PHP_METHOD(PDO, __wakeup)
+{
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances");
+}
+/* }}} */
+
+/* {{{ proto int PDO::__sleep()
+ Prevents serialization of a PDO instance */
+static PHP_METHOD(PDO, __sleep)
+{
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDO instances");
+}
+/* }}} */
+
+/* {{{ proto array pdo_drivers()
+ Return array of available PDO drivers */
+static PHP_METHOD(PDO, getAvailableDrivers)
+{
+ HashPosition pos;
+ pdo_driver_t **pdriver;
+
+ array_init(return_value);
+
+ zend_hash_internal_pointer_reset_ex(&pdo_driver_hash, &pos);
+ while (SUCCESS == zend_hash_get_current_data_ex(&pdo_driver_hash, (void**)&pdriver, &pos)) {
+ add_next_index_stringl(return_value, (char*)(*pdriver)->driver_name, (*pdriver)->driver_name_len, 1);
+ zend_hash_move_forward_ex(&pdo_driver_hash, &pos);
+ }
+}
+/* }}} */
+
+function_entry pdo_dbh_functions[] = {
+ ZEND_MALIAS(PDO, __construct, dbh_constructor, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, prepare, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, beginTransaction,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)
+ PHP_ME(PDO, exec, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, query, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, lastInsertId, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, errorCode, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, errorInfo, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, getAttribute, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, quote, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
+ PHP_ME(PDO, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
+ PHP_ME(PDO, getAvailableDrivers, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+ {NULL, NULL, NULL}
+};
+
+/* {{{ overloaded object handlers for PDO class */
+int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
+{
+ function_entry *funcs;
+ zend_function func;
+ zend_internal_function *ifunc = (zend_internal_function*)&func;
+ int namelen;
+ char *lc_name;
+
+ if (!dbh->methods->get_driver_methods) {
+ return 0;
+ }
+ funcs = dbh->methods->get_driver_methods(dbh,
+ PDO_DBH_DRIVER_METHOD_KIND_DBH TSRMLS_CC);
+ if (!funcs) {
+ return 0;
+ }
+
+ if (!(dbh->cls_methods[kind] = pemalloc(sizeof(HashTable), dbh->is_persistent))) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "out of memory while allocating PDO methods.");
+ }
+ zend_hash_init_ex(dbh->cls_methods[kind], 8, NULL, NULL, dbh->is_persistent, 0);
+
+ while (funcs->fname) {
+ ifunc->type = ZEND_INTERNAL_FUNCTION;
+ ifunc->handler = funcs->handler;
+ ifunc->function_name = funcs->fname;
+ ifunc->scope = dbh->ce;
+ ifunc->prototype = NULL;
+ if (funcs->arg_info) {
+ ifunc->arg_info = funcs->arg_info + 1;
+ ifunc->num_args = funcs->num_args;
+ if (funcs->arg_info[0].required_num_args == -1) {
+ ifunc->required_num_args = funcs->num_args;
+ } else {
+ ifunc->required_num_args = funcs->arg_info[0].required_num_args;
+ }
+ ifunc->pass_rest_by_reference = funcs->arg_info[0].pass_by_reference;
+ ifunc->return_reference = funcs->arg_info[0].return_reference;
+ } else {
+ ifunc->arg_info = NULL;
+ ifunc->num_args = 0;
+ ifunc->required_num_args = 0;
+ ifunc->pass_rest_by_reference = 0;
+ ifunc->return_reference = 0;
+ }
+ if (funcs->flags) {
+ ifunc->fn_flags = funcs->flags;
+ } else {
+ ifunc->fn_flags = ZEND_ACC_PUBLIC;
+ }
+ namelen = strlen(funcs->fname);
+ lc_name = emalloc(namelen+1);
+ zend_str_tolower_copy(lc_name, funcs->fname, namelen);
+ zend_hash_add(dbh->cls_methods[kind], lc_name, namelen+1, &func, sizeof(func), NULL);
+ efree(lc_name);
+ funcs++;
+ }
+
+ return 1;
+}
+
+static union _zend_function *dbh_method_get(
+#if PHP_API_VERSION >= 20041225
+ zval **object_pp,
+#else
+ zval *object,
+#endif
+ char *method_name, int method_len TSRMLS_DC)
+{
+ zend_function *fbc = NULL;
+ char *lc_method_name;
+#if PHP_API_VERSION >= 20041225
+ zval *object = *object_pp;
+#endif
+ pdo_dbh_t *dbh = zend_object_store_get_object(object TSRMLS_CC);
+
+ lc_method_name = emalloc(method_len + 1);
+ zend_str_tolower_copy(lc_method_name, method_name, method_len);
+
+ if (zend_hash_find(&dbh->ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
+ /* not a pre-defined method, nor a user-defined method; check
+ * the driver specific methods */
+ if (!dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
+ if (!pdo_hash_methods(dbh,
+ PDO_DBH_DRIVER_METHOD_KIND_DBH TSRMLS_CC)
+ || !dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
+ goto out;
+ }
+ }
+
+ if (zend_hash_find(dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH],
+ lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
+ fbc = NULL;
+ goto out;
+ }
+ /* got it */
+ }
+
+out:
+ efree(lc_method_name);
+ return fbc;
+}
+
+static int dbh_compare(zval *object1, zval *object2 TSRMLS_DC)
+{
+ return -1;
+}
+
+static zend_object_handlers pdo_dbh_object_handlers;
+
+PDO_API void php_pdo_declare_stringl_constant(const char *const_name,
+ size_t name_len, const char *value, size_t value_len TSRMLS_DC)
+{
+#if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
+ zend_declare_class_constant_stringl(pdo_dbh_ce, (char*)const_name, name_len, (char*)value, value_len TSRMLS_CC);
+#else
+ zval *constant = malloc(sizeof(*constant));
+ ZVAL_STRINGL(constant, zend_strndup(value, value_len), value_len, 0);
+ INIT_PZVAL(constant);
+ zend_hash_update(&pdo_dbh_ce->constants_table, (char*)const_name, name_len+1, &constant, sizeof(zval*), NULL);
+#endif
+}
+
+PDO_API void php_pdo_declare_long_constant(const char *const_name,
+ size_t name_len, long value TSRMLS_DC)
+{
+#if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
+ zend_declare_class_constant_long(pdo_dbh_ce, (char*)const_name, name_len, value TSRMLS_CC);
+#else
+ zval *constant = malloc(sizeof(*constant));
+ ZVAL_LONG(constant, value);
+ INIT_PZVAL(constant);
+ zend_hash_update(&pdo_dbh_ce->constants_table, (char*)const_name, name_len+1, &constant, sizeof(zval*), NULL);
+#endif
+}
+
+void pdo_dbh_init(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
+ pdo_dbh_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ pdo_dbh_ce->create_object = pdo_dbh_new;
+
+ memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
+ pdo_dbh_object_handlers.get_method = dbh_method_get;
+ pdo_dbh_object_handlers.compare_objects = dbh_compare;
+
+ REGISTER_PDO_CLASS_CONST_LONG("PARAM_BOOL", (long)PDO_PARAM_BOOL);
+ REGISTER_PDO_CLASS_CONST_LONG("PARAM_NULL", (long)PDO_PARAM_NULL);
+ REGISTER_PDO_CLASS_CONST_LONG("PARAM_INT", (long)PDO_PARAM_INT);
+ REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR", (long)PDO_PARAM_STR);
+ REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB", (long)PDO_PARAM_LOB);
+ REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT", (long)PDO_PARAM_STMT);
+ REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT", (long)PDO_PARAM_INPUT_OUTPUT);
+
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (long)PDO_FETCH_LAZY);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC",(long)PDO_FETCH_ASSOC);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM", (long)PDO_FETCH_NUM);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH", (long)PDO_FETCH_BOTH);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ", (long)PDO_FETCH_OBJ);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND",(long)PDO_FETCH_BOUND);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN",(long)PDO_FETCH_COLUMN);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASS",(long)PDO_FETCH_CLASS);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_INTO", (long)PDO_FETCH_INTO);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_FUNC", (long)PDO_FETCH_FUNC);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_GROUP",(long)PDO_FETCH_GROUP);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_UNIQUE",(long)PDO_FETCH_UNIQUE);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASSTYPE",(long)PDO_FETCH_CLASSTYPE);
+#if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_SERIALIZE",(long)PDO_FETCH_SERIALIZE);
+#endif
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_NAMED",(long)PDO_FETCH_NAMED);
+
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_AUTOCOMMIT", (long)PDO_ATTR_AUTOCOMMIT);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_PREFETCH", (long)PDO_ATTR_PREFETCH);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_TIMEOUT", (long)PDO_ATTR_TIMEOUT);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_ERRMODE", (long)PDO_ATTR_ERRMODE);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_VERSION", (long)PDO_ATTR_SERVER_VERSION);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_CLIENT_VERSION", (long)PDO_ATTR_CLIENT_VERSION);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_INFO", (long)PDO_ATTR_SERVER_INFO);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_CONNECTION_STATUS", (long)PDO_ATTR_CONNECTION_STATUS);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_CASE", (long)PDO_ATTR_CASE);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR_NAME", (long)PDO_ATTR_CURSOR_NAME);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR", (long)PDO_ATTR_CURSOR);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_ORACLE_NULLS", (long)PDO_ATTR_ORACLE_NULLS);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_PERSISTENT", (long)PDO_ATTR_PERSISTENT);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_STATEMENT_CLASS", (long)PDO_ATTR_STATEMENT_CLASS);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_TABLE_NAMES", (long)PDO_ATTR_FETCH_TABLE_NAMES);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_CATALOG_NAMES", (long)PDO_ATTR_FETCH_CATALOG_NAMES);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_DRIVER_NAME", (long)PDO_ATTR_DRIVER_NAME);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_STRINGIFY_FETCHES",(long)PDO_ATTR_STRINGIFY_FETCHES);
+ REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN",(long)PDO_ATTR_MAX_COLUMN_LEN);
+
+ REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT", (long)PDO_ERRMODE_SILENT);
+ REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING", (long)PDO_ERRMODE_WARNING);
+ REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION", (long)PDO_ERRMODE_EXCEPTION);
+
+ REGISTER_PDO_CLASS_CONST_LONG("CASE_NATURAL", (long)PDO_CASE_NATURAL);
+ REGISTER_PDO_CLASS_CONST_LONG("CASE_LOWER", (long)PDO_CASE_LOWER);
+ REGISTER_PDO_CLASS_CONST_LONG("CASE_UPPER", (long)PDO_CASE_UPPER);
+
+ REGISTER_PDO_CLASS_CONST_LONG("NULL_NATURAL", (long)PDO_NULL_NATURAL);
+ REGISTER_PDO_CLASS_CONST_LONG("NULL_EMPTY_STRING", (long)PDO_NULL_EMPTY_STRING);
+ REGISTER_PDO_CLASS_CONST_LONG("NULL_TO_STRING", (long)PDO_NULL_TO_STRING);
+
+ REGISTER_PDO_CLASS_CONST_STRING("ERR_NONE", PDO_ERR_NONE);
+
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_NEXT", (long)PDO_FETCH_ORI_NEXT);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_PRIOR", (long)PDO_FETCH_ORI_PRIOR);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_FIRST", (long)PDO_FETCH_ORI_FIRST);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_LAST", (long)PDO_FETCH_ORI_LAST);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_ABS", (long)PDO_FETCH_ORI_ABS);
+ REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_REL", (long)PDO_FETCH_ORI_REL);
+
+ REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY", (long)PDO_CURSOR_FWDONLY);
+ REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL", (long)PDO_CURSOR_SCROLL);
+
+#if 0
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_CANT_MAP", (long)PDO_ERR_CANT_MAP);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_SYNTAX", (long)PDO_ERR_SYNTAX);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_CONSTRAINT", (long)PDO_ERR_CONSTRAINT);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_FOUND", (long)PDO_ERR_NOT_FOUND);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_ALREADY_EXISTS", (long)PDO_ERR_ALREADY_EXISTS);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_IMPLEMENTED", (long)PDO_ERR_NOT_IMPLEMENTED);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_MISMATCH", (long)PDO_ERR_MISMATCH);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_TRUNCATED", (long)PDO_ERR_TRUNCATED);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_DISCONNECTED", (long)PDO_ERR_DISCONNECTED);
+ REGISTER_PDO_CLASS_CONST_LONG("ERR_NO_PERM", (long)PDO_ERR_NO_PERM);
+#endif
+
+}
+
+static void dbh_free(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ int i;
+
+ if (--dbh->refcount)
+ return;
+
+ if (dbh->methods) {
+ dbh->methods->closer(dbh TSRMLS_CC);
+ }
+
+ if (dbh->data_source) {
+ pefree((char *)dbh->data_source, dbh->is_persistent);
+ }
+ if (dbh->username) {
+ pefree(dbh->username, dbh->is_persistent);
+ }
+ if (dbh->password) {
+ pefree(dbh->password, dbh->is_persistent);
+ }
+
+ if (dbh->def_stmt_ctor_args) {
+ zval_ptr_dtor(&dbh->def_stmt_ctor_args);
+ }
+
+ for (i = 0; i < PDO_DBH_DRIVER_METHOD_KIND__MAX; i++) {
+ if (dbh->cls_methods[i]) {
+ zend_hash_destroy(dbh->cls_methods[i]);
+ }
+ }
+
+ pefree(dbh, dbh->is_persistent);
+}
+
+PDO_API void php_pdo_dbh_addref(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ dbh->refcount++;
+}
+
+PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ dbh_free(dbh TSRMLS_CC);
+}
+
+static void pdo_dbh_free_storage(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ if (dbh->in_txn && dbh->methods && dbh->methods->rollback) {
+ dbh->methods->rollback(dbh TSRMLS_CC);
+ dbh->in_txn = 0;
+ }
+
+ if (dbh->properties) {
+ zend_hash_destroy(dbh->properties);
+ efree(dbh->properties);
+ dbh->properties = NULL;
+ }
+
+ if (!dbh->is_persistent) {
+ dbh_free(dbh TSRMLS_CC);
+ } else if (dbh->methods && dbh->methods->persistent_shutdown) {
+ dbh->methods->persistent_shutdown(dbh TSRMLS_CC);
+ }
+}
+
+zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ pdo_dbh_t *dbh;
+ zval *tmp;
+
+ dbh = emalloc(sizeof(*dbh));
+ memset(dbh, 0, sizeof(*dbh));
+ dbh->ce = ce;
+ dbh->refcount = 1;
+ ALLOC_HASHTABLE(dbh->properties);
+ zend_hash_init(dbh->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_copy(dbh->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+ dbh->def_stmt_ce = pdo_dbstmt_ce;
+
+ 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);
+ retval.handlers = &pdo_dbh_object_handlers;
+
+ return retval;
+}
+
+/* }}} */
+
+ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor)
+{
+ if (rsrc->ptr) {
+ pdo_dbh_t *dbh = (pdo_dbh_t*)rsrc->ptr;
+ dbh_free(dbh TSRMLS_CC);
+ rsrc->ptr = NULL;
+ }
+}
+
+/*
+ * 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
+ */
diff --git a/ext/pdo/pdo_sql_parser.c b/ext/pdo/pdo_sql_parser.c
new file mode 100644
index 0000000000..beb066e61e
--- /dev/null
+++ b/ext/pdo/pdo_sql_parser.c
@@ -0,0 +1,712 @@
+/* Generated by re2c 0.9.9.rc1 on Sat Sep 10 15:53:03 2005 */
+#line 1 "ext/pdo/pdo_sql_parser.re"
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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: George Schlossnagle <george@omniti.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_pdo_driver.h"
+#include "php_pdo_int.h"
+
+#define PDO_PARSER_TEXT 1
+#define PDO_PARSER_BIND 2
+#define PDO_PARSER_BIND_POS 3
+#define PDO_PARSER_EOI 4
+
+#define RET(i) {s->cur = cursor; return i; }
+
+#define YYCTYPE char
+#define YYCURSOR cursor
+#define YYLIMIT s->lim
+#define YYMARKER s->ptr
+#define YYFILL(n)
+
+typedef struct Scanner {
+ char *lim, *ptr, *cur, *tok;
+} Scanner;
+
+static int scan(Scanner *s)
+{
+ char *cursor = s->cur;
+
+ s->tok = cursor;
+ #line 55 "ext/pdo/pdo_sql_parser.re"
+
+
+ {
+ static unsigned char yybm[] = {
+ 0, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 52, 162, 162, 162, 162, 196,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 244, 162, 162, 162, 162, 244,
+ 162, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 162, 2, 162, 162, 170,
+ 162, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162,
+ };
+
+#line 89 "<stdout>"
+{
+ YYCTYPE yych;
+ unsigned int yyaccept;
+ goto yy0;
+ ++YYCURSOR;
+yy0:
+ if((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
+ yych = *YYCURSOR;
+ if(yybm[0+yych] & 2) {
+ goto yy8;
+ }
+ if(yych <= 0x00) goto yy11;
+ if(yych <= '&') goto yy2;
+ if(yych <= '\'') goto yy4;
+ if(yych <= '>') goto yy5;
+ goto yy6;
+yy2: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yybm[0+yych] & 64) {
+ goto yy30;
+ }
+ if(yych <= 0x00) goto yy3;
+ if(yych == '"') goto yy28;
+ goto yy33;
+yy3:
+#line 63 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_TEXT); }
+#line 117 "<stdout>"
+yy4: yyaccept = 0;
+ yych = *(YYMARKER = ++YYCURSOR);
+ if(yybm[0+yych] & 16) {
+ goto yy19;
+ }
+ if(yych <= 0x00) goto yy3;
+ if(yych == '\'') goto yy21;
+ goto yy24;
+yy5: yych = *++YYCURSOR;
+ if(yybm[0+yych] & 4) {
+ goto yy13;
+ }
+ if(yych <= 'Z'){
+ if(yych <= '/') goto yy3;
+ if(yych <= ':') goto yy16;
+ if(yych <= '@') goto yy3;
+ goto yy16;
+ } else {
+ if(yych <= '_'){
+ if(yych <= '^') goto yy3;
+ goto yy16;
+ } else {
+ if(yych <= '`') goto yy3;
+ if(yych <= 'z') goto yy16;
+ goto yy3;
+ }
+ }
+yy6: ++YYCURSOR;
+ if(yybm[0+(yych = *YYCURSOR)] & 4) {
+ yych = *YYCURSOR;
+ goto yy13;
+ }
+ goto yy7;
+yy7:
+#line 62 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_BIND_POS); }
+#line 154 "<stdout>"
+yy8: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ goto yy9;
+yy9: if(yybm[0+yych] & 2) {
+ goto yy8;
+ }
+ goto yy10;
+yy10:
+#line 64 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_TEXT); }
+#line 166 "<stdout>"
+yy11: ++YYCURSOR;
+ goto yy12;
+yy12:
+#line 65 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_EOI); }
+#line 172 "<stdout>"
+yy13: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ goto yy14;
+yy14: if(yybm[0+yych] & 4) {
+ goto yy13;
+ }
+ goto yy15;
+yy15:
+#line 60 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_TEXT); }
+#line 184 "<stdout>"
+yy16: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ goto yy17;
+yy17: if(yybm[0+yych] & 8) {
+ goto yy16;
+ }
+ goto yy18;
+yy18:
+#line 61 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_BIND); }
+#line 196 "<stdout>"
+yy19: yyaccept = 1;
+ YYMARKER = ++YYCURSOR;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ goto yy20;
+yy20: if(yybm[0+yych] & 16) {
+ goto yy19;
+ }
+ if(yych <= '\''){
+ if(yych <= 0x00) goto yy15;
+ if(yych <= '&') goto yy23;
+ goto yy21;
+ } else {
+ if(yych == '\\') goto yy26;
+ goto yy23;
+ }
+yy21: ++YYCURSOR;
+ if(yybm[0+(yych = *YYCURSOR)] & 4) {
+ yych = *YYCURSOR;
+ goto yy13;
+ }
+ goto yy22;
+yy22:
+#line 59 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_TEXT); }
+#line 222 "<stdout>"
+yy23: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ goto yy24;
+yy24: if(yybm[0+yych] & 32) {
+ goto yy23;
+ }
+ if(yych <= 0x00) goto yy25;
+ if(yych <= '[') goto yy27;
+ goto yy26;
+yy25: YYCURSOR = YYMARKER;
+ switch(yyaccept){
+ case 1: goto yy15;
+ case 0: goto yy3;
+ }
+yy26: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yych == '\'') goto yy23;
+ goto yy25;
+yy27: yych = *++YYCURSOR;
+ goto yy22;
+yy28: ++YYCURSOR;
+ if(yybm[0+(yych = *YYCURSOR)] & 4) {
+ yych = *YYCURSOR;
+ goto yy13;
+ }
+ goto yy29;
+yy29:
+#line 58 "ext/pdo/pdo_sql_parser.re"
+{ RET(PDO_PARSER_TEXT); }
+#line 254 "<stdout>"
+yy30: yyaccept = 1;
+ YYMARKER = ++YYCURSOR;
+ if((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+ yych = *YYCURSOR;
+ goto yy31;
+yy31: if(yybm[0+yych] & 64) {
+ goto yy30;
+ }
+ if(yych <= '"'){
+ if(yych <= 0x00) goto yy15;
+ if(yych >= '"') goto yy28;
+ goto yy32;
+ } else {
+ if(yych == '\\') goto yy34;
+ goto yy32;
+ }
+yy32: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ goto yy33;
+yy33: if(yybm[0+yych] & 128) {
+ goto yy32;
+ }
+ if(yych <= 0x00) goto yy25;
+ if(yych <= '[') goto yy35;
+ goto yy34;
+yy34: ++YYCURSOR;
+ if(YYLIMIT == YYCURSOR) YYFILL(1);
+ yych = *YYCURSOR;
+ if(yych == '"') goto yy32;
+ goto yy25;
+yy35: ++YYCURSOR;
+ yych = *YYCURSOR;
+ goto yy29;
+}
+}
+#line 66 "ext/pdo/pdo_sql_parser.re"
+
+}
+
+struct placeholder {
+ char *pos;
+ int len;
+ int bindno;
+ int qlen; /* quoted length of value */
+ char *quoted; /* quoted value */
+ int freeq;
+ struct placeholder *next;
+};
+
+PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
+ char **outquery, int *outquery_len TSRMLS_DC)
+{
+ Scanner s;
+ char *ptr, *newbuffer;
+ int t;
+ int bindno = 0;
+ int ret = 0;
+ int newbuffer_len;
+ HashTable *params;
+ struct pdo_bound_param_data *param;
+ int query_type = PDO_PLACEHOLDER_NONE;
+ struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
+
+ ptr = *outquery;
+ s.cur = inquery;
+ s.lim = inquery + inquery_len;
+
+ /* phase 1: look for args */
+ while((t = scan(&s)) != PDO_PARSER_EOI) {
+ if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
+ if (t == PDO_PARSER_BIND) {
+ query_type |= PDO_PLACEHOLDER_NAMED;
+ } else {
+ query_type |= PDO_PLACEHOLDER_POSITIONAL;
+ }
+
+ plc = emalloc(sizeof(*plc));
+ memset(plc, 0, sizeof(*plc));
+ plc->next = NULL;
+ plc->pos = s.tok;
+ plc->len = s.cur - s.tok;
+ plc->bindno = bindno++;
+
+ if (placetail) {
+ placetail->next = plc;
+ } else {
+ placeholders = plc;
+ }
+ placetail = plc;
+ }
+ }
+
+ if (bindno == 0) {
+ /* nothing to do; good! */
+ return 0;
+ }
+
+ /* did the query make sense to me? */
+ if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
+ /* they mixed both types; punt */
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
+ return -1;
+ }
+
+
+ if (stmt->supports_placeholders == query_type && !stmt->named_rewrite_template) {
+ /* query matches native syntax */
+ ret = 0;
+ goto clean_up;
+ }
+
+ if (stmt->named_rewrite_template) {
+ /* magic/hack.
+ * We we pretend that the query was positional even if
+ * it was named so that we fall into the
+ * named rewrite case below. Not too pretty,
+ * but it works. */
+ query_type = PDO_PLACEHOLDER_POSITIONAL;
+ }
+
+ params = stmt->bound_params;
+
+ /* Do we have placeholders but no bound params */
+ if (bindno && !params && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
+ ret = -1;
+ goto clean_up;
+ }
+
+ /* what are we going to do ? */
+
+ if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
+ /* query generation */
+
+ newbuffer_len = inquery_len;
+
+ /* let's quote all the values */
+ for (plc = placeholders; plc; plc = plc->next) {
+ if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
+ ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
+ } else {
+ ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
+ }
+ if (ret == FAILURE) {
+ /* parameter was not defined */
+ ret = -1;
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
+ goto clean_up;
+ }
+ if (stmt->dbh->methods->quoter) {
+ if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
+ php_stream *stm;
+
+ php_stream_from_zval_no_verify(stm, &param->parameter);
+ if (stm) {
+ size_t len;
+ char *buf = NULL;
+
+ len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
+ if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
+ param->param_type TSRMLS_CC)) {
+ /* bork */
+ ret = -1;
+ strcpy(stmt->error_code, stmt->dbh->error_code);
+ efree(buf);
+ goto clean_up;
+ }
+ efree(buf);
+
+ } else {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
+ ret = -1;
+ goto clean_up;
+ }
+ plc->freeq = 1;
+ } else {
+ switch (Z_TYPE_P(param->parameter)) {
+ case IS_NULL:
+ plc->quoted = "NULL";
+ plc->qlen = sizeof("NULL")-1;
+ plc->freeq = 0;
+ break;
+
+ case IS_LONG:
+ case IS_DOUBLE:
+ convert_to_string(param->parameter);
+ plc->qlen = Z_STRLEN_P(param->parameter);
+ plc->quoted = Z_STRVAL_P(param->parameter);
+ plc->freeq = 0;
+ break;
+
+ case IS_BOOL:
+ convert_to_long(param->parameter);
+ default:
+ convert_to_string(param->parameter);
+ if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
+ Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
+ param->param_type TSRMLS_CC)) {
+ /* bork */
+ ret = -1;
+ strcpy(stmt->error_code, stmt->dbh->error_code);
+ goto clean_up;
+ }
+ plc->freeq = 1;
+ }
+ }
+ } else {
+ plc->quoted = Z_STRVAL_P(param->parameter);
+ plc->qlen = Z_STRLEN_P(param->parameter);
+ }
+ newbuffer_len += plc->qlen;
+ }
+
+rewrite:
+ /* allocate output buffer */
+ newbuffer = emalloc(newbuffer_len + 1);
+ *outquery = newbuffer;
+
+ /* and build the query */
+ plc = placeholders;
+ ptr = inquery;
+
+ do {
+ t = plc->pos - ptr;
+ if (t) {
+ memcpy(newbuffer, ptr, t);
+ newbuffer += t;
+ }
+ memcpy(newbuffer, plc->quoted, plc->qlen);
+ newbuffer += plc->qlen;
+ ptr = plc->pos + plc->len;
+
+ plc = plc->next;
+ } while (plc);
+
+ t = (inquery + inquery_len) - ptr;
+ if (t) {
+ memcpy(newbuffer, ptr, t);
+ newbuffer += t;
+ }
+ *newbuffer = '\0';
+ *outquery_len = newbuffer - *outquery;
+
+ ret = 1;
+ goto clean_up;
+
+ } else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
+ /* rewrite ? to :pdoX */
+ char idxbuf[32];
+ const char *tmpl = stmt->named_rewrite_template ? stmt->named_rewrite_template : ":pdo%d";
+ char *name;
+
+ newbuffer_len = inquery_len;
+
+ if (stmt->bound_param_map == NULL) {
+ ALLOC_HASHTABLE(stmt->bound_param_map);
+ zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
+ }
+
+ for (plc = placeholders; plc; plc = plc->next) {
+ snprintf(idxbuf, sizeof(idxbuf), tmpl, plc->bindno + 1);
+ plc->quoted = estrdup(idxbuf);
+ plc->qlen = strlen(plc->quoted);
+ plc->freeq = 1;
+ newbuffer_len += plc->qlen;
+
+ name = estrndup(plc->pos, plc->len);
+
+ if (stmt->named_rewrite_template) {
+ /* create a mapping */
+
+ zend_hash_update(stmt->bound_param_map, name, plc->len + 1, idxbuf, plc->qlen + 1, NULL);
+ }
+
+ /* map number to name */
+ zend_hash_index_update(stmt->bound_param_map, plc->bindno, idxbuf, plc->qlen + 1, NULL);
+
+ efree(name);
+ }
+
+ goto rewrite;
+
+ } else {
+ /* rewrite :name to ? */
+
+ newbuffer_len = inquery_len;
+
+ if (stmt->bound_param_map == NULL) {
+ ALLOC_HASHTABLE(stmt->bound_param_map);
+ zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
+ }
+
+ for (plc = placeholders; plc; plc = plc->next) {
+ char *name;
+
+ name = estrndup(plc->pos, plc->len);
+ zend_hash_index_update(stmt->bound_param_map, plc->bindno, name, plc->len + 1, NULL);
+ efree(name);
+ plc->quoted = "?";
+ plc->qlen = 1;
+ }
+
+ goto rewrite;
+ }
+
+clean_up:
+
+ while (placeholders) {
+ plc = placeholders;
+ placeholders = plc->next;
+
+ if (plc->freeq) {
+ efree(plc->quoted);
+ }
+
+ efree(plc);
+ }
+
+ return ret;
+}
+
+#if 0
+int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
+ int *outquery_len TSRMLS_DC)
+{
+ Scanner s;
+ char *ptr;
+ int t;
+ int bindno = 0;
+ int newbuffer_len;
+ int padding;
+ HashTable *params = stmt->bound_params;
+ struct pdo_bound_param_data *param;
+ /* allocate buffer for query with expanded binds, ptr is our writing pointer */
+ newbuffer_len = inquery_len;
+
+ /* calculate the possible padding factor due to quoting */
+ if(stmt->dbh->max_escaped_char_length) {
+ padding = stmt->dbh->max_escaped_char_length;
+ } else {
+ padding = 3;
+ }
+ if(params) {
+ zend_hash_internal_pointer_reset(params);
+ while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
+ if(param->parameter) {
+ convert_to_string(param->parameter);
+ /* accomodate a string that needs to be fully quoted
+ bind placeholders are at least 2 characters, so
+ the accomodate their own "'s
+ */
+ newbuffer_len += padding * Z_STRLEN_P(param->parameter);
+ }
+ zend_hash_move_forward(params);
+ }
+ }
+ *outquery = (char *) emalloc(newbuffer_len + 1);
+ *outquery_len = 0;
+
+ ptr = *outquery;
+ s.cur = inquery;
+ s.lim = inquery + inquery_len;
+ while((t = scan(&s)) != PDO_PARSER_EOI) {
+ if(t == PDO_PARSER_TEXT) {
+ memcpy(ptr, s.tok, s.cur - s.tok);
+ ptr += (s.cur - s.tok);
+ *outquery_len += (s.cur - s.tok);
+ }
+ else if(t == PDO_PARSER_BIND) {
+ if(!params) {
+ /* error */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ /* lookup bind first via hash and then index */
+ /* stupid keys need to be null-terminated, even though we know their length */
+ if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)&param))
+ ||
+ (SUCCESS == zend_hash_index_find(params, bindno, (void **)&param)))
+ {
+ char *quotedstr;
+ int quotedstrlen;
+ /* restore the in-string key, doesn't need null-termination here */
+ /* currently everything is a string here */
+
+ /* quote the bind value if necessary */
+ if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
+ Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
+ {
+ memcpy(ptr, quotedstr, quotedstrlen);
+ ptr += quotedstrlen;
+ *outquery_len += quotedstrlen;
+ efree(quotedstr);
+ } else {
+ memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
+ ptr += Z_STRLEN_P(param->parameter);
+ *outquery_len += (Z_STRLEN_P(param->parameter));
+ }
+ }
+ else {
+ /* error and cleanup */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ bindno++;
+ }
+ else if(t == PDO_PARSER_BIND_POS) {
+ if(!params) {
+ /* error */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ /* lookup bind by index */
+ if(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))
+ {
+ char *quotedstr;
+ int quotedstrlen;
+ /* currently everything is a string here */
+
+ /* quote the bind value if necessary */
+ if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
+ Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
+ {
+ memcpy(ptr, quotedstr, quotedstrlen);
+ ptr += quotedstrlen;
+ *outquery_len += quotedstrlen;
+ efree(quotedstr);
+ } else {
+ memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
+ ptr += Z_STRLEN_P(param->parameter);
+ *outquery_len += (Z_STRLEN_P(param->parameter));
+ }
+ }
+ else {
+ /* error and cleanup */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ bindno++;
+ }
+ }
+ *ptr = '\0';
+ return 0;
+}
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker ft=c
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/pdo/pdo_sql_parser.re b/ext/pdo/pdo_sql_parser.re
new file mode 100644
index 0000000000..eeae984573
--- /dev/null
+++ b/ext/pdo/pdo_sql_parser.re
@@ -0,0 +1,487 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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: George Schlossnagle <george@omniti.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "php_pdo_driver.h"
+#include "php_pdo_int.h"
+
+#define PDO_PARSER_TEXT 1
+#define PDO_PARSER_BIND 2
+#define PDO_PARSER_BIND_POS 3
+#define PDO_PARSER_EOI 4
+
+#define RET(i) {s->cur = cursor; return i; }
+
+#define YYCTYPE char
+#define YYCURSOR cursor
+#define YYLIMIT s->lim
+#define YYMARKER s->ptr
+#define YYFILL(n)
+
+typedef struct Scanner {
+ char *lim, *ptr, *cur, *tok;
+} Scanner;
+
+static int scan(Scanner *s)
+{
+ char *cursor = s->cur;
+
+ s->tok = cursor;
+ /*!re2c
+ BINDCHR = [:][a-zA-Z0-9_]+;
+ QUESTION = [?];
+ SPECIALS = [:?"'];
+ ESCQQ = [\\]["];
+ ESCQ = [\\]['];
+ EOF = [\000];
+ ANYNOEOF = [\001-\377];
+ */
+
+ /*!re2c
+ (["] (ESCQQ|ANYNOEOF\[\\"])* ["]) { RET(PDO_PARSER_TEXT); }
+ (['] (ESCQ|ANYNOEOF\[\\'])* [']) { RET(PDO_PARSER_TEXT); }
+ SPECIALS{2,} { RET(PDO_PARSER_TEXT); }
+ BINDCHR { RET(PDO_PARSER_BIND); }
+ QUESTION { RET(PDO_PARSER_BIND_POS); }
+ SPECIALS { RET(PDO_PARSER_TEXT); }
+ (ANYNOEOF\SPECIALS)+ { RET(PDO_PARSER_TEXT); }
+ EOF { RET(PDO_PARSER_EOI); }
+ */
+}
+
+struct placeholder {
+ char *pos;
+ int len;
+ int bindno;
+ int qlen; /* quoted length of value */
+ char *quoted; /* quoted value */
+ int freeq;
+ struct placeholder *next;
+};
+
+PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
+ char **outquery, int *outquery_len TSRMLS_DC)
+{
+ Scanner s;
+ char *ptr, *newbuffer;
+ int t;
+ int bindno = 0;
+ int ret = 0;
+ int newbuffer_len;
+ HashTable *params;
+ struct pdo_bound_param_data *param;
+ int query_type = PDO_PLACEHOLDER_NONE;
+ struct placeholder *placeholders = NULL, *placetail = NULL, *plc = NULL;
+
+ ptr = *outquery;
+ s.cur = inquery;
+ s.lim = inquery + inquery_len;
+
+ /* phase 1: look for args */
+ while((t = scan(&s)) != PDO_PARSER_EOI) {
+ if (t == PDO_PARSER_BIND || t == PDO_PARSER_BIND_POS) {
+ if (t == PDO_PARSER_BIND) {
+ query_type |= PDO_PLACEHOLDER_NAMED;
+ } else {
+ query_type |= PDO_PLACEHOLDER_POSITIONAL;
+ }
+
+ plc = emalloc(sizeof(*plc));
+ memset(plc, 0, sizeof(*plc));
+ plc->next = NULL;
+ plc->pos = s.tok;
+ plc->len = s.cur - s.tok;
+ plc->bindno = bindno++;
+
+ if (placetail) {
+ placetail->next = plc;
+ } else {
+ placeholders = plc;
+ }
+ placetail = plc;
+ }
+ }
+
+ if (bindno == 0) {
+ /* nothing to do; good! */
+ return 0;
+ }
+
+ /* did the query make sense to me? */
+ if (query_type == (PDO_PLACEHOLDER_NAMED|PDO_PLACEHOLDER_POSITIONAL)) {
+ /* they mixed both types; punt */
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "mixed named and positional parameters" TSRMLS_CC);
+ return -1;
+ }
+
+
+ if (stmt->supports_placeholders == query_type && !stmt->named_rewrite_template) {
+ /* query matches native syntax */
+ ret = 0;
+ goto clean_up;
+ }
+
+ if (stmt->named_rewrite_template) {
+ /* magic/hack.
+ * We we pretend that the query was positional even if
+ * it was named so that we fall into the
+ * named rewrite case below. Not too pretty,
+ * but it works. */
+ query_type = PDO_PLACEHOLDER_POSITIONAL;
+ }
+
+ params = stmt->bound_params;
+
+ /* Do we have placeholders but no bound params */
+ if (bindno && !params && stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "no parameters were bound" TSRMLS_CC);
+ ret = -1;
+ goto clean_up;
+ }
+
+ /* what are we going to do ? */
+
+ if (stmt->supports_placeholders == PDO_PLACEHOLDER_NONE) {
+ /* query generation */
+
+ newbuffer_len = inquery_len;
+
+ /* let's quote all the values */
+ for (plc = placeholders; plc; plc = plc->next) {
+ if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
+ ret = zend_hash_index_find(params, plc->bindno, (void**) &param);
+ } else {
+ ret = zend_hash_find(params, plc->pos, plc->len, (void**) &param);
+ }
+ if (ret == FAILURE) {
+ /* parameter was not defined */
+ ret = -1;
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
+ goto clean_up;
+ }
+ if (stmt->dbh->methods->quoter) {
+ if (param->param_type == PDO_PARAM_LOB && Z_TYPE_P(param->parameter) == IS_RESOURCE) {
+ php_stream *stm;
+
+ php_stream_from_zval_no_verify(stm, &param->parameter);
+ if (stm) {
+ size_t len;
+ char *buf = NULL;
+
+ len = php_stream_copy_to_mem(stm, &buf, PHP_STREAM_COPY_ALL, 0);
+ if (!stmt->dbh->methods->quoter(stmt->dbh, buf, len, &plc->quoted, &plc->qlen,
+ param->param_type TSRMLS_CC)) {
+ /* bork */
+ ret = -1;
+ strcpy(stmt->error_code, stmt->dbh->error_code);
+ efree(buf);
+ goto clean_up;
+ }
+ efree(buf);
+
+ } else {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
+ ret = -1;
+ goto clean_up;
+ }
+ plc->freeq = 1;
+ } else {
+ switch (Z_TYPE_P(param->parameter)) {
+ case IS_NULL:
+ plc->quoted = "NULL";
+ plc->qlen = sizeof("NULL")-1;
+ plc->freeq = 0;
+ break;
+
+ case IS_LONG:
+ case IS_DOUBLE:
+ convert_to_string(param->parameter);
+ plc->qlen = Z_STRLEN_P(param->parameter);
+ plc->quoted = Z_STRVAL_P(param->parameter);
+ plc->freeq = 0;
+ break;
+
+ case IS_BOOL:
+ convert_to_long(param->parameter);
+ default:
+ convert_to_string(param->parameter);
+ if (!stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
+ Z_STRLEN_P(param->parameter), &plc->quoted, &plc->qlen,
+ param->param_type TSRMLS_CC)) {
+ /* bork */
+ ret = -1;
+ strcpy(stmt->error_code, stmt->dbh->error_code);
+ goto clean_up;
+ }
+ plc->freeq = 1;
+ }
+ }
+ } else {
+ plc->quoted = Z_STRVAL_P(param->parameter);
+ plc->qlen = Z_STRLEN_P(param->parameter);
+ }
+ newbuffer_len += plc->qlen;
+ }
+
+rewrite:
+ /* allocate output buffer */
+ newbuffer = emalloc(newbuffer_len + 1);
+ *outquery = newbuffer;
+
+ /* and build the query */
+ plc = placeholders;
+ ptr = inquery;
+
+ do {
+ t = plc->pos - ptr;
+ if (t) {
+ memcpy(newbuffer, ptr, t);
+ newbuffer += t;
+ }
+ memcpy(newbuffer, plc->quoted, plc->qlen);
+ newbuffer += plc->qlen;
+ ptr = plc->pos + plc->len;
+
+ plc = plc->next;
+ } while (plc);
+
+ t = (inquery + inquery_len) - ptr;
+ if (t) {
+ memcpy(newbuffer, ptr, t);
+ newbuffer += t;
+ }
+ *newbuffer = '\0';
+ *outquery_len = newbuffer - *outquery;
+
+ ret = 1;
+ goto clean_up;
+
+ } else if (query_type == PDO_PLACEHOLDER_POSITIONAL) {
+ /* rewrite ? to :pdoX */
+ char idxbuf[32];
+ const char *tmpl = stmt->named_rewrite_template ? stmt->named_rewrite_template : ":pdo%d";
+ char *name;
+
+ newbuffer_len = inquery_len;
+
+ if (stmt->bound_param_map == NULL) {
+ ALLOC_HASHTABLE(stmt->bound_param_map);
+ zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
+ }
+
+ for (plc = placeholders; plc; plc = plc->next) {
+ snprintf(idxbuf, sizeof(idxbuf), tmpl, plc->bindno + 1);
+ plc->quoted = estrdup(idxbuf);
+ plc->qlen = strlen(plc->quoted);
+ plc->freeq = 1;
+ newbuffer_len += plc->qlen;
+
+ name = estrndup(plc->pos, plc->len);
+
+ if (stmt->named_rewrite_template) {
+ /* create a mapping */
+
+ zend_hash_update(stmt->bound_param_map, name, plc->len + 1, idxbuf, plc->qlen + 1, NULL);
+ }
+
+ /* map number to name */
+ zend_hash_index_update(stmt->bound_param_map, plc->bindno, idxbuf, plc->qlen + 1, NULL);
+
+ efree(name);
+ }
+
+ goto rewrite;
+
+ } else {
+ /* rewrite :name to ? */
+
+ newbuffer_len = inquery_len;
+
+ if (stmt->bound_param_map == NULL) {
+ ALLOC_HASHTABLE(stmt->bound_param_map);
+ zend_hash_init(stmt->bound_param_map, 13, NULL, NULL, 0);
+ }
+
+ for (plc = placeholders; plc; plc = plc->next) {
+ char *name;
+
+ name = estrndup(plc->pos, plc->len);
+ zend_hash_index_update(stmt->bound_param_map, plc->bindno, name, plc->len + 1, NULL);
+ efree(name);
+ plc->quoted = "?";
+ plc->qlen = 1;
+ }
+
+ goto rewrite;
+ }
+
+clean_up:
+
+ while (placeholders) {
+ plc = placeholders;
+ placeholders = plc->next;
+
+ if (plc->freeq) {
+ efree(plc->quoted);
+ }
+
+ efree(plc);
+ }
+
+ return ret;
+}
+
+#if 0
+int old_pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len, char **outquery,
+ int *outquery_len TSRMLS_DC)
+{
+ Scanner s;
+ char *ptr;
+ int t;
+ int bindno = 0;
+ int newbuffer_len;
+ int padding;
+ HashTable *params = stmt->bound_params;
+ struct pdo_bound_param_data *param;
+ /* allocate buffer for query with expanded binds, ptr is our writing pointer */
+ newbuffer_len = inquery_len;
+
+ /* calculate the possible padding factor due to quoting */
+ if(stmt->dbh->max_escaped_char_length) {
+ padding = stmt->dbh->max_escaped_char_length;
+ } else {
+ padding = 3;
+ }
+ if(params) {
+ zend_hash_internal_pointer_reset(params);
+ while (SUCCESS == zend_hash_get_current_data(params, (void**)&param)) {
+ if(param->parameter) {
+ convert_to_string(param->parameter);
+ /* accomodate a string that needs to be fully quoted
+ bind placeholders are at least 2 characters, so
+ the accomodate their own "'s
+ */
+ newbuffer_len += padding * Z_STRLEN_P(param->parameter);
+ }
+ zend_hash_move_forward(params);
+ }
+ }
+ *outquery = (char *) emalloc(newbuffer_len + 1);
+ *outquery_len = 0;
+
+ ptr = *outquery;
+ s.cur = inquery;
+ s.lim = inquery + inquery_len;
+ while((t = scan(&s)) != PDO_PARSER_EOI) {
+ if(t == PDO_PARSER_TEXT) {
+ memcpy(ptr, s.tok, s.cur - s.tok);
+ ptr += (s.cur - s.tok);
+ *outquery_len += (s.cur - s.tok);
+ }
+ else if(t == PDO_PARSER_BIND) {
+ if(!params) {
+ /* error */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ /* lookup bind first via hash and then index */
+ /* stupid keys need to be null-terminated, even though we know their length */
+ if((SUCCESS == zend_hash_find(params, s.tok, s.cur-s.tok,(void **)&param))
+ ||
+ (SUCCESS == zend_hash_index_find(params, bindno, (void **)&param)))
+ {
+ char *quotedstr;
+ int quotedstrlen;
+ /* restore the in-string key, doesn't need null-termination here */
+ /* currently everything is a string here */
+
+ /* quote the bind value if necessary */
+ if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
+ Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
+ {
+ memcpy(ptr, quotedstr, quotedstrlen);
+ ptr += quotedstrlen;
+ *outquery_len += quotedstrlen;
+ efree(quotedstr);
+ } else {
+ memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
+ ptr += Z_STRLEN_P(param->parameter);
+ *outquery_len += (Z_STRLEN_P(param->parameter));
+ }
+ }
+ else {
+ /* error and cleanup */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ bindno++;
+ }
+ else if(t == PDO_PARSER_BIND_POS) {
+ if(!params) {
+ /* error */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ /* lookup bind by index */
+ if(SUCCESS == zend_hash_index_find(params, bindno, (void **)&param))
+ {
+ char *quotedstr;
+ int quotedstrlen;
+ /* currently everything is a string here */
+
+ /* quote the bind value if necessary */
+ if(stmt->dbh->methods->quoter(stmt->dbh, Z_STRVAL_P(param->parameter),
+ Z_STRLEN_P(param->parameter), &quotedstr, &quotedstrlen TSRMLS_CC))
+ {
+ memcpy(ptr, quotedstr, quotedstrlen);
+ ptr += quotedstrlen;
+ *outquery_len += quotedstrlen;
+ efree(quotedstr);
+ } else {
+ memcpy(ptr, Z_STRVAL_P(param->parameter), Z_STRLEN_P(param->parameter));
+ ptr += Z_STRLEN_P(param->parameter);
+ *outquery_len += (Z_STRLEN_P(param->parameter));
+ }
+ }
+ else {
+ /* error and cleanup */
+ efree(*outquery);
+ *outquery = NULL;
+ return (int) (s.cur - inquery);
+ }
+ bindno++;
+ }
+ }
+ *ptr = '\0';
+ return 0;
+}
+#endif
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker ft=c
+ * vim<600: noet sw=4 ts=4
+ */
diff --git a/ext/pdo/pdo_sqlstate.c b/ext/pdo/pdo_sqlstate.c
new file mode 100644
index 0000000000..07f2589aa4
--- /dev/null
+++ b/ext/pdo/pdo_sqlstate.c
@@ -0,0 +1,340 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#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"
+
+struct pdo_sqlstate_info {
+ char state[6];
+ const char *desc;
+};
+
+static HashTable err_hash;
+
+static struct pdo_sqlstate_info err_initializer[] = {
+ { "00000", "No error" },
+ { "01000", "Warning" },
+ { "01001", "Cursor operation conflict" },
+ { "01002", "Disconnect error" },
+ { "01003", "NULL value eliminated in set function" },
+ { "01004", "String data, right truncated" },
+ { "01006", "Privilege not revoked" },
+ { "01007", "Privilege not granted" },
+ { "01008", "Implicit zero bit padding" },
+ { "0100C", "Dynamic result sets returned" },
+ { "01P01", "Deprecated feature" },
+ { "01S00", "Invalid connection string attribute" },
+ { "01S01", "Error in row" },
+ { "01S02", "Option value changed" },
+ { "01S06", "Attempt to fetch before the result set returned the first rowset" },
+ { "01S07", "Fractional truncation" },
+ { "01S08", "Error saving File DSN" },
+ { "01S09", "Invalid keyword" },
+ { "02000", "No data" },
+ { "02001", "No additional dynamic result sets returned" },
+ { "03000", "Sql statement not yet complete" },
+ { "07002", "COUNT field incorrect" },
+ { "07005", "Prepared statement not a cursor-specification" },
+ { "07006", "Restricted data type attribute violation" },
+ { "07009", "Invalid descriptor index" },
+ { "07S01", "Invalid use of default parameter" },
+ { "08000", "Connection exception" },
+ { "08001", "Client unable to establish connection" },
+ { "08002", "Connection name in use" },
+ { "08003", "Connection does not exist" },
+ { "08004", "Server rejected the connection" },
+ { "08006", "Connection failure" },
+ { "08007", "Connection failure during transaction" },
+ { "08S01", "Communication link failure" },
+ { "09000", "Triggered action exception" },
+ { "0A000", "Feature not supported" },
+ { "0B000", "Invalid transaction initiation" },
+ { "0F000", "Locator exception" },
+ { "0F001", "Invalid locator specification" },
+ { "0L000", "Invalid grantor" },
+ { "0LP01", "Invalid grant operation" },
+ { "0P000", "Invalid role specification" },
+ { "21000", "Cardinality violation" },
+ { "21S01", "Insert value list does not match column list" },
+ { "21S02", "Degree of derived table does not match column list" },
+ { "22000", "Data exception" },
+ { "22001", "String data, right truncated" },
+ { "22002", "Indicator variable required but not supplied" },
+ { "22003", "Numeric value out of range" },
+ { "22004", "Null value not allowed" },
+ { "22005", "Error in assignment" },
+ { "22007", "Invalid datetime format" },
+ { "22008", "Datetime field overflow" },
+ { "22009", "Invalid time zone displacement value" },
+ { "2200B", "Escape character conflict" },
+ { "2200C", "Invalid use of escape character" },
+ { "2200D", "Invalid escape octet" },
+ { "2200F", "Zero length character string" },
+ { "2200G", "Most specific type mismatch" },
+ { "22010", "Invalid indicator parameter value" },
+ { "22011", "Substring error" },
+ { "22012", "Division by zero" },
+ { "22015", "Interval field overflow" },
+ { "22018", "Invalid character value for cast specification" },
+ { "22019", "Invalid escape character" },
+ { "2201B", "Invalid regular expression" },
+ { "2201E", "Invalid argument for logarithm" },
+ { "2201F", "Invalid argument for power function" },
+ { "2201G", "Invalid argument for width bucket function" },
+ { "22020", "Invalid limit value" },
+ { "22021", "Character not in repertoire" },
+ { "22022", "Indicator overflow" },
+ { "22023", "Invalid parameter value" },
+ { "22024", "Unterminated c string" },
+ { "22025", "Invalid escape sequence" },
+ { "22026", "String data, length mismatch" },
+ { "22027", "Trim error" },
+ { "2202E", "Array subscript error" },
+ { "22P01", "Floating point exception" },
+ { "22P02", "Invalid text representation" },
+ { "22P03", "Invalid binary representation" },
+ { "22P04", "Bad copy file format" },
+ { "22P05", "Untranslatable character" },
+ { "23000", "Integrity constraint violation" },
+ { "23001", "Restrict violation" },
+ { "23502", "Not null violation" },
+ { "23503", "Foreign key violation" },
+ { "23505", "Unique violation" },
+ { "23514", "Check violation" },
+ { "24000", "Invalid cursor state" },
+ { "25000", "Invalid transaction state" },
+ { "25001", "Active sql transaction" },
+ { "25002", "Branch transaction already active" },
+ { "25003", "Inappropriate access mode for branch transaction" },
+ { "25004", "Inappropriate isolation level for branch transaction" },
+ { "25005", "No active sql transaction for branch transaction" },
+ { "25006", "Read only sql transaction" },
+ { "25007", "Schema and data statement mixing not supported" },
+ { "25008", "Held cursor requires same isolation level" },
+ { "25P01", "No active sql transaction" },
+ { "25P02", "In failed sql transaction" },
+ { "25S01", "Transaction state" },
+ { "25S02", "Transaction is still active" },
+ { "25S03", "Transaction is rolled back" },
+ { "26000", "Invalid sql statement name" },
+ { "27000", "Triggered data change violation" },
+ { "28000", "Invalid authorization specification" },
+ { "2B000", "Dependent privilege descriptors still exist" },
+ { "2BP01", "Dependent objects still exist" },
+ { "2D000", "Invalid transaction termination" },
+ { "2F000", "Sql routine exception" },
+ { "2F002", "Modifying sql data not permitted" },
+ { "2F003", "Prohibited sql statement attempted" },
+ { "2F004", "Reading sql data not permitted" },
+ { "2F005", "Function executed no return statement" },
+ { "34000", "Invalid cursor name" },
+ { "38000", "External routine exception" },
+ { "38001", "Containing sql not permitted" },
+ { "38002", "Modifying sql data not permitted" },
+ { "38003", "Prohibited sql statement attempted" },
+ { "38004", "Reading sql data not permitted" },
+ { "39000", "External routine invocation exception" },
+ { "39001", "Invalid sqlstate returned" },
+ { "39004", "Null value not allowed" },
+ { "39P01", "Trigger protocol violated" },
+ { "39P02", "Srf protocol violated" },
+ { "3B000", "Savepoint exception" },
+ { "3B001", "Invalid savepoint specification" },
+ { "3C000", "Duplicate cursor name" },
+ { "3D000", "Invalid catalog name" },
+ { "3F000", "Invalid schema name" },
+ { "40000", "Transaction rollback" },
+ { "40001", "Serialization failure" },
+ { "40002", "Transaction integrity constraint violation" },
+ { "40003", "Statement completion unknown" },
+ { "40P01", "Deadlock detected" },
+ { "42000", "Syntax error or access violation" },
+ { "42501", "Insufficient privilege" },
+ { "42601", "Syntax error" },
+ { "42602", "Invalid name" },
+ { "42611", "Invalid column definition" },
+ { "42622", "Name too long" },
+ { "42701", "Duplicate column" },
+ { "42702", "Ambiguous column" },
+ { "42703", "Undefined column" },
+ { "42704", "Undefined object" },
+ { "42710", "Duplicate object" },
+ { "42712", "Duplicate alias" },
+ { "42723", "Duplicate function" },
+ { "42725", "Ambiguous function" },
+ { "42803", "Grouping error" },
+ { "42804", "Datatype mismatch" },
+ { "42809", "Wrong object type" },
+ { "42830", "Invalid foreign key" },
+ { "42846", "Cannot coerce" },
+ { "42883", "Undefined function" },
+ { "42939", "Reserved name" },
+ { "42P01", "Undefined table" },
+ { "42P02", "Undefined parameter" },
+ { "42P03", "Duplicate cursor" },
+ { "42P04", "Duplicate database" },
+ { "42P05", "Duplicate prepared statement" },
+ { "42P06", "Duplicate schema" },
+ { "42P07", "Duplicate table" },
+ { "42P08", "Ambiguous parameter" },
+ { "42P09", "Ambiguous alias" },
+ { "42P10", "Invalid column reference" },
+ { "42P11", "Invalid cursor definition" },
+ { "42P12", "Invalid database definition" },
+ { "42P13", "Invalid function definition" },
+ { "42P14", "Invalid prepared statement definition" },
+ { "42P15", "Invalid schema definition" },
+ { "42P16", "Invalid table definition" },
+ { "42P17", "Invalid object definition" },
+ { "42P18", "Indeterminate datatype" },
+ { "42S01", "Base table or view already exists" },
+ { "42S02", "Base table or view not found" },
+ { "42S11", "Index already exists" },
+ { "42S12", "Index not found" },
+ { "42S21", "Column already exists" },
+ { "42S22", "Column not found" },
+ { "44000", "WITH CHECK OPTION violation" },
+ { "53000", "Insufficient resources" },
+ { "53100", "Disk full" },
+ { "53200", "Out of memory" },
+ { "53300", "Too many connections" },
+ { "54000", "Program limit exceeded" },
+ { "54001", "Statement too complex" },
+ { "54011", "Too many columns" },
+ { "54023", "Too many arguments" },
+ { "55000", "Object not in prerequisite state" },
+ { "55006", "Object in use" },
+ { "55P02", "Cant change runtime param" },
+ { "55P03", "Lock not available" },
+ { "57000", "Operator intervention" },
+ { "57014", "Query canceled" },
+ { "57P01", "Admin shutdown" },
+ { "57P02", "Crash shutdown" },
+ { "57P03", "Cannot connect now" },
+ { "58030", "Io error" },
+ { "58P01", "Undefined file" },
+ { "58P02", "Duplicate file" },
+ { "F0000", "Config file error" },
+ { "F0001", "Lock file exists" },
+ { "HY000", "General error" },
+ { "HY001", "Memory allocation error" },
+ { "HY003", "Invalid application buffer type" },
+ { "HY004", "Invalid SQL data type" },
+ { "HY007", "Associated statement is not prepared" },
+ { "HY008", "Operation canceled" },
+ { "HY009", "Invalid use of null pointer" },
+ { "HY010", "Function sequence error" },
+ { "HY011", "Attribute cannot be set now" },
+ { "HY012", "Invalid transaction operation code" },
+ { "HY013", "Memory management error" },
+ { "HY014", "Limit on the number of handles exceeded" },
+ { "HY015", "No cursor name available" },
+ { "HY016", "Cannot modify an implementation row descriptor" },
+ { "HY017", "Invalid use of an automatically allocated descriptor handle" },
+ { "HY018", "Server declined cancel request" },
+ { "HY019", "Non-character and non-binary data sent in pieces" },
+ { "HY020", "Attempt to concatenate a null value" },
+ { "HY021", "Inconsistent descriptor information" },
+ { "HY024", "Invalid attribute value" },
+ { "HY090", "Invalid string or buffer length" },
+ { "HY091", "Invalid descriptor field identifier" },
+ { "HY092", "Invalid attribute/option identifier" },
+ { "HY093", "Invalid parameter number" },
+ { "HY095", "Function type out of range" },
+ { "HY096", "Invalid information type" },
+ { "HY097", "Column type out of range" },
+ { "HY098", "Scope type out of range" },
+ { "HY099", "Nullable type out of range" },
+ { "HY100", "Uniqueness option type out of range" },
+ { "HY101", "Accuracy option type out of range" },
+ { "HY103", "Invalid retrieval code" },
+ { "HY104", "Invalid precision or scale value" },
+ { "HY105", "Invalid parameter type" },
+ { "HY106", "Fetch type out of range" },
+ { "HY107", "Row value out of range" },
+ { "HY109", "Invalid cursor position" },
+ { "HY110", "Invalid driver completion" },
+ { "HY111", "Invalid bookmark value" },
+ { "HYC00", "Optional feature not implemented" },
+ { "HYT00", "Timeout expired" },
+ { "HYT01", "Connection timeout expired" },
+ { "IM001", "Driver does not support this function" },
+ { "IM002", "Data source name not found and no default driver specified" },
+ { "IM003", "Specified driver could not be loaded" },
+ { "IM004", "Driver's SQLAllocHandle on SQL_HANDLE_ENV failed" },
+ { "IM005", "Driver's SQLAllocHandle on SQL_HANDLE_DBC failed" },
+ { "IM006", "Driver's SQLSetConnectAttr failed" },
+ { "IM007", "No data source or driver specified; dialog prohibited" },
+ { "IM008", "Dialog failed" },
+ { "IM009", "Unable to load translation DLL" },
+ { "IM010", "Data source name too long" },
+ { "IM011", "Driver name too long" },
+ { "IM012", "DRIVER keyword syntax error" },
+ { "IM013", "Trace file error" },
+ { "IM014", "Invalid name of File DSN" },
+ { "IM015", "Corrupt file data source" },
+ { "P0000", "Plpgsql error" },
+ { "P0001", "Raise exception" },
+ { "XX000", "Internal error" },
+ { "XX001", "Data corrupted" },
+ { "XX002", "Index corrupted" }
+};
+
+void pdo_sqlstate_fini_error_table(void)
+{
+ zend_hash_destroy(&err_hash);
+}
+
+int pdo_sqlstate_init_error_table(void)
+{
+ int i;
+ struct pdo_sqlstate_info *info;
+
+ if (FAILURE == zend_hash_init(&err_hash,
+ sizeof(err_initializer)/sizeof(err_initializer[0]), NULL, NULL, 1)) {
+ return FAILURE;
+ }
+
+ for (i = 0; i < sizeof(err_initializer)/sizeof(err_initializer[0]); i++) {
+ info = &err_initializer[i];
+
+ zend_hash_add(&err_hash, info->state, sizeof(info->state), &info, sizeof(info), NULL);
+ }
+
+ return SUCCESS;
+}
+
+const char *pdo_sqlstate_state_to_description(char *state)
+{
+ struct pdo_sqlstate_info **info;
+ if (SUCCESS == zend_hash_find(&err_hash, state, sizeof(err_initializer[0].state),
+ (void**)&info)) {
+ return (*info)->desc;
+ }
+ return NULL;
+}
+
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
new file mode 100755
index 0000000000..a6f7d1f826
--- /dev/null
+++ b/ext/pdo/pdo_stmt.c
@@ -0,0 +1,2499 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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 Statement Handle Class */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_var.h"
+#include "php_pdo.h"
+#include "php_pdo_driver.h"
+#include "php_pdo_int.h"
+#include "zend_exceptions.h"
+#include "zend_interfaces.h"
+#include "php_memory_streams.h"
+
+#if COMPILE_DL_PDO
+/* {{{ content from zend_arg_defs.c:
+ * since it is a .c file, it won't be installed for use by PECL extensions, so we include it here. */
+ZEND_BEGIN_ARG_INFO(first_arg_force_ref, 0)
+ ZEND_ARG_PASS_INFO(1)
+ZEND_END_ARG_INFO();
+
+
+ZEND_BEGIN_ARG_INFO(second_arg_force_ref, 0)
+ ZEND_ARG_PASS_INFO(0)
+ ZEND_ARG_PASS_INFO(1)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(third_arg_force_ref, 0)
+ ZEND_ARG_PASS_INFO(0)
+ ZEND_ARG_PASS_INFO(0)
+ ZEND_ARG_PASS_INFO(1)
+ZEND_END_ARG_INFO();
+
+
+ZEND_BEGIN_ARG_INFO(fourth_arg_force_ref, 0)
+ ZEND_ARG_PASS_INFO(0)
+ ZEND_ARG_PASS_INFO(0)
+ ZEND_ARG_PASS_INFO(0)
+ ZEND_ARG_PASS_INFO(1)
+ZEND_END_ARG_INFO();
+
+ZEND_BEGIN_ARG_INFO(all_args_by_ref, 1)
+ZEND_END_ARG_INFO();
+/* }}} */
+#endif
+
+#define PHP_STMT_GET_OBJ \
+ pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); \
+ if (!stmt->dbh) { \
+ RETURN_FALSE; \
+ } \
+
+static PHP_FUNCTION(dbstmt_constructor) /* {{{ */
+{
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "You should not create a PDOStatement manually");
+}
+/* }}} */
+
+static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC) /* {{{ */
+{
+ if (stmt->bound_param_map) {
+ /* rewriting :name to ? style.
+ * We need to fixup the parameter numbers on the parameters.
+ * If we find that a given named parameter has been used twice,
+ * we will raise an error, as we can't be sure that it is safe
+ * to bind multiple parameters onto the same zval in the underlying
+ * driver */
+ char *name;
+ int position = 0;
+
+ if (stmt->named_rewrite_template) {
+ /* this is not an error here */
+ return 1;
+ }
+ if (!param->name) {
+ /* do the reverse; map the parameter number to the name */
+ if (SUCCESS == zend_hash_index_find(stmt->bound_param_map, param->paramno, (void**)&name)) {
+ param->name = estrdup(name);
+ param->namelen = strlen(param->name);
+ return 1;
+ }
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
+ return 0;
+ }
+
+ zend_hash_internal_pointer_reset(stmt->bound_param_map);
+ while (SUCCESS == zend_hash_get_current_data(stmt->bound_param_map, (void**)&name)) {
+ if (strcmp(name, param->name)) {
+ position++;
+ zend_hash_move_forward(stmt->bound_param_map);
+ continue;
+ }
+ if (param->paramno >= 0) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO refuses to handle repeating the same :named parameter for multiple positions with this driver, as it might be unsafe to do so. Consider using a separate name for each parameter instead" TSRMLS_CC);
+ return -1;
+ }
+ param->paramno = position;
+ return 1;
+ }
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
+ return 0;
+ }
+ return 1;
+}
+/* }}} */
+
+/* trigger callback hook for parameters */
+static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
+{
+ int ret = 1, is_param = 1;
+ struct pdo_bound_param_data *param;
+ HashTable *ht;
+
+ if (!stmt->methods->param_hook) {
+ return 1;
+ }
+
+ ht = stmt->bound_params;
+
+iterate:
+ if (ht) {
+ zend_hash_internal_pointer_reset(ht);
+ while (SUCCESS == zend_hash_get_current_data(ht, (void**)&param)) {
+ if (!stmt->methods->param_hook(stmt, param, event_type TSRMLS_CC)) {
+ ret = 0;
+ break;
+ }
+
+ zend_hash_move_forward(ht);
+ }
+ }
+ if (ret && is_param) {
+ ht = stmt->bound_columns;
+ is_param = 0;
+ goto iterate;
+ }
+
+ return ret;
+}
+/* }}} */
+
+int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ int col;
+
+ stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
+
+ for (col = 0; col < stmt->column_count; col++) {
+ if (!stmt->methods->describer(stmt, col TSRMLS_CC)) {
+ return 0;
+ }
+
+ /* if we are applying case conversions on column names, do so now */
+ if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
+ char *s = stmt->columns[col].name;
+
+ switch (stmt->dbh->desired_case) {
+ case PDO_CASE_UPPER:
+ while (*s != '\0') {
+ *s = toupper(*s);
+ s++;
+ }
+ break;
+ case PDO_CASE_LOWER:
+ while (*s != '\0') {
+ *s = tolower(*s);
+ s++;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+#if 0
+ /* update the column index on named bound parameters */
+ if (stmt->bound_params) {
+ struct pdo_bound_param_data *param;
+
+ if (SUCCESS == zend_hash_find(stmt->bound_params, stmt->columns[col].name,
+ stmt->columns[col].namelen, (void**)&param)) {
+ param->paramno = col;
+ }
+ }
+#endif
+ if (stmt->bound_columns) {
+ struct pdo_bound_param_data *param;
+
+ if (SUCCESS == zend_hash_find(stmt->bound_columns, stmt->columns[col].name,
+ stmt->columns[col].namelen, (void**)&param)) {
+ param->paramno = col;
+ }
+ }
+
+ }
+ return 1;
+}
+/* }}} */
+
+static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC) /* {{{ */
+{
+ if (Z_TYPE(stmt->lazy_object_ref) == IS_NULL) {
+ Z_TYPE(stmt->lazy_object_ref) = IS_OBJECT;
+ Z_OBJ_HANDLE(stmt->lazy_object_ref) = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_row_free_storage, NULL TSRMLS_CC);
+ Z_OBJ_HT(stmt->lazy_object_ref) = &pdo_row_object_handlers;
+ /* stmt->refcount++; */
+ }
+ Z_TYPE_P(return_value) = IS_OBJECT;
+ Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE(stmt->lazy_object_ref);
+ Z_OBJ_HT_P(return_value) = Z_OBJ_HT(stmt->lazy_object_ref);
+ zend_objects_store_add_ref(return_value TSRMLS_CC);
+}
+/* }}} */
+
+static void param_dtor(void *data) /* {{{ */
+{
+ struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)data;
+ TSRMLS_FETCH();
+
+ /* tell the driver that it is going away */
+ if (param->stmt->methods->param_hook) {
+ param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE TSRMLS_CC);
+ }
+
+ if (param->name) {
+ efree(param->name);
+ }
+
+ zval_ptr_dtor(&(param->parameter));
+ if (param->driver_params) {
+ zval_ptr_dtor(&(param->driver_params));
+ }
+}
+/* }}} */
+
+static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param TSRMLS_DC) /* {{{ */
+{
+ HashTable *hash;
+ struct pdo_bound_param_data *pparam = NULL;
+
+ hash = is_param ? stmt->bound_params : stmt->bound_columns;
+
+ if (!hash) {
+ ALLOC_HASHTABLE(hash);
+ zend_hash_init(hash, 13, NULL, param_dtor, 0);
+
+ if (is_param) {
+ stmt->bound_params = hash;
+ } else {
+ stmt->bound_columns = hash;
+ }
+ }
+
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
+ convert_to_string(param->parameter);
+ }
+
+ param->stmt = stmt;
+ param->is_param = is_param;
+
+ ZVAL_ADDREF(param->parameter);
+ if (param->driver_params) {
+ ZVAL_ADDREF(param->driver_params);
+ }
+
+ if (!is_param && param->name && stmt->columns) {
+ /* try to map the name to the column */
+ int i;
+
+ for (i = 0; i < stmt->column_count; i++) {
+ if (strcmp(stmt->columns[i].name, param->name) == 0) {
+ param->paramno = i;
+ break;
+ }
+ }
+
+ /* if you prepare and then execute passing an array of params keyed by names,
+ * then this will trigger, and we don't want that */
+ if (param->paramno == -1) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Did not found column name '%s' in the defined columns; it will not be bound", param->name);
+ }
+ }
+
+ if (param->name) {
+ if (is_param && param->name[0] != ':') {
+ char *temp = emalloc(++param->namelen + 1);
+ temp[0] = ':';
+ memmove(temp+1, param->name, param->namelen);
+ param->name = temp;
+ } else {
+ param->name = estrndup(param->name, param->namelen);
+ }
+ }
+
+ if (is_param && !rewrite_name_to_position(stmt, param TSRMLS_CC)) {
+ if (param->name) {
+ efree(param->name);
+ param->name = NULL;
+ }
+ return 0;
+ }
+
+ /* tell the driver we just created a parameter */
+ if (stmt->methods->param_hook) {
+ if (!stmt->methods->param_hook(stmt, param,
+ PDO_PARAM_EVT_ALLOC TSRMLS_CC)) {
+ return 0;
+ }
+ }
+
+ if (param->paramno >= 0) {
+ zend_hash_index_del(hash, param->paramno);
+ }
+
+ if (param->name) {
+ zend_hash_update(hash, param->name, param->namelen, param, sizeof(*param), (void**)&pparam);
+ } else {
+ zend_hash_index_update(hash, param->paramno, param, sizeof(*param), (void**)&pparam);
+ }
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ proto bool PDOStatement::execute([array $bound_input_params])
+ Execute a prepared statement, optionally binding parameters */
+static PHP_METHOD(PDOStatement, execute)
+{
+ zval *input_params = NULL;
+ int ret = 1;
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &input_params)) {
+ RETURN_FALSE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+
+ if (input_params) {
+ struct pdo_bound_param_data param;
+ zval **tmp;
+ uint str_length;
+ ulong num_index;
+
+ zend_hash_internal_pointer_reset(Z_ARRVAL_P(input_params));
+ while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(input_params), (void*)&tmp)) {
+ memset(&param, 0, sizeof(param));
+
+ if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_P(input_params),
+ &param.name, &str_length, &num_index, 0, NULL)) {
+ /* yes this is correct. we don't want to count the null byte. ask wez */
+ param.namelen = str_length - 1;
+ param.paramno = -1;
+ } else {
+ /* we're okay to be zero based here */
+ if (num_index < 0) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ param.paramno = num_index;
+ }
+
+ param.param_type = PDO_PARAM_STR;
+ MAKE_STD_ZVAL(param.parameter);
+ *param.parameter = **tmp;
+ zval_copy_ctor(param.parameter);
+ INIT_PZVAL(param.parameter);
+
+ if (!really_register_bound_param(&param, stmt, 1 TSRMLS_CC)) {
+ zval_ptr_dtor(&param.parameter);
+ RETURN_FALSE;
+ }
+ zval_ptr_dtor(&param.parameter);
+
+ zend_hash_move_forward(Z_ARRVAL_P(input_params));
+ }
+ }
+
+ if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
+ /* handle the emulated parameter binding,
+ * stmt->active_query_string holds the query with binds expanded and
+ * quoted.
+ */
+
+ ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
+ &stmt->active_query_string, &stmt->active_query_stringlen TSRMLS_CC);
+
+ if (ret == 0) {
+ /* no changes were made */
+ stmt->active_query_string = stmt->query_string;
+ stmt->active_query_stringlen = stmt->query_stringlen;
+ } else if (ret == -1) {
+ /* something broke */
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+ }
+ } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+ }
+ if (stmt->methods->executer(stmt TSRMLS_CC)) {
+ if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
+ efree(stmt->active_query_string);
+ }
+ stmt->active_query_string = NULL;
+ if (!stmt->executed) {
+ /* this is the first execute */
+
+ if (stmt->dbh->alloc_own_columns) {
+ /* for "big boy" drivers, we need to allocate memory to fetch
+ * the results into, so lets do that now */
+ ret = pdo_stmt_describe_columns(stmt TSRMLS_CC);
+ }
+
+ stmt->executed = 1;
+ }
+
+ if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ RETURN_BOOL(ret);
+ }
+ if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
+ efree(stmt->active_query_string);
+ }
+ stmt->active_query_string = NULL;
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+}
+/* }}} */
+
+static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override TSRMLS_DC) /* {{{ */
+{
+ struct pdo_column_data *col;
+ char *value = NULL;
+ unsigned long value_len = 0;
+ int caller_frees = 0;
+ int type, new_type;
+
+ col = &stmt->columns[colno];
+ type = PDO_PARAM_TYPE(col->param_type);
+ new_type = type_override ? PDO_PARAM_TYPE(*type_override) : type;
+
+ value = NULL;
+ value_len = 0;
+
+ stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees TSRMLS_CC);
+
+ switch (type) {
+ case PDO_PARAM_INT:
+ if (value && value_len == sizeof(long)) {
+ ZVAL_LONG(dest, *(long*)value);
+ break;
+ }
+ ZVAL_NULL(dest);
+ break;
+
+ case PDO_PARAM_BOOL:
+ if (value && value_len == sizeof(zend_bool)) {
+ ZVAL_BOOL(dest, *(zend_bool*)value);
+ break;
+ }
+ ZVAL_NULL(dest);
+ break;
+
+ case PDO_PARAM_LOB:
+ if (value == NULL) {
+ ZVAL_NULL(dest);
+ } else if (value_len == 0) {
+ if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) {
+ char *buf = NULL;
+ size_t len;
+ len = php_stream_copy_to_mem((php_stream*)value, &buf, PHP_STREAM_COPY_ALL, 0);
+ ZVAL_STRINGL(dest, buf, len, 0);
+ php_stream_close((php_stream*)value);
+ } else {
+ php_stream_to_zval((php_stream*)value, dest);
+ }
+ } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
+ /* they gave us a string, but LOBs are represented as streams in PDO */
+ php_stream *stm;
+#ifdef TEMP_STREAM_TAKE_BUFFER
+ if (caller_frees) {
+ stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
+ if (stm) {
+ caller_frees = 0;
+ }
+ } else
+#endif
+ {
+ stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
+ }
+ if (stm) {
+ php_stream_to_zval(stm, dest);
+ } else {
+ ZVAL_NULL(dest);
+ }
+ } else {
+ ZVAL_STRINGL(dest, value, value_len, !caller_frees);
+ if (caller_frees) {
+ caller_frees = 0;
+ }
+ }
+ break;
+
+ case PDO_PARAM_STR:
+ if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
+ ZVAL_STRINGL(dest, value, value_len, !caller_frees);
+ if (caller_frees) {
+ caller_frees = 0;
+ }
+ break;
+ }
+ default:
+ ZVAL_NULL(dest);
+ }
+
+ if (type != new_type) {
+ switch (new_type) {
+ case PDO_PARAM_INT:
+ convert_to_long_ex(&dest);
+ break;
+ case PDO_PARAM_BOOL:
+ convert_to_boolean_ex(&dest);
+ break;
+ case PDO_PARAM_STR:
+ convert_to_string_ex(&dest);
+ break;
+ case PDO_PARAM_NULL:
+ convert_to_null_ex(&dest);
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (caller_frees && value) {
+ efree(value);
+ }
+
+ if (stmt->dbh->stringify) {
+ switch (Z_TYPE_P(dest)) {
+ case IS_LONG:
+ case IS_DOUBLE:
+ convert_to_string(dest);
+ break;
+ }
+ }
+
+ if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
+ ZVAL_EMPTY_STRING(dest);
+ }
+}
+/* }}} */
+
+static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,
+ long offset, int do_bind TSRMLS_DC) /* {{{ */
+{
+ if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE TSRMLS_CC)) {
+ return 0;
+ }
+
+ if (!stmt->methods->fetcher(stmt, ori, offset TSRMLS_CC)) {
+ return 0;
+ }
+
+ /* some drivers might need to describe the columns now */
+ if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) {
+ return 0;
+ }
+
+ if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST TSRMLS_CC)) {
+ return 0;
+ }
+
+ if (do_bind && stmt->bound_columns) {
+ /* update those bound column variables now */
+ struct pdo_bound_param_data *param;
+
+ zend_hash_internal_pointer_reset(stmt->bound_columns);
+ while (SUCCESS == zend_hash_get_current_data(stmt->bound_columns, (void**)&param)) {
+ if (param->paramno >= 0) {
+ convert_to_string(param->parameter);
+
+ /* delete old value */
+ zval_dtor(param->parameter);
+
+ /* set new value */
+ fetch_value(stmt, param->parameter, param->paramno, (int *)&param->param_type TSRMLS_CC);
+
+ /* TODO: some smart thing that avoids duplicating the value in the
+ * general loop below. For now, if you're binding output columns,
+ * it's better to use LAZY or BOUND fetches if you want to shave
+ * off those cycles */
+ }
+
+ zend_hash_move_forward(stmt->bound_columns);
+ }
+ }
+
+ return 1;
+}
+/* }}} */
+
+static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ zend_class_entry * ce = stmt->fetch.cls.ce;
+ zend_fcall_info * fci = &stmt->fetch.cls.fci;
+ zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
+
+ fci->size = sizeof(zend_fcall_info);
+
+ if (!ce) {
+ stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
+ }
+
+ if (ce->constructor) {
+ fci->function_table = &ce->function_table;
+ fci->function_name = NULL;
+ fci->symbol_table = NULL;
+ fci->retval_ptr_ptr = &stmt->fetch.cls.retval_ptr;
+ if (stmt->fetch.cls.ctor_args) {
+ HashTable *ht = Z_ARRVAL_P(stmt->fetch.cls.ctor_args);
+ Bucket *p;
+
+ fci->param_count = 0;
+ fci->params = safe_emalloc(sizeof(zval**), ht->nNumOfElements, 0);
+ p = ht->pListHead;
+ while (p != NULL) {
+ fci->params[fci->param_count++] = (zval**)p->pData;
+ p = p->pListNext;
+ }
+ } else {
+ fci->param_count = 0;
+ fci->params = NULL;
+ }
+ fci->no_separation = 1;
+
+ fcc->initialized = 1;
+ fcc->function_handler = ce->constructor;
+ fcc->calling_scope = EG(scope);
+ return 1;
+ } else if (stmt->fetch.cls.ctor_args) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not have a constructor, use NULL for the ctor_params parameter, or simply omit it" TSRMLS_CC);
+ return 0;
+ } else {
+ return 1; /* no ctor no args is also ok */
+ }
+}
+/* }}} */
+
+static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args TSRMLS_DC) /* {{{ */
+{
+ zval **object = NULL, **method;
+ char *fname, *cname;
+ zend_class_entry * ce = NULL, **pce;
+ zend_function *function_handler;
+
+ if (Z_TYPE_P(callable) == IS_ARRAY) {
+ if (Z_ARRVAL_P(callable)->nNumOfElements < 2) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC);
+ return 0;
+ }
+ object = (zval**)Z_ARRVAL_P(callable)->pListHead->pData;
+ method = (zval**)Z_ARRVAL_P(callable)->pListHead->pListNext->pData;
+
+ if (Z_TYPE_PP(object) == IS_STRING) { /* static call */
+ object = NULL;
+ } else if (Z_TYPE_PP(object) == IS_OBJECT) { /* object call */
+ ce = Z_OBJCE_PP(object);
+ } else {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback; bogus object/class name" TSRMLS_CC);
+ return 0;
+ }
+
+ if (Z_TYPE_PP(method) != IS_STRING) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback; bogus method name" TSRMLS_CC);
+ return 0;
+ }
+ }
+
+ if (!zend_is_callable(callable, 0, &fname)) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC);
+ return 0;
+ }
+
+ /* ATM we do not support array($obj, "CLASS::FUNC") or "CLASS_FUNC" */
+ cname = fname;
+ if ((fname = strstr(fname, "::")) == NULL) {
+ fname = cname;
+ cname = NULL;
+ } else {
+ *fname = '\0';
+ fname += 2;
+ }
+ if (cname) {
+ if (zend_lookup_class(cname, strlen(cname), &pce TSRMLS_CC) == FAILURE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not exist" TSRMLS_CC);
+ return 0;
+ } else {
+ if (ce) {
+ /* pce must be base of ce or ce itself */
+ if (ce != *pce && !instanceof_function(ce, *pce TSRMLS_CC)) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class has bogus lineage" TSRMLS_CC);
+ return 0;
+ }
+ }
+ ce = *pce;
+ }
+ }
+
+ zend_str_tolower_copy(fname, fname, strlen(fname));
+ fci->function_table = ce ? &ce->function_table : EG(function_table);
+ if (zend_hash_find(fci->function_table, fname, strlen(fname)+1, (void **)&function_handler) == FAILURE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function does not exist" TSRMLS_CC);
+ return 0;
+ }
+ efree(cname ? cname : fname);
+
+ fci->size = sizeof(zend_fcall_info);
+ fci->function_name = NULL;
+ fci->symbol_table = NULL;
+ fci->param_count = num_args; /* probably less */
+ fci->params = safe_emalloc(sizeof(zval**), num_args, 0);
+ fci->object_pp = object;
+
+ fcc->initialized = 1;
+ fcc->function_handler = function_handler;
+ fcc->calling_scope = EG(scope);
+ fcc->object_pp = object;
+
+ return 1;
+}
+/* }}} */
+
+static int do_fetch_func_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ zend_fcall_info * fci = &stmt->fetch.cls.fci;
+ zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
+
+ if (!make_callable_ex(stmt, stmt->fetch.func.function, fci, fcc, stmt->column_count TSRMLS_CC)) {
+ return 0;
+ } else {
+ stmt->fetch.func.values = safe_emalloc(sizeof(zval*), stmt->column_count, 0);
+ return 1;
+ }
+}
+/* }}} */
+
+static int do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs TSRMLS_DC) /* {{{ */
+{
+ /* fci.size is used to check if it is valid */
+ if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
+ efree(stmt->fetch.cls.fci.params);
+ stmt->fetch.cls.fci.params = NULL;
+ }
+ stmt->fetch.cls.fci.size = 0;
+ if (stmt->fetch.cls.ctor_args && free_ctor_agrs) {
+ zval_ptr_dtor(&stmt->fetch.cls.ctor_args);
+ stmt->fetch.cls.ctor_args = NULL;
+ stmt->fetch.cls.fci.param_count = 0;
+ }
+ if (stmt->fetch.func.values) {
+ FREE_ZVAL(stmt->fetch.func.values);
+ stmt->fetch.func.values = NULL;
+ }
+ return 1;
+}
+/* }}} */
+
+/* perform a fetch. If do_bind is true, update any bound columns.
+ * If return_value is not null, store values into it according to HOW. */
+static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
+ enum pdo_fetch_type how, enum pdo_fetch_orientation ori, long offset, zval *return_all TSRMLS_DC) /* {{{ */
+{
+ int flags = how & PDO_FETCH_FLAGS, idx, old_arg_count;
+ zend_class_entry * ce, * old_ce;
+ zval grp_val, *grp, **pgrp, *retval, *old_ctor_args;
+
+ how = how & ~PDO_FETCH_FLAGS;
+ if (how == PDO_FETCH_USE_DEFAULT) {
+ how = stmt->default_fetch_type;
+ }
+
+ if (!do_fetch_common(stmt, ori, offset, do_bind TSRMLS_CC)) {
+ return 0;
+ }
+
+ if (how == PDO_FETCH_BOUND) {
+ RETVAL_TRUE;
+ return 1;
+ }
+
+ if (return_value) {
+ int i = 0;
+
+ if (how == PDO_FETCH_LAZY) {
+ get_lazy_object(stmt, return_value TSRMLS_CC);
+ return 1;
+ }
+
+ RETVAL_FALSE;
+
+ switch (how) {
+ case PDO_FETCH_ASSOC:
+ case PDO_FETCH_BOTH:
+ case PDO_FETCH_NUM:
+ case PDO_FETCH_NAMED:
+ array_init(return_value);
+ break;
+
+ case PDO_FETCH_COLUMN:
+ if (stmt->fetch.column >= 0 && stmt->fetch.column < stmt->column_count) {
+ fetch_value(stmt, return_value, stmt->fetch.column, NULL TSRMLS_CC);
+ if (!return_all) {
+ return 1;
+ } else {
+ break;
+ }
+ }
+ return 0;
+
+ case PDO_FETCH_OBJ:
+ object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
+ break;
+
+ case PDO_FETCH_CLASS:
+ if (flags & PDO_FETCH_CLASSTYPE) {
+ zval val;
+ zend_class_entry **cep;
+
+ old_ce = stmt->fetch.cls.ce;
+ old_ctor_args = stmt->fetch.cls.ctor_args;
+ old_arg_count = stmt->fetch.cls.fci.param_count;
+ do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
+
+ INIT_PZVAL(&val);
+ fetch_value(stmt, &val, i++, NULL TSRMLS_CC);
+ if (Z_TYPE(val) != IS_NULL) {
+ convert_to_string(&val);
+ if (zend_lookup_class(Z_STRVAL(val), Z_STRLEN(val), &cep TSRMLS_CC) == FAILURE) {
+ stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
+ } else {
+ stmt->fetch.cls.ce = *cep;
+ }
+ }
+
+ do_fetch_class_prepare(stmt TSRMLS_CC);
+ zval_dtor(&val);
+ }
+ ce = stmt->fetch.cls.ce;
+ if ((flags & PDO_FETCH_SERIALIZE) == 0) {
+ object_init_ex(return_value, ce);
+ if (!stmt->fetch.cls.fci.size) {
+ if (!do_fetch_class_prepare(stmt TSRMLS_CC))
+ {
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case PDO_FETCH_INTO:
+ if (!stmt->fetch.into) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified." TSRMLS_CC);
+ return 0;
+ break;
+ }
+
+ Z_TYPE_P(return_value) = IS_OBJECT;
+ Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE_P(stmt->fetch.into);
+ Z_OBJ_HT_P(return_value) = Z_OBJ_HT_P(stmt->fetch.into);
+ zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
+
+ if (zend_get_class_entry(return_value TSRMLS_CC) == ZEND_STANDARD_CLASS_DEF_PTR) {
+ how = PDO_FETCH_OBJ;
+ }
+ break;
+
+ case PDO_FETCH_FUNC:
+ if (!stmt->fetch.func.fci.size) {
+ if (!do_fetch_func_prepare(stmt TSRMLS_CC))
+ {
+ return 0;
+ }
+ }
+ break;
+
+
+ default:
+ /* shouldn't happen */
+ return 0;
+ }
+
+ if (return_all) {
+ INIT_PZVAL(&grp_val);
+ fetch_value(stmt, &grp_val, i, NULL TSRMLS_CC);
+ convert_to_string(&grp_val);
+ if (how == PDO_FETCH_COLUMN) {
+ i = stmt->column_count; /* no more data to fetch */
+ } else {
+ i++;
+ }
+ }
+
+ for (idx = 0; i < stmt->column_count; i++, idx++) {
+ zval *val;
+ MAKE_STD_ZVAL(val);
+ fetch_value(stmt, val, i, NULL TSRMLS_CC);
+
+ switch (how) {
+ case PDO_FETCH_ASSOC:
+ add_assoc_zval(return_value, stmt->columns[i].name, val);
+ break;
+
+ case PDO_FETCH_BOTH:
+ add_assoc_zval(return_value, stmt->columns[i].name, val);
+ ZVAL_ADDREF(val);
+ add_next_index_zval(return_value, val);
+ break;
+
+ case PDO_FETCH_NAMED:
+ /* already have an item with this name? */
+ {
+ zval **curr_val = NULL;
+ if (zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name,
+ strlen(stmt->columns[i].name)+1,
+ (void**)&curr_val) == SUCCESS) {
+ zval *arr;
+ if (Z_TYPE_PP(curr_val) != IS_ARRAY) {
+ /* a little bit of black magic here:
+ * we're creating a new array and swapping it for the
+ * zval that's already stored in the hash under the name
+ * we want. We then add that zval to the array.
+ * This is effectively the same thing as:
+ * if (!is_array($hash[$name])) {
+ * $hash[$name] = array($hash[$name]);
+ * }
+ * */
+ zval *cur;
+
+ MAKE_STD_ZVAL(arr);
+ array_init(arr);
+
+ cur = *curr_val;
+ *curr_val = arr;
+
+ add_next_index_zval(arr, cur);
+ } else {
+ arr = *curr_val;
+ }
+ add_next_index_zval(arr, val);
+ } else {
+ add_assoc_zval(return_value, stmt->columns[i].name, val);
+ }
+ }
+ break;
+
+ case PDO_FETCH_NUM:
+ add_next_index_zval(return_value, val);
+ break;
+
+ case PDO_FETCH_OBJ:
+ case PDO_FETCH_INTO:
+ zend_update_property(NULL, return_value,
+ stmt->columns[i].name, stmt->columns[i].namelen,
+ val TSRMLS_CC);
+ zval_ptr_dtor(&val);
+ break;
+
+ case PDO_FETCH_CLASS:
+ if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
+ zend_update_property(ce, return_value,
+ stmt->columns[i].name, stmt->columns[i].namelen,
+ val TSRMLS_CC);
+ zval_ptr_dtor(&val);
+ } else {
+#ifdef MBO_0
+ php_unserialize_data_t var_hash;
+
+ PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ if (php_var_unserialize(&return_value, (const unsigned char**)&Z_STRVAL_P(val), Z_STRVAL_P(val)+Z_STRLEN_P(val), NULL TSRMLS_CC) == FAILURE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize data" TSRMLS_CC);
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ return 0;
+ }
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+#endif
+#if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
+ if (!ce->unserialize) {
+ zval_ptr_dtor(&val);
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
+ return 0;
+ } else if (ce->unserialize(&return_value, ce, Z_TYPE_P(val) == IS_STRING ? Z_STRVAL_P(val) : "", Z_TYPE_P(val) == IS_STRING ? Z_STRLEN_P(val) : 0, NULL TSRMLS_CC) == FAILURE) {
+ zval_ptr_dtor(&val);
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
+ zval_dtor(return_value);
+ ZVAL_NULL(return_value);
+ return 0;
+ } else {
+ zval_ptr_dtor(&val);
+ }
+#endif
+ }
+ break;
+
+ case PDO_FETCH_FUNC:
+ stmt->fetch.func.values[idx] = val;
+ stmt->fetch.cls.fci.params[idx] = &stmt->fetch.func.values[idx];
+ break;
+
+ default:
+ zval_ptr_dtor(&val);
+ pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC);
+ return 0;
+ break;
+ }
+ }
+
+ switch (how) {
+ case PDO_FETCH_CLASS:
+ if (ce->constructor) {
+ stmt->fetch.cls.fci.object_pp = &return_value;
+ stmt->fetch.cls.fcc.object_pp = &return_value;
+ if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
+ return 0;
+ } else {
+ if (stmt->fetch.cls.retval_ptr) {
+ zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
+ }
+ }
+ }
+ if (flags & PDO_FETCH_CLASSTYPE) {
+ do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
+ stmt->fetch.cls.ce = old_ce;
+ stmt->fetch.cls.ctor_args = old_ctor_args;
+ stmt->fetch.cls.fci.param_count = old_arg_count;
+ }
+ break;
+
+ case PDO_FETCH_FUNC:
+ stmt->fetch.func.fci.param_count = idx;
+ stmt->fetch.func.fci.retval_ptr_ptr = &retval;
+ if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc TSRMLS_CC) == FAILURE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function" TSRMLS_CC);
+ return 0;
+ } else {
+ if (return_all) {
+ zval_ptr_dtor(&return_value); /* we don't need that */
+ return_value = retval;
+ } else {
+ *return_value = *retval;
+ zval_copy_ctor(return_value);
+ INIT_PZVAL(return_value);
+ zval_ptr_dtor(&retval);
+ }
+ }
+ while(idx--) {
+ zval_ptr_dtor(&stmt->fetch.func.values[idx]);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (return_all) {
+ if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
+ add_assoc_zval(return_all, Z_STRVAL(grp_val), return_value);
+ } else {
+ if (zend_symtable_find(Z_ARRVAL_P(return_all), Z_STRVAL(grp_val), Z_STRLEN(grp_val)+1, (void**)&pgrp) == FAILURE) {
+ MAKE_STD_ZVAL(grp);
+ array_init(grp);
+ add_assoc_zval(return_all, Z_STRVAL(grp_val), grp);
+ } else {
+ grp = *pgrp;
+ }
+ add_next_index_zval(grp, return_value);
+ }
+ zval_dtor(&grp_val);
+ }
+
+ }
+
+ return 1;
+}
+/* }}} */
+
+static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, int mode, int fetch_all TSRMLS_DC) /* {{{ */
+{
+ int flags = mode & PDO_FETCH_FLAGS;
+
+ mode = mode & ~PDO_FETCH_FLAGS;
+
+ if (mode == PDO_FETCH_USE_DEFAULT) {
+ flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
+ mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
+ }
+
+#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1
+ if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO::FETCH_SERIALIZE is not supported in this PHP version" TSRMLS_CC);
+ return 0;
+ }
+#endif
+
+ switch(mode) {
+ case PDO_FETCH_FUNC:
+ if (!fetch_all) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()" TSRMLS_CC);
+ return 0;
+ }
+ return 1;
+
+ case PDO_FETCH_LAZY:
+ if (fetch_all) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()" TSRMLS_CC);
+ return 0;
+ }
+ /* fall through */
+
+ default:
+ if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
+ return 0;
+ }
+ if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
+ return 0;
+ }
+ if (mode >= PDO_FETCH__MAX) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
+ return 0;
+ }
+ /* no break; */
+
+ case PDO_FETCH_CLASS:
+ return 1;
+ }
+}
+/* }}} */
+
+/* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
+ Fetches the next row and returns it, or false if there are no more rows */
+static PHP_METHOD(PDOStatement, fetch)
+{
+ long how = PDO_FETCH_USE_DEFAULT;
+ long ori = PDO_FETCH_ORI_NEXT;
+ long off = 0;
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lll", &how,
+ &ori, &off)) {
+ RETURN_FALSE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+
+ if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto mixed PDOStatement::fetchObject(string class_name [, NULL|array ctor_args])
+ Fetches the next row and returns it as an object. */
+static PHP_METHOD(PDOStatement, fetchObject)
+{
+ long how = PDO_FETCH_CLASS;
+ long ori = PDO_FETCH_ORI_NEXT;
+ long off = 0;
+ char *class_name;
+ int class_name_len;
+ zend_class_entry *old_ce;
+ zval *old_ctor_args, *ctor_args;
+ int error = 0, old_arg_count;
+
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sz",
+ &class_name, &class_name_len, &ctor_args)) {
+ RETURN_FALSE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+
+ if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ old_ce = stmt->fetch.cls.ce;
+ old_ctor_args = stmt->fetch.cls.ctor_args;
+ old_arg_count = stmt->fetch.cls.fci.param_count;
+
+ do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
+
+ switch(ZEND_NUM_ARGS()) {
+ case 0:
+ stmt->fetch.cls.ce = zend_standard_class_def;
+ break;
+ case 2:
+ if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
+ error = 1;
+ break;
+ }
+ if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
+ ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
+ *stmt->fetch.cls.ctor_args = *ctor_args;
+ zval_copy_ctor(stmt->fetch.cls.ctor_args);
+ } else {
+ stmt->fetch.cls.ctor_args = NULL;
+ }
+ /* no break */
+ case 1:
+ stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
+
+ if (!stmt->fetch.cls.ce) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC);
+ error = 1;
+ break;
+ }
+ }
+
+ if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
+ error = 1;
+ }
+ if (error) {
+ PDO_HANDLE_STMT_ERR();
+ }
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
+
+ stmt->fetch.cls.ce = old_ce;
+ stmt->fetch.cls.ctor_args = old_ctor_args;
+ stmt->fetch.cls.fci.param_count = old_arg_count;
+ if (error) {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string PDOStatement::fetchColumn([int column_number])
+ Returns a data of the specified column in the result set. */
+static PHP_METHOD(PDOStatement, fetchColumn)
+{
+ long col_n = 0;
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
+ RETURN_FALSE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+
+ if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+ }
+
+ fetch_value(stmt, return_value, col_n, NULL TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
+ Returns an array of all of the results. */
+static PHP_METHOD(PDOStatement, fetchAll)
+{
+ long how = PDO_FETCH_USE_DEFAULT;
+ zval *data, *return_all;
+ zval *arg2;
+ zend_class_entry *old_ce;
+ zval *old_ctor_args, *ctor_args = NULL;
+ int error = 0, old_arg_count;
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
+ RETURN_FALSE;
+ }
+
+ if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
+ RETURN_FALSE;
+ }
+
+ old_ce = stmt->fetch.cls.ce;
+ old_ctor_args = stmt->fetch.cls.ctor_args;
+ old_arg_count = stmt->fetch.cls.fci.param_count;
+
+ do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
+
+ switch(how & ~PDO_FETCH_FLAGS) {
+ case PDO_FETCH_CLASS:
+ switch(ZEND_NUM_ARGS()) {
+ case 0:
+ case 1:
+ stmt->fetch.cls.ce = zend_standard_class_def;
+ break;
+ case 3:
+ if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
+ error = 1;
+ break;
+ }
+ if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
+ ctor_args = NULL;
+ }
+ /* no break */
+ case 2:
+ stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */
+ if (Z_TYPE_P(arg2) != IS_STRING) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC);
+ error = 1;
+ break;
+ } else {
+ stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
+ if (!stmt->fetch.cls.ce) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC);
+ error = 1;
+ break;
+ }
+ }
+ }
+ if (!error) {
+ do_fetch_class_prepare(stmt TSRMLS_CC);
+ }
+ break;
+
+ case PDO_FETCH_FUNC:
+ switch(ZEND_NUM_ARGS()) {
+ case 0:
+ case 1:
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified" TSRMLS_CC);
+ error = 1;
+ break;
+ case 3:
+ case 2:
+ stmt->fetch.func.function = arg2;
+ do_fetch_func_prepare(stmt TSRMLS_CC);
+ break;
+ }
+ break;
+
+ case PDO_FETCH_COLUMN:
+ switch(ZEND_NUM_ARGS()) {
+ case 0:
+ case 1:
+ stmt->fetch.column = how & PDO_FETCH_GROUP ? 1 : 0;
+ break;
+ case 2:
+ convert_to_long(arg2);
+ stmt->fetch.column = Z_LVAL_P(arg2);
+ break;
+ case 3:
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN" TSRMLS_CC);
+ error = 1;
+ }
+ break;
+
+ default:
+ if (ZEND_NUM_ARGS() > 1) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC);
+ error = 1;
+ }
+ }
+
+ if (!error) {
+ PDO_STMT_CLEAR_ERR();
+ MAKE_STD_ZVAL(data);
+ if (how & PDO_FETCH_GROUP) {
+ array_init(return_value);
+ return_all = return_value;
+ } else {
+ return_all = 0;
+ }
+ if (!do_fetch(stmt, TRUE, data, how, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
+ FREE_ZVAL(data);
+ error = 2;
+ }
+ }
+ if (!error) {
+ if ((how & PDO_FETCH_GROUP)) {
+ do {
+ MAKE_STD_ZVAL(data);
+ } while (do_fetch(stmt, TRUE, data, how, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
+ } else {
+ array_init(return_value);
+ do {
+ add_next_index_zval(return_value, data);
+ MAKE_STD_ZVAL(data);
+ } while (do_fetch(stmt, TRUE, data, how, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
+ }
+ FREE_ZVAL(data);
+ }
+
+ do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
+
+ stmt->fetch.cls.ce = old_ce;
+ stmt->fetch.cls.ctor_args = old_ctor_args;
+ stmt->fetch.cls.fci.param_count = old_arg_count;
+
+ if (error) {
+ PDO_HANDLE_STMT_ERR();
+ if (error != 2) {
+ RETURN_FALSE;
+ } else { /* on no results, return an empty array */
+ if (Z_TYPE_P(return_value) != IS_ARRAY) {
+ array_init(return_value);
+ }
+ return;
+ }
+ }
+}
+/* }}} */
+
+static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
+{
+ struct pdo_bound_param_data param = {0};
+
+ param.paramno = -1;
+ param.param_type = PDO_PARAM_STR;
+
+ if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
+ "lz|llz!", &param.paramno, &param.parameter, &param.param_type, &param.max_value_len,
+ &param.driver_params)) {
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", &param.name,
+ &param.namelen, &param.parameter, &param.param_type, &param.max_value_len,
+ &param.driver_params)) {
+ return 0;
+ }
+ }
+
+ if (param.paramno > 0) {
+ --param.paramno; /* make it zero-based internally */
+ } else if (!param.name) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
+ return 0;
+ }
+
+ return really_register_bound_param(&param, stmt, is_param TSRMLS_CC);
+} /* }}} */
+
+/* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
+ bind an input parameter to the value of a PHP variable. $paramno is the 1-based position of the placeholder in the SQL statement (but can be the parameter name for drivers that support named placeholders). It should be called prior to execute(). */
+static PHP_METHOD(PDOStatement, bindValue)
+{
+ struct pdo_bound_param_data param = {0};
+ PHP_STMT_GET_OBJ;
+
+ param.paramno = -1;
+ param.param_type = PDO_PARAM_STR;
+
+ if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
+ "lz/|l", &param.paramno, &param.parameter, &param.param_type)) {
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", &param.name,
+ &param.namelen, &param.parameter, &param.param_type)) {
+ RETURN_FALSE;
+ }
+ }
+
+ if (param.paramno > 0) {
+ --param.paramno; /* make it zero-based internally */
+ } else if (!param.name) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ RETURN_BOOL(really_register_bound_param(&param, stmt, TRUE TSRMLS_CC));
+}
+/* }}} */
+
+
+/* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
+ bind a parameter to a PHP variable. $paramno is the 1-based position of the placeholder in the SQL statement (but can be the parameter name for drivers that support named placeholders). This isn't supported by all drivers. It should be called prior to execute(). */
+static PHP_METHOD(PDOStatement, bindParam)
+{
+ PHP_STMT_GET_OBJ;
+ RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
+}
+/* }}} */
+
+/* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
+ bind a column to a PHP variable. On each row fetch $param will contain the value of the corresponding column. $column is the 1-based offset of the column, or the column name. For portability, don't call this before execute(). */
+static PHP_METHOD(PDOStatement, bindColumn)
+{
+ PHP_STMT_GET_OBJ;
+ RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, FALSE));
+}
+/* }}} */
+
+/* {{{ proto int PDOStatement::rowCount()
+ Returns the number of rows in a result set, or the number of rows affected by the last execute(). It is not always meaningful. */
+static PHP_METHOD(PDOStatement, rowCount)
+{
+ PHP_STMT_GET_OBJ;
+
+ RETURN_LONG(stmt->row_count);
+}
+/* }}} */
+
+/* {{{ proto string PDOStatement::errorCode()
+ Fetch the error code associated with the last operation on the statement handle */
+static PHP_METHOD(PDOStatement, errorCode)
+{
+ PHP_STMT_GET_OBJ;
+
+ if (ZEND_NUM_ARGS()) {
+ RETURN_FALSE;
+ }
+
+ RETURN_STRING(stmt->error_code, 1);
+}
+/* }}} */
+
+/* {{{ proto array PDOStatement::errorInfo()
+ Fetch extended error information associated with the last operation on the statement handle */
+static PHP_METHOD(PDOStatement, errorInfo)
+{
+ PHP_STMT_GET_OBJ;
+
+ if (ZEND_NUM_ARGS()) {
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ add_next_index_string(return_value, stmt->error_code, 1);
+
+ if (stmt->dbh->methods->fetch_err) {
+ stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
+ }
+}
+/* }}} */
+
+/* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
+ Set an attribute */
+static PHP_METHOD(PDOStatement, setAttribute)
+{
+ long attr;
+ zval *value = NULL;
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
+ RETURN_FALSE;
+ }
+
+ if (!stmt->methods->set_attribute) {
+ goto fail;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+ if (stmt->methods->set_attribute(stmt, attr, value TSRMLS_CC)) {
+ RETURN_TRUE;
+ }
+
+fail:
+ if (!stmt->methods->set_attribute) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC);
+ } else {
+ PDO_HANDLE_STMT_ERR();
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto mixed PDOStatement::getAttribute(long attribute)
+ Get an attribute */
+static PHP_METHOD(PDOStatement, getAttribute)
+{
+ long attr;
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
+ RETURN_FALSE;
+ }
+
+ if (!stmt->methods->get_attribute) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support getting attributes" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+ switch (stmt->methods->get_attribute(stmt, attr, return_value TSRMLS_CC)) {
+ case -1:
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+
+ case 0:
+ /* XXX: should do something better here */
+ pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support getting that attribute" TSRMLS_CC);
+ RETURN_FALSE;
+
+ default:
+ return;
+ }
+}
+/* }}} */
+
+/* {{{ proto int PDOStatement::columnCount()
+ Returns the number of columns in the result set */
+static PHP_METHOD(PDOStatement, columnCount)
+{
+ PHP_STMT_GET_OBJ;
+ if (ZEND_NUM_ARGS()) {
+ RETURN_FALSE;
+ }
+ RETURN_LONG(stmt->column_count);
+}
+/* }}} */
+
+/* {{{ proto array PDOStatement::getColumnMeta(int $column)
+ Returns meta data for a numbered column */
+static PHP_METHOD(PDOStatement, getColumnMeta)
+{
+ long colno;
+ struct pdo_column_data *col;
+ PHP_STMT_GET_OBJ;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &colno)) {
+ RETURN_FALSE;
+ }
+ if(colno < 0) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ if (!stmt->methods->get_column_meta) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+ if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value TSRMLS_CC)) {
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+ }
+
+ /* add stock items */
+ col = &stmt->columns[colno];
+ add_assoc_string(return_value, "name", col->name, 1);
+ add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
+ add_assoc_long(return_value, "precision", col->precision);
+ add_assoc_long(return_value, "pdo_type", col->param_type);
+}
+/* }}} */
+
+/* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
+ Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
+
+int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
+{
+ long mode = PDO_FETCH_BOTH;
+ int argc = ZEND_NUM_ARGS() - skip;
+ zval ***args;
+ zend_class_entry **cep;
+
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
+
+ switch (stmt->default_fetch_type) {
+ case PDO_FETCH_INTO:
+ if (stmt->fetch.into) {
+ ZVAL_DELREF(stmt->fetch.into);
+ stmt->fetch.into = NULL;
+ }
+ break;
+ default:
+ ;
+ }
+
+ stmt->default_fetch_type = PDO_FETCH_BOTH;
+
+ if (argc == 0) {
+ return SUCCESS;
+ }
+
+ args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
+
+ if (FAILURE == zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args)) {
+fail_out:
+ efree(args);
+ return FAILURE;
+ }
+
+ convert_to_long_ex(args[skip]);
+ mode = Z_LVAL_PP(args[skip]);
+
+ if (!pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC)) {
+ return FAILURE;
+ }
+
+ switch (mode & ~PDO_FETCH_FLAGS) {
+ case PDO_FETCH_LAZY:
+ case PDO_FETCH_ASSOC:
+ case PDO_FETCH_NUM:
+ case PDO_FETCH_BOTH:
+ case PDO_FETCH_OBJ:
+ case PDO_FETCH_BOUND:
+ case PDO_FETCH_NAMED:
+ break;
+
+ case PDO_FETCH_COLUMN:
+ if (argc != 2) {
+ goto fail_out;
+ }
+ convert_to_long_ex(args[skip+1]);
+ stmt->fetch.column = Z_LVAL_PP(args[skip+1]);
+ break;
+
+ case PDO_FETCH_CLASS:
+ if (argc < 2 || argc > 3) {
+ goto fail_out;
+ }
+ convert_to_string_ex(args[skip+1]);
+
+ if (FAILURE == zend_lookup_class(Z_STRVAL_PP(args[skip+1]),
+ Z_STRLEN_PP(args[skip+1]), &cep TSRMLS_CC)) {
+ goto fail_out;
+ }
+
+ if (!cep || !*cep) {
+ goto fail_out;
+ }
+
+ stmt->fetch.cls.ce = *cep;
+ stmt->fetch.cls.ctor_args = NULL;
+
+ if (stmt->dbh->is_persistent) {
+ /* TODO: CRITICAL for final release */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement. This will be fixed in a later release");
+ }
+
+ if (argc == 3) {
+ if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
+ } else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) {
+ ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
+ *stmt->fetch.cls.ctor_args = **args[skip+2];
+ zval_copy_ctor(stmt->fetch.cls.ctor_args);
+ }
+ }
+
+ do_fetch_class_prepare(stmt TSRMLS_CC);
+ break;
+
+ case PDO_FETCH_INTO:
+ if (argc != 2) {
+ goto fail_out;
+ }
+ if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) {
+ goto fail_out;
+ }
+
+ if (stmt->dbh->is_persistent) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement. This will be fixed in a later release");
+ }
+
+ MAKE_STD_ZVAL(stmt->fetch.into);
+
+ Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
+ Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]);
+ Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
+ zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
+ break;
+
+ default:
+ if ((mode & ~PDO_FETCH_FLAGS) < PDO_FETCH__MAX && (mode & ~PDO_FETCH_FLAGS) >= 0) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "22003", "unhandled mode; this is a PDO bug, please report it" TSRMLS_CC);
+ } else {
+ pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC);
+ }
+ return FAILURE;
+ }
+
+ stmt->default_fetch_type = mode;
+ efree(args);
+
+ return SUCCESS;
+}
+
+static PHP_METHOD(PDOStatement, setFetchMode)
+{
+ PHP_STMT_GET_OBJ;
+
+ RETVAL_BOOL(
+ pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
+ stmt, 0) == SUCCESS ? 1 : 0
+ );
+}
+/* }}} */
+
+/* {{{ proto bool PDOStatement::nextRowset()
+ Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */
+
+static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
+ return 0;
+ }
+
+ /* un-describe */
+ if (stmt->columns) {
+ int i;
+ struct pdo_column_data *cols = stmt->columns;
+
+ for (i = 0; i < stmt->column_count; i++) {
+ efree(cols[i].name);
+ }
+ efree(stmt->columns);
+ stmt->columns = NULL;
+ stmt->column_count = 0;
+ }
+
+ pdo_stmt_describe_columns(stmt TSRMLS_CC);
+
+ return 1;
+}
+
+static PHP_METHOD(PDOStatement, nextRowset)
+{
+ PHP_STMT_GET_OBJ;
+
+ if (!stmt->methods->next_rowset) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+
+ if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+ }
+
+ pdo_stmt_describe_columns(stmt TSRMLS_CC);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool PDOStatement::closeCursor()
+ Closes the cursor, leaving the statement ready for re-execution. */
+static PHP_METHOD(PDOStatement, closeCursor)
+{
+ PHP_STMT_GET_OBJ;
+
+ if (!stmt->methods->cursor_closer) {
+ /* emulate it by fetching and discarding rows */
+ do {
+ while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC))
+ ;
+ if (!stmt->methods->next_rowset) {
+ break;
+ }
+
+ if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
+ break;
+ }
+
+ } while (1);
+ RETURN_TRUE;
+ }
+
+ PDO_STMT_CLEAR_ERR();
+
+ if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
+ PDO_HANDLE_STMT_ERR();
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto void PDOStatement::debugDumpParams()
+ A utility for internals hackers to debug parameter internals */
+static PHP_METHOD(PDOStatement, debugDumpParams)
+{
+ php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
+ HashPosition pos;
+ struct pdo_bound_param_data *param;
+ PHP_STMT_GET_OBJ;
+
+ php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
+ stmt->query_stringlen,
+ stmt->query_stringlen, stmt->query_string);
+
+ php_stream_printf(out TSRMLS_CC, "Params: %d\n",
+ stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
+
+ if (stmt->bound_params) {
+ zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
+ while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
+ (void**)&param, &pos)) {
+ char *str;
+ uint len;
+ ulong num;
+
+ if (zend_hash_get_current_key_ex(stmt->bound_params, &str, &len, &num, 0, &pos) == HASH_KEY_IS_STRING) {
+ php_stream_printf(out TSRMLS_CC, "Key: Position #%d:\n", num);
+ } else {
+ php_stream_printf(out TSRMLS_CC, "Key: Name: [%d] %.*s\n", len, len, str);
+ }
+
+ php_stream_printf(out TSRMLS_CC, "paramno=%d\nname=[%d] %.*s\nis_param=%d\nparam_type=%d\n",
+ param->paramno, param->namelen, param->namelen, param->name,
+ param->is_param,
+ param->param_type);
+
+ }
+ }
+
+ php_stream_close(out);
+}
+/* }}} */
+
+/* {{{ proto int PDOStatement::__wakeup()
+ Prevents use of a PDOStatement instance that has been unserialized */
+static PHP_METHOD(PDOStatement, __wakeup)
+{
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
+}
+/* }}} */
+
+/* {{{ proto int PDOStatement::__sleep()
+ Prevents serialization of a PDOStatement instance */
+static PHP_METHOD(PDOStatement, __sleep)
+{
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
+}
+/* }}} */
+
+function_entry pdo_dbstmt_functions[] = {
+ PHP_ME(PDOStatement, execute, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, fetch, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, bindParam, second_arg_force_ref, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, bindColumn, second_arg_force_ref, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, bindValue, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, rowCount, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, fetchColumn, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, fetchAll, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, fetchObject, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, errorCode, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, errorInfo, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, setAttribute, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, getAttribute, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, columnCount, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, getColumnMeta, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, setFetchMode, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, nextRowset, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, closeCursor, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, debugDumpParams, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDOStatement, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
+ PHP_ME(PDOStatement, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
+ {NULL, NULL, NULL}
+};
+
+/* {{{ overloaded handlers for PDOStatement class */
+static void dbstmt_prop_write(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+ pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
+
+ convert_to_string(member);
+
+ if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
+ } else {
+ std_object_handlers.write_property(object, member, value TSRMLS_CC);
+ }
+}
+
+static void dbstmt_prop_delete(zval *object, zval *member TSRMLS_DC)
+{
+ pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
+
+ convert_to_string(member);
+
+ if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
+ } else {
+ std_object_handlers.unset_property(object, member TSRMLS_CC);
+ }
+}
+
+static union _zend_function *dbstmt_method_get(
+#if PHP_API_VERSION >= 20041225
+ zval **object_pp,
+#else
+ zval *object,
+#endif
+ char *method_name, int method_len TSRMLS_DC)
+{
+ zend_function *fbc = NULL;
+ char *lc_method_name;
+#if PHP_API_VERSION >= 20041225
+ zval *object = *object_pp;
+#endif
+
+ lc_method_name = emalloc(method_len + 1);
+ zend_str_tolower_copy(lc_method_name, method_name, method_len);
+
+ if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name,
+ method_len+1, (void**)&fbc) == FAILURE) {
+ pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
+ /* not a pre-defined method, nor a user-defined method; check
+ * the driver specific methods */
+ if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
+ if (!pdo_hash_methods(stmt->dbh,
+ PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
+ || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
+ goto out;
+ }
+ }
+
+ if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
+ lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
+ fbc = NULL;
+ goto out;
+ }
+ /* got it */
+ }
+
+out:
+ efree(lc_method_name);
+ return fbc;
+}
+
+static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
+{
+ return -1;
+}
+
+zend_object_handlers pdo_dbstmt_object_handlers;
+
+void pdo_stmt_init(TSRMLS_D)
+{
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
+ pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
+ pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
+ zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable);
+ zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
+
+ memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
+ pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
+ pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
+ pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
+ pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
+
+ INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
+ pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
+ pdo_row_ce->create_object = pdo_row_new;
+}
+
+static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ if (stmt->properties) {
+ zend_hash_destroy(stmt->properties);
+ efree(stmt->properties);
+ stmt->properties = NULL;
+ }
+
+ if (stmt->bound_params) {
+ zend_hash_destroy(stmt->bound_params);
+ FREE_HASHTABLE(stmt->bound_params);
+ stmt->bound_params = NULL;
+ }
+ if (stmt->bound_param_map) {
+ zend_hash_destroy(stmt->bound_param_map);
+ FREE_HASHTABLE(stmt->bound_param_map);
+ stmt->bound_param_map = NULL;
+ }
+ if (stmt->bound_columns) {
+ zend_hash_destroy(stmt->bound_columns);
+ FREE_HASHTABLE(stmt->bound_columns);
+ stmt->bound_columns = NULL;
+ }
+
+ if (stmt->methods && stmt->methods->dtor) {
+ stmt->methods->dtor(stmt TSRMLS_CC);
+ }
+ if (stmt->query_string) {
+ efree(stmt->query_string);
+ }
+
+ if (stmt->columns) {
+ int i;
+ struct pdo_column_data *cols = stmt->columns;
+
+ for (i = 0; i < stmt->column_count; i++) {
+ if (cols[i].name) {
+ efree(cols[i].name);
+ cols[i].name = NULL;
+ }
+ }
+ efree(stmt->columns);
+ stmt->columns = NULL;
+ }
+
+ if (stmt->fetch.into && stmt->default_fetch_type == PDO_FETCH_INTO) {
+ FREE_ZVAL(stmt->fetch.into);
+ stmt->fetch.into = NULL;
+ }
+
+ do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
+
+ zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
+ efree(stmt);
+}
+
+PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ stmt->refcount++;
+}
+
+PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ if (--stmt->refcount == 0) {
+ free_statement(stmt TSRMLS_CC);
+ }
+}
+
+void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ php_pdo_stmt_delref(stmt TSRMLS_CC);
+}
+
+zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+ zval *tmp;
+
+ pdo_stmt_t *stmt;
+ stmt = emalloc(sizeof(*stmt));
+ memset(stmt, 0, sizeof(*stmt));
+ stmt->ce = ce;
+ stmt->refcount = 1;
+ ALLOC_HASHTABLE(stmt->properties);
+ zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_copy(stmt->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+
+ retval.handle = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbstmt_free_storage, NULL TSRMLS_CC);
+ retval.handlers = &pdo_dbstmt_object_handlers;
+
+ return retval;
+}
+/* }}} */
+
+/* {{{ statement iterator */
+
+struct php_pdo_iterator {
+ zend_object_iterator iter;
+ pdo_stmt_t *stmt;
+ ulong key;
+ zval *fetch_ahead;
+};
+
+static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
+{
+ struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
+
+ if (--I->stmt->refcount == 0) {
+ free_statement(I->stmt TSRMLS_CC);
+ }
+
+ if (I->fetch_ahead) {
+ zval_ptr_dtor(&I->fetch_ahead);
+ }
+
+ efree(I);
+}
+
+static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC)
+{
+ struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
+
+ return I->fetch_ahead ? SUCCESS : FAILURE;
+}
+
+static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
+{
+ struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
+
+ /* sanity */
+ if (!I->fetch_ahead) {
+ *data = NULL;
+ return;
+ }
+
+ *data = &I->fetch_ahead;
+}
+
+static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
+ ulong *int_key TSRMLS_DC)
+{
+ struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
+
+ if (I->key == (ulong)-1) {
+ return HASH_KEY_NON_EXISTANT;
+ }
+ *int_key = I->key;
+ return HASH_KEY_IS_LONG;
+}
+
+static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
+{
+ struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
+
+ if (I->fetch_ahead) {
+ zval_ptr_dtor(&I->fetch_ahead);
+ I->fetch_ahead = NULL;
+ }
+
+ MAKE_STD_ZVAL(I->fetch_ahead);
+
+ if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
+ PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
+ pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */
+
+ PDO_HANDLE_STMT_ERR();
+ I->key = (ulong)-1;
+ FREE_ZVAL(I->fetch_ahead);
+ I->fetch_ahead = NULL;
+
+ return;
+ }
+
+ I->key++;
+}
+
+static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
+ pdo_stmt_iter_dtor,
+ pdo_stmt_iter_valid,
+ pdo_stmt_iter_get_data,
+ pdo_stmt_iter_get_key,
+ pdo_stmt_iter_move_forwards,
+ NULL
+};
+
+zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC)
+{
+ pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
+ struct php_pdo_iterator *I;
+
+ I = ecalloc(1, sizeof(*I));
+ I->iter.funcs = &pdo_stmt_iter_funcs;
+ I->iter.data = I;
+ I->stmt = stmt;
+ stmt->refcount++;
+
+ MAKE_STD_ZVAL(I->fetch_ahead);
+ if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
+ PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
+ PDO_HANDLE_STMT_ERR();
+ I->key = (ulong)-1;
+ FREE_ZVAL(I->fetch_ahead);
+ I->fetch_ahead = NULL;
+ }
+
+ return &I->iter;
+}
+
+/* }}} */
+
+/* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
+
+function_entry pdo_row_functions[] = {
+ {NULL, NULL, NULL}
+};
+
+static zval *row_prop_or_dim_read(zval *object, zval *member, int type TSRMLS_DC)
+{
+ zval *return_value;
+ pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
+ int colno = -1;
+
+ MAKE_STD_ZVAL(return_value);
+
+ if (Z_TYPE_P(member) == IS_LONG) {
+ if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
+ fetch_value(stmt, return_value, Z_LVAL_P(member), NULL TSRMLS_CC);
+ }
+ } else {
+ convert_to_string(member);
+ /* TODO: replace this with a hash of available column names to column
+ * numbers */
+ for (colno = 0; colno < stmt->column_count; colno++) {
+ if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
+ fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
+ break;
+ }
+ }
+ }
+
+ return_value->refcount = 0;
+ return_value->is_ref = 0;
+
+ return return_value;
+}
+
+static void row_prop_or_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
+}
+
+static int row_prop_or_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
+{
+ pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
+ int colno = -1;
+
+ if (Z_TYPE_P(member) == IS_LONG) {
+ return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
+ } else {
+ convert_to_string(member);
+
+ /* TODO: replace this with a hash of available column names to column
+ * numbers */
+ for (colno = 0; colno < stmt->column_count; colno++) {
+ if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void row_prop_or_dim_delete(zval *object, zval *offset TSRMLS_DC)
+{
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
+}
+
+static HashTable *row_get_properties(zval *object TSRMLS_DC)
+{
+ zval *tmp;
+ pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
+ int i;
+ HashTable *ht;
+
+ MAKE_STD_ZVAL(tmp);
+ array_init(tmp);
+
+ for (i = 0; i < stmt->column_count; i++) {
+ zval *val;
+ MAKE_STD_ZVAL(val);
+ fetch_value(stmt, val, i, NULL TSRMLS_CC);
+
+ add_assoc_zval(tmp, stmt->columns[i].name, val);
+ }
+
+ ht = Z_ARRVAL_P(tmp);
+
+ ZVAL_NULL(tmp);
+ FREE_ZVAL(tmp);
+
+ return ht;
+}
+
+static union _zend_function *row_method_get(
+#if PHP_API_VERSION >= 20041225
+ zval **object_pp,
+#else
+ zval *object,
+#endif
+ char *method_name, int method_len TSRMLS_DC)
+{
+ zend_function *fbc;
+ char *lc_method_name;
+
+ lc_method_name = emalloc(method_len + 1);
+ zend_str_tolower_copy(lc_method_name, method_name, method_len);
+
+ if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
+ efree(lc_method_name);
+ return NULL;
+ }
+
+ efree(lc_method_name);
+ return fbc;
+}
+
+static int row_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
+{
+ return FAILURE;
+}
+
+static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
+{
+ static zend_internal_function ctor = {0};
+
+ ctor.type = ZEND_INTERNAL_FUNCTION;
+ ctor.function_name = "__construct";
+ ctor.scope = pdo_row_ce;
+ ctor.handler = ZEND_FN(dbstmt_constructor);
+
+ return (union _zend_function*)&ctor;
+}
+
+static zend_class_entry *row_get_ce(zval *object TSRMLS_DC)
+{
+ return pdo_dbstmt_ce;
+}
+
+static int row_get_classname(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
+{
+ *class_name = estrndup("PDORow", sizeof("PDORow")-1);
+ *class_name_len = sizeof("PDORow")-1;
+ return 0;
+}
+
+static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
+{
+ return -1;
+}
+
+zend_object_handlers pdo_row_object_handlers = {
+ ZEND_OBJECTS_STORE_HANDLERS,
+ row_prop_or_dim_read,
+ row_prop_or_dim_write,
+ row_prop_or_dim_read,
+ row_prop_or_dim_write,
+ NULL,
+ NULL,
+ NULL,
+ row_prop_or_dim_exists,
+ row_prop_or_dim_delete,
+ row_prop_or_dim_exists,
+ row_prop_or_dim_delete,
+ row_get_properties,
+ row_method_get,
+ row_call_method,
+ row_get_ctor,
+ row_get_ce,
+ row_get_classname,
+ row_compare,
+ NULL, /* cast */
+ NULL
+};
+
+void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
+{
+#if 0
+ ZVAL_NULL(&stmt->lazy_object_ref);
+
+ if (--stmt->refcount == 0) {
+ free_statement(stmt TSRMLS_CC);
+ }
+#endif
+}
+
+zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
+{
+ zend_object_value retval;
+
+ retval.handle = zend_objects_store_put(NULL, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_row_free_storage, NULL TSRMLS_CC);
+ retval.handlers = &pdo_row_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
+ */
diff --git a/ext/pdo/php_pdo.h b/ext/pdo/php_pdo.h
new file mode 100755
index 0000000000..e4bc15943f
--- /dev/null
+++ b/ext/pdo/php_pdo.h
@@ -0,0 +1,91 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PDO_H
+#define PHP_PDO_H
+
+#include "zend.h"
+
+#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)
+#define can_handle_soft_dependency_on_SPL 1
+#endif
+
+extern zend_module_entry pdo_module_entry;
+#define phpext_pdo_ptr &pdo_module_entry
+
+#ifdef PHP_WIN32
+# if defined(PDO_EXPORTS) || (!defined(COMPILE_DL_PDO))
+# define PDO_API __declspec(dllexport)
+# elif defined(COMPILE_DL_PDO)
+# define PDO_API __declspec(dllimport)
+# else
+# define PDO_API /* nothing special */
+# endif
+#else
+# define PDO_API /* nothing special */
+#endif
+
+#ifdef ZTS
+# include "TSRM.h"
+#endif
+
+PHP_MINIT_FUNCTION(pdo);
+PHP_MSHUTDOWN_FUNCTION(pdo);
+PHP_RINIT_FUNCTION(pdo);
+PHP_RSHUTDOWN_FUNCTION(pdo);
+PHP_MINFO_FUNCTION(pdo);
+
+ZEND_BEGIN_MODULE_GLOBALS(pdo)
+ long global_value;
+ZEND_END_MODULE_GLOBALS(pdo)
+
+#ifdef ZTS
+# define PDOG(v) TSRMG(pdo_globals_id, zend_pdo_globals *, v)
+#else
+# define PDOG(v) (pdo_globals.v)
+#endif
+
+PDO_API void php_pdo_declare_long_constant(const char *const_name, size_t name_len, long value TSRMLS_DC);
+PDO_API void php_pdo_declare_stringl_constant(const char *const_name, size_t name_len, const char *value, size_t value_len TSRMLS_DC);
+
+#define REGISTER_PDO_CLASS_CONST_LONG(const_name, value) \
+ php_pdo_declare_long_constant(const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
+
+#define REGISTER_PDO_CLASS_CONST_STRING(const_name, value) \
+ php_pdo_declare_stringl_constant(const_name, sizeof(const_name)-1, value, sizeof(value)-1 TSRMLS_CC);
+
+#define PDO_CONSTRUCT_CHECK \
+ if (!dbh->driver) { \
+ pdo_raise_impl_error(dbh, NULL, "00000", "PDO constructor was not called" TSRMLS_CC); \
+ return; \
+ } \
+
+
+#endif /* PHP_PDO_H */
+
+
+/*
+ * 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
+ */
diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h
new file mode 100755
index 0000000000..38f65d6af2
--- /dev/null
+++ b/ext/pdo/php_pdo_driver.h
@@ -0,0 +1,663 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PDO_DRIVER_H
+#define PHP_PDO_DRIVER_H
+
+#include "php_pdo.h"
+
+/* forward declarations */
+typedef struct _pdo_dbh_t pdo_dbh_t;
+typedef struct _pdo_stmt_t pdo_stmt_t;
+struct pdo_bound_param_data;
+
+#ifdef PHP_WIN32
+typedef __int64 pdo_int64_t;
+typedef unsigned __int64 pdo_uint64_t;
+#else
+typedef long long int pdo_int64_t;
+typedef unsigned long long int pdo_uint64_t;
+#endif
+PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC);
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#define PDO_DRIVER_API 20051128
+
+enum pdo_param_type {
+ PDO_PARAM_NULL,
+
+ /* int as in long (the php native int type).
+ * If you mark a column as an int, PDO expects get_col to return
+ * a pointer to a long */
+ PDO_PARAM_INT,
+
+ /* get_col ptr should point to start of the string buffer */
+ PDO_PARAM_STR,
+
+ /* get_col: when len is 0 ptr should point to a php_stream *,
+ * otherwise it should behave like a string. Indicate a NULL field
+ * value by setting the ptr to NULL */
+ PDO_PARAM_LOB,
+
+ /* get_col: will expect the ptr to point to a new PDOStatement object handle,
+ * but this isn't wired up yet */
+ PDO_PARAM_STMT, /* hierarchical result set */
+
+ /* get_col ptr should point to a zend_bool */
+ PDO_PARAM_BOOL,
+};
+
+/* magic flag to denote a parameter as being input/output */
+#define PDO_PARAM_INPUT_OUTPUT 0x80000000
+
+#define PDO_PARAM_FLAGS 0xFFFF0000
+
+#define PDO_PARAM_TYPE(x) ((x) & ~PDO_PARAM_FLAGS)
+
+enum pdo_fetch_type {
+ PDO_FETCH_USE_DEFAULT,
+ PDO_FETCH_LAZY,
+ PDO_FETCH_ASSOC,
+ PDO_FETCH_NUM,
+ PDO_FETCH_BOTH,
+ PDO_FETCH_OBJ,
+ PDO_FETCH_BOUND, /* return true/false only; rely on bound columns */
+ PDO_FETCH_COLUMN, /* fetch a numbered column only */
+ PDO_FETCH_CLASS, /* create an instance of named class, call ctor and set properties */
+ PDO_FETCH_INTO, /* fetch row into an existing object */
+ PDO_FETCH_FUNC, /* fetch into function and return its result */
+ PDO_FETCH_NAMED, /* like PDO_FETCH_ASSOC, but can handle duplicate names */
+ PDO_FETCH__MAX /* must be last */
+};
+
+#define PDO_FETCH_FLAGS 0xFFFF0000 /* fetchAll() modes or'd to PDO_FETCH_XYZ */
+#define PDO_FETCH_GROUP 0x00010000 /* fetch into groups */
+#define PDO_FETCH_UNIQUE 0x00030000 /* fetch into groups assuming first col is unique */
+#define PDO_FETCH_CLASSTYPE 0x00040000 /* fetch class gets its class name from 1st column */
+#define PDO_FETCH_SERIALIZE 0x00080000 /* fetch class instances by calling serialize */
+
+/* fetch orientation for scrollable cursors */
+enum pdo_fetch_orientation {
+ PDO_FETCH_ORI_NEXT, /* default: fetch the next available row */
+ PDO_FETCH_ORI_PRIOR, /* scroll back to prior row and fetch that */
+ PDO_FETCH_ORI_FIRST, /* scroll to the first row and fetch that */
+ PDO_FETCH_ORI_LAST, /* scroll to the last row and fetch that */
+ PDO_FETCH_ORI_ABS, /* scroll to an absolute numbered row and fetch that */
+ PDO_FETCH_ORI_REL /* scroll relative to the current row, and fetch that */
+};
+
+enum pdo_attribute_type {
+ PDO_ATTR_AUTOCOMMIT, /* use to turn on or off auto-commit mode */
+ PDO_ATTR_PREFETCH, /* configure the prefetch size for drivers that support it. Size is in KB */
+ PDO_ATTR_TIMEOUT, /* connection timeout in seconds */
+ PDO_ATTR_ERRMODE, /* control how errors are handled */
+ PDO_ATTR_SERVER_VERSION, /* database server version */
+ PDO_ATTR_CLIENT_VERSION, /* client library version */
+ PDO_ATTR_SERVER_INFO, /* server information */
+ PDO_ATTR_CONNECTION_STATUS, /* connection status */
+ PDO_ATTR_CASE, /* control case folding for portability */
+ PDO_ATTR_CURSOR_NAME, /* name a cursor for use in "WHERE CURRENT OF <name>" */
+ PDO_ATTR_CURSOR, /* cursor type */
+ PDO_ATTR_ORACLE_NULLS, /* convert empty strings to NULL */
+ PDO_ATTR_PERSISTENT, /* pconnect style connection */
+ PDO_ATTR_STATEMENT_CLASS, /* array(classname, array(ctor_args)) to specify the class of the constructed statement */
+ PDO_ATTR_FETCH_TABLE_NAMES, /* include table names in the column names, where available */
+ PDO_ATTR_FETCH_CATALOG_NAMES, /* include the catalog/db name names in the column names, where available */
+ PDO_ATTR_DRIVER_NAME, /* name of the driver (as used in the constructor) */
+ PDO_ATTR_STRINGIFY_FETCHES, /* converts integer/float types to strings during fetch */
+ PDO_ATTR_MAX_COLUMN_LEN, /* make database calculate maximum length of data found in a column */
+
+ /* this defines the start of the range for driver specific options.
+ * Drivers should define their own attribute constants beginning with this
+ * value. */
+ PDO_ATTR_DRIVER_SPECIFIC = 1000
+};
+
+enum pdo_cursor_type {
+ PDO_CURSOR_FWDONLY, /* forward only cursor (default) */
+ PDO_CURSOR_SCROLL /* scrollable cursor */
+};
+
+/* SQL-92 SQLSTATE error codes.
+
+The character string value returned for an SQLSTATE consists of a two-character
+class value followed by a three-character subclass value. A class value of 01
+indicates a warning and is accompanied by a return code of
+SQL_SUCCESS_WITH_INFO.
+
+Class values other than '01', except for the class 'IM',
+indicate an error and are accompanied by a return code of SQL_ERROR. The class
+'IM' is specific to warnings and errors that derive from the implementation of
+ODBC itself.
+
+The subclass value '000' in any class indicates that there is no
+subclass for that SQLSTATE. The assignment of class and subclass values is
+defined by SQL-92.
+*/
+
+typedef char pdo_error_type[6]; /* SQLSTATE */
+
+
+#define PDO_ERR_NONE "00000"
+
+enum pdo_error_mode {
+ PDO_ERRMODE_SILENT, /* just set error codes */
+ PDO_ERRMODE_WARNING, /* raise E_WARNING */
+ PDO_ERRMODE_EXCEPTION /* throw exceptions */
+};
+
+enum pdo_case_conversion {
+ PDO_CASE_NATURAL,
+ PDO_CASE_UPPER,
+ PDO_CASE_LOWER
+};
+
+/* oracle interop settings */
+enum pdo_null_handling {
+ PDO_NULL_NATURAL = 0,
+ PDO_NULL_EMPTY_STRING = 1,
+ PDO_NULL_TO_STRING = 2,
+};
+
+/* {{{ utils for reading attributes set as driver_options */
+static inline long pdo_attr_lval(zval *options, enum pdo_attribute_type option_name, long defval TSRMLS_DC)
+{
+ zval **v;
+
+ if (options && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), option_name, (void**)&v)) {
+ convert_to_long_ex(v);
+ return Z_LVAL_PP(v);
+ }
+ return defval;
+}
+static inline char *pdo_attr_strval(zval *options, enum pdo_attribute_type option_name, char *defval TSRMLS_DC)
+{
+ zval **v;
+
+ if (options && SUCCESS == zend_hash_index_find(Z_ARRVAL_P(options), option_name, (void**)&v)) {
+ convert_to_string_ex(v);
+ return estrndup(Z_STRVAL_PP(v), Z_STRLEN_PP(v));
+ }
+ return defval ? estrdup(defval) : NULL;
+}
+/* }}} */
+
+/* This structure is registered with PDO when a PDO driver extension is
+ * initialized */
+typedef struct {
+ const char *driver_name;
+ unsigned long driver_name_len;
+ unsigned long api_version; /* needs to be compatible with PDO */
+
+#define PDO_DRIVER_HEADER(name) \
+ #name, sizeof(#name)-1, \
+ PDO_DRIVER_API
+
+ /* create driver specific portion of the database handle and stash it into
+ * the dbh. dbh contains the data source string and flags for this
+ * instance. You MUST respect dbh->is_persistent and pass that flag to
+ * pemalloc() for all allocations that are stored in the dbh or your instance
+ * data in the db, otherwise you will crash PHP when persistent connections
+ * are used.
+ */
+ int (*db_handle_factory)(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC);
+
+} pdo_driver_t;
+
+/* {{{ methods for a database handle */
+
+/* close or otherwise disconnect the database */
+typedef int (*pdo_dbh_close_func)(pdo_dbh_t *dbh TSRMLS_DC);
+
+/* prepare a statement and stash driver specific portion into stmt */
+typedef int (*pdo_dbh_prepare_func)(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC);
+
+/* execute a statement (that does not return a result set) */
+typedef long (*pdo_dbh_do_func)(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC);
+
+/* quote a string */
+typedef int (*pdo_dbh_quote_func)(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC);
+
+/* transaction related */
+typedef int (*pdo_dbh_txn_func)(pdo_dbh_t *dbh TSRMLS_DC);
+
+/* setting of attributes */
+typedef int (*pdo_dbh_set_attr_func)(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC);
+
+/* return last insert id. NULL indicates error condition, otherwise, the return value
+ * MUST be an emalloc'd NULL terminated string. */
+typedef char *(*pdo_dbh_last_id_func)(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC);
+
+/* fetch error information. if stmt is not null, fetch information pertaining
+ * to the statement, otherwise fetch global error information. The driver
+ * should add the following information to the array "info" in this order:
+ * - native error code
+ * - string representation of the error code ... any other optional driver
+ * specific data ... */
+typedef int (*pdo_dbh_fetch_error_func)(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC);
+
+/* fetching of attributes */
+typedef int (*pdo_dbh_get_attr_func)(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC);
+
+/* checking/pinging persistent connections; return SUCCESS if the connection
+ * is still alive and ready to be used, FAILURE otherwise.
+ * You may set this handler to NULL, which is equivalent to returning SUCCESS. */
+typedef int (*pdo_dbh_check_liveness_func)(pdo_dbh_t *dbh TSRMLS_DC);
+
+/* called at request end for each persistent dbh; this gives the driver
+ * the opportunity to safely release resources that only have per-request
+ * scope */
+typedef void (*pdo_dbh_request_shutdown)(pdo_dbh_t *dbh TSRMLS_DC);
+
+/* for adding methods to the dbh or stmt objects
+pointer to a list of driver specific functions. The convention is
+to prefix the function names using the PDO driver name; this will
+reduce the chance of collisions with future functionality in the
+PDO class or in user code (they can extend the PDO object).
+*/
+enum {
+ PDO_DBH_DRIVER_METHOD_KIND_DBH = 0,
+ PDO_DBH_DRIVER_METHOD_KIND_STMT,
+ PDO_DBH_DRIVER_METHOD_KIND__MAX
+};
+
+typedef function_entry *(*pdo_dbh_get_driver_methods_func)(pdo_dbh_t *dbh, int kind TSRMLS_DC);
+
+struct pdo_dbh_methods {
+ pdo_dbh_close_func closer;
+ pdo_dbh_prepare_func preparer;
+ pdo_dbh_do_func doer;
+ pdo_dbh_quote_func quoter;
+ pdo_dbh_txn_func begin;
+ pdo_dbh_txn_func commit;
+ pdo_dbh_txn_func rollback;
+ pdo_dbh_set_attr_func set_attribute;
+ pdo_dbh_last_id_func last_id;
+ pdo_dbh_fetch_error_func fetch_err;
+ pdo_dbh_get_attr_func get_attribute;
+ pdo_dbh_check_liveness_func check_liveness;
+ pdo_dbh_get_driver_methods_func get_driver_methods;
+ pdo_dbh_request_shutdown persistent_shutdown;
+};
+
+/* }}} */
+
+/* {{{ methods for a statement handle */
+
+/* free the statement handle */
+typedef int (*pdo_stmt_dtor_func)(pdo_stmt_t *stmt TSRMLS_DC);
+
+/* start the query */
+typedef int (*pdo_stmt_execute_func)(pdo_stmt_t *stmt TSRMLS_DC);
+
+/* causes the next row in the set to be fetched; indicates if there are no
+ * more rows. The ori and offset params modify which row should be returned,
+ * if the stmt represents a scrollable cursor */
+typedef int (*pdo_stmt_fetch_func)(pdo_stmt_t *stmt,
+ enum pdo_fetch_orientation ori, long offset TSRMLS_DC);
+
+/* queries information about the type of a column, by index (0 based).
+ * Driver should populate stmt->columns[colno] with appropriate info */
+typedef int (*pdo_stmt_describe_col_func)(pdo_stmt_t *stmt, int colno TSRMLS_DC);
+
+/* retrieves pointer and size of the value for a column.
+ * Note that PDO expects the driver to manage the lifetime of this data;
+ * it will copy the value into a zval on behalf of the script.
+ * If the driver sets caller_frees, ptr should point to emalloc'd memory
+ * and PDO will free it as soon as it is done using it.
+ */
+typedef int (*pdo_stmt_get_col_data_func)(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC);
+
+/* hook for bound params */
+enum pdo_param_event {
+ PDO_PARAM_EVT_ALLOC,
+ PDO_PARAM_EVT_FREE,
+ PDO_PARAM_EVT_EXEC_PRE,
+ PDO_PARAM_EVT_EXEC_POST,
+ PDO_PARAM_EVT_FETCH_PRE,
+ PDO_PARAM_EVT_FETCH_POST
+};
+
+typedef int (*pdo_stmt_param_hook_func)(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC);
+
+/* setting of attributes */
+typedef int (*pdo_stmt_set_attr_func)(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC);
+
+/* fetching of attributes */
+typedef int (*pdo_stmt_get_attr_func)(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC);
+
+/* retrieves meta data for a numbered column.
+ * Returns SUCCESS/FAILURE.
+ * On SUCCESS, fill in return_value with an array with the following fields.
+ * If a particular field is not supported, then the driver simply does not add it to
+ * the array, so that scripts can use isset() to check for it.
+ *
+ * ### this is just a rough first cut, and subject to change ###
+ *
+ * these are added by PDO itself, based on data from the describe handler:
+ * name => the column name
+ * len => the length/size of the column
+ * precision => precision of the column
+ * pdo_type => an integer, one of the PDO_PARAM_XXX values
+ *
+ * scale => the floating point scale
+ * table => the table for that column
+ * type => a string representation of the type, mapped to the PHP equivalent type name
+ * native_type => a string representation of the type, native style, if different from
+ * the mapped name.
+ * flags => an array of flags including zero or more of the following:
+ * primary_key, not_null, unique_key, multiple_key, unsigned, auto_increment, blob
+ *
+ * Any driver specific data should be returned using a prefixed key or value.
+ * Eg: custom data for the mysql driver would use either
+ * 'mysql:foobar' => 'some data' // to add a new key to the array
+ * or
+ * 'flags' => array('not_null', 'mysql:some_flag'); // to add data to an existing key
+ */
+typedef int (*pdo_stmt_get_column_meta_func)(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC);
+
+/* advances the statement to the next rowset of the batch.
+ * If it returns 1, PDO will tear down its idea of columns
+ * and meta data. If it returns 0, PDO will indicate an error
+ * to the caller. */
+typedef int (*pdo_stmt_next_rowset_func)(pdo_stmt_t *stmt TSRMLS_DC);
+
+/* closes the active cursor on a statement, leaving the prepared
+ * statement ready for re-execution. Useful to explicitly state
+ * that you are done with a given rowset, without having to explicitly
+ * fetch all the rows. */
+typedef int (*pdo_stmt_cursor_closer_func)(pdo_stmt_t *stmt TSRMLS_DC);
+
+struct pdo_stmt_methods {
+ pdo_stmt_dtor_func dtor;
+ pdo_stmt_execute_func executer;
+ pdo_stmt_fetch_func fetcher;
+ pdo_stmt_describe_col_func describer;
+ pdo_stmt_get_col_data_func get_col;
+ pdo_stmt_param_hook_func param_hook;
+ pdo_stmt_set_attr_func set_attribute;
+ pdo_stmt_get_attr_func get_attribute;
+ pdo_stmt_get_column_meta_func get_column_meta;
+ pdo_stmt_next_rowset_func next_rowset;
+ pdo_stmt_cursor_closer_func cursor_closer;
+};
+
+/* }}} */
+
+enum pdo_placeholder_support {
+ PDO_PLACEHOLDER_NONE=0,
+ PDO_PLACEHOLDER_NAMED=1,
+ PDO_PLACEHOLDER_POSITIONAL=2
+};
+
+/* represents a connection to a database */
+struct _pdo_dbh_t {
+ /* these items must appear in this order at the beginning of the
+ struct so that this can be cast as a zend_object. we need this
+ to allow the extending class to escape all the custom handlers
+ that PDO declares.
+ */
+ zend_class_entry *ce;
+ HashTable *properties;
+ unsigned int in_get:1;
+ unsigned int in_set:1;
+
+ /* driver specific methods */
+ struct pdo_dbh_methods *methods;
+ /* driver specific data */
+ void *driver_data;
+
+ /* credentials */
+ char *username, *password;
+
+ /* if true, then data stored and pointed at by this handle must all be
+ * persistently allocated */
+ unsigned is_persistent:1;
+
+ /* if true, driver should act as though a COMMIT were executed between
+ * each executed statement; otherwise, COMMIT must be carried out manually
+ * */
+ unsigned auto_commit:1;
+
+ /* if true, the handle has been closed and will not function anymore */
+ unsigned is_closed:1;
+
+ /* if true, the driver requires that memory be allocated explicitly for
+ * the columns that are returned */
+ unsigned alloc_own_columns:1;
+
+ /* if true, commit or rollBack is allowed to be called */
+ unsigned in_txn:1;
+
+ /* max length a single character can become after correct quoting */
+ unsigned max_escaped_char_length:3;
+
+ /* oracle compat; see enum pdo_null_handling */
+ unsigned oracle_nulls:2;
+
+ /* when set, convert int/floats to strings */
+ unsigned stringify:1;
+
+ /* the sum of the number of bits here and the bit fields preceeding should
+ * equal 32 */
+ unsigned _reserved_flags:21;
+
+ /* data source string used to open this handle */
+ const char *data_source;
+ unsigned long data_source_len;
+
+ /* the global error code. */
+ pdo_error_type error_code;
+
+ enum pdo_error_mode error_mode;
+
+ enum pdo_case_conversion native_case, desired_case;
+
+ /* persistent hash key associated with this handle */
+ const char *persistent_id;
+ int persistent_id_len;
+ unsigned int refcount;
+
+ /* driver specific "class" methods for the dbh and stmt */
+ HashTable *cls_methods[PDO_DBH_DRIVER_METHOD_KIND__MAX];
+
+ pdo_driver_t *driver;
+
+ zend_class_entry *def_stmt_ce;
+ zval *def_stmt_ctor_args;
+
+ /* when calling PDO::query(), we need to keep the error
+ * context from the statement around until we next clear it.
+ * This will allow us to report the correct error message
+ * when PDO::query() fails */
+ pdo_stmt_t *query_stmt;
+ zval query_stmt_zval;
+};
+
+/* describes a column */
+struct pdo_column_data {
+ char *name;
+ long namelen;
+ unsigned long maxlen;
+ enum pdo_param_type param_type;
+ unsigned long precision;
+
+ /* don't touch this unless your name is dbdo */
+ void *dbdo_data;
+};
+
+/* describes a bound parameter */
+struct pdo_bound_param_data {
+ long paramno; /* if -1, then it has a name, and we don't know the index *yet* */
+ char *name;
+ long namelen;
+
+ long max_value_len; /* as a hint for pre-allocation */
+
+ zval *parameter; /* the variable itself */
+ enum pdo_param_type param_type; /* desired or suggested type */
+
+ zval *driver_params; /* optional parameter(s) for the driver */
+ void *driver_data;
+
+ pdo_stmt_t *stmt; /* for convenience in dtor */
+ int is_param; /* parameter or column ? */
+};
+
+/* represents a prepared statement */
+struct _pdo_stmt_t {
+ /* these items must appear in this order at the beginning of the
+ struct so that this can be cast as a zend_object. we need this
+ to allow the extending class to escape all the custom handlers
+ that PDO declares.
+ */
+ zend_class_entry *ce;
+ HashTable *properties;
+ unsigned int in_get:1;
+ unsigned int in_set:1;
+
+ /* driver specifics */
+ struct pdo_stmt_methods *methods;
+ void *driver_data;
+
+ /* if true, we've already successfully executed this statement at least
+ * once */
+ unsigned executed:1;
+ /* if true, the statement supports placeholders and can implement
+ * bindParam() for its prepared statements, if false, PDO should
+ * emulate prepare and bind on its behalf */
+ unsigned supports_placeholders:2;
+
+ unsigned _reserved:29;
+
+ /* the number of columns in the result set; not valid until after
+ * the statement has been executed at least once. In some cases, might
+ * not be valid until fetch (at the driver level) has been called at least once.
+ * */
+ int column_count;
+ struct pdo_column_data *columns;
+
+ /* we want to keep the dbh alive while we live, so we own a reference */
+ zval database_object_handle;
+ pdo_dbh_t *dbh;
+
+ /* keep track of bound input parameters. Some drivers support
+ * input/output parameters, but you can't rely on that working */
+ HashTable *bound_params;
+ /* When rewriting from named to positional, this maps positions to names */
+ HashTable *bound_param_map;
+ /* keep track of PHP variables bound to named (or positional) columns
+ * in the result set */
+ HashTable *bound_columns;
+
+ /* not always meaningful */
+ long row_count;
+
+ /* used to hold the statement's current query */
+ char *query_string;
+ int query_stringlen;
+
+ /* the copy of the query with expanded binds ONLY for emulated-prepare drivers */
+ char *active_query_string;
+ int active_query_stringlen;
+
+ /* the cursor specific error code. */
+ pdo_error_type error_code;
+
+ /* for lazy fetches, we always return the same lazy object handle.
+ * Let's keep it here. */
+ zval lazy_object_ref;
+ unsigned long refcount;
+
+ /* defaults for fetches */
+ enum pdo_fetch_type default_fetch_type;
+ union {
+ int column;
+ struct {
+ zend_class_entry *ce;
+ zval *ctor_args; /* freed */
+ zval *retval_ptr;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ } cls;
+ struct {
+ zval *function;
+ zval *fetch_args; /* freed */
+ zval *object;
+ zend_fcall_info fci;
+ zend_fcall_info_cache fcc;
+ zval **values; /* freed */
+ } func;
+ zval *into;
+ } fetch;
+
+ /* used by the query parser for driver specific
+ * parameter naming (see pgsql driver for example) */
+ const char *named_rewrite_template;
+};
+
+/* call this in MINIT to register your PDO driver */
+PDO_API int php_pdo_register_driver(pdo_driver_t *driver);
+/* call this in MSHUTDOWN to unregister your PDO driver */
+PDO_API void php_pdo_unregister_driver(pdo_driver_t *driver);
+
+/* For the convenience of drivers, this function will parse a data source
+ * string, of the form "name=value; name2=value2" and populate variables
+ * according to the data you pass in and array of pdo_data_src_parser structures */
+struct pdo_data_src_parser {
+ const char *optname;
+ char *optval;
+ int freeme;
+};
+
+PDO_API int php_pdo_parse_data_source(const char *data_source,
+ unsigned long data_source_len, struct pdo_data_src_parser *parsed,
+ int nparams);
+
+PDO_API zend_class_entry *php_pdo_get_exception(void);
+
+PDO_API int pdo_parse_params(pdo_stmt_t *stmt, char *inquery, int inquery_len,
+ char **outquery, int *outquery_len TSRMLS_DC);
+
+PDO_API void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt,
+ const char *sqlstate, const char *supp TSRMLS_DC);
+
+PDO_API void php_pdo_dbh_addref(pdo_dbh_t *dbh TSRMLS_DC);
+PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh TSRMLS_DC);
+
+PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC);
+PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC);
+
+
+#endif /* PHP_PDO_DRIVER_H */
+/*
+ * 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
+ */
diff --git a/ext/pdo/php_pdo_int.h b/ext/pdo/php_pdo_int.h
new file mode 100755
index 0000000000..e7c2487b58
--- /dev/null
+++ b/ext/pdo/php_pdo_int.h
@@ -0,0 +1,84 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2005 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$ */
+
+/* Stuff private to the PDO extension and not for consumption by PDO drivers
+ * */
+
+extern HashTable pdo_driver_hash;
+extern zend_class_entry *pdo_exception_ce;
+PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC);
+int php_pdo_list_entry(void);
+
+void pdo_dbh_init(TSRMLS_D);
+void pdo_stmt_init(TSRMLS_D);
+
+extern zend_object_value pdo_dbh_new(zend_class_entry *ce TSRMLS_DC);
+extern function_entry pdo_dbh_functions[];
+extern zend_class_entry *pdo_dbh_ce;
+extern ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor);
+
+extern zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC);
+extern function_entry pdo_dbstmt_functions[];
+extern zend_class_entry *pdo_dbstmt_ce;
+void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC);
+zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC);
+extern zend_object_handlers pdo_dbstmt_object_handlers;
+int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC);
+int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip_first_arg);
+
+extern zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC);
+extern function_entry pdo_row_functions[];
+extern zend_class_entry *pdo_row_ce;
+void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC);
+extern zend_object_handlers pdo_row_object_handlers;
+
+zend_object_iterator *php_pdo_dbstmt_iter_get(zend_class_entry *ce, zval *object TSRMLS_DC);
+
+extern pdo_driver_t *pdo_find_driver(const char *name, int namelen);
+
+extern void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC);
+
+#define PDO_DBH_CLEAR_ERR() do { \
+ strcpy(dbh->error_code, PDO_ERR_NONE); \
+ if (dbh->query_stmt) { \
+ dbh->query_stmt = NULL; \
+ zend_objects_store_del_ref(&dbh->query_stmt_zval TSRMLS_CC); \
+ } \
+} while (0)
+#define PDO_STMT_CLEAR_ERR() strcpy(stmt->error_code, PDO_ERR_NONE)
+#define PDO_HANDLE_DBH_ERR() if (strcmp(dbh->error_code, PDO_ERR_NONE)) { pdo_handle_error(dbh, NULL TSRMLS_CC); }
+#define PDO_HANDLE_STMT_ERR() if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); }
+
+int pdo_sqlstate_init_error_table(void);
+void pdo_sqlstate_fini_error_table(void);
+const char *pdo_sqlstate_state_to_description(char *state);
+int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC);
+
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_mysql/CREDITS b/ext/pdo_mysql/CREDITS
new file mode 100755
index 0000000000..0bee1ee76e
--- /dev/null
+++ b/ext/pdo_mysql/CREDITS
@@ -0,0 +1,3 @@
+mySQL driver for PDO
+George Schlossnagle, Wez Furlong, Ilia Alshanetsky
+
diff --git a/ext/pdo_mysql/config.m4 b/ext/pdo_mysql/config.m4
new file mode 100755
index 0000000000..8424199203
--- /dev/null
+++ b/ext/pdo_mysql/config.m4
@@ -0,0 +1,134 @@
+dnl
+dnl $Id$
+dnl
+
+if test "$PHP_PDO" != "no"; then
+
+AC_DEFUN([PDO_MYSQL_LIB_CHK], [
+ str="$PDO_MYSQL_DIR/$1/libmysqlclient.*"
+ for j in `echo $str`; do
+ if test -r $j; then
+ PDO_MYSQL_LIB_DIR=$MYSQL_DIR/$1
+ break 2
+ fi
+ done
+])
+
+PHP_ARG_WITH(pdo-mysql, for MySQL support for PDO,
+[ --with-pdo-mysql[=DIR] PDO: MySQL support. DIR is the MySQL base directory])
+
+if test "$PHP_PDO_MYSQL" != "no"; then
+ AC_DEFINE(HAVE_MYSQL, 1, [Whether you have MySQL])
+
+ AC_MSG_CHECKING([for mysql_config])
+
+ if test -f $PHP_PDO_MYSQL && test -x $PHP_PDO_MYSQL ; then
+ PDO_MYSQL_CONFIG=$PHP_PDO_MYSQL
+ elif test "$PHP_PDO_MYSQL" != "yes"; then
+ if test -d "$PHP_PDO_MYSQL" ; then
+ if test -x "$PHP_PDO_MYSQL/bin/mysql_config" ; then
+ PDO_MYSQL_CONFIG="$PHP_PDO_MYSQL/bin/mysql_config"
+ else
+ PDO_MYSQL_DIR="$PHP_PDO_MYSQL"
+ fi
+ else
+ AC_MSG_RESULT([$PHP_PDO_MYSQL is not a directory])
+ AC_MSG_ERROR([can not find mysql under the "$PHP_PDO_MYSQL" that you specified])
+ fi
+ else
+ for i in /usr/local /usr ; do
+ if test -x "$i/bin/mysql_config" ; then
+ PDO_MYSQL_CONFIG="$i/bin/mysql_config"
+ break;
+ fi
+ if test -r $i/include/mysql/mysql.h || test -r $i/include/mysql.h ; then
+ PDO_MYSQL_DIR="$i"
+ break;
+ fi
+ done
+ fi
+
+ if test -n "$PDO_MYSQL_CONFIG" && test -x "$PDO_MYSQL_CONFIG" ; then
+ AC_MSG_RESULT($PDO_MYSQL_CONFIG)
+ if test "x$SED" = "x"; then
+ AC_PATH_PROG(SED, sed)
+ fi
+ PDO_MYSQL_INCLUDE=`$PDO_MYSQL_CONFIG --cflags | $SED -e "s/'//g"`
+ PDO_MYSQL_LIBS=`$PDO_MYSQL_CONFIG --libs | $SED -e "s/'//g"`
+ PDO_MYSQL_SOCKET=`$PDO_MYSQL_CONFIG --socket`
+ elif test -z "$PDO_MYSQL_DIR"; then
+ AC_MSG_RESULT([not found])
+ AC_MSG_ERROR([Cannot find MySQL header files under $PDO_MYSQL_DIR])
+ else
+ AC_MSG_RESULT([not found])
+ AC_MSG_CHECKING([for mysql install under $PDO_MYSQL_DIR])
+ if test -r $PDO_MYSQL_DIR/include/mysql; then
+ PDO_MYSQL_INC_DIR=$PDO_MYSQL_DIR/include/mysql
+ else
+ PDO_MYSQL_INC_DIR=$PDO_MYSQL_DIR/include
+ fi
+ if test -r $PDO_MYSQL_DIR/lib/mysql; then
+ PDO_MYSQL_LIB_DIR=$PDO_MYSQL_DIR/lib/mysql
+ else
+ PDO_MYSQL_LIB_DIR=$PDO_MYSQL_DIR/lib
+ fi
+
+ if test -r "$PDO_MYSQL_LIB_DIR"; then
+ AC_MSG_RESULT([libs under $PDO_MYSQL_LIB_DIR; seems promising])
+ else
+ AC_MSG_RESULT([can not find it])
+ AC_MSG_ERROR([Unable to find your mysql installation])
+ fi
+
+ PHP_ADD_LIBRARY_WITH_PATH(mysqlclient, $PDO_MYSQL_LIB_DIR, PDO_MYSQL_SHARED_LIBADD)
+ PHP_ADD_INCLUDE($PDO_MYSQL_INC_DIR)
+ PDO_MYSQL_INCLUDE=-I$PDO_MYSQL_INC_DIR
+ fi
+
+ AC_DEFINE_UNQUOTED(PDO_MYSQL_UNIX_ADDR, "$PDO_MYSQL_SOCKET", [ ])
+
+
+ _SAVE_LIBS=$LIBS
+ LIBS="$LIBS $PDO_MYSQL_LIBS"
+ PHP_CHECK_LIBRARY(mysqlclient, mysql_query,
+ [
+ PHP_EVAL_LIBLINE($PDO_MYSQL_LIBS, PDO_MYSQL_SHARED_LIBADD)
+ ],[
+ AC_MSG_ERROR([mysql_query missing!?])
+ ],[
+ $PDO_MYSQL_LIBS
+ ])
+ AC_CHECK_FUNCS([mysql_commit mysql_stmt_prepare mysql_next_result mysql_sqlstate])
+ LIBS=$_SAVE_LIBS
+
+ ifdef([PHP_CHECK_PDO_INCLUDES],
+ [
+ PHP_CHECK_PDO_INCLUDES
+ ],[
+ AC_MSG_CHECKING([for PDO includes])
+ if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
+ pdo_inc_path=$abs_srcdir/ext
+ elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then
+ pdo_inc_path=$abs_srcdir/ext
+ elif test -f $prefix/include/php/ext/pdo/php_pdo_driver.h; then
+ pdo_inc_path=$prefix/include/php/ext
+ else
+ AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
+ fi
+ AC_MSG_RESULT($pdo_inc_path)
+ ])
+
+ PHP_NEW_EXTENSION(pdo_mysql, pdo_mysql.c mysql_driver.c mysql_statement.c, $ext_shared,,-I$pdo_inc_path $PDO_MYSQL_INCLUDE)
+ ifdef([PHP_ADD_EXTENSION_DEP],
+ [
+ PHP_ADD_EXTENSION_DEP(pdo_mysql, pdo)
+ ])
+ PDO_MYSQL_MODULE_TYPE=external
+
+ PDO_MYSQL_SHARED_LIBADD=$PDO_MYSQL_LIBS
+ PHP_SUBST(PDO_MYSQL_SHARED_LIBADD)
+ PHP_SUBST_OLD(PDO_MYSQL_MODULE_TYPE)
+fi
+
+fi
+dnl vim: se ts=2 sw=2 et:
diff --git a/ext/pdo_mysql/config.w32 b/ext/pdo_mysql/config.w32
new file mode 100644
index 0000000000..24b2f7cf53
--- /dev/null
+++ b/ext/pdo_mysql/config.w32
@@ -0,0 +1,15 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_WITH("pdo-mysql", "MySQL support for PDO", "no");
+
+if (PHP_PDO_MYSQL != "no") {
+ if (CHECK_LIB("libmysql.lib", "pdo_mysql", PHP_PDO_MYSQL) &&
+ CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL", PHP_PHP_BUILD + "\\include\\mysql;" + PHP_PDO_MYSQL)) {
+ EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c");
+ ADD_FLAG('CFLAGS_PDO_MYSQL', "/I ..\\pecl");
+ } else {
+ WARNING("pdo_mysql not enabled; libraries and headers not found");
+ }
+ ADD_EXTENSION_DEP('pdo_mysql', 'pdo');
+}
diff --git a/ext/pdo_mysql/get_error_codes.php b/ext/pdo_mysql/get_error_codes.php
new file mode 100644
index 0000000000..2785c93b99
--- /dev/null
+++ b/ext/pdo_mysql/get_error_codes.php
@@ -0,0 +1,27 @@
+<?php
+ $codes = array();
+ $maxlen = 0;
+
+ while (!feof(STDIN)) {
+ $line = fgets(STDIN);
+
+ if (ereg('^(ER_.*),[[:space:]]+"(.*)",[[:space:]]+"(.*)"', $line, $matches)) {
+ $codes[$matches[1]] = $matches[2];
+ $maxlen = max($maxlen, strlen($matches[1]));
+ }
+ }
+
+ if (empty($codes)) {
+ fputs(STDERR, "input doesn't look like a MySQL sql_state.h file\n");
+ exit(3);
+ }
+
+ echo "/* DO NOT EDIT THIS FILE!!! It is auto generated by get_error_codes.php */\n";
+ foreach ($codes as $code => $state) {
+ echo "#ifdef $code\n";
+ printf(" case %-{$maxlen}s: return \"%s\";\n", $code, $state);
+ echo "#endif\n";
+ }
+
+
+?> \ No newline at end of file
diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
new file mode 100755
index 0000000000..51e502ccaa
--- /dev/null
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -0,0 +1,573 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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: George Schlossnagle <george@omniti.com> |
+ | Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+#include "pdo/php_pdo_driver.h"
+#include "php_pdo_mysql.h"
+#include "php_pdo_mysql_int.h"
+#include <mysqld_error.h>
+#include "zend_exceptions.h"
+
+
+const char *pdo_mysql_get_sqlstate(unsigned int my_errno) {
+ switch (my_errno) {
+ /* import auto-generated case: code */
+#include "php_pdo_mysql_sqlstate.h"
+ default: return "HY000";
+ }
+}
+
+int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC) /* {{{ */
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+ pdo_error_type *pdo_err;
+ pdo_mysql_error_info *einfo;
+ pdo_mysql_stmt *S = NULL;
+
+ if (stmt) {
+ S = (pdo_mysql_stmt*)stmt->driver_data;
+ pdo_err = &stmt->error_code;
+ einfo = &S->einfo;
+ } else {
+ pdo_err = &dbh->error_code;
+ einfo = &H->einfo;
+ }
+
+#if HAVE_MYSQL_STMT_PREPARE
+ if (S && S->stmt) {
+ einfo->errcode = mysql_stmt_errno(S->stmt);
+ }
+ else
+#endif
+ {
+ einfo->errcode = mysql_errno(H->server);
+ }
+
+ einfo->file = file;
+ einfo->line = line;
+
+ if (einfo->errmsg) {
+ pefree(einfo->errmsg, dbh->is_persistent);
+ einfo->errmsg = NULL;
+ }
+
+ if (einfo->errcode) {
+ if (2014 != einfo->errcode) {
+ einfo->errmsg = pestrdup(mysql_error(H->server), dbh->is_persistent);
+ } else {
+ einfo->errmsg = pestrdup(
+ "Cannot execute queries while other unbuffered queries are active. "
+ "Consider using PDOStatement::fetchAll(). Alternatively, if your code "
+ "is only ever going to run against mysql, you may enable query "
+ "buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.",
+ dbh->is_persistent);
+ }
+ } else { /* no error */
+ strcpy(*pdo_err, PDO_ERR_NONE);
+ return 0;
+ }
+
+#if HAVE_MYSQL_SQLSTATE
+# if HAVE_MYSQL_STMT_PREPARE
+ if (S && S->stmt) {
+ strcpy(*pdo_err, mysql_stmt_sqlstate(S->stmt));
+ } else
+# endif
+ {
+ strcpy(*pdo_err, mysql_sqlstate(H->server));
+ }
+#else
+ strcpy(*pdo_err, pdo_mysql_get_sqlstate(einfo->errcode));
+#endif
+
+ if (!dbh->methods) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
+ *pdo_err, einfo->errcode, einfo->errmsg);
+ }
+/* printf("** [%s:%d] %s %s\n", file, line, *pdo_err, einfo->errmsg); */
+
+ return einfo->errcode;
+}
+/* }}} */
+
+static int pdo_mysql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+ pdo_mysql_error_info *einfo = &H->einfo;
+
+ if (stmt) {
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ einfo = &S->einfo;
+ } else {
+ einfo = &H->einfo;
+ }
+
+ if (einfo->errcode) {
+ add_next_index_long(info, einfo->errcode);
+ add_next_index_string(info, einfo->errmsg, 1);
+ }
+
+ return 1;
+}
+
+static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+
+ if (H) {
+ if (H->server) {
+ mysql_close(H->server);
+ H->server = NULL;
+ }
+ if (H->einfo.errmsg) {
+ pefree(H->einfo.errmsg, dbh->is_persistent);
+ H->einfo.errmsg = NULL;
+ }
+ pefree(H, dbh->is_persistent);
+ dbh->driver_data = NULL;
+ }
+ return 0;
+}
+/* }}} */
+
+static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+ pdo_mysql_stmt *S = ecalloc(1, sizeof(pdo_mysql_stmt));
+#if HAVE_MYSQL_STMT_PREPARE
+ char *nsql = NULL;
+ int nsql_len = 0;
+ int ret;
+ int server_version;
+#endif
+
+ S->H = H;
+ stmt->driver_data = S;
+ stmt->methods = &mysql_stmt_methods;
+
+ if (H->emulate_prepare) {
+ goto end;
+ }
+
+#if HAVE_MYSQL_STMT_PREPARE
+ server_version = mysql_get_server_version(H->server);
+ if (server_version < 40100) {
+ goto fallback;
+ }
+ stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
+ ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
+
+ if (ret == 1) {
+ /* query was rewritten */
+ sql = nsql;
+ sql_len = nsql_len;
+ } else if (ret == -1) {
+ /* failed to parse */
+ strcpy(dbh->error_code, stmt->error_code);
+ return 0;
+ }
+
+ if (!(S->stmt = mysql_stmt_init(H->server))) {
+ pdo_mysql_error(dbh);
+ if (nsql) {
+ efree(nsql);
+ }
+ return 0;
+ }
+
+ if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
+ /* TODO: might need to pull statement specific info here? */
+ /* if the query isn't supported by the protocol, fallback to emulation */
+ if (mysql_errno(H->server) == 1295) {
+ if (nsql) {
+ efree(nsql);
+ }
+ goto fallback;
+ }
+ pdo_mysql_error(dbh);
+ if (nsql) {
+ efree(nsql);
+ }
+ return 0;
+ }
+ if (nsql) {
+ efree(nsql);
+ }
+
+ S->num_params = mysql_stmt_param_count(S->stmt);
+
+ if (S->num_params) {
+ S->params = ecalloc(S->num_params, sizeof(MYSQL_BIND));
+ S->in_null = ecalloc(S->num_params, sizeof(my_bool));
+ S->in_length = ecalloc(S->num_params, sizeof(unsigned long));
+ }
+
+ dbh->alloc_own_columns = 1;
+
+ S->max_length = pdo_attr_lval(driver_options, PDO_ATTR_MAX_COLUMN_LEN, 0 TSRMLS_CC);
+
+ return 1;
+
+fallback:
+#endif
+end:
+ stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
+
+ return 1;
+}
+
+static long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+
+ if (mysql_real_query(H->server, sql, sql_len)) {
+ pdo_mysql_error(dbh);
+ return -1;
+ } else {
+ my_ulonglong c = mysql_affected_rows(H->server);
+ if (c == (my_ulonglong) -1) {
+ pdo_mysql_error(dbh);
+ return (H->einfo.errcode ? -1 : 0);
+ } else {
+ return c;
+ }
+ }
+}
+
+static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+ char *id = php_pdo_int64_to_str(mysql_insert_id(H->server) TSRMLS_CC);
+ *len = strlen(id);
+ return id;
+}
+
+static int mysql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+ *quoted = safe_emalloc(2, unquotedlen, 3);
+ *quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
+ (*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
+ (*quoted)[++*quotedlen] = '\0';
+ return 1;
+}
+
+static int mysql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ return 0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC);
+}
+
+static int mysql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ return 0 <= mysql_handle_doer(dbh, ZEND_STRL("COMMIT") TSRMLS_CC);
+}
+
+static int mysql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ return 0 <= mysql_handle_doer(dbh, ZEND_STRL("ROLLBACK") TSRMLS_CC);
+}
+
+static int mysql_handle_autocommit(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ if (dbh->auto_commit) {
+ return 0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=1") TSRMLS_CC);
+ } else {
+ return 0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=0") TSRMLS_CC);
+ }
+}
+
+static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
+{
+ switch (attr) {
+ case PDO_ATTR_AUTOCOMMIT:
+
+ convert_to_boolean(val);
+
+ /* ignore if the new value equals the old one */
+ if (dbh->auto_commit ^ Z_BVAL_P(val)) {
+ dbh->auto_commit = Z_BVAL_P(val);
+ mysql_handle_autocommit(dbh TSRMLS_CC);
+ }
+ return 1;
+
+ case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
+ ((pdo_mysql_db_handle *)dbh->driver_data)->buffered = Z_BVAL_P(val);
+ return 1;
+ case PDO_MYSQL_ATTR_DIRECT_QUERY:
+ case PDO_ATTR_EMULATE_PREPARES:
+ ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
+{
+ pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+
+ switch (attr) {
+ case PDO_ATTR_CLIENT_VERSION:
+ ZVAL_STRING(return_value, (char *)mysql_get_client_info(), 1);
+ break;
+
+ case PDO_ATTR_SERVER_VERSION:
+ ZVAL_STRING(return_value, (char *)mysql_get_server_info(H->server), 1);
+ break;
+
+ case PDO_ATTR_CONNECTION_STATUS:
+ ZVAL_STRING(return_value, (char *)mysql_get_host_info(H->server), 1);
+ break;
+
+ case PDO_ATTR_SERVER_INFO: {
+ char *tmp;
+
+ if ((tmp = (char *)mysql_stat(H->server))) {
+ ZVAL_STRING(return_value, tmp, 1);
+ } else {
+ pdo_mysql_error(dbh);
+ return -1;
+ }
+ }
+ break;
+
+ case PDO_ATTR_AUTOCOMMIT:
+ ZVAL_LONG(return_value, dbh->auto_commit);
+ return 1;
+
+ case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
+ ZVAL_LONG(return_value, H->buffered);
+ return 1;
+
+ case PDO_MYSQL_ATTR_DIRECT_QUERY:
+ ZVAL_LONG(return_value, H->emulate_prepare);
+ return 1;
+
+ case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
+ ZVAL_LONG(return_value, H->max_buffer_size);
+ return 1;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static struct pdo_dbh_methods mysql_methods = {
+ mysql_handle_closer,
+ mysql_handle_preparer,
+ mysql_handle_doer,
+ mysql_handle_quoter,
+ mysql_handle_begin,
+ mysql_handle_commit,
+ mysql_handle_rollback,
+ pdo_mysql_set_attribute,
+ pdo_mysql_last_insert_id,
+ pdo_mysql_fetch_error_func,
+ pdo_mysql_get_attribute,
+ NULL /* check_liveness: TODO: ping */
+};
+
+#ifndef PDO_MYSQL_UNIX_ADDR
+# ifdef PHP_WIN32
+# define PDO_MYSQL_UNIX_ADDR "MySQL"
+# else
+# define PDO_MYSQL_UNIX_ADDR "/tmp/mysql.sock"
+# endif
+#endif
+
+static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
+{
+ pdo_mysql_db_handle *H;
+ int i, ret = 0;
+ char *host = NULL, *unix_socket = NULL;
+ unsigned int port = 3306;
+ char *dbname;
+ struct pdo_data_src_parser vars[] = {
+ { "charset", NULL, 0 },
+ { "dbname", "", 0 },
+ { "host", "localhost", 0 },
+ { "port", "3306", 0 },
+ { "unix_socket", PDO_MYSQL_UNIX_ADDR, 0 },
+ };
+ int connect_opts = 0
+#ifdef CLIENT_MULTI_RESULTS
+ |CLIENT_MULTI_RESULTS
+#endif
+#ifdef CLIENT_MULTI_STATEMENTS
+ |CLIENT_MULTI_STATEMENTS
+#endif
+ ;
+
+ php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
+
+ H = pecalloc(1, sizeof(pdo_mysql_db_handle), dbh->is_persistent);
+
+ H->einfo.errcode = 0;
+ H->einfo.errmsg = NULL;
+
+ /* at the time of writing, the mysql documentation states:
+ * http://mysql.localhost.net.ar/doc/refman/5.0/en/query-cache-how.html
+ * "A query also is not cached under these conditions:
+ * ...
+ * It was issued as a prepared statement, even if no placeholders were employed."
+ *
+ * We default to emulating prepared statements
+ * in order to take advantage of the query cache
+FIXME: H->emulate_prepare = 1; a bit risky to do this so late in the RC, so defer it.
+ */
+
+ /* allocate an environment */
+
+ /* handle for the server */
+ if (!(H->server = mysql_init(NULL))) {
+ pdo_mysql_error(dbh);
+ goto cleanup;
+ }
+
+ dbh->driver_data = H;
+ H->max_buffer_size = 1024*1024;
+
+ /* handle MySQL options */
+ if (driver_options) {
+ long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
+ long local_infile = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE, 0 TSRMLS_CC);
+ char *init_cmd = NULL, *default_file = NULL, *default_group = NULL;
+
+ H->buffered = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 0 TSRMLS_CC);
+
+ H->emulate_prepare = pdo_attr_lval(driver_options,
+ PDO_MYSQL_ATTR_DIRECT_QUERY, H->emulate_prepare TSRMLS_CC);
+ H->emulate_prepare = pdo_attr_lval(driver_options,
+ PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare TSRMLS_CC);
+
+ H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
+
+ if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
+ pdo_mysql_error(dbh);
+ goto cleanup;
+ }
+
+ if (mysql_options(H->server, MYSQL_OPT_LOCAL_INFILE, (const char *)&local_infile)) {
+ pdo_mysql_error(dbh);
+ goto cleanup;
+ }
+
+#ifdef MYSQL_OPT_RECONNECT
+ /* since 5.0.3, the default for this option is 0 if not specified.
+ * we want the old behaviour */
+ {
+ long reconnect = 1;
+ mysql_options(H->server, MYSQL_OPT_RECONNECT, (const char*)&reconnect);
+ }
+#endif
+
+ init_cmd = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_INIT_COMMAND, NULL TSRMLS_CC);
+ if (init_cmd) {
+ if (mysql_options(H->server, MYSQL_INIT_COMMAND, (const char *)init_cmd)) {
+ efree(init_cmd);
+ pdo_mysql_error(dbh);
+ goto cleanup;
+ }
+ efree(init_cmd);
+ }
+
+ default_file = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_FILE, NULL TSRMLS_CC);
+ if (default_file) {
+ if (mysql_options(H->server, MYSQL_READ_DEFAULT_FILE, (const char *)default_file)) {
+ efree(default_file);
+ pdo_mysql_error(dbh);
+ goto cleanup;
+ }
+ efree(default_file);
+ }
+
+ default_group= pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP, NULL TSRMLS_CC);
+ if (default_group) {
+ if (mysql_options(H->server, MYSQL_READ_DEFAULT_GROUP, (const char *)default_group)) {
+ efree(default_group);
+ pdo_mysql_error(dbh);
+ goto cleanup;
+ }
+ efree(default_group);
+ }
+ }
+
+ dbname = vars[1].optval;
+ host = vars[2].optval;
+ if(vars[3].optval) {
+ port = atoi(vars[3].optval);
+ }
+ if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
+ unix_socket = vars[4].optval;
+ }
+ if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
+ pdo_mysql_error(dbh);
+ goto cleanup;
+ }
+
+ if (!dbh->auto_commit) {
+ mysql_handle_autocommit(dbh TSRMLS_CC);
+ }
+
+ H->attached = 1;
+
+ dbh->alloc_own_columns = 1;
+ dbh->max_escaped_char_length = 2;
+ dbh->methods = &mysql_methods;
+
+ ret = 1;
+
+cleanup:
+ for (i = 0; i < sizeof(vars)/sizeof(vars[0]); i++) {
+ if (vars[i].freeme) {
+ efree(vars[i].optval);
+ }
+ }
+
+ dbh->methods = &mysql_methods;
+
+ return ret;
+}
+/* }}} */
+
+pdo_driver_t pdo_mysql_driver = {
+ PDO_DRIVER_HEADER(mysql),
+ pdo_mysql_handle_factory
+};
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_mysql/mysql_statement.c b/ext/pdo_mysql/mysql_statement.c
new file mode 100755
index 0000000000..920702b3c9
--- /dev/null
+++ b/ext/pdo_mysql/mysql_statement.c
@@ -0,0 +1,642 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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: George Schlossnagle <george@omniti.com> |
+ | Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+#include "pdo/php_pdo_driver.h"
+#include "php_pdo_mysql.h"
+#include "php_pdo_mysql_int.h"
+
+
+static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+
+ if (S->result) {
+ /* free the resource */
+ mysql_free_result(S->result);
+ S->result = NULL;
+ }
+ if (S->einfo.errmsg) {
+ pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
+ S->einfo.errmsg = NULL;
+ }
+#if HAVE_MYSQL_STMT_PREPARE
+ if (S->stmt) {
+ mysql_stmt_close(S->stmt);
+ S->stmt = NULL;
+ }
+ if (S->params) {
+ efree(S->params);
+ efree(S->in_null);
+ efree(S->in_length);
+ }
+ if (S->bound_result)
+ {
+ int i;
+ for (i = 0; i < stmt->column_count; i++) {
+ efree(S->bound_result[i].buffer);
+ }
+
+ efree(S->bound_result);
+ efree(S->out_null);
+ efree(S->out_length);
+ }
+#endif
+#if HAVE_MYSQL_NEXT_RESULT
+ while (mysql_more_results(S->H->server)) {
+ MYSQL_RES *res;
+ if (mysql_next_result(S->H->server) != 0) {
+ break;
+ }
+
+ res = mysql_store_result(S->H->server);
+ if (res) {
+ mysql_free_result(res);
+ }
+ }
+#endif
+ efree(S);
+ return 1;
+}
+
+static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ pdo_mysql_db_handle *H = S->H;
+ my_ulonglong row_count;
+#if HAVE_MYSQL_STMT_PREPARE
+ int i;
+
+ if (S->stmt) {
+ /* (re)bind the parameters */
+ if (mysql_stmt_bind_param(S->stmt, S->params)) {
+ pdo_mysql_error_stmt(stmt);
+ return 0;
+ }
+
+ if (mysql_stmt_execute(S->stmt)) {
+ pdo_mysql_error_stmt(stmt);
+ return 0;
+ }
+
+ if (!S->result) {
+ /* figure out the result set format, if any */
+ S->result = mysql_stmt_result_metadata(S->stmt);
+ if (S->result) {
+ int calc_max_length = H->buffered && S->max_length == 1;
+
+ S->fields = mysql_fetch_fields(S->result);
+
+ if (S->bound_result) {
+ int i;
+ for (i = 0; i < stmt->column_count; i++) {
+ efree(S->bound_result[i].buffer);
+ }
+ efree(S->bound_result);
+ efree(S->out_null);
+ efree(S->out_length);
+ }
+
+ stmt->column_count = (int)mysql_num_fields(S->result);
+ S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
+ S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
+ S->out_length = ecalloc(stmt->column_count, sizeof(unsigned long));
+
+ /* summon memory to hold the row */
+ for (i = 0; i < stmt->column_count; i++) {
+ if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
+ my_bool on = 1;
+ mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
+ calc_max_length = 0;
+ }
+ switch (S->fields[i].type) {
+ case FIELD_TYPE_INT24:
+ S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH;
+ break;
+ case FIELD_TYPE_LONG:
+ S->bound_result[i].buffer_length = MAX_INT_WIDTH;
+ break;
+ case FIELD_TYPE_LONGLONG:
+ S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH;
+ break;
+ case FIELD_TYPE_TINY:
+ S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH;
+ break;
+ case FIELD_TYPE_SHORT:
+ S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH;
+ break;
+ default:
+ S->bound_result[i].buffer_length =
+ S->fields[i].max_length? S->fields[i].max_length:
+ S->fields[i].length;
+ /* work-around for longtext and alike */
+ if (S->bound_result[i].buffer_length > H->max_buffer_size) {
+ S->bound_result[i].buffer_length = H->max_buffer_size;
+ }
+ }
+#if 0
+ printf("%d: max_length=%d length=%d buffer_length=%d type=%d\n",
+ i,
+ S->fields[i].max_length,
+ S->fields[i].length,
+ S->bound_result[i].buffer_length,
+ S->fields[i].type
+ );
+#endif
+
+ /* there are cases where the length reported by mysql is too short.
+ * eg: when describing a table that contains an enum column. Since
+ * we have no way of knowing the true length either, we'll bump up
+ * our buffer size to a reasonable size, just in case */
+ if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
+ S->bound_result[i].buffer_length = 128;
+ }
+
+ S->out_length[i] = 0;
+
+ S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
+ S->bound_result[i].is_null = &S->out_null[i];
+ S->bound_result[i].length = &S->out_length[i];
+ S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
+ }
+
+ if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
+ pdo_mysql_error_stmt(stmt);
+ return 0;
+ }
+
+ /* if buffered, pre-fetch all the data */
+ if (H->buffered) {
+ mysql_stmt_store_result(S->stmt);
+ }
+ }
+ }
+
+ row_count = mysql_stmt_affected_rows(S->stmt);
+ if (row_count != (my_ulonglong)-1) {
+ stmt->row_count = row_count;
+ }
+ return 1;
+ }
+#endif
+ /* ensure that we free any previous unfetched results */
+ if (S->result) {
+ mysql_free_result(S->result);
+ S->result = NULL;
+ }
+
+ if (mysql_real_query(H->server, stmt->active_query_string, stmt->active_query_stringlen) != 0) {
+ pdo_mysql_error_stmt(stmt);
+ return 0;
+ }
+
+ row_count = mysql_affected_rows(H->server);
+ if (row_count == (my_ulonglong)-1) {
+ /* we either have a query that returned a result set or an error occured
+ lets see if we have access to a result set */
+ if (!H->buffered) {
+ S->result = mysql_use_result(H->server);
+ } else {
+ S->result = mysql_store_result(H->server);
+ }
+ if (NULL == S->result) {
+ pdo_mysql_error_stmt(stmt);
+ return 0;
+ }
+
+ stmt->row_count = 0;
+
+ if (!stmt->executed) {
+ stmt->column_count = (int) mysql_num_fields(S->result);
+ S->fields = mysql_fetch_fields(S->result);
+ }
+ } else {
+ /* this was a DML or DDL query (INSERT, UPDATE, DELETE, ... */
+ stmt->row_count = row_count;
+ }
+
+ return 1;
+}
+
+static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
+{
+#if HAVE_MYSQL_NEXT_RESULT
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ pdo_mysql_db_handle *H = S->H;
+ my_ulonglong row_count;
+ int ret;
+
+ /* ensure that we free any previous unfetched results */
+#if HAVE_MYSQL_STMT_PREPARE
+ if (S->stmt) {
+ mysql_stmt_free_result(S->stmt);
+ }
+#endif
+ if (S->result) {
+ mysql_free_result(S->result);
+ S->result = NULL;
+ }
+
+ ret = mysql_next_result(H->server);
+
+ if (ret > 0) {
+ pdo_mysql_error_stmt(stmt);
+ return 0;
+ } else if (ret < 0) {
+ /* No more results */
+ return 0;
+ } else {
+ if ((my_ulonglong)-1 == (row_count = mysql_affected_rows(H->server))) {
+ pdo_mysql_error_stmt(stmt);
+ return 0;
+ }
+
+ if (!H->buffered) {
+ S->result = mysql_use_result(H->server);
+ } else {
+ S->result = mysql_store_result(H->server);
+ }
+
+ if (NULL == S->result) {
+ return 0;
+ }
+
+ stmt->row_count = row_count;
+ stmt->column_count = (int) mysql_num_fields(S->result);
+ S->fields = mysql_fetch_fields(S->result);
+ return 1;
+ }
+#else
+ strcpy(stmt->error_code, "HYC00");
+ return 0;
+#endif
+}
+
+
+static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
+ enum pdo_param_event event_type TSRMLS_DC)
+{
+#if HAVE_MYSQL_STMT_PREPARE
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ MYSQL_BIND *b;
+
+ if (S->stmt && param->is_param) {
+ switch (event_type) {
+ case PDO_PARAM_EVT_ALLOC:
+ /* sanity check parameter number range */
+ if (param->paramno < 0 || param->paramno >= S->num_params) {
+ strcpy(stmt->error_code, "HY093");
+ return 0;
+ }
+ b = &S->params[param->paramno];
+ param->driver_data = b;
+ b->is_null = &S->in_null[param->paramno];
+ b->length = &S->in_length[param->paramno];
+ return 1;
+
+ case PDO_PARAM_EVT_EXEC_PRE:
+ b = (MYSQL_BIND*)param->driver_data;
+
+ *b->is_null = 0;
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
+ Z_TYPE_P(param->parameter) == IS_NULL) {
+ *b->is_null = 1;
+ b->buffer_type = MYSQL_TYPE_STRING;
+ b->buffer = NULL;
+ b->buffer_length = 0;
+ *b->length = 0;
+ return 1;
+ }
+
+ switch (PDO_PARAM_TYPE(param->param_type)) {
+ case PDO_PARAM_STMT:
+ return 0;
+ case PDO_PARAM_LOB:
+ if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
+ php_stream *stm;
+ php_stream_from_zval_no_verify(stm, &param->parameter);
+ if (stm) {
+ SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
+ Z_TYPE_P(param->parameter) = IS_STRING;
+ Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm,
+ &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0);
+ } else {
+ pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
+ return 0;
+ }
+ }
+ /* fall through */
+
+ default:
+ ;
+ }
+
+ switch (Z_TYPE_P(param->parameter)) {
+ case IS_STRING:
+ b->buffer_type = MYSQL_TYPE_STRING;
+ b->buffer = Z_STRVAL_P(param->parameter);
+ b->buffer_length = Z_STRLEN_P(param->parameter);
+ *b->length = Z_STRLEN_P(param->parameter);
+ return 1;
+
+ case IS_LONG:
+ b->buffer_type = MYSQL_TYPE_LONG;
+ b->buffer = &Z_LVAL_P(param->parameter);
+ return 1;
+
+ case IS_DOUBLE:
+ b->buffer_type = MYSQL_TYPE_DOUBLE;
+ b->buffer = &Z_DVAL_P(param->parameter);
+ return 1;
+
+ default:
+ return 0;
+ }
+ }
+ }
+#endif
+ return 1;
+}
+
+static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt,
+ enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+#if HAVE_MYSQL_STMT_PREPARE
+ int ret;
+
+ if (S->stmt) {
+ ret = mysql_stmt_fetch(S->stmt);
+
+#ifdef MYSQL_DATA_TRUNCATED
+ if (ret == MYSQL_DATA_TRUNCATED) {
+ ret = 0;
+ }
+#endif
+
+ if (ret) {
+ if (ret != MYSQL_NO_DATA) {
+ pdo_mysql_error_stmt(stmt);
+ }
+ return 0;
+ }
+
+ return 1;
+ }
+#endif
+
+ if (!S->result) {
+ return 0;
+ }
+ if ((S->current_data = mysql_fetch_row(S->result)) == NULL) {
+ if (mysql_errno(S->H->server)) {
+ pdo_mysql_error_stmt(stmt);
+ }
+ return 0;
+ }
+ S->current_lengths = mysql_fetch_lengths(S->result);
+ return 1;
+}
+
+static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ struct pdo_column_data *cols = stmt->columns;
+ unsigned int i;
+
+ if (!S->result) {
+ return 0;
+ }
+
+ if (colno >= stmt->column_count) {
+ /* error invalid column */
+ return 0;
+ }
+
+ /* fetch all on demand, this seems easiest
+ ** if we've been here before bail out
+ */
+ if (cols[0].name) {
+ return 1;
+ }
+ for (i=0; i < stmt->column_count; i++) {
+ int namelen;
+ namelen = strlen(S->fields[i].name);
+ cols[i].precision = S->fields[i].decimals;
+ cols[i].maxlen = S->fields[i].length;
+ cols[i].namelen = namelen;
+ cols[i].name = estrndup(S->fields[i].name, namelen);
+ cols[i].param_type = PDO_PARAM_STR;
+ }
+ return 1;
+}
+
+static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+
+#if HAVE_MYSQL_STMT_PREPARE
+ if (!S->stmt) {
+#endif
+ if (S->current_data == NULL || !S->result) {
+ return 0;
+ }
+#if HAVE_MYSQL_STMT_PREPARE
+ }
+#endif
+ if (colno >= stmt->column_count) {
+ /* error invalid column */
+ return 0;
+ }
+#if HAVE_MYSQL_STMT_PREPARE
+ if (S->stmt) {
+ if (S->out_null[colno]) {
+ *ptr = NULL;
+ *len = 0;
+ return 1;
+ }
+ *ptr = S->bound_result[colno].buffer;
+ if (S->out_length[colno] > S->bound_result[colno].buffer_length) {
+ /* mysql lied about the column width */
+ strcpy(stmt->error_code, "01004"); /* truncated */
+ S->out_length[colno] = S->bound_result[colno].buffer_length;
+ *len = S->out_length[colno];
+ return 0;
+ }
+ *len = S->out_length[colno];
+ return 1;
+ }
+#endif
+ *ptr = S->current_data[colno];
+ *len = S->current_lengths[colno];
+ return 1;
+}
+
+static char *type_to_name_native(int type)
+{
+#define PDO_MYSQL_NATIVE_TYPE_NAME(x) case FIELD_TYPE_##x: return #x;
+
+ switch (type) {
+ PDO_MYSQL_NATIVE_TYPE_NAME(STRING)
+ PDO_MYSQL_NATIVE_TYPE_NAME(VAR_STRING)
+#ifdef MYSQL_HAS_TINY
+ PDO_MYSQL_NATIVE_TYPE_NAME(TINY)
+#endif
+ PDO_MYSQL_NATIVE_TYPE_NAME(SHORT)
+ PDO_MYSQL_NATIVE_TYPE_NAME(LONG)
+ PDO_MYSQL_NATIVE_TYPE_NAME(LONGLONG)
+ PDO_MYSQL_NATIVE_TYPE_NAME(INT24)
+ PDO_MYSQL_NATIVE_TYPE_NAME(FLOAT)
+ PDO_MYSQL_NATIVE_TYPE_NAME(DOUBLE)
+ PDO_MYSQL_NATIVE_TYPE_NAME(DECIMAL)
+#ifdef FIELD_TYPE_NEWDECIMAL
+ PDO_MYSQL_NATIVE_TYPE_NAME(NEWDECIMAL)
+#endif
+#ifdef FIELD_TYPE_GEOMETRY
+ PDO_MYSQL_NATIVE_TYPE_NAME(GEOMETRY)
+#endif
+ PDO_MYSQL_NATIVE_TYPE_NAME(TIMESTAMP)
+#ifdef MYSQL_HAS_YEAR
+ PDO_MYSQL_NATIVE_TYPE_NAME(YEAR)
+#endif
+ PDO_MYSQL_NATIVE_TYPE_NAME(SET)
+ PDO_MYSQL_NATIVE_TYPE_NAME(ENUM)
+ PDO_MYSQL_NATIVE_TYPE_NAME(DATE)
+#ifdef FIELD_TYPE_NEWDATE
+ PDO_MYSQL_NATIVE_TYPE_NAME(NEWDATE)
+#endif
+ PDO_MYSQL_NATIVE_TYPE_NAME(TIME)
+ PDO_MYSQL_NATIVE_TYPE_NAME(DATETIME)
+ PDO_MYSQL_NATIVE_TYPE_NAME(TINY_BLOB)
+ PDO_MYSQL_NATIVE_TYPE_NAME(MEDIUM_BLOB)
+ PDO_MYSQL_NATIVE_TYPE_NAME(LONG_BLOB)
+ PDO_MYSQL_NATIVE_TYPE_NAME(BLOB)
+ PDO_MYSQL_NATIVE_TYPE_NAME(NULL)
+ default:
+ return NULL;
+ }
+}
+
+static int pdo_mysql_stmt_col_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC)
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ MYSQL_FIELD *F;
+ zval *flags;
+ char *str;
+
+ if (!S->result) {
+ return FAILURE;
+ }
+ if (colno >= stmt->column_count) {
+ /* error invalid column */
+ return FAILURE;
+ }
+
+ array_init(return_value);
+ MAKE_STD_ZVAL(flags);
+ array_init(flags);
+
+ F = S->fields + colno;
+
+ if (F->def) {
+ add_assoc_string(return_value, "mysql:def", F->def, 1);
+ }
+ if (IS_NOT_NULL(F->flags)) {
+ add_next_index_string(flags, "not_null", 1);
+ }
+ if (IS_PRI_KEY(F->flags)) {
+ add_next_index_string(flags, "primary_key", 1);
+ }
+ if (F->flags & MULTIPLE_KEY_FLAG) {
+ add_next_index_string(flags, "multiple_key", 1);
+ }
+ if (F->flags & UNIQUE_KEY_FLAG) {
+ add_next_index_string(flags, "unique_key", 1);
+ }
+ if (IS_BLOB(F->flags)) {
+ add_next_index_string(flags, "blob", 1);
+ }
+ str = type_to_name_native(F->type);
+ if (str) {
+ add_assoc_string(return_value, "native_type", str, 1);
+ }
+
+ add_assoc_zval(return_value, "flags", flags);
+ return SUCCESS;
+}
+
+static int pdo_mysql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+#if HAVE_MYSQL_STMT_PREPARE
+ if (S->stmt) {
+ int retval = mysql_stmt_free_result(S->stmt);
+ return retval ? 0 : 1;
+ }
+#endif
+ if (S->result) {
+ mysql_free_result(S->result);
+ S->result = NULL;
+ }
+#if HAVE_MYSQL_NEXT_RESULT
+ while (mysql_more_results(S->H->server)) {
+ MYSQL_RES *res;
+ if (mysql_next_result(S->H->server) != 0) {
+ break;
+ }
+ res = mysql_store_result(S->H->server);
+ if (res) {
+ mysql_free_result(res);
+ }
+ }
+#endif
+ return 1;
+}
+
+struct pdo_stmt_methods mysql_stmt_methods = {
+ pdo_mysql_stmt_dtor,
+ pdo_mysql_stmt_execute,
+ pdo_mysql_stmt_fetch,
+ pdo_mysql_stmt_describe,
+ pdo_mysql_stmt_get_col,
+ pdo_mysql_stmt_param_hook,
+ NULL, /* set_attr */
+ NULL, /* get_attr */
+ pdo_mysql_stmt_col_meta,
+ pdo_mysql_stmt_next_rowset,
+ pdo_mysql_stmt_cursor_closer
+};
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_mysql/package2.xml b/ext/pdo_mysql/package2.xml
new file mode 100644
index 0000000000..cee6cc7dea
--- /dev/null
+++ b/ext/pdo_mysql/package2.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>PDO_MYSQL</name>
+ <channel>pecl.php.net</channel>
+ <summary>MySQL driver for PDO</summary>
+ <description>This extension provides a MySQL driver for PDO.
+ </description>
+ <lead>
+ <name>George Schlossnagle</name>
+ <user>gschlossnagle</user>
+ <email>george@omniti.com</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Ilia Alshanetsky</name>
+ <user>iliaa</user>
+ <email>iliaa@php.net</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Wez Furlong</name>
+ <user>wez</user>
+ <email>wez@php.net</email>
+ <active>yes</active>
+ </lead>
+ <date>2006-05-01</date>
+ <version>
+ <release>1.0.2</release>
+ <api>1.0.2</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>
+This PECL release corresponds to PHP 5.1.3.
+
+Added PDO::ATTR_EMULATE_PREPARES which can be used to force use of emulated or
+native prepares. This attribute should can be set on the database handle, and
+will cause subsequent prepares to use emulation.
+
+- Fixed bug #36572 (cannot use native prepared statements with internal
+ queries like "show master status") (Ilia)
+- Repackage using package2.xml
+- Fixed Bug #35480 and #35415, crash when using persistent connections.
+- Improved error detection for OPTIMIZE queries
+- Added PDO::MYSQL_ATTR_LOCAL_INFILE, PDO::MYSQL_ATTR_INIT_COMMAND,
+ PDO::MYSQL_ATTR_READ_DEFAULT_FILE, PDO::MYSQL_ATTR_READ_DEFAULT_GROUP
+- Improved error reporting when using native prepared statements
+- Fixed PECL Bug #5193: improved bounds checking when calling getColumnMeta()
+- Fixed Bug #34630: improved (emulated) LOB support
+- Fixed Bug #34623: crash when selecting longtext fields
+- Fixed PECL Bug #5802; is_null flag was sticking
+- Fixed PECL Bug #5645; added mysql client library version information to phpinfo() output.
+
+Windows binaries can be found at http://pecl4win.php.net/ext.php/php_pdo_mysql.dll
+
+ </notes>
+ <contents>
+ <dir name="/">
+ <file name="config.m4" role="src" />
+ <file name="CREDITS" role="doc" />
+ <file name="mysql_driver.c" role="src" />
+ <file name="mysql_statement.c" role="src" />
+ <file name="pdo_mysql.c" role="src" />
+ <file name="php_pdo_mysql.h" role="src" />
+ <file name="php_pdo_mysql_int.h" role="src" />
+ <file name="php_pdo_mysql_sqlstate.h" role="src" />
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.0.3</min>
+ </php>
+ <pearinstaller>
+ <min>1.4.0</min>
+ </pearinstaller>
+ <package>
+ <name>pdo</name>
+ <channel>pecl.php.net</channel>
+ <min>1.0.3</min>
+ <providesextension>PDO</providesextension>
+ </package>
+ </required>
+ </dependencies>
+ <providesextension>PDO_MYSQL</providesextension>
+ <extsrcrelease />
+</package>
diff --git a/ext/pdo_mysql/pdo_mysql.c b/ext/pdo_mysql/pdo_mysql.c
new file mode 100755
index 0000000000..a3d4c12c09
--- /dev/null
+++ b/ext/pdo_mysql/pdo_mysql.c
@@ -0,0 +1,116 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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: George Schlossnagle <george@omniti.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+#include "pdo/php_pdo_driver.h"
+#include "php_pdo_mysql.h"
+#include "php_pdo_mysql_int.h"
+
+/* {{{ pdo_mysql_functions[] */
+zend_function_entry pdo_mysql_functions[] = {
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ pdo_mysql_functions[] */
+#if ZEND_MODULE_API_NO >= 20050922
+static zend_module_dep pdo_mysql_deps[] = {
+ ZEND_MOD_REQUIRED("pdo")
+ {NULL, NULL, NULL}
+};
+#endif
+/* }}} */
+
+/* {{{ pdo_mysql_module_entry */
+zend_module_entry pdo_mysql_module_entry = {
+#if ZEND_MODULE_API_NO >= 20050922
+ STANDARD_MODULE_HEADER_EX, NULL,
+ pdo_mysql_deps,
+#else
+ STANDARD_MODULE_HEADER,
+#endif
+ "pdo_mysql",
+ pdo_mysql_functions,
+ PHP_MINIT(pdo_mysql),
+ PHP_MSHUTDOWN(pdo_mysql),
+ NULL,
+ NULL,
+ PHP_MINFO(pdo_mysql),
+ "1.0.2",
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_PDO_MYSQL
+ZEND_GET_MODULE(pdo_mysql)
+#endif
+
+/* true global environment */
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(pdo_mysql)
+{
+ REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_USE_BUFFERED_QUERY", (long)PDO_MYSQL_ATTR_USE_BUFFERED_QUERY);
+ REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_LOCAL_INFILE", (long)PDO_MYSQL_ATTR_LOCAL_INFILE);
+ REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_INIT_COMMAND", (long)PDO_MYSQL_ATTR_INIT_COMMAND);
+ REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_FILE", (long)PDO_MYSQL_ATTR_READ_DEFAULT_FILE);
+ REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_GROUP", (long)PDO_MYSQL_ATTR_READ_DEFAULT_GROUP);
+ REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_MAX_BUFFER_SIZE", (long)PDO_MYSQL_ATTR_MAX_BUFFER_SIZE);
+ REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_DIRECT_QUERY", (long)PDO_MYSQL_ATTR_DIRECT_QUERY);
+
+ return php_pdo_register_driver(&pdo_mysql_driver);
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_MSHUTDOWN_FUNCTION(pdo_mysql)
+{
+ php_pdo_unregister_driver(&pdo_mysql_driver);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(pdo_mysql)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "PDO Driver for MySQL, client library version", mysql_get_client_info());
+ php_info_print_table_end();
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_mysql/php_pdo_mysql.h b/ext/pdo_mysql/php_pdo_mysql.h
new file mode 100755
index 0000000000..82b9f98d45
--- /dev/null
+++ b/ext/pdo_mysql/php_pdo_mysql.h
@@ -0,0 +1,53 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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: George Schlossnagle <george@omniti.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PDO_MYSQL_H
+#define PHP_PDO_MYSQL_H
+
+extern zend_module_entry pdo_mysql_module_entry;
+#define phpext_pdo_mysql_ptr &pdo_mysql_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_PDO_MYSQL_API __declspec(dllexport)
+#else
+#define PHP_PDO_MYSQL_API
+#endif
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+PHP_MINIT_FUNCTION(pdo_mysql);
+PHP_MSHUTDOWN_FUNCTION(pdo_mysql);
+PHP_RINIT_FUNCTION(pdo_mysql);
+PHP_RSHUTDOWN_FUNCTION(pdo_mysql);
+PHP_MINFO_FUNCTION(pdo_mysql);
+
+#endif /* PHP_PDO_MYSQL_H */
+
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_mysql/php_pdo_mysql_int.h b/ext/pdo_mysql/php_pdo_mysql_int.h
new file mode 100755
index 0000000000..0ae9486c0a
--- /dev/null
+++ b/ext/pdo_mysql/php_pdo_mysql_int.h
@@ -0,0 +1,90 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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: George Schlossnagle <george@omniti.com> |
+ | Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PDO_MYSQL_INT_H
+#define PHP_PDO_MYSQL_INT_H
+
+#include <mysql.h>
+
+typedef struct {
+ const char *file;
+ int line;
+ unsigned int errcode;
+ char *errmsg;
+} pdo_mysql_error_info;
+
+/* stuff we use in a mySQL database handle */
+typedef struct {
+ MYSQL *server;
+
+ unsigned attached:1;
+ unsigned buffered:1;
+ unsigned emulate_prepare:1;
+ unsigned _reserved:31;
+ unsigned long max_buffer_size;
+
+ pdo_mysql_error_info einfo;
+} pdo_mysql_db_handle;
+
+typedef struct {
+ MYSQL_FIELD *def;
+} pdo_mysql_column;
+
+typedef struct {
+ pdo_mysql_db_handle *H;
+ MYSQL_RES *result;
+ MYSQL_FIELD *fields;
+ MYSQL_ROW current_data;
+ long *current_lengths;
+ pdo_mysql_error_info einfo;
+#if HAVE_MYSQL_STMT_PREPARE
+ MYSQL_STMT *stmt;
+
+ int num_params;
+ MYSQL_BIND *params;
+ my_bool *in_null;
+ unsigned long *in_length;
+
+ MYSQL_BIND *bound_result;
+ my_bool *out_null;
+ unsigned long *out_length;
+ unsigned max_length:1;
+#endif
+} pdo_mysql_stmt;
+
+extern pdo_driver_t pdo_mysql_driver;
+
+extern int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC);
+#define pdo_mysql_error(s) _pdo_mysql_error(s, NULL, __FILE__, __LINE__ TSRMLS_CC)
+#define pdo_mysql_error_stmt(s) _pdo_mysql_error(stmt->dbh, stmt, __FILE__, __LINE__ TSRMLS_CC)
+
+extern struct pdo_stmt_methods mysql_stmt_methods;
+
+enum {
+ PDO_MYSQL_ATTR_USE_BUFFERED_QUERY = PDO_ATTR_DRIVER_SPECIFIC,
+ PDO_MYSQL_ATTR_LOCAL_INFILE,
+ PDO_MYSQL_ATTR_INIT_COMMAND,
+ PDO_MYSQL_ATTR_READ_DEFAULT_FILE,
+ PDO_MYSQL_ATTR_READ_DEFAULT_GROUP,
+ PDO_MYSQL_ATTR_MAX_BUFFER_SIZE,
+ PDO_MYSQL_ATTR_DIRECT_QUERY,
+};
+#endif
diff --git a/ext/pdo_mysql/php_pdo_mysql_sqlstate.h b/ext/pdo_mysql/php_pdo_mysql_sqlstate.h
new file mode 100644
index 0000000000..97724b72e9
--- /dev/null
+++ b/ext/pdo_mysql/php_pdo_mysql_sqlstate.h
@@ -0,0 +1,388 @@
+/* DO NOT EDIT THIS FILE!!! It is auto generated by get_error_codes.php */
+#ifdef ER_DUP_KEY
+ case ER_DUP_KEY : return "23000";
+#endif
+#ifdef ER_OUTOFMEMORY
+ case ER_OUTOFMEMORY : return "HY001";
+#endif
+#ifdef ER_OUT_OF_SORTMEMORY
+ case ER_OUT_OF_SORTMEMORY : return "HY001";
+#endif
+#ifdef ER_CON_COUNT_ERROR
+ case ER_CON_COUNT_ERROR : return "08004";
+#endif
+#ifdef ER_BAD_HOST_ERROR
+ case ER_BAD_HOST_ERROR : return "08S01";
+#endif
+#ifdef ER_HANDSHAKE_ERROR
+ case ER_HANDSHAKE_ERROR : return "08S01";
+#endif
+#ifdef ER_DBACCESS_DENIED_ERROR
+ case ER_DBACCESS_DENIED_ERROR : return "42000";
+#endif
+#ifdef ER_ACCESS_DENIED_ERROR
+ case ER_ACCESS_DENIED_ERROR : return "28000";
+#endif
+#ifdef ER_NO_DB_ERROR
+ case ER_NO_DB_ERROR : return "3D000";
+#endif
+#ifdef ER_UNKNOWN_COM_ERROR
+ case ER_UNKNOWN_COM_ERROR : return "08S01";
+#endif
+#ifdef ER_BAD_NULL_ERROR
+ case ER_BAD_NULL_ERROR : return "23000";
+#endif
+#ifdef ER_BAD_DB_ERROR
+ case ER_BAD_DB_ERROR : return "42000";
+#endif
+#ifdef ER_TABLE_EXISTS_ERROR
+ case ER_TABLE_EXISTS_ERROR : return "42S01";
+#endif
+#ifdef ER_BAD_TABLE_ERROR
+ case ER_BAD_TABLE_ERROR : return "42S02";
+#endif
+#ifdef ER_NON_UNIQ_ERROR
+ case ER_NON_UNIQ_ERROR : return "23000";
+#endif
+#ifdef ER_SERVER_SHUTDOWN
+ case ER_SERVER_SHUTDOWN : return "08S01";
+#endif
+#ifdef ER_BAD_FIELD_ERROR
+ case ER_BAD_FIELD_ERROR : return "42S22";
+#endif
+#ifdef ER_WRONG_FIELD_WITH_GROUP
+ case ER_WRONG_FIELD_WITH_GROUP : return "42000";
+#endif
+#ifdef ER_WRONG_GROUP_FIELD
+ case ER_WRONG_GROUP_FIELD : return "42000";
+#endif
+#ifdef ER_WRONG_SUM_SELECT
+ case ER_WRONG_SUM_SELECT : return "42000";
+#endif
+#ifdef ER_WRONG_VALUE_COUNT
+ case ER_WRONG_VALUE_COUNT : return "21S01";
+#endif
+#ifdef ER_TOO_LONG_IDENT
+ case ER_TOO_LONG_IDENT : return "42000";
+#endif
+#ifdef ER_DUP_FIELDNAME
+ case ER_DUP_FIELDNAME : return "42S21";
+#endif
+#ifdef ER_DUP_KEYNAME
+ case ER_DUP_KEYNAME : return "42000";
+#endif
+#ifdef ER_DUP_ENTRY
+ case ER_DUP_ENTRY : return "23000";
+#endif
+#ifdef ER_WRONG_FIELD_SPEC
+ case ER_WRONG_FIELD_SPEC : return "42000";
+#endif
+#ifdef ER_PARSE_ERROR
+ case ER_PARSE_ERROR : return "42000";
+#endif
+#ifdef ER_NONUNIQ_TABLE
+ case ER_NONUNIQ_TABLE : return "42000";
+#endif
+#ifdef ER_INVALID_DEFAULT
+ case ER_INVALID_DEFAULT : return "42000";
+#endif
+#ifdef ER_MULTIPLE_PRI_KEY
+ case ER_MULTIPLE_PRI_KEY : return "42000";
+#endif
+#ifdef ER_TOO_MANY_KEYS
+ case ER_TOO_MANY_KEYS : return "42000";
+#endif
+#ifdef ER_TOO_MANY_KEY_PARTS
+ case ER_TOO_MANY_KEY_PARTS : return "42000";
+#endif
+#ifdef ER_TOO_LONG_KEY
+ case ER_TOO_LONG_KEY : return "42000";
+#endif
+#ifdef ER_KEY_COLUMN_DOES_NOT_EXITS
+ case ER_KEY_COLUMN_DOES_NOT_EXITS : return "42000";
+#endif
+#ifdef ER_BLOB_USED_AS_KEY
+ case ER_BLOB_USED_AS_KEY : return "42000";
+#endif
+#ifdef ER_TOO_BIG_FIELDLENGTH
+ case ER_TOO_BIG_FIELDLENGTH : return "42000";
+#endif
+#ifdef ER_WRONG_AUTO_KEY
+ case ER_WRONG_AUTO_KEY : return "42000";
+#endif
+#ifdef ER_FORCING_CLOSE
+ case ER_FORCING_CLOSE : return "08S01";
+#endif
+#ifdef ER_IPSOCK_ERROR
+ case ER_IPSOCK_ERROR : return "08S01";
+#endif
+#ifdef ER_NO_SUCH_INDEX
+ case ER_NO_SUCH_INDEX : return "42S12";
+#endif
+#ifdef ER_WRONG_FIELD_TERMINATORS
+ case ER_WRONG_FIELD_TERMINATORS : return "42000";
+#endif
+#ifdef ER_BLOBS_AND_NO_TERMINATED
+ case ER_BLOBS_AND_NO_TERMINATED : return "42000";
+#endif
+#ifdef ER_CANT_REMOVE_ALL_FIELDS
+ case ER_CANT_REMOVE_ALL_FIELDS : return "42000";
+#endif
+#ifdef ER_CANT_DROP_FIELD_OR_KEY
+ case ER_CANT_DROP_FIELD_OR_KEY : return "42000";
+#endif
+#ifdef ER_BLOB_CANT_HAVE_DEFAULT
+ case ER_BLOB_CANT_HAVE_DEFAULT : return "42000";
+#endif
+#ifdef ER_WRONG_DB_NAME
+ case ER_WRONG_DB_NAME : return "42000";
+#endif
+#ifdef ER_WRONG_TABLE_NAME
+ case ER_WRONG_TABLE_NAME : return "42000";
+#endif
+#ifdef ER_TOO_BIG_SELECT
+ case ER_TOO_BIG_SELECT : return "42000";
+#endif
+#ifdef ER_UNKNOWN_PROCEDURE
+ case ER_UNKNOWN_PROCEDURE : return "42000";
+#endif
+#ifdef ER_WRONG_PARAMCOUNT_TO_PROCEDURE
+ case ER_WRONG_PARAMCOUNT_TO_PROCEDURE : return "42000";
+#endif
+#ifdef ER_UNKNOWN_TABLE
+ case ER_UNKNOWN_TABLE : return "42S02";
+#endif
+#ifdef ER_FIELD_SPECIFIED_TWICE
+ case ER_FIELD_SPECIFIED_TWICE : return "42000";
+#endif
+#ifdef ER_UNSUPPORTED_EXTENSION
+ case ER_UNSUPPORTED_EXTENSION : return "42000";
+#endif
+#ifdef ER_TABLE_MUST_HAVE_COLUMNS
+ case ER_TABLE_MUST_HAVE_COLUMNS : return "42000";
+#endif
+#ifdef ER_UNKNOWN_CHARACTER_SET
+ case ER_UNKNOWN_CHARACTER_SET : return "42000";
+#endif
+#ifdef ER_TOO_BIG_ROWSIZE
+ case ER_TOO_BIG_ROWSIZE : return "42000";
+#endif
+#ifdef ER_WRONG_OUTER_JOIN
+ case ER_WRONG_OUTER_JOIN : return "42000";
+#endif
+#ifdef ER_NULL_COLUMN_IN_INDEX
+ case ER_NULL_COLUMN_IN_INDEX : return "42000";
+#endif
+#ifdef ER_PASSWORD_ANONYMOUS_USER
+ case ER_PASSWORD_ANONYMOUS_USER : return "42000";
+#endif
+#ifdef ER_PASSWORD_NOT_ALLOWED
+ case ER_PASSWORD_NOT_ALLOWED : return "42000";
+#endif
+#ifdef ER_PASSWORD_NO_MATCH
+ case ER_PASSWORD_NO_MATCH : return "42000";
+#endif
+#ifdef ER_WRONG_VALUE_COUNT_ON_ROW
+ case ER_WRONG_VALUE_COUNT_ON_ROW : return "21S01";
+#endif
+#ifdef ER_INVALID_USE_OF_NULL
+ case ER_INVALID_USE_OF_NULL : return "42000";
+#endif
+#ifdef ER_REGEXP_ERROR
+ case ER_REGEXP_ERROR : return "42000";
+#endif
+#ifdef ER_NONEXISTING_GRANT
+ case ER_NONEXISTING_GRANT : return "42000";
+#endif
+#ifdef ER_TABLEACCESS_DENIED_ERROR
+ case ER_TABLEACCESS_DENIED_ERROR : return "42000";
+#endif
+#ifdef ER_COLUMNACCESS_DENIED_ERROR
+ case ER_COLUMNACCESS_DENIED_ERROR : return "42000";
+#endif
+#ifdef ER_ILLEGAL_GRANT_FOR_TABLE
+ case ER_ILLEGAL_GRANT_FOR_TABLE : return "42000";
+#endif
+#ifdef ER_GRANT_WRONG_HOST_OR_USER
+ case ER_GRANT_WRONG_HOST_OR_USER : return "42000";
+#endif
+#ifdef ER_NO_SUCH_TABLE
+ case ER_NO_SUCH_TABLE : return "42S02";
+#endif
+#ifdef ER_NONEXISTING_TABLE_GRANT
+ case ER_NONEXISTING_TABLE_GRANT : return "42000";
+#endif
+#ifdef ER_NOT_ALLOWED_COMMAND
+ case ER_NOT_ALLOWED_COMMAND : return "42000";
+#endif
+#ifdef ER_SYNTAX_ERROR
+ case ER_SYNTAX_ERROR : return "42000";
+#endif
+#ifdef ER_ABORTING_CONNECTION
+ case ER_ABORTING_CONNECTION : return "08S01";
+#endif
+#ifdef ER_NET_PACKET_TOO_LARGE
+ case ER_NET_PACKET_TOO_LARGE : return "08S01";
+#endif
+#ifdef ER_NET_READ_ERROR_FROM_PIPE
+ case ER_NET_READ_ERROR_FROM_PIPE : return "08S01";
+#endif
+#ifdef ER_NET_FCNTL_ERROR
+ case ER_NET_FCNTL_ERROR : return "08S01";
+#endif
+#ifdef ER_NET_PACKETS_OUT_OF_ORDER
+ case ER_NET_PACKETS_OUT_OF_ORDER : return "08S01";
+#endif
+#ifdef ER_NET_UNCOMPRESS_ERROR
+ case ER_NET_UNCOMPRESS_ERROR : return "08S01";
+#endif
+#ifdef ER_NET_READ_ERROR
+ case ER_NET_READ_ERROR : return "08S01";
+#endif
+#ifdef ER_NET_READ_INTERRUPTED
+ case ER_NET_READ_INTERRUPTED : return "08S01";
+#endif
+#ifdef ER_NET_ERROR_ON_WRITE
+ case ER_NET_ERROR_ON_WRITE : return "08S01";
+#endif
+#ifdef ER_NET_WRITE_INTERRUPTED
+ case ER_NET_WRITE_INTERRUPTED : return "08S01";
+#endif
+#ifdef ER_TOO_LONG_STRING
+ case ER_TOO_LONG_STRING : return "42000";
+#endif
+#ifdef ER_TABLE_CANT_HANDLE_BLOB
+ case ER_TABLE_CANT_HANDLE_BLOB : return "42000";
+#endif
+#ifdef ER_TABLE_CANT_HANDLE_AUTO_INCREMENT
+ case ER_TABLE_CANT_HANDLE_AUTO_INCREMENT : return "42000";
+#endif
+#ifdef ER_WRONG_COLUMN_NAME
+ case ER_WRONG_COLUMN_NAME : return "42000";
+#endif
+#ifdef ER_WRONG_KEY_COLUMN
+ case ER_WRONG_KEY_COLUMN : return "42000";
+#endif
+#ifdef ER_DUP_UNIQUE
+ case ER_DUP_UNIQUE : return "23000";
+#endif
+#ifdef ER_BLOB_KEY_WITHOUT_LENGTH
+ case ER_BLOB_KEY_WITHOUT_LENGTH : return "42000";
+#endif
+#ifdef ER_PRIMARY_CANT_HAVE_NULL
+ case ER_PRIMARY_CANT_HAVE_NULL : return "42000";
+#endif
+#ifdef ER_TOO_MANY_ROWS
+ case ER_TOO_MANY_ROWS : return "42000";
+#endif
+#ifdef ER_REQUIRES_PRIMARY_KEY
+ case ER_REQUIRES_PRIMARY_KEY : return "42000";
+#endif
+#ifdef ER_CHECK_NO_SUCH_TABLE
+ case ER_CHECK_NO_SUCH_TABLE : return "42000";
+#endif
+#ifdef ER_CHECK_NOT_IMPLEMENTED
+ case ER_CHECK_NOT_IMPLEMENTED : return "42000";
+#endif
+#ifdef ER_CANT_DO_THIS_DURING_AN_TRANSACTION
+ case ER_CANT_DO_THIS_DURING_AN_TRANSACTION: return "25000";
+#endif
+#ifdef ER_NEW_ABORTING_CONNECTION
+ case ER_NEW_ABORTING_CONNECTION : return "08S01";
+#endif
+#ifdef ER_MASTER_NET_READ
+ case ER_MASTER_NET_READ : return "08S01";
+#endif
+#ifdef ER_MASTER_NET_WRITE
+ case ER_MASTER_NET_WRITE : return "08S01";
+#endif
+#ifdef ER_TOO_MANY_USER_CONNECTIONS
+ case ER_TOO_MANY_USER_CONNECTIONS : return "42000";
+#endif
+#ifdef ER_READ_ONLY_TRANSACTION
+ case ER_READ_ONLY_TRANSACTION : return "25000";
+#endif
+#ifdef ER_LOCK_DEADLOCK
+ case ER_LOCK_DEADLOCK : return "40001";
+#endif
+#ifdef ER_NO_REFERENCED_ROW
+ case ER_NO_REFERENCED_ROW : return "23000";
+#endif
+#ifdef ER_ROW_IS_REFERENCED
+ case ER_ROW_IS_REFERENCED : return "23000";
+#endif
+#ifdef ER_CONNECT_TO_MASTER
+ case ER_CONNECT_TO_MASTER : return "08S01";
+#endif
+#ifdef ER_USER_LIMIT_REACHED
+ case ER_USER_LIMIT_REACHED : return "42000";
+#endif
+#ifdef ER_NO_DEFAULT
+ case ER_NO_DEFAULT : return "42000";
+#endif
+#ifdef ER_WRONG_VALUE_FOR_VAR
+ case ER_WRONG_VALUE_FOR_VAR : return "42000";
+#endif
+#ifdef ER_WRONG_TYPE_FOR_VAR
+ case ER_WRONG_TYPE_FOR_VAR : return "42000";
+#endif
+#ifdef ER_CANT_USE_OPTION_HERE
+ case ER_CANT_USE_OPTION_HERE : return "42000";
+#endif
+#ifdef ER_NOT_SUPPORTED_YET
+ case ER_NOT_SUPPORTED_YET : return "42000";
+#endif
+#ifdef ER_WRONG_FK_DEF
+ case ER_WRONG_FK_DEF : return "42000";
+#endif
+#ifdef ER_OPERAND_COLUMNS
+ case ER_OPERAND_COLUMNS : return "21000";
+#endif
+#ifdef ER_SUBQUERY_NO_1_ROW
+ case ER_SUBQUERY_NO_1_ROW : return "21000";
+#endif
+#ifdef ER_ILLEGAL_REFERENCE
+ case ER_ILLEGAL_REFERENCE : return "42S22";
+#endif
+#ifdef ER_DERIVED_MUST_HAVE_ALIAS
+ case ER_DERIVED_MUST_HAVE_ALIAS : return "42000";
+#endif
+#ifdef ER_SELECT_REDUCED
+ case ER_SELECT_REDUCED : return "01000";
+#endif
+#ifdef ER_TABLENAME_NOT_ALLOWED_HERE
+ case ER_TABLENAME_NOT_ALLOWED_HERE : return "42000";
+#endif
+#ifdef ER_NOT_SUPPORTED_AUTH_MODE
+ case ER_NOT_SUPPORTED_AUTH_MODE : return "08004";
+#endif
+#ifdef ER_SPATIAL_CANT_HAVE_NULL
+ case ER_SPATIAL_CANT_HAVE_NULL : return "42000";
+#endif
+#ifdef ER_COLLATION_CHARSET_MISMATCH
+ case ER_COLLATION_CHARSET_MISMATCH : return "42000";
+#endif
+#ifdef ER_WARN_TOO_FEW_RECORDS
+ case ER_WARN_TOO_FEW_RECORDS : return "01000";
+#endif
+#ifdef ER_WARN_TOO_MANY_RECORDS
+ case ER_WARN_TOO_MANY_RECORDS : return "01000";
+#endif
+#ifdef ER_WARN_NULL_TO_NOTNULL
+ case ER_WARN_NULL_TO_NOTNULL : return "01000";
+#endif
+#ifdef ER_WARN_DATA_OUT_OF_RANGE
+ case ER_WARN_DATA_OUT_OF_RANGE : return "01000";
+#endif
+#ifdef ER_WARN_DATA_TRUNCATED
+ case ER_WARN_DATA_TRUNCATED : return "01000";
+#endif
+#ifdef ER_WRONG_NAME_FOR_INDEX
+ case ER_WRONG_NAME_FOR_INDEX : return "42000";
+#endif
+#ifdef ER_WRONG_NAME_FOR_CATALOG
+ case ER_WRONG_NAME_FOR_CATALOG : return "42000";
+#endif
+#ifdef ER_UNKNOWN_STORAGE_ENGINE
+ case ER_UNKNOWN_STORAGE_ENGINE : return "42000";
+#endif
diff --git a/ext/pdo_mysql/tests/bug_33689.phpt b/ext/pdo_mysql/tests/bug_33689.phpt
new file mode 100644
index 0000000000..609e3dce54
--- /dev/null
+++ b/ext/pdo_mysql/tests/bug_33689.phpt
@@ -0,0 +1,50 @@
+--TEST--
+PDO MySQL Bug #33689
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$db->exec('CREATE TABLE test (bar INT NOT NULL)');
+$db->exec('INSERT INTO test VALUES(1)');
+
+var_dump($db->query('SELECT * from test'));
+foreach ($db->query('SELECT * from test') as $row) {
+ print_r($row);
+}
+
+$stmt = $db->prepare('SELECT * from test');
+print_r($stmt->getColumnMeta(0));
+$stmt->execute();
+print_r($stmt->getColumnMeta(0));
+
+--EXPECTF--
+object(PDOStatement)#%d (1) {
+ ["queryString"]=>
+ string(18) "SELECT * from test"
+}
+Array
+(
+ [bar] => 1
+ [0] => 1
+)
+Array
+(
+ [native_type] => LONG
+ [flags] => Array
+ (
+ [0] => not_null
+ )
+
+ [name] => bar
+ [len] => 11
+ [precision] => 0
+ [pdo_type] => 2
+)
diff --git a/ext/pdo_mysql/tests/common.phpt b/ext/pdo_mysql/tests/common.phpt
new file mode 100644
index 0000000000..8179454cf7
--- /dev/null
+++ b/ext/pdo_mysql/tests/common.phpt
@@ -0,0 +1,28 @@
+--TEST--
+MySQL
+--SKIPIF--
+<?php # vim:ft=php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) print 'skip not loaded';
+?>
+--REDIRECTTEST--
+# magic auto-configuration
+
+$config = array(
+ 'TESTS' => 'ext/pdo/tests'
+);
+
+if (false !== getenv('PDO_MYSQL_TEST_DSN')) {
+ # user set them from their shell
+ $config['ENV']['PDOTEST_DSN'] = getenv('PDO_MYSQL_TEST_DSN');
+ $config['ENV']['PDOTEST_USER'] = getenv('PDO_MYSQL_TEST_USER');
+ $config['ENV']['PDOTEST_PASS'] = getenv('PDO_MYSQL_TEST_PASS');
+ if (false !== getenv('PDO_MYSQL_TEST_ATTR')) {
+ $config['ENV']['PDOTEST_ATTR'] = getenv('PDO_MYSQL_TEST_ATTR');
+ }
+} else {
+ $config['ENV']['PDOTEST_DSN'] = 'mysql:host=localhost;dbname=test';
+ $config['ENV']['PDOTEST_USER'] = 'root';
+ $config['ENV']['PDOTEST_PASS'] = '';
+}
+
+return $config;
diff --git a/ext/pdo_mysql/tests/config.inc b/ext/pdo_mysql/tests/config.inc
new file mode 100644
index 0000000000..855f89bc1e
--- /dev/null
+++ b/ext/pdo_mysql/tests/config.inc
@@ -0,0 +1,19 @@
+<?php
+
+if (false !== getenv('PDO_MYSQL_TEST_DSN')) {
+ # user set them from their shell
+ $config['ENV']['PDOTEST_DSN'] = getenv('PDO_MYSQL_TEST_DSN');
+ $config['ENV']['PDOTEST_USER'] = getenv('PDO_MYSQL_TEST_USER');
+ $config['ENV']['PDOTEST_PASS'] = getenv('PDO_MYSQL_TEST_PASS');
+ if (false !== getenv('PDO_MYSQL_TEST_ATTR')) {
+ $config['ENV']['PDOTEST_ATTR'] = getenv('PDO_MYSQL_TEST_ATTR');
+ }
+} else {
+ $config['ENV']['PDOTEST_DSN'] = 'mysql:host=localhost;dbname=test';
+ $config['ENV']['PDOTEST_USER'] = 'root';
+ $config['ENV']['PDOTEST_PASS'] = '';
+}
+
+foreach ($config['ENV'] as $k => $v) {
+ putenv("$k=$v");
+}
diff --git a/ext/pdo_mysql/tests/pecl_bug_5200.phpt b/ext/pdo_mysql/tests/pecl_bug_5200.phpt
new file mode 100644
index 0000000000..2dffd1141f
--- /dev/null
+++ b/ext/pdo_mysql/tests/pecl_bug_5200.phpt
@@ -0,0 +1,30 @@
+--TEST--
+PDO MySQL PECL Bug #5200
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__). '/common.phpt');
+
+$db->exec("CREATE TABLE test (bar INT NOT NULL, phase enum('please_select', 'I', 'II', 'IIa', 'IIb', 'III', 'IV'))");
+
+foreach ($db->query('DESCRIBE test phase')->fetchAll(PDO::FETCH_ASSOC) as $row) {
+ print_r($row);
+}
+
+--EXPECT--
+Array
+(
+ [field] => phase
+ [type] => enum('please_select','I','II','IIa','IIb','III','IV')
+ [null] => YES
+ [key] =>
+ [default] =>
+ [extra] =>
+)
diff --git a/ext/pdo_mysql/tests/pecl_bug_5780.phpt b/ext/pdo_mysql/tests/pecl_bug_5780.phpt
new file mode 100644
index 0000000000..643597c016
--- /dev/null
+++ b/ext/pdo_mysql/tests/pecl_bug_5780.phpt
@@ -0,0 +1,41 @@
+--TEST--
+PDO MySQL PECL Bug #5780
+--SKIPIF--
+<?php # vim:ft=php:
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__). '/common.phpt');
+
+$db->exec("CREATE TABLE test (login varchar(32) NOT NULL, data varchar(64) NOT NULL)");
+$db->exec("CREATE TABLE test2 (login varchar(32) NOT NULL, password varchar(64) NOT NULL)");
+$db->exec("INSERT INTO test2 (login, password) VALUES ('testing', 'testing')");
+$db->exec("INSERT INTO test2 (login, password) VALUES ('test2', 'testpw2')");
+
+$logstmt = $db->prepare('INSERT INTO test (login, data) VALUES (:var1, :var2)');
+$authstmt = $db->prepare('SELECT * FROM test2 WHERE login = :varlog AND password = :varpass');
+$authstmt->execute(array(':varlog' => 'testing', ':varpass' => 'testing'));
+var_dump($authstmt->fetch(PDO::FETCH_NUM));
+@var_dump($logstmt->execute(array(':var1' => 'test1', ':var2' => 'test2')));
+$info = $logstmt->errorInfo();
+unset($info[2]);
+var_dump($info);
+--EXPECT--
+array(2) {
+ [0]=>
+ string(7) "testing"
+ [1]=>
+ string(7) "testing"
+}
+bool(false)
+array(2) {
+ [0]=>
+ string(5) "HY000"
+ [1]=>
+ int(2014)
+}
diff --git a/ext/pdo_mysql/tests/pecl_bug_5802.phpt b/ext/pdo_mysql/tests/pecl_bug_5802.phpt
new file mode 100644
index 0000000000..70bd461635
--- /dev/null
+++ b/ext/pdo_mysql/tests/pecl_bug_5802.phpt
@@ -0,0 +1,52 @@
+--TEST--
+PDO MySQL PECL Bug #5802
+--SKIPIF--
+<?php # vim:ft=php:
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__). '/common.phpt');
+
+$db->exec('create table test ( bar char(3) NULL )');
+$stmt = $db->prepare('insert into test (bar) values(:bar)') or var_dump($db->errorInfo());
+
+$bar = 'foo';
+$stmt->bindParam(':bar', $bar);
+$stmt->execute() or var_dump($stmt->errorInfo());
+
+$bar = null;
+$stmt->bindParam(':bar', $bar);
+$stmt->execute() or var_dump($stmt->errorInfo());
+
+$bar = 'qaz';
+$stmt->bindParam(':bar', $bar);
+$stmt->execute() or var_dump($stmt->errorInfo());
+
+$stmt = $db->prepare('select * from test') or var_dump($db->errorInfo());
+
+if($stmt) $stmt->execute();
+if($stmt) var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
+
+--EXPECT--
+array(3) {
+ [0]=>
+ array(1) {
+ ["bar"]=>
+ string(3) "foo"
+ }
+ [1]=>
+ array(1) {
+ ["bar"]=>
+ NULL
+ }
+ [2]=>
+ array(1) {
+ ["bar"]=>
+ string(3) "qaz"
+ }
+}
diff --git a/ext/pdo_mysql/tests/show_tables.phpt b/ext/pdo_mysql/tests/show_tables.phpt
new file mode 100644
index 0000000000..90b07db32e
--- /dev/null
+++ b/ext/pdo_mysql/tests/show_tables.phpt
@@ -0,0 +1,20 @@
+--TEST--
+PDO MySQL SHOW TABLES
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+print_r($db->query('SHOW TABLES'));
+--EXPECT--
+PDOStatement Object
+(
+ [queryString] => SHOW TABLES
+)
diff --git a/ext/pdo_pgsql/CREDITS b/ext/pdo_pgsql/CREDITS
new file mode 100644
index 0000000000..bbb7b94428
--- /dev/null
+++ b/ext/pdo_pgsql/CREDITS
@@ -0,0 +1,2 @@
+PostgreSQL driver for PDO
+Edin Kadribasic, Ilia Alshanetsky
diff --git a/ext/pdo_pgsql/config.m4 b/ext/pdo_pgsql/config.m4
new file mode 100644
index 0000000000..9f356db64a
--- /dev/null
+++ b/ext/pdo_pgsql/config.m4
@@ -0,0 +1,131 @@
+dnl
+dnl $Id$
+dnl
+
+if test "$PHP_PDO" != "no"; then
+
+AC_DEFUN([PHP_PGSQL_CHECK_FUNCTIONS],[
+])
+
+PHP_ARG_WITH(pdo-pgsql,for PostgreSQL support for PDO,
+[ --with-pdo-pgsql[=DIR] PDO: PostgreSQL support. DIR is the PostgreSQL base
+ install directory or the path to pg_config])
+
+if test "$PHP_PDO_PGSQL" != "no"; then
+ PHP_EXPAND_PATH($PGSQL_INCLUDE, PGSQL_INCLUDE)
+
+ AC_MSG_CHECKING(for pg_config)
+ for i in $PHP_PDO_PGSQL $PHP_PDO_PGSQL/bin /usr/local/pgsql/bin /usr/local/bin /usr/bin ""; do
+ if test -x $i/pg_config; then
+ PG_CONFIG="$i/pg_config"
+ break;
+ fi
+ done
+
+ if test -n "$PG_CONFIG"; then
+ AC_MSG_RESULT([$PG_CONFIG])
+ PGSQL_INCLUDE=`$PG_CONFIG --includedir`
+ PGSQL_LIBDIR=`$PG_CONFIG --libdir`
+ AC_DEFINE(HAVE_PG_CONFIG_H,1,[Whether to have pg_config.h])
+ else
+ AC_MSG_RESULT(not found)
+ if test "$PHP_PDO_PGSQL" = "yes"; then
+ PGSQL_SEARCH_PATHS="/usr /usr/local /usr/local/pgsql"
+ else
+ PGSQL_SEARCH_PATHS=$PHP_PDO_PGSQL
+ fi
+
+ for i in $PGSQL_SEARCH_PATHS; do
+ for j in include include/pgsql include/postgres include/postgresql ""; do
+ if test -r "$i/$j/libpq-fe.h"; then
+ PGSQL_INC_BASE=$i
+ PGSQL_INCLUDE=$i/$j
+ if test -r "$i/$j/pg_config.h"; then
+ AC_DEFINE(HAVE_PG_CONFIG_H,1,[Whether to have pg_config.h])
+ fi
+ fi
+ done
+
+ for j in lib lib/pgsql lib/postgres lib/postgresql ""; do
+ if test -f "$i/$j/libpq.so" || test -f "$i/$j/libpq.a"; then
+ PGSQL_LIBDIR=$i/$j
+ fi
+ done
+ done
+ fi
+
+ if test -z "$PGSQL_INCLUDE"; then
+ AC_MSG_ERROR(Cannot find libpq-fe.h. Please specify correct PostgreSQL installation path)
+ fi
+
+ if test -z "$PGSQL_LIBDIR"; then
+ AC_MSG_ERROR(Cannot find libpq.so. Please specify correct PostgreSQL installation path)
+ fi
+
+ if test -z "$PGSQL_INCLUDE" -a -z "$PGSQL_LIBDIR" ; then
+ AC_MSG_ERROR([Unable to find libpq anywhere under $withval])
+ fi
+
+ AC_DEFINE(HAVE_PDO_PGSQL,1,[Whether to build PostgreSQL for PDO support or not])
+
+ AC_MSG_CHECKING([for openssl dependencies])
+ if grep -q openssl $PGSQL_INCLUDE/libpq-fe.h ; then
+ AC_MSG_RESULT([yes])
+ if pkg-config openssl ; then
+ PDO_PGSQL_CFLAGS="`pkg-config openssl --cflags`"
+ fi
+ else
+ AC_MSG_RESULT([no])
+ fi
+
+ old_LIBS=$LIBS
+ old_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -L$PGSQL_LIBDIR"
+ AC_CHECK_LIB(pq, PQescapeString,AC_DEFINE(HAVE_PQESCAPE,1,[PostgreSQL 7.2.0 or later]))
+ AC_CHECK_LIB(pq, PQsetnonblocking,AC_DEFINE(HAVE_PQSETNONBLOCKING,1,[PostgreSQL 7.0.x or later]))
+ AC_CHECK_LIB(pq, PQcmdTuples,AC_DEFINE(HAVE_PQCMDTUPLES,1,[Broken libpq under windows]))
+ AC_CHECK_LIB(pq, PQoidValue,AC_DEFINE(HAVE_PQOIDVALUE,1,[Older PostgreSQL]))
+ AC_CHECK_LIB(pq, PQclientEncoding,AC_DEFINE(HAVE_PQCLIENTENCODING,1,[PostgreSQL 7.0.x or later]))
+ AC_CHECK_LIB(pq, PQparameterStatus,AC_DEFINE(HAVE_PQPARAMETERSTATUS,1,[PostgreSQL 7.4 or later]))
+ AC_CHECK_LIB(pq, PQprotocolVersion,AC_DEFINE(HAVE_PQPROTOCOLVERSION,1,[PostgreSQL 7.4 or later]))
+ AC_CHECK_LIB(pq, PQtransactionStatus,AC_DEFINE(HAVE_PGTRANSACTIONSTATUS,1,[PostgreSQL 7.4 or later]))
+ AC_CHECK_LIB(pq, PQunescapeBytea,AC_DEFINE(HAVE_PQUNESCAPEBYTEA,1,[PostgreSQL 7.4 or later]))
+ AC_CHECK_LIB(pq, PQExecParams,AC_DEFINE(HAVE_PQEXECPARAMS,1,[PostgreSQL 7.4 or later]))
+ AC_CHECK_LIB(pq, PQresultErrorField,AC_DEFINE(HAVE_PQRESULTERRORFIELD,1,[PostgreSQL 7.4 or later]))
+ AC_CHECK_LIB(pq, pg_encoding_to_char,AC_DEFINE(HAVE_PGSQL_WITH_MULTIBYTE_SUPPORT,1,[Whether libpq is compiled with --enable-multibyte]))
+
+ AC_CHECK_LIB(pq, PQprepare,AC_DEFINE(HAVE_PQPREPARE,1,[prepared statements]))
+
+ LIBS=$old_LIBS
+ LDFLAGS=$old_LDFLAGS
+
+ PHP_ADD_LIBRARY_WITH_PATH(pq, $PGSQL_LIBDIR, PDO_PGSQL_SHARED_LIBADD)
+ PHP_SUBST(PDO_PGSQL_SHARED_LIBADD)
+
+ PHP_ADD_INCLUDE($PGSQL_INCLUDE)
+
+ ifdef([PHP_CHECK_PDO_INCLUDES],
+ [
+ PHP_CHECK_PDO_INCLUDES
+ ],[
+ AC_MSG_CHECKING([for PDO includes])
+ if test -f $abs_srcdir/include/php/ext/pdo/php_pdo_driver.h; then
+ pdo_inc_path=$abs_srcdir/ext
+ elif test -f $abs_srcdir/ext/pdo/php_pdo_driver.h; then
+ pdo_inc_path=$abs_srcdir/ext
+ elif test -f $prefix/include/php/ext/pdo/php_pdo_driver.h; then
+ pdo_inc_path=$prefix/include/php/ext
+ else
+ AC_MSG_ERROR([Cannot find php_pdo_driver.h.])
+ fi
+ AC_MSG_RESULT($pdo_inc_path)
+ ])
+
+ PHP_NEW_EXTENSION(pdo_pgsql, pdo_pgsql.c pgsql_driver.c pgsql_statement.c, $ext_shared,,-I$pdo_inc_path $PDO_PGSQL_CFLAGS)
+ ifdef([PHP_ADD_EXTENSION_DEP],
+ [
+ PHP_ADD_EXTENSION_DEP(pdo_pgsql, pdo)
+ ])
+fi
+
+fi
diff --git a/ext/pdo_pgsql/config.w32 b/ext/pdo_pgsql/config.w32
new file mode 100644
index 0000000000..3c74c9bf00
--- /dev/null
+++ b/ext/pdo_pgsql/config.w32
@@ -0,0 +1,22 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_WITH("pdo-pgsql", "PostgreSQL support for PDO", "no");
+
+if (PHP_PDO_PGSQL != "no") {
+ if (CHECK_LIB("libpq.lib", "pdo_pgsql", PHP_PDO_PGSQL) &&
+ CHECK_HEADER_ADD_INCLUDE("libpq-fe.h", "CFLAGS_PDO_PGSQL", PHP_PDO_PGSQL + ";" + PHP_PHP_BUILD + "\\include\\pgsql")) {
+ EXTENSION("pdo_pgsql", "pdo_pgsql.c pgsql_driver.c pgsql_statement.c");
+
+ if (CHECK_HEADER_ADD_INCLUDE("pg_config.h", "CFLAGS_PDO_PGSQL", PHP_PDO_PGSQL + ";" + PHP_PHP_BUILD + "\\include\\pgsql")) {
+ ADD_FLAG('CFLAGS_PDO_PGSQL', "/D HAVE_PG_CONFIG_H");
+ }
+
+ ADD_FLAG('CFLAGS_PDO_PGSQL', "/I ..\\pecl");
+ AC_DEFINE('HAVE_PDO_PGSQL', 1, 'Have PostgreSQL library');
+ ADD_FLAG('CFLAGS_PDO_PGSQL', "/D HAVE_PQPARAMETERSTATUS=1 /D HAVE_PQPROTOCOLVERSION=1 /D HAVE_PGTRANSACTIONSTATUS=1 /D HAVE_PQUNESCAPEBYTEA=1 /D HAVE_PQRESULTERRORFIELD=1");
+ } else {
+ WARNING("pdo_pgsql not enabled; libraries and headers not found");
+ }
+ ADD_EXTENSION_DEP('pdo_pgsql', 'pdo');
+}
diff --git a/ext/pdo_pgsql/package2.xml b/ext/pdo_pgsql/package2.xml
new file mode 100644
index 0000000000..e397958a7d
--- /dev/null
+++ b/ext/pdo_pgsql/package2.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>PDO_PGSQL</name>
+ <channel>pecl.php.net</channel>
+ <summary>PostgreSQL driver for PDO</summary>
+ <description>This extension provides an PostgreSQL driver for PDO.
+ </description>
+ <lead>
+ <name>Edin Kadribasic</name>
+ <user>edink</user>
+ <email>edink@php.net</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Ilia Alshanetsky</name>
+ <user>iliaa</user>
+ <email>iliaa@php.net</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Wez Furlong</name>
+ <user>wez</user>
+ <email>wez@php.net</email>
+ <active>yes</active>
+ </lead>
+ <date>2006-05-01</date>
+ <version>
+ <release>1.0.2</release>
+ <api>1.0.2</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.php.net/license">PHP</license>
+ <notes>
+This PECL release corresponds to PHP 5.1.3.
+
+- Fixed bug #36727 (segfault in pdo_pgsql bindValue() when no parameters are
+ defined). (Tony)
+- Fixed bug #36382 (PDO/PgSQL's getColumnMeta() crashes). (Derick)
+- Fixed bug #36176 (PDO_PGSQL - PDO::exec() does not return number of rows
+ affected by the operation). (Ilia)
+- Fixed prepared statement name conflict handling in PDO_PGSQL. (Thies, Ilia)
+- repackage with package2.xml
+- Added PDO::pgsqlLOBCreate(), PDO::pgsqlLOBOpen() and PDO::pgsqlLOBUnlink().
+
+You require PostgreSQL client libraries installed on the machine where you
+intend to build and/or use this package.
+
+If you are running on windows, you can download the binary from here:
+http://pecl4win.php.net/ext.php/php_pdo_pgsql.dll
+ </notes>
+ <contents>
+ <dir name="/">
+ <file name="config.m4" role="src" />
+ <file name="config.w32" role="src" />
+ <file name="CREDITS" role="doc" />
+ <file name="pdo_pgsql.c" role="src" />
+ <file name="pgsql_driver.c" role="src" />
+ <file name="pgsql_statement.c" role="src" />
+ <file name="php_pdo_pgsql.h" role="src" />
+ <file name="php_pdo_pgsql_int.h" role="src" />
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.0.3</min>
+ </php>
+ <pearinstaller>
+ <min>1.4.0</min>
+ </pearinstaller>
+ <package>
+ <name>pdo</name>
+ <channel>pecl.php.net</channel>
+ <min>1.0.3</min>
+ <providesextension>PDO</providesextension>
+ </package>
+ </required>
+ </dependencies>
+ <providesextension>PDO_PGSQL</providesextension>
+ <extsrcrelease />
+</package>
diff --git a/ext/pdo_pgsql/pdo_pgsql.c b/ext/pdo_pgsql/pdo_pgsql.c
new file mode 100644
index 0000000000..d3730afb90
--- /dev/null
+++ b/ext/pdo_pgsql/pdo_pgsql.c
@@ -0,0 +1,139 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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: Edin Kadribasic <edink@emini.dk> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+#include "pdo/php_pdo_driver.h"
+#include "php_pdo_pgsql.h"
+#include "php_pdo_pgsql_int.h"
+
+#ifdef HAVE_PG_CONFIG_H
+#include <pg_config.h>
+#endif
+
+/* {{{ pdo_pgsql_functions[] */
+zend_function_entry pdo_pgsql_functions[] = {
+ {NULL, NULL, NULL}
+};
+/* }}} */
+
+/* {{{ pdo_sqlite_deps
+ */
+#if ZEND_MODULE_API_NO >= 20050922
+static zend_module_dep pdo_pgsql_deps[] = {
+ ZEND_MOD_REQUIRED("pdo")
+ {NULL, NULL, NULL}
+};
+#endif
+/* }}} */
+
+/* {{{ pdo_pgsql_module_entry */
+zend_module_entry pdo_pgsql_module_entry = {
+#if ZEND_MODULE_API_NO >= 20050922
+ STANDARD_MODULE_HEADER_EX, NULL,
+ pdo_pgsql_deps,
+#else
+ STANDARD_MODULE_HEADER,
+#endif
+ "pdo_pgsql",
+ pdo_pgsql_functions,
+ PHP_MINIT(pdo_pgsql),
+ PHP_MSHUTDOWN(pdo_pgsql),
+ PHP_RINIT(pdo_pgsql),
+ PHP_RSHUTDOWN(pdo_pgsql),
+ PHP_MINFO(pdo_pgsql),
+ "1.0.2",
+ STANDARD_MODULE_PROPERTIES
+};
+/* }}} */
+
+#ifdef COMPILE_DL_PDO_PGSQL
+ZEND_GET_MODULE(pdo_pgsql)
+#endif
+
+/* true global environment */
+
+/* {{{ PHP_MINIT_FUNCTION
+ */
+PHP_MINIT_FUNCTION(pdo_pgsql)
+{
+ php_pdo_register_driver(&pdo_pgsql_driver);
+ REGISTER_PDO_CLASS_CONST_LONG("PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT", PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_MSHUTDOWN_FUNCTION(pdo_pgsql)
+{
+ php_pdo_unregister_driver(&pdo_pgsql_driver);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_RINIT_FUNCTION
+ */
+PHP_RINIT_FUNCTION(pdo_pgsql)
+{
+ /* php_pdo_register_driver(&pdo_pgsql_driver); */
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MSHUTDOWN_FUNCTION
+ */
+PHP_RSHUTDOWN_FUNCTION(pdo_pgsql)
+{
+ /* php_pdo_unregister_driver(&pdo_pgsql_driver); */
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ PHP_MINFO_FUNCTION
+ */
+PHP_MINFO_FUNCTION(pdo_pgsql)
+{
+ php_info_print_table_start();
+ php_info_print_table_header(2, "PDO Driver for PostgreSQL", "enabled");
+#ifdef HAVE_PG_CONFIG_H
+ php_info_print_table_row(2, "PostgreSQL(libpq) Version", PG_VERSION);
+#endif
+ php_info_print_table_row(2, "Module version", pdo_pgsql_module_entry.version);
+ php_info_print_table_row(2, "Revision", " $Id$ ");
+
+ php_info_print_table_end();
+}
+/* }}} */
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
new file mode 100644
index 0000000000..7b1561506a
--- /dev/null
+++ b/ext/pdo_pgsql/pgsql_driver.c
@@ -0,0 +1,711 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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. |
+ +----------------------------------------------------------------------+
+ | Authors: Edin Kadribasic <edink@emini.dk> |
+ | Ilia Alshanestsky <ilia@prohost.org> |
+ | Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+#include "pdo/php_pdo_driver.h"
+
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include "pg_config.h" /* needed for PG_VERSION */
+#include "php_pdo_pgsql.h"
+#include "php_pdo_pgsql_int.h"
+#include "zend_exceptions.h"
+
+static char * _pdo_pgsql_trim_message(const char *message, int persistent)
+{
+ register int i = strlen(message)-1;
+ char *tmp;
+
+ if (i>1 && (message[i-1] == '\r' || message[i-1] == '\n') && message[i] == '.') {
+ --i;
+ }
+ while (i>0 && (message[i] == '\r' || message[i] == '\n')) {
+ --i;
+ }
+ ++i;
+ tmp = pemalloc(i + 1, persistent);
+ memcpy(tmp, message, i);
+ tmp[i] = '\0';
+
+ return tmp;
+}
+
+int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *file, int line TSRMLS_DC) /* {{{ */
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code;
+ pdo_pgsql_error_info *einfo = &H->einfo;
+ char *errmsg = PQerrorMessage(H->server);
+
+ einfo->errcode = errcode;
+ einfo->file = file;
+ einfo->line = line;
+
+ if (einfo->errmsg) {
+ pefree(einfo->errmsg, dbh->is_persistent);
+ einfo->errmsg = NULL;
+ }
+
+ if (sqlstate == NULL) {
+ strcpy(*pdo_err, "HY000");
+ }
+ else {
+ strcpy(*pdo_err, sqlstate);
+ }
+
+ if (errmsg) {
+ einfo->errmsg = _pdo_pgsql_trim_message(errmsg, dbh->is_persistent);
+ }
+
+ if (!dbh->methods) {
+ zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
+ *pdo_err, einfo->errcode, einfo->errmsg);
+ }
+
+ return errcode;
+}
+/* }}} */
+
+static void _pdo_pgsql_notice(pdo_dbh_t *dbh, const char *message) /* {{{ */
+{
+/* pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; */
+}
+/* }}} */
+
+static int pdo_pgsql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) /* {{{ */
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ pdo_pgsql_error_info *einfo = &H->einfo;
+
+ if (einfo->errcode) {
+ add_next_index_long(info, einfo->errcode);
+ add_next_index_string(info, einfo->errmsg, 1);
+ }
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ pdo_pgsql_create_lob_stream */
+static size_t pgsql_lob_write(php_stream *stream, const char *buf, size_t count TSRMLS_DC)
+{
+ struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
+ return lo_write(self->conn, self->lfd, (char*)buf, count);
+}
+
+static size_t pgsql_lob_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
+{
+ struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
+ return lo_read(self->conn, self->lfd, buf, count);
+}
+
+static int pgsql_lob_close(php_stream *stream, int close_handle TSRMLS_DC)
+{
+ struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
+ pdo_dbh_t *dbh = self->dbh;
+
+ if (close_handle) {
+ lo_close(self->conn, self->lfd);
+ }
+ efree(self);
+ php_pdo_dbh_delref(dbh TSRMLS_CC);
+ return 0;
+}
+
+static int pgsql_lob_flush(php_stream *stream TSRMLS_DC)
+{
+ return 0;
+}
+
+static int pgsql_lob_seek(php_stream *stream, off_t offset, int whence,
+ off_t *newoffset TSRMLS_DC)
+{
+ struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stream->abstract;
+ int pos = lo_lseek(self->conn, self->lfd, offset, whence);
+ *newoffset = pos;
+ return pos >= 0 ? 0 : -1;
+}
+
+php_stream_ops pdo_pgsql_lob_stream_ops = {
+ pgsql_lob_write,
+ pgsql_lob_read,
+ pgsql_lob_close,
+ pgsql_lob_flush,
+ "pdo_pgsql lob stream",
+ pgsql_lob_seek,
+ NULL,
+ NULL,
+ NULL
+};
+
+php_stream *pdo_pgsql_create_lob_stream(pdo_dbh_t *dbh, int lfd, Oid oid TSRMLS_DC)
+{
+ php_stream *stm;
+ struct pdo_pgsql_lob_self *self = ecalloc(1, sizeof(*self));
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+
+ self->dbh = dbh;
+ self->lfd = lfd;
+ self->oid = oid;
+ self->conn = H->server;
+
+ stm = php_stream_alloc(&pdo_pgsql_lob_stream_ops, self, 0, "r+b");
+
+ if (stm) {
+ php_pdo_dbh_addref(dbh TSRMLS_CC);
+ return stm;
+ }
+
+ efree(self);
+ return NULL;
+}
+/* }}} */
+
+static int pgsql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ if (H) {
+ if (H->server) {
+ PQfinish(H->server);
+ H->server = NULL;
+ }
+ if (H->einfo.errmsg) {
+ pefree(H->einfo.errmsg, dbh->is_persistent);
+ H->einfo.errmsg = NULL;
+ }
+ pefree(H, dbh->is_persistent);
+ dbh->driver_data = NULL;
+ }
+ return 0;
+}
+/* }}} */
+
+static int pgsql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ pdo_pgsql_stmt *S = ecalloc(1, sizeof(pdo_pgsql_stmt));
+ int scrollable;
+#if HAVE_PQPREPARE
+ int ret;
+ char *nsql = NULL;
+ int nsql_len = 0;
+ int emulate = 0;
+#endif
+
+ S->H = H;
+ stmt->driver_data = S;
+ stmt->methods = &pgsql_stmt_methods;
+
+ scrollable = pdo_attr_lval(driver_options, PDO_ATTR_CURSOR,
+ PDO_CURSOR_FWDONLY TSRMLS_CC) == PDO_CURSOR_SCROLL;
+
+ if (scrollable) {
+ /* TODO: check how scrollable cursors related to prepared statements */
+ spprintf(&S->cursor_name, 0, "pdo_pgsql_cursor_%08x", (unsigned int) stmt);
+ }
+
+#if HAVE_PQPREPARE
+
+ if (driver_options) {
+ if (pdo_attr_lval(driver_options,
+ PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT, 0 TSRMLS_CC) == 1) {
+ emulate = 1;
+ } else if (pdo_attr_lval(driver_options, PDO_ATTR_EMULATE_PREPARES,
+ 0 TSRMLS_CC) == 1) {
+ emulate = 1;
+ }
+ }
+
+ if (!emulate && PQprotocolVersion(H->server) > 2) {
+ stmt->supports_placeholders = PDO_PLACEHOLDER_NAMED;
+ stmt->named_rewrite_template = "$%d";
+ ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
+
+ if (ret == 1) {
+ /* query was re-written */
+ sql = nsql;
+ } else if (ret == -1) {
+ /* couldn't grok it */
+ strcpy(dbh->error_code, stmt->error_code);
+ return 0;
+ }
+
+ spprintf(&S->stmt_name, 0, "pdo_pgsql_stmt_%08x", (unsigned int)stmt);
+ /* that's all for now; we'll defer the actual prepare until the first execute call */
+
+ if (nsql) {
+ S->query = nsql;
+ } else {
+ S->query = estrdup(sql);
+ }
+
+ return 1;
+ }
+#endif
+
+ stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
+ return 1;
+}
+
+static long pgsql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ PGresult *res;
+ long ret = 1;
+ ExecStatusType qs;
+
+ if (!(res = PQexec(H->server, sql))) {
+ /* fatal error */
+ pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
+ return -1;
+ }
+ qs = PQresultStatus(res);
+ if (qs != PGRES_COMMAND_OK && qs != PGRES_TUPLES_OK) {
+ pdo_pgsql_error(dbh, qs, pdo_pgsql_sqlstate(res));
+ PQclear(res);
+ return -1;
+ }
+ H->pgoid = PQoidValue(res);
+#if HAVE_PQCMDTUPLES
+ ret = atol(PQcmdTuples(res));
+#endif
+ PQclear(res);
+
+ return ret;
+}
+
+static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
+{
+ unsigned char *escaped;
+
+ switch (paramtype) {
+ case PDO_PARAM_LOB:
+ /* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
+ escaped = PQescapeBytea(unquoted, unquotedlen, quotedlen);
+ *quotedlen += 1;
+ *quoted = emalloc(*quotedlen + 1);
+ memcpy((*quoted)+1, escaped, *quotedlen-2);
+ (*quoted)[0] = '\'';
+ (*quoted)[*quotedlen-1] = '\'';
+ (*quoted)[*quotedlen] = '\0';
+ free(escaped);
+ break;
+ default:
+ *quoted = emalloc(2*unquotedlen + 3);
+ (*quoted)[0] = '\'';
+ *quotedlen = PQescapeString(*quoted + 1, unquoted, unquotedlen);
+ (*quoted)[*quotedlen + 1] = '\'';
+ (*quoted)[*quotedlen + 2] = '\0';
+ *quotedlen += 2;
+ }
+ return 1;
+}
+
+static char *pdo_pgsql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ char *id = NULL;
+
+ if (name == NULL) {
+ if (H->pgoid == InvalidOid) {
+ return NULL;
+ }
+ *len = spprintf(&id, 0, "%ld", (long) H->pgoid);
+ } else {
+ PGresult *res;
+ ExecStatusType status;
+#ifdef HAVE_PQEXECPARAMS
+ const char *q[1];
+ q[0] = name;
+ res = PQexecParams(H->server, "SELECT CURRVAL($1)", 1, NULL, q, NULL, NULL, 0);
+#else
+ char *name_escaped, *q;
+ size_t l = strlen(name);
+
+ name_escaped = safe_emalloc(l, 2, 1);
+ PQescapeString(name_escaped, name, l);
+ spprintf(&q, 0, "SELECT CURRVAL('%s')", name_escaped);
+ res = PQexec(H->server, q);
+ efree(name_escaped);
+ efree(q);
+#endif
+ status = PQresultStatus(res);
+
+ if (res && (status == PGRES_TUPLES_OK)) {
+ id = estrdup((char *)PQgetvalue(res, 0, 0));
+ *len = PQgetlength(res, 0, 0);
+ } else {
+ pdo_pgsql_error(dbh, status, pdo_pgsql_sqlstate(res));
+ }
+
+ if (res) {
+ PQclear(res);
+ }
+ }
+ return id;
+}
+
+static int pdo_pgsql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+
+ switch (attr) {
+ case PDO_ATTR_CLIENT_VERSION:
+ ZVAL_STRING(return_value, PG_VERSION, 1);
+ break;
+
+ case PDO_ATTR_SERVER_VERSION:
+#ifdef HAVE_PQPROTOCOLVERSION
+ if (PQprotocolVersion(H->server) >= 3) { /* PostgreSQL 7.4 or later */
+ ZVAL_STRING(return_value, (char*)PQparameterStatus(H->server, "server_version"), 1);
+ } else /* emulate above via a query */
+#endif
+ {
+ PGresult *res = PQexec(H->server, "SELECT VERSION()");
+ if (res && PQresultStatus(res) == PGRES_TUPLES_OK) {
+ ZVAL_STRING(return_value, (char *)PQgetvalue(res, 0, 0), 1);
+ }
+
+ if (res) {
+ PQclear(res);
+ }
+ }
+ break;
+
+ case PDO_ATTR_CONNECTION_STATUS:
+ switch (PQstatus(H->server)) {
+ case CONNECTION_STARTED:
+ ZVAL_STRINGL(return_value, "Waiting for connection to be made.", sizeof("Waiting for connection to be made.")-1, 1);
+ break;
+
+ case CONNECTION_MADE:
+ case CONNECTION_OK:
+ ZVAL_STRINGL(return_value, "Connection OK; waiting to send.", sizeof("Connection OK; waiting to send.")-1, 1);
+ break;
+
+ case CONNECTION_AWAITING_RESPONSE:
+ ZVAL_STRINGL(return_value, "Waiting for a response from the server.", sizeof("Waiting for a response from the server.")-1, 1);
+ break;
+
+ case CONNECTION_AUTH_OK:
+ ZVAL_STRINGL(return_value, "Received authentication; waiting for backend start-up to finish.", sizeof("Received authentication; waiting for backend start-up to finish.")-1, 1);
+ break;
+#ifdef CONNECTION_SSL_STARTUP
+ case CONNECTION_SSL_STARTUP:
+ ZVAL_STRINGL(return_value, "Negotiating SSL encryption.", sizeof("Negotiating SSL encryption.")-1, 1);
+ break;
+#endif
+ case CONNECTION_SETENV:
+ ZVAL_STRINGL(return_value, "Negotiating environment-driven parameter settings.", sizeof("Negotiating environment-driven parameter settings.")-1, 1);
+ break;
+
+ case CONNECTION_BAD:
+ default:
+ ZVAL_STRINGL(return_value, "Bad connection.", sizeof("Bad connection.")-1, 1);
+ break;
+ }
+ break;
+
+ case PDO_ATTR_SERVER_INFO: {
+ int spid = PQbackendPID(H->server);
+ char *tmp;
+#ifdef HAVE_PQPROTOCOLVERSION
+ spprintf(&tmp, 0,
+ "PID: %d; Client Encoding: %s; Is Superuser: %s; Session Authorization: %s; Date Style: %s",
+ spid,
+ (char*)PQparameterStatus(H->server, "client_encoding"),
+ (char*)PQparameterStatus(H->server, "is_superuser"),
+ (char*)PQparameterStatus(H->server, "session_authorization"),
+ (char*)PQparameterStatus(H->server, "DateStyle"));
+#else
+ spprintf(&tmp, 0, "PID: %d", spid);
+#endif
+ ZVAL_STRING(return_value, tmp, 0);
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static int pdo_pgsql_transaction_cmd(const char *cmd, pdo_dbh_t *dbh TSRMLS_DC)
+{
+ pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ PGresult *res;
+ int ret = 1;
+
+ res = PQexec(H->server, cmd);
+
+ if (PQresultStatus(res) != PGRES_COMMAND_OK) {
+ ret = 0;
+ }
+
+ PQclear(res);
+ return ret;
+}
+
+static int pgsql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ return pdo_pgsql_transaction_cmd("BEGIN", dbh TSRMLS_CC);
+}
+
+static int pgsql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ return pdo_pgsql_transaction_cmd("COMMIT", dbh TSRMLS_CC);
+}
+
+static int pgsql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
+{
+ return pdo_pgsql_transaction_cmd("ROLLBACK", dbh TSRMLS_CC);
+}
+
+/* {{{ proto string PDO::pgsqlLOBCreate()
+ Creates a new large object, returning its identifier. Must be called inside a transaction. */
+static PHP_METHOD(PDO, pgsqlLOBCreate)
+{
+ pdo_dbh_t *dbh;
+ pdo_pgsql_db_handle *H;
+ Oid lfd;
+
+ dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_pgsql_db_handle *)dbh->driver_data;
+ lfd = lo_creat(H->server, INV_READ|INV_WRITE);
+
+ if (lfd != InvalidOid) {
+ char *buf;
+ spprintf(&buf, 0, "%lu", (long) lfd);
+ RETURN_STRING(buf, 0);
+ }
+
+ pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto resource PDO::pgsqlLOBOpen(string oid [, string mode = 'rb'])
+ Opens an existing large object stream. Must be called inside a transaction. */
+static PHP_METHOD(PDO, pgsqlLOBOpen)
+{
+ pdo_dbh_t *dbh;
+ pdo_pgsql_db_handle *H;
+ Oid oid;
+ int lfd;
+ char *oidstr;
+ int oidstrlen;
+ char *modestr = "rb";
+ int modestrlen;
+ int mode = INV_READ;
+ char *end_ptr;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s",
+ &oidstr, &oidstrlen, &modestr, &modestrlen)) {
+ RETURN_FALSE;
+ }
+
+ oid = (Oid)strtoul(oidstr, &end_ptr, 10);
+ if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
+ RETURN_FALSE;
+ }
+
+ if (strpbrk(modestr, "+w")) {
+ mode = INV_READ|INV_WRITE;
+ }
+
+ dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_pgsql_db_handle *)dbh->driver_data;
+
+ lfd = lo_open(H->server, oid, mode);
+
+ if (lfd >= 0) {
+ php_stream *stream = pdo_pgsql_create_lob_stream(dbh, lfd, oid TSRMLS_CC);
+ if (stream) {
+ php_stream_to_zval(stream, return_value);
+ return;
+ }
+ } else {
+ pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool PDO::pgsqlLOBUnlink(string oid)
+ Deletes the large object identified by oid. Must be called inside a transaction. */
+static PHP_METHOD(PDO, pgsqlLOBUnlink)
+{
+ pdo_dbh_t *dbh;
+ pdo_pgsql_db_handle *H;
+ Oid oid;
+ char *oidstr, *end_ptr;
+ int oidlen;
+
+ if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &oidstr, &oidlen)) {
+ RETURN_FALSE;
+ }
+
+ oid = (Oid)strtoul(oidstr, &end_ptr, 10);
+ if (oid == 0 && (errno == ERANGE || errno == EINVAL)) {
+ RETURN_FALSE;
+ }
+
+ dbh = zend_object_store_get_object(getThis() TSRMLS_CC);
+ PDO_CONSTRUCT_CHECK;
+
+ H = (pdo_pgsql_db_handle *)dbh->driver_data;
+
+ if (1 == lo_unlink(H->server, oid)) {
+ RETURN_TRUE;
+ }
+ pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000");
+ RETURN_FALSE;
+}
+/* }}} */
+
+
+static zend_function_entry dbh_methods[] = {
+ PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, pgsqlLOBOpen, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(PDO, pgsqlLOBUnlink, NULL, ZEND_ACC_PUBLIC)
+ {NULL, NULL, NULL}
+};
+
+static zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
+{
+ switch (kind) {
+ case PDO_DBH_DRIVER_METHOD_KIND_DBH:
+ return dbh_methods;
+ default:
+ return NULL;
+ }
+}
+
+static struct pdo_dbh_methods pgsql_methods = {
+ pgsql_handle_closer,
+ pgsql_handle_preparer,
+ pgsql_handle_doer,
+ pgsql_handle_quoter,
+ pgsql_handle_begin,
+ pgsql_handle_commit,
+ pgsql_handle_rollback,
+ NULL, /* set_attr */
+ pdo_pgsql_last_insert_id,
+ pdo_pgsql_fetch_error_func,
+ pdo_pgsql_get_attribute,
+ NULL, /* check_liveness */
+ pdo_pgsql_get_driver_methods /* get_driver_methods */
+};
+
+static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
+{
+ pdo_pgsql_db_handle *H;
+ int ret = 0;
+ char *conn_str, *p, *e;
+
+ H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent);
+ dbh->driver_data = H;
+
+ H->einfo.errcode = 0;
+ H->einfo.errmsg = NULL;
+
+ /* PostgreSQL wants params in the connect string to be separated by spaces,
+ * if the PDO standard semicolons are used, we convert them to spaces
+ */
+ e = (char *) dbh->data_source + strlen(dbh->data_source);
+ p = (char *) dbh->data_source;
+ while ((p = memchr(p, ';', (e - p)))) {
+ *p = ' ';
+ }
+
+ /* support both full connection string & connection string + login and/or password */
+ if (!dbh->username || !dbh->password) {
+ conn_str = (char *) dbh->data_source;
+ } else if (dbh->username && dbh->password) {
+ spprintf(&conn_str, 0, "%s user=%s password=%s", dbh->data_source, dbh->username, dbh->password);
+ } else if (dbh->username) {
+ spprintf(&conn_str, 0, "%s user=%s", dbh->data_source, dbh->username);
+ } else {
+ spprintf(&conn_str, 0, "%s password=%s", dbh->data_source, dbh->password);
+ }
+
+ H->server = PQconnectdb(conn_str);
+
+ if (conn_str != dbh->data_source) {
+ efree(conn_str);
+ }
+
+ if (PQstatus(H->server) != CONNECTION_OK) {
+ pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, PHP_PDO_PGSQL_CONNECTION_FAILURE_SQLSTATE);
+ goto cleanup;
+ }
+
+ PQsetNoticeProcessor(H->server, (void(*)(void*,const char*))_pdo_pgsql_notice, (void *)&dbh);
+
+ H->attached = 1;
+ H->pgoid = -1;
+
+ dbh->methods = &pgsql_methods;
+ dbh->alloc_own_columns = 1;
+ dbh->max_escaped_char_length = 2;
+
+ ret = 1;
+
+cleanup:
+ dbh->methods = &pgsql_methods;
+ if (!ret) {
+ pgsql_handle_closer(dbh TSRMLS_CC);
+ }
+
+ return ret;
+}
+/* }}} */
+
+pdo_driver_t pdo_pgsql_driver = {
+ PDO_DRIVER_HEADER(pgsql),
+ pdo_pgsql_handle_factory
+};
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c
new file mode 100644
index 0000000000..d83b86ad78
--- /dev/null
+++ b/ext/pdo_pgsql/pgsql_statement.c
@@ -0,0 +1,664 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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. |
+ +----------------------------------------------------------------------+
+ | Authors: Edin Kadribasic <edink@emini.dk> |
+ | Ilia Alshanestsky <ilia@prohost.org> |
+ | Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "pdo/php_pdo.h"
+#include "pdo/php_pdo_driver.h"
+#include "php_pdo_pgsql.h"
+#include "php_pdo_pgsql_int.h"
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+/* from postgresql/src/include/catalog/pg_type.h */
+#define BOOLOID 16
+#define BYTEAOID 17
+#define INT8OID 20
+#define INT2OID 21
+#define INT4OID 23
+#define TEXTOID 25
+#define OIDOID 26
+
+static int pgsql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
+
+ if (S->result) {
+ /* free the resource */
+ PQclear(S->result);
+ S->result = NULL;
+ }
+
+#if HAVE_PQPREPARE
+ if (S->stmt_name) {
+ pdo_pgsql_db_handle *H = S->H;
+ char *q = NULL;
+ PGresult *res;
+
+ spprintf(&q, 0, "DEALLOCATE %s", S->stmt_name);
+ res = PQexec(H->server, q);
+ efree(q);
+ if (res) PQclear(res);
+ efree(S->stmt_name);
+ S->stmt_name = NULL;
+ }
+ if (S->param_lengths) {
+ efree(S->param_lengths);
+ S->param_lengths = NULL;
+ }
+ if (S->param_values) {
+ efree(S->param_values);
+ S->param_values = NULL;
+ }
+ if (S->param_formats) {
+ efree(S->param_formats);
+ S->param_formats = NULL;
+ }
+ if (S->param_types) {
+ efree(S->param_types);
+ S->param_types = NULL;
+ }
+ if (S->query) {
+ efree(S->query);
+ S->query = NULL;
+ }
+#endif
+
+ if (S->cursor_name) {
+ pdo_pgsql_db_handle *H = S->H;
+ char *q = NULL;
+ PGresult *res;
+
+ spprintf(&q, 0, "CLOSE %s", S->cursor_name);
+ res = PQexec(H->server, q);
+ efree(q);
+ if (res) PQclear(res);
+ efree(S->cursor_name);
+ S->cursor_name = NULL;
+ }
+
+ if(S->cols) {
+ efree(S->cols);
+ S->cols = NULL;
+ }
+ efree(S);
+ stmt->driver_data = NULL;
+ return 1;
+}
+
+static int pgsql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
+ pdo_pgsql_db_handle *H = S->H;
+ ExecStatusType status;
+
+ /* ensure that we free any previous unfetched results */
+ if(S->result) {
+ PQclear(S->result);
+ S->result = NULL;
+ }
+
+ S->current_row = 0;
+
+#if HAVE_PQPREPARE
+ if (S->stmt_name) {
+ /* using a prepared statement */
+
+ if (!S->is_prepared) {
+stmt_retry:
+ /* we deferred the prepare until now, because we didn't
+ * know anything about the parameter types; now we do */
+ S->result = PQprepare(H->server, S->stmt_name, S->query,
+ stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0,
+ S->param_types);
+ status = PQresultStatus(S->result);
+ switch (status) {
+ case PGRES_COMMAND_OK:
+ case PGRES_TUPLES_OK:
+ /* it worked */
+ S->is_prepared = 1;
+ PQclear(S->result);
+ break;
+ default: {
+ char *sqlstate = pdo_pgsql_sqlstate(S->result);
+ /* 42P05 means that the prepared statement already existed. this can happen if you use
+ * a connection pooling software line pgpool which doesn't close the db-connection once
+ * php disconnects. if php dies (no chanche to run RSHUTDOWN) during execution it has no
+ * chance to DEALLOCATE the prepared statements it has created. so, if we hit a 42P05 we
+ * deallocate it and retry ONCE (thies 2005.12.15)
+ */
+ if (!strcmp(sqlstate, "42P05")) {
+ char buf[100]; /* stmt_name == "pdo_pgsql_cursor_%08x" */
+ PGresult *res;
+ snprintf(buf, sizeof(buf), "DEALLOCATE %s", S->stmt_name);
+ res = PQexec(H->server, buf);
+ if (res) {
+ PQclear(res);
+ }
+ goto stmt_retry;
+ } else {
+ pdo_pgsql_error_stmt(stmt, status, sqlstate);
+ return 0;
+ }
+ }
+ }
+ }
+ S->result = PQexecPrepared(H->server, S->stmt_name,
+ stmt->bound_params ?
+ zend_hash_num_elements(stmt->bound_params) :
+ 0,
+ (const char**)S->param_values,
+ S->param_lengths,
+ S->param_formats,
+ 0);
+ } else
+#endif
+ if (S->cursor_name) {
+ char *q = NULL;
+ spprintf(&q, 0, "DECLARE %s CURSOR FOR %s", S->cursor_name, stmt->active_query_string);
+ S->result = PQexec(H->server, q);
+ efree(q);
+ } else {
+ S->result = PQexec(H->server, stmt->active_query_string);
+ }
+ status = PQresultStatus(S->result);
+
+ if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
+ pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
+ return 0;
+ }
+
+ if(!stmt->executed) {
+ stmt->column_count = (int) PQnfields(S->result);
+ S->cols = ecalloc(stmt->column_count, sizeof(pdo_pgsql_column));
+ }
+
+ if (status == PGRES_COMMAND_OK) {
+ stmt->row_count = (long)atoi(PQcmdTuples(S->result));
+ H->pgoid = PQoidValue(S->result);
+ } else {
+ stmt->row_count = (long)PQntuples(S->result);
+ }
+
+ return 1;
+}
+
+static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
+ enum pdo_param_event event_type TSRMLS_DC)
+{
+ pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
+#if HAVE_PQPREPARE
+ if (S->stmt_name && param->is_param) {
+ switch (event_type) {
+ case PDO_PARAM_EVT_FREE:
+ if (param->driver_data) {
+ efree(param->driver_data);
+ }
+ break;
+
+ case PDO_PARAM_EVT_NORMALIZE:
+ /* decode name from $1, $2 into 0, 1 etc. */
+ if (param->name) {
+ if (param->name[0] == '$') {
+ param->paramno = atoi(param->name + 1);
+ } else {
+ /* resolve parameter name to rewritten name */
+ char *nameptr;
+ if (stmt->bound_param_map && SUCCESS == zend_hash_find(stmt->bound_param_map,
+ param->name, param->namelen + 1, (void**)&nameptr)) {
+ param->paramno = atoi(nameptr + 1) - 1;
+ } else {
+ pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY093");
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case PDO_PARAM_EVT_ALLOC:
+ /* work is handled by EVT_NORMALIZE */
+ return 1;
+
+ case PDO_PARAM_EVT_EXEC_PRE:
+ if (!S->param_values) {
+ S->param_values = ecalloc(
+ zend_hash_num_elements(stmt->bound_params),
+ sizeof(char*));
+ S->param_lengths = ecalloc(
+ zend_hash_num_elements(stmt->bound_params),
+ sizeof(int));
+ S->param_formats = ecalloc(
+ zend_hash_num_elements(stmt->bound_params),
+ sizeof(int));
+ S->param_types = ecalloc(
+ zend_hash_num_elements(stmt->bound_params),
+ sizeof(Oid));
+ }
+ if (param->paramno >= 0) {
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB &&
+ Z_TYPE_P(param->parameter) == IS_RESOURCE) {
+ php_stream *stm;
+ php_stream_from_zval_no_verify(stm, &param->parameter);
+ if (stm) {
+ if (php_stream_is(stm, &pdo_pgsql_lob_stream_ops)) {
+ struct pdo_pgsql_lob_self *self = (struct pdo_pgsql_lob_self*)stm->abstract;
+ pdo_pgsql_bound_param *P = param->driver_data;
+
+ if (P == NULL) {
+ P = ecalloc(1, sizeof(*P));
+ param->driver_data = P;
+ }
+ P->oid = htonl(self->oid);
+ S->param_values[param->paramno] = (char*)&P->oid;
+ S->param_lengths[param->paramno] = sizeof(P->oid);
+ S->param_formats[param->paramno] = 1;
+ S->param_types[param->paramno] = OIDOID;
+ return 1;
+ } else {
+ SEPARATE_ZVAL_IF_NOT_REF(&param->parameter);
+ Z_TYPE_P(param->parameter) = IS_STRING;
+ Z_STRLEN_P(param->parameter) = php_stream_copy_to_mem(stm,
+ &Z_STRVAL_P(param->parameter), PHP_STREAM_COPY_ALL, 0);
+ }
+ } else {
+ /* expected a stream resource */
+ pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
+ return 0;
+ }
+ }
+
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
+ Z_TYPE_P(param->parameter) == IS_NULL) {
+ S->param_values[param->paramno] = NULL;
+ S->param_lengths[param->paramno] = 0;
+ } else if (Z_TYPE_P(param->parameter) == IS_BOOL) {
+ S->param_values[param->paramno] = Z_BVAL_P(param->parameter) ? "t" : "f";
+ S->param_lengths[param->paramno] = 1;
+ S->param_formats[param->paramno] = 0;
+ } else {
+ convert_to_string(param->parameter);
+ S->param_values[param->paramno] = Z_STRVAL_P(param->parameter);
+ S->param_lengths[param->paramno] = Z_STRLEN_P(param->parameter);
+ S->param_formats[param->paramno] = 0;
+ }
+
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
+ S->param_types[param->paramno] = 0;
+ S->param_formats[param->paramno] = 1;
+ } else {
+ S->param_types[param->paramno] = 0;
+ }
+ }
+ break;
+ }
+ }
+#endif
+ return 1;
+}
+
+static int pgsql_stmt_fetch(pdo_stmt_t *stmt,
+ enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
+{
+ pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
+
+ if (S->cursor_name) {
+ char *ori_str;
+ char *q = NULL;
+ ExecStatusType status;
+
+ switch (ori) {
+ case PDO_FETCH_ORI_NEXT: ori_str = "FORWARD"; break;
+ case PDO_FETCH_ORI_PRIOR: ori_str = "BACKWARD"; break;
+ case PDO_FETCH_ORI_REL: ori_str = "RELATIVE"; break;
+ default:
+ return 0;
+ }
+
+ spprintf(&q, 0, "FETCH %s %ld FROM %s", ori_str, offset, S->cursor_name);
+ S->result = PQexec(S->H->server, q);
+ status = PQresultStatus(S->result);
+
+ if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
+ pdo_pgsql_error_stmt(stmt, status, pdo_pgsql_sqlstate(S->result));
+ return 0;
+ }
+
+ S->current_row = 1;
+ return 1;
+
+ } else {
+ if (S->current_row < stmt->row_count) {
+ S->current_row++;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+static int pgsql_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
+{
+ pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
+ struct pdo_column_data *cols = stmt->columns;
+ struct pdo_bound_param_data *param;
+
+ if (!S->result) {
+ return 0;
+ }
+
+ cols[colno].name = estrdup(PQfname(S->result, colno));
+ cols[colno].namelen = strlen(cols[colno].name);
+ cols[colno].maxlen = PQfsize(S->result, colno);
+ cols[colno].precision = PQfmod(S->result, colno);
+ S->cols[colno].pgsql_type = PQftype(S->result, colno);
+
+ switch(S->cols[colno].pgsql_type) {
+
+ case BOOLOID:
+ cols[colno].param_type = PDO_PARAM_BOOL;
+ break;
+
+ case OIDOID:
+ /* did the user bind the column as a LOB ? */
+ if (stmt->bound_columns && (
+ SUCCESS == zend_hash_index_find(stmt->bound_columns,
+ colno, (void**)&param) ||
+ SUCCESS == zend_hash_find(stmt->bound_columns,
+ cols[colno].name, cols[colno].namelen,
+ (void**)&param))) {
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_LOB) {
+ cols[colno].param_type = PDO_PARAM_LOB;
+ break;
+ }
+ }
+ cols[colno].param_type = PDO_PARAM_INT;
+ break;
+
+ case INT2OID:
+ case INT4OID:
+ cols[colno].param_type = PDO_PARAM_INT;
+ break;
+
+ case INT8OID:
+ if (sizeof(long)>=8) {
+ cols[colno].param_type = PDO_PARAM_INT;
+ } else {
+ cols[colno].param_type = PDO_PARAM_STR;
+ }
+ break;
+
+ case BYTEAOID:
+ cols[colno].param_type = PDO_PARAM_LOB;
+ break;
+
+ default:
+ cols[colno].param_type = PDO_PARAM_STR;
+ }
+
+ return 1;
+}
+
+/* PQunescapeBytea() from PostgreSQL 7.3 to provide bytea unescape feature to 7.2 users.
+ Renamed to php_pdo_pgsql_unescape_bytea() */
+/*
+ * PQunescapeBytea - converts the null terminated string representation
+ * of a bytea, strtext, into binary, filling a buffer. It returns a
+ * pointer to the buffer which is NULL on error, and the size of the
+ * buffer in retbuflen. The pointer may subsequently be used as an
+ * argument to the function free(3). It is the reverse of PQescapeBytea.
+ *
+ * The following transformations are reversed:
+ * '\0' == ASCII 0 == \000
+ * '\'' == ASCII 39 == \'
+ * '\\' == ASCII 92 == \\
+ *
+ * States:
+ * 0 normal 0->1->2->3->4
+ * 1 \ 1->5
+ * 2 \0 1->6
+ * 3 \00
+ * 4 \000
+ * 5 \'
+ * 6 \\
+ */
+static unsigned char *php_pdo_pgsql_unescape_bytea(unsigned char *strtext, size_t *retbuflen)
+{
+ size_t buflen;
+ unsigned char *buffer,
+ *sp,
+ *bp;
+ unsigned int state = 0;
+
+ if (strtext == NULL)
+ return NULL;
+ buflen = strlen(strtext); /* will shrink, also we discover if
+ * strtext */
+ buffer = (unsigned char *) emalloc(buflen); /* isn't NULL terminated */
+ for (bp = buffer, sp = strtext; *sp != '\0'; bp++, sp++)
+ {
+ switch (state)
+ {
+ case 0:
+ if (*sp == '\\')
+ state = 1;
+ *bp = *sp;
+ break;
+ case 1:
+ if (*sp == '\'') /* state=5 */
+ { /* replace \' with 39 */
+ bp--;
+ *bp = '\'';
+ buflen--;
+ state = 0;
+ }
+ else if (*sp == '\\') /* state=6 */
+ { /* replace \\ with 92 */
+ bp--;
+ *bp = '\\';
+ buflen--;
+ state = 0;
+ }
+ else
+ {
+ if (isdigit(*sp))
+ state = 2;
+ else
+ state = 0;
+ *bp = *sp;
+ }
+ break;
+ case 2:
+ if (isdigit(*sp))
+ state = 3;
+ else
+ state = 0;
+ *bp = *sp;
+ break;
+ case 3:
+ if (isdigit(*sp)) /* state=4 */
+ {
+ unsigned char *start, *end, buf[4]; /* 000 + '\0' */
+
+ bp -= 3;
+ memcpy(buf, sp-2, 3);
+ buf[3] = '\0';
+ start = buf;
+ *bp = (unsigned char)strtoul(start, (char **)&end, 8);
+ buflen -= 3;
+ state = 0;
+ }
+ else
+ {
+ *bp = *sp;
+ state = 0;
+ }
+ break;
+ }
+ }
+ buffer = erealloc(buffer, buflen+1);
+ buffer[buflen] = '\0';
+
+ *retbuflen = buflen;
+ return buffer;
+}
+
+static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
+{
+ pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
+ struct pdo_column_data *cols = stmt->columns;
+ size_t tmp_len;
+
+ if (!S->result) {
+ return 0;
+ }
+
+ /* We have already increased count by 1 in pgsql_stmt_fetch() */
+ if (PQgetisnull(S->result, S->current_row - 1, colno)) { /* Check if we got NULL */
+ *ptr = NULL;
+ *len = 0;
+ } else {
+ *ptr = PQgetvalue(S->result, S->current_row - 1, colno);
+ *len = PQgetlength(S->result, S->current_row - 1, colno);
+
+ switch(cols[colno].param_type) {
+
+ case PDO_PARAM_INT:
+ S->cols[colno].intval = atol(*ptr);
+ *ptr = (char *) &(S->cols[colno].intval);
+ *len = sizeof(long);
+ break;
+
+ case PDO_PARAM_BOOL:
+ S->cols[colno].boolval = **ptr == 't' ? 1: 0;
+ *ptr = (char *) &(S->cols[colno].boolval);
+ *len = sizeof(zend_bool);
+ break;
+
+ case PDO_PARAM_LOB:
+ if (S->cols[colno].pgsql_type == OIDOID) {
+ /* ooo, a real large object */
+ char *end_ptr;
+ Oid oid = (Oid)strtoul(*ptr, &end_ptr, 10);
+ int loid = lo_open(S->H->server, oid, INV_READ);
+ if (loid >= 0) {
+ *ptr = (char*)pdo_pgsql_create_lob_stream(stmt->dbh, loid, oid TSRMLS_CC);
+ *len = 0;
+ return *ptr ? 1 : 0;
+ }
+ *ptr = NULL;
+ *len = 0;
+ return 0;
+ } else {
+ *ptr = php_pdo_pgsql_unescape_bytea(*ptr, &tmp_len);
+ *len = tmp_len;
+ *caller_frees = 1;
+ }
+ break;
+ case PDO_PARAM_NULL:
+ case PDO_PARAM_STR:
+ case PDO_PARAM_STMT:
+ case PDO_PARAM_INPUT_OUTPUT:
+ break;
+ }
+ }
+
+ return 1;
+}
+
+static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC)
+{
+ pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
+ PGresult *res;
+ char *q=NULL;
+ ExecStatusType status;
+
+ if (!S->result) {
+ return FAILURE;
+ }
+
+ if (colno >= stmt->column_count) {
+ return FAILURE;
+ }
+
+ array_init(return_value);
+ add_assoc_long(return_value, "pgsql:oid", S->cols[colno].pgsql_type);
+
+ /* Fetch metadata from Postgres system catalogue */
+ spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%d", S->cols[colno].pgsql_type);
+ res = PQexec(S->H->server, q);
+ efree(q);
+
+ status = PQresultStatus(res);
+
+ if (status != PGRES_TUPLES_OK) {
+ /* Failed to get system catalogue, but return success
+ * with the data we have collected so far
+ */
+ PQclear(res);
+ return 1;
+ }
+
+ /* We want exactly one row returned */
+ if (1 != PQntuples(res)) {
+ PQclear(res);
+ return 1;
+ }
+
+ add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0), 1);
+
+ PQclear(res);
+ return 1;
+}
+
+static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
+{
+ return 1;
+}
+
+struct pdo_stmt_methods pgsql_stmt_methods = {
+ pgsql_stmt_dtor,
+ pgsql_stmt_execute,
+ pgsql_stmt_fetch,
+ pgsql_stmt_describe,
+ pgsql_stmt_get_col,
+ pgsql_stmt_param_hook,
+ NULL, /* set_attr */
+ NULL, /* get_attr */
+ pgsql_stmt_get_column_meta,
+ NULL, /* next_rowset */
+ pdo_pgsql_stmt_cursor_closer
+};
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_pgsql/php_pdo_pgsql.h b/ext/pdo_pgsql/php_pdo_pgsql.h
new file mode 100644
index 0000000000..4096566870
--- /dev/null
+++ b/ext/pdo_pgsql/php_pdo_pgsql.h
@@ -0,0 +1,55 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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: Edin Kadribasic <edink@emini.dk> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PDO_PGSQL_H
+#define PHP_PDO_PGSQL_H
+
+#include <libpq-fe.h>
+
+extern zend_module_entry pdo_pgsql_module_entry;
+#define phpext_pdo_pgsql_ptr &pdo_pgsql_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_PDO_PGSQL_API __declspec(dllexport)
+#else
+#define PHP_PDO_PGSQL_API
+#endif
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+PHP_MINIT_FUNCTION(pdo_pgsql);
+PHP_MSHUTDOWN_FUNCTION(pdo_pgsql);
+PHP_RINIT_FUNCTION(pdo_pgsql);
+PHP_RSHUTDOWN_FUNCTION(pdo_pgsql);
+PHP_MINFO_FUNCTION(pdo_pgsql);
+
+#endif /* PHP_PDO_PGSQL_H */
+
+
+/*
+ * 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
+ */
diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h
new file mode 100644
index 0000000000..7cdd340988
--- /dev/null
+++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h
@@ -0,0 +1,114 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 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_01.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. |
+ +----------------------------------------------------------------------+
+ | Authors: Edin Kadribasic <edink@emini.dk> |
+ | Ilia Alshanestsky <ilia@prohost.org> |
+ | Wez Furlong <wez@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef PHP_PDO_PGSQL_INT_H
+#define PHP_PDO_PGSQL_INT_H
+
+#include <libpq-fe.h>
+#include <libpq/libpq-fs.h>
+#include <php.h>
+
+#define PHP_PDO_PGSQL_CONNECTION_FAILURE_SQLSTATE "08006"
+
+typedef struct {
+ const char *file;
+ int line;
+ unsigned int errcode;
+ char *errmsg;
+} pdo_pgsql_error_info;
+
+/* stuff we use in a pgsql database handle */
+typedef struct {
+ PGconn *server;
+ unsigned attached:1;
+ unsigned _reserved:31;
+ pdo_pgsql_error_info einfo;
+ Oid pgoid;
+} pdo_pgsql_db_handle;
+
+typedef struct {
+ char *def;
+ Oid pgsql_type;
+ long intval;
+ zend_bool boolval;
+} pdo_pgsql_column;
+
+typedef struct {
+ pdo_pgsql_db_handle *H;
+ PGresult *result;
+ int current_row;
+ pdo_pgsql_column *cols;
+ char *cursor_name;
+#if HAVE_PQPREPARE
+ char *stmt_name;
+ char *query;
+ char **param_values;
+ int *param_lengths;
+ int *param_formats;
+ Oid *param_types;
+ zend_bool is_prepared;
+#endif
+} pdo_pgsql_stmt;
+
+typedef struct {
+ Oid oid;
+} pdo_pgsql_bound_param;
+
+extern pdo_driver_t pdo_pgsql_driver;
+
+extern int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *file, int line TSRMLS_DC);
+#define pdo_pgsql_error(d,e,z) _pdo_pgsql_error(d, NULL, e, z, __FILE__, __LINE__ TSRMLS_CC)
+#define pdo_pgsql_error_stmt(s,e,z) _pdo_pgsql_error(s->dbh, s, e, z, __FILE__, __LINE__ TSRMLS_CC)
+
+extern struct pdo_stmt_methods pgsql_stmt_methods;
+
+#ifdef HAVE_PQRESULTERRORFIELD
+#define pdo_pgsql_sqlstate(r) PQresultErrorField(r, PG_DIAG_SQLSTATE)
+#else
+#define pdo_pgsql_sqlstate(r) (const char *)NULL
+#endif
+
+enum {
+ PDO_PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT = PDO_ATTR_DRIVER_SPECIFIC,
+};
+
+struct pdo_pgsql_lob_self {
+ pdo_dbh_t *dbh;
+ PGconn *conn;
+ int lfd;
+ Oid oid;
+};
+
+
+php_stream *pdo_pgsql_create_lob_stream(pdo_dbh_t *stmt, int lfd, Oid oid TSRMLS_DC);
+extern php_stream_ops pdo_pgsql_lob_stream_ops;
+
+#endif /* PHP_PDO_PGSQL_INT_H */
+
+/*
+ * 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
+ */
diff --git a/ext/sqlite/tests/bug26911.phpt b/ext/sqlite/tests/bug26911.phpt
deleted file mode 100644
index e81aeae763..0000000000
--- a/ext/sqlite/tests/bug26911.phpt
+++ /dev/null
@@ -1,10 +0,0 @@
---TEST--
-Bug #26911 (crash when fetching data from empty queries)
---FILE--
-<?php
- $db = sqlite_open(":memory:");
- $a = sqlite_query($db, " ");
- echo "I am ok\n";
-?>
---EXPECT--
-I am ok
diff --git a/ext/sqlite/tests/sqlite_018.phpt b/ext/sqlite/tests/sqlite_018.phpt
deleted file mode 100755
index bc14bb1c8d..0000000000
--- a/ext/sqlite/tests/sqlite_018.phpt
+++ /dev/null
@@ -1,13 +0,0 @@
---TEST--
-sqlite: crash on bad queries inside sqlite_array_query()
---SKIPIF--
-<?php # vim:ft=php
-if (!extension_loaded("sqlite")) print "skip"; ?>
---FILE--
-<?php
-include "blankdb.inc";
-
-sqlite_array_query($db, "SELECT foo FROM foobar");
-?>
---EXPECTF--
-Warning: sqlite_array_query(): no such table: foobar in %s on line %d
diff --git a/ext/sqlite/tests/sqlite_019.phpt b/ext/sqlite/tests/sqlite_019.phpt
deleted file mode 100755
index b67d5d2899..0000000000
--- a/ext/sqlite/tests/sqlite_019.phpt
+++ /dev/null
@@ -1,46 +0,0 @@
---TEST--
-sqlite: single query
---SKIPIF--
-<?php # vim:ft=php
-if (!extension_loaded("sqlite")) print "skip"; ?>
---FILE--
-<?php
-include "blankdb.inc";
-
-sqlite_query($db, "CREATE TABLE test_db ( id INTEGER PRIMARY KEY, data VARCHAR(100) )");
-for ($i = 0; $i < 10; $i++) {
- sqlite_query($db, "INSERT INTO test_db (data) VALUES('{$i}data')");
-}
-sqlite_query($db, "INSERT INTO test_db (data) VALUES(NULL)");
-
-var_dump(sqlite_single_query($db, "SELECT id FROM test_db WHERE id=5"));
-var_dump(sqlite_single_query($db, "SELECT * FROM test_db WHERE id=4"));
-var_dump(sqlite_single_query($db, "SELECT data FROM test_db WHERE id=6"));
-var_dump(sqlite_single_query($db, "SELECT * FROM test_db WHERE id < 5"));
-var_dump(sqlite_single_query($db, "SELECT * FROM test db WHERE id < 4"));
-var_dump(sqlite_single_query($db, "SELECT * FROM test_db WHERE id=999999"));
-var_dump(sqlite_single_query($db, "SELECT id FROM test_db WHERE id=5", FALSE));
-
-?>
---EXPECTF--
-string(1) "5"
-string(1) "4"
-string(5) "5data"
-array(4) {
- [0]=>
- string(1) "1"
- [1]=>
- string(1) "2"
- [2]=>
- string(1) "3"
- [3]=>
- string(1) "4"
-}
-
-Warning: sqlite_single_query(): no such table: test in %s on line %d
-bool(false)
-NULL
-array(1) {
- [0]=>
- string(1) "5"
-}
diff --git a/ext/sqlite/tests/sqlite_022.phpt b/ext/sqlite/tests/sqlite_022.phpt
deleted file mode 100755
index bd95eab441..0000000000
--- a/ext/sqlite/tests/sqlite_022.phpt
+++ /dev/null
@@ -1,98 +0,0 @@
---TEST--
-sqlite: sqlite_seek
---INI--
-sqlite.assoc_case=0
---SKIPIF--
-<?php # vim:ft=php
-if (!extension_loaded("sqlite")) print "skip"; ?>
---FILE--
-<?php
-include "blankdb.inc";
-
-$data = array(
- "one",
- "two",
- "three"
- );
-
-sqlite_query("CREATE TABLE strings(a)", $db);
-
-foreach ($data as $str) {
- sqlite_query("INSERT INTO strings VALUES('$str')", $db);
-}
-
-$res = sqlite_query("SELECT a FROM strings", $db, SQLITE_NUM);
-for ($idx = -1; $idx < 4; $idx++) {
- echo "====SEEK:$idx====\n";
- sqlite_seek($res, $idx);
- var_dump(sqlite_current($res));
-}
-echo "====AGAIN====\n";
-for ($idx = -1; $idx < 4; $idx++) {
- echo "====SEEK:$idx====\n";
- sqlite_seek($res, $idx);
- var_dump(sqlite_current($res));
-}
-echo "====DONE!====\n";
-?>
---EXPECTF--
-====SEEK:-1====
-
-Warning: sqlite_seek(): row -1 out of range in %ssqlite_022.php on line %d
-array(1) {
- [0]=>
- string(3) "one"
-}
-====SEEK:0====
-array(1) {
- [0]=>
- string(3) "one"
-}
-====SEEK:1====
-array(1) {
- [0]=>
- string(3) "two"
-}
-====SEEK:2====
-array(1) {
- [0]=>
- string(5) "three"
-}
-====SEEK:3====
-
-Warning: sqlite_seek(): row 3 out of range in %ssqlite_022.php on line %d
-array(1) {
- [0]=>
- string(5) "three"
-}
-====AGAIN====
-====SEEK:-1====
-
-Warning: sqlite_seek(): row -1 out of range in %ssqlite_022.php on line %d
-array(1) {
- [0]=>
- string(5) "three"
-}
-====SEEK:0====
-array(1) {
- [0]=>
- string(3) "one"
-}
-====SEEK:1====
-array(1) {
- [0]=>
- string(3) "two"
-}
-====SEEK:2====
-array(1) {
- [0]=>
- string(5) "three"
-}
-====SEEK:3====
-
-Warning: sqlite_seek(): row 3 out of range in %ssqlite_022.php on line %d
-array(1) {
- [0]=>
- string(5) "three"
-}
-====DONE!====
diff --git a/ext/tidy/CREDITS b/ext/tidy/CREDITS
deleted file mode 100644
index 1c77b2ff3b..0000000000
--- a/ext/tidy/CREDITS
+++ /dev/null
@@ -1,2 +0,0 @@
-tidy
-John Coggeshall, Ilia Alshanetsky
diff --git a/ext/tidy/README b/ext/tidy/README
deleted file mode 100644
index 2d4e015176..0000000000
--- a/ext/tidy/README
+++ /dev/null
@@ -1,122 +0,0 @@
-
-README FOR ext/tidy by John Coggeshall <john@php.net>
-
-Tidy Version: 0.7b
-
-Tidy is an extension based on Libtidy (http://tidy.sf.net/) and allows a PHP developer
-to clean, repair, and traverse HTML, XHTML, and XML documents -- including ones with
-embedded scripting languages such as PHP or ASP within them using OO constructs.
-
----------------------------------------------------------------------------------------
-!! Important Note !!
----------------------------------------------------------------------------------------
-At this time libtidy has a small memory leak inside the ParseConfigFileEnc() function
-used to load configuration from a file. If you intend to use this functionality apply
-the "libtidy.txt" patch (cd tidy/src/; patch -p0 < libtidy.txt) to libtidy sources and
-then recompile libtidy.
----------------------------------------------------------------------------------------
-
-The Tidy extension has two separate APIs, one for general parsing, cleaning, and
-repairing and another for document traversal. The general API is provided below:
-
- tidy_create() Reinitialize the tidy engine
- tidy_parse_file($file) Parse the document stored in $file
- tidy_parse_string($str) Parse the string stored in $str
-
- tidy_clean_repair() Clean and repair the document
- tidy_diagnose() Diagnose a parsed document
-
- tidy_setopt($opt, $val) Set a configuration option $opt to $val
- tidy_getopt($opt) Retrieve a configuration option
-
- ** note: $opt is a string representing the option. Although no formal
- documentation yet exists for PHP, you can find a description of many
- of them at http://www.w3.org/People/Raggett/tidy/ and a list of supported
- options in the phpinfo(); output**
-
- tidy_get_output() Return the cleaned tidy HTML as a string
- tidy_get_error_buffer() Return a log of the errors and warnings
- returned by tidy
-
- tidy_get_release() Return the Libtidy release date
- tidy_get_status() Return the status of the document
- tidy_get_html_ver() Return the major HTML version detected for
- the document;
-
- tidy_is_xhtml() Determines if the document is XHTML
- tidy_is_xml() Determines if the document is a generic XML
-
- tidy_error_count() Returns the number of errors in the document
- tidy_warning_count() Returns the number of warnings in the document
- tidy_access_count() Returns the number of accessibility-related
- warnings in the document.
- tidy_config_count() Returns the number of configuration errors found
-
- tidy_load_config($file) Loads the specified configuration file
- tidY_load_config_enc($file,
- $enc) Loads the specified config file using the specified
- character encoding
- tidy_set_encoding($enc) Sets the current character encoding for the document
- tidy_save_config($file) Saves the current config to $file
-
-
-Beyond these general-purpose API functions, Tidy also supports the following
-functions which are used to retrieve an object for document traversal:
-
- tidy_get_root() Returns an object starting at the root of the
- document
- tidy_get_head() Returns an object starting at the <HEAD> tag
- tidy_get_html() Returns an object starting at the <HTML> tag
- tidy_get_body() Returns an object starting at the <BODY> tag
-
-All Navigation of the specified document is done via the PHP5 object constructs.
-There are two types of objects which Tidy can create. The first is TidyNode, which
-represents HTML Tags, Text, and more (see the TidyNode_Type Constants). The second
-is TidyAttr, which represents an attribute within an HTML tag (TidyNode). The
-functionality of these objects is represented by the following schema:
-
-class TidyNode {
-
- public $name; // name of node (i.e. HEAD)
- public $value; // value of node (everything between tags)
- public $type; // type of node (text, php, asp, etc.)
- public $id; // id of node (i.e. TIDY_TAG_HEAD)
-
- public function attributes(); // an array of attributes (see TidyAttr)
- public function children(); // an array of child nodes
-
- function has_siblings(); // any sibling nodes?
- function has_children(); // any child nodes?
-
- function is_comment(); // is node a comment?
- function is_xhtml(); // is document XHTML?
- function is_xml(); // is document generic XML (not HTML/XHTML)
- function is_text(); // is node text?
- function is_html(); // is node an HTML tag?
-
- function is_jste(); // is jste block?
- function is_asp(); // is Microsoft ASP block?
- function is_php(); // is PHP block?
-
- function next(); // returns next node
- function prev(); // returns prev node
-
- /* Searches for a particular attribute in the current node based
- on node ID. If found returns a TidyAttr object for it */
- function get_attr($attr_id);
-
- /*
-}
-
-class TidyAttr {
-
- public $name; // attribute name i.e. HREF
- public $value; // attribute value
- public $id; // attribute id i.e. TIDY_ATTR_HREF
-
-}
-
-Examples of using these objects to navigate the tree can be found in the examples/
-directory (I suggest looking at urlgrab.php and dumpit.php)
-
-E-mail thoughts, suggestions, patches, etc. to <john@php.net>
diff --git a/ext/tidy/TODO b/ext/tidy/TODO
deleted file mode 100644
index 699c207dcb..0000000000
--- a/ext/tidy/TODO
+++ /dev/null
@@ -1,3 +0,0 @@
-TODO
-
- - Implement get_nodes() method
diff --git a/ext/tidy/config.m4 b/ext/tidy/config.m4
deleted file mode 100644
index 069b3ee6b4..0000000000
--- a/ext/tidy/config.m4
+++ /dev/null
@@ -1,35 +0,0 @@
-dnl
-dnl $Id$
-dnl
-
-PHP_ARG_WITH(tidy,for TIDY support,
-[ --with-tidy[=DIR] Include TIDY support])
-
-if test "$PHP_TIDY" != "no"; then
- PHP_NEW_EXTENSION(tidy, tidy.c, $ext_shared)
- if test "$PHP_TIDY" != "yes"; then
- TIDY_SEARCH_DIRS=$PHP_TIDY
- else
- TIDY_SEARCH_DIRS="/usr/local /usr"
- fi
- for i in $TIDY_SEARCH_DIRS; do
- if test -f $i/include/tidy/tidy.h; then
- TIDY_DIR=$i
- TIDY_INCDIR=$i/include/tidy
- elif test -f $i/include/tidy.h; then
- TIDY_DIR=$i
- TIDY_INCDIR=$i/include
- fi
- done
-
- if test -z "$TIDY_DIR"; then
- AC_MSG_ERROR(Cannot find libtidy)
- fi
-
- TIDY_LIBDIR=$TIDY_DIR/lib
-
- AC_DEFINE(HAVE_TIDY,1,[ ])
- PHP_SUBST(TIDY_SHARED_LIBADD)
- PHP_ADD_LIBRARY_WITH_PATH(tidy, $TIDY_LIBDIR, TIDY_SHARED_LIBADD)
- PHP_ADD_INCLUDE($TIDY_INCDIR)
-fi
diff --git a/ext/tidy/examples/cleanhtml.php b/ext/tidy/examples/cleanhtml.php
deleted file mode 100644
index 9d054cda4f..0000000000
--- a/ext/tidy/examples/cleanhtml.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-
- /*
- * cleanhtml.php
- *
- * A simple script to clean and repair HTML,XHTML,PHP,ASP,etc. documents
- * if no file is provided, it reads from standard input.
- *
- * By: John Coggeshall <john@php.net>
- *
- * Usage: php cleanhtml.php [filename]
- *
- */
-
- if(!isset($_SERVER['argv'][1])) {
- $data = file_get_contents("php://stdin");
- tidy_parse_string($data);
- } else {
- tidy_parse_file($_SERVER['argv'][1]);
- }
-
- tidy_clean_repair();
-
- if(tidy_warning_count() ||
- tidy_error_count()) {
-
- echo "\n\nThe following errors or warnings occured:\n";
- echo tidy_get_error_buffer();
- echo "\n";
- }
-
- echo tidy_get_output();
-
-?>
-
-
-
- \ No newline at end of file
diff --git a/ext/tidy/examples/dumpit.php b/ext/tidy/examples/dumpit.php
deleted file mode 100644
index e77b7b9323..0000000000
--- a/ext/tidy/examples/dumpit.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
- /*
- * dumpit.php
- *
- * a command-line script which dumps the given HTML, PHP, ASP, XHTML, etc.
- * file as it is represented in the document model.
- *
- * By: John Coggeshall <john@php.net>
- *
- * Usage; php dumpit.php <filename>
- */
-
- tidy_parse_file($_SERVER['argv'][1]);
-
- /* Optionally you can do this here if you want to fix up the document */
-
- /* tidy_clean_repair(); */
-
- $tree = tidy_get_root();
- dump_tree($tree);
- echo "\n";
-
- function node_type($type) {
-
- switch($type) {
-
- case TIDY_NODETYPE_ROOT: return "Root Node";
- case TIDY_NODETYPE_DOCTYPE: return "DocType Node";
- case TIDY_NODETYPE_COMMENT: return "Comment Node";
- case TIDY_NODETYPE_PROCINS: return "ProcIns Node";
- case TIDY_NODETYPE_TEXT: return "Text Node";
- case TIDY_NODETYPE_START: return "Start Node";
- case TIDY_NODETYPE_END: return "End Node";
- case TIDY_NODETYPE_STARTEND: return "Start/End Node";
- case TIDY_NODETYPE_CDATA: return "CDATA Node";
- case TIDY_NODETYPE_SECTION: return "Section Node";
- case TIDY_NODETYPE_ASP: return "ASP Source Code Node";
- case TIDY_NODETYPE_PHP: return "PHP Source Code Node";
- case TIDY_NODETYPE_JSTE: return "JSTE Source Code";
- case TIDY_NODETYPE_XMLDECL: return "XML Declaration Node";
- default: return "Unknown Node";
- }
- }
-
- function do_leaf($string, $indent) {
- for($i = 0; $i < $indent; $i++) {
- echo " ";
- }
- echo $string;
- }
-
- function dump_tree($node, $indent = 0) {
- if($node) {
- /* Put something there if the node name is empty */
- $nodename = trim(strtoupper($node->name));
- $nodename = (empty($nodename)) ? "[EMPTY]" : $nodename;
-
- /* Generate the Node, and a pretty name for it */
- do_leaf(" + $nodename (".node_type($node->type).")\n", $indent);
-
- /* Check to see if this node is a text node. Text nodes are
- generated by start/end tags and contain the text in between.
- i.e. <B>foo</B> will create a text node with $node->value
- equal to 'foo' */
- if($node->type == TIDY_NODETYPE_TEXT) {
- do_leaf(" |\n", $indent);
- do_leaf(" +---- Value: '{$node->value}'\n", $indent);
- }
-
- /* Any attributes on this node? */
- if(count($node->attributes())) {
- do_leaf(" |\n", $indent);
- do_leaf(" +---- Attributes\n", $indent);
-
- /* Cycle through the attributes and display them and their values. */
- foreach($node->attributes() as $attrib) {
- do_leaf(" +--{$attrib->name}\n", $indent);
- do_leaf(" | +-- Value: {$attrib->value}\n", $indent);
- }
- }
-
- /* Recurse along the children to generate the remaining nodes */
- if($node->has_children()) {
- foreach($node->children() as $child) {
- dump_tree($child, $indent + 3);
- }
- }
- }
- }
-
- echo tidy_get_output();
-
-?> \ No newline at end of file
diff --git a/ext/tidy/examples/urlgrab.php b/ext/tidy/examples/urlgrab.php
deleted file mode 100644
index 7896792ea5..0000000000
--- a/ext/tidy/examples/urlgrab.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-
- /*
- * urlgrab.php
- *
- * A simple command-line utility to extract all of the URLS contained
- * within <A HREF> tags from a document.
- *
- * By: John Coggeshall <john@php.net>
- *
- * Usage: php urlgrab.php <file>
- *
- */
-
- /* Parse the document */
- tidy_parse_file($_SERVER['argv'][1]);
-
- /* Fix up the document */
- tidy_clean_repair();
-
- /* Get an object representing everything from the <HTML> tag in */
- $html = tidy_get_html();
-
- /* Traverse the document tree */
- print_r(get_links($html));
-
- function get_links($node) {
- $urls = array();
-
- /* Check to see if we are on an <A> tag or not */
- if($node->id == TIDY_TAG_A) {
- /* If we are, find the HREF attribute */
- $attrib = $node->get_attr(TIDY_ATTR_HREF);
- if($attrib) {
- /* Add the value of the HREF attrib to $urls */
- $urls[] = $attrib->value;
- }
-
- }
-
- /* Are there any children? */
- if($node->has_children()) {
-
- /* Traverse down each child recursively */
- foreach($node->children() as $child) {
-
- /* Append the results from recursion to $urls */
- foreach(get_links($child) as $url) {
-
- $urls[] = $url;
-
- }
-
- }
- }
-
- return $urls;
- }
-
-?> \ No newline at end of file
diff --git a/ext/tidy/package.xml b/ext/tidy/package.xml
deleted file mode 100644
index 266cc5d7c6..0000000000
--- a/ext/tidy/package.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1" ?>
-<!DOCTYPE package SYSTEM "../pear/package.dtd">
-<package>
- <name>tidy</name>
- <summary>Tidy HTML Repairing and Parsing</summary>
- <maintainers>
- <maintainer>
- <user>john</user>
- <name>John Coggeshall</name>
- <email>john@php.net</email>
- <role>lead</role>
- </maintainer>
- <maintainer>
- <user>iliaa</user>
- <name>Ilia Alshanetsky</name>
- <email>ilia@php.net</email>
- <role>lead</role>
- </maintainer>
- </maintainers>
- <description>
-Tidy is a binding for the Tidy HTML clean and repair utility which
-allows you to not only clean and otherwise manipluate HTML documents,
-but also traverse the document tree using the Zend Engine 2 OO semantics.
- </description>
- <license>PHP</license>
- <release>
- <state>stable</state>
- <version>1.0</version>
- <date>2003-11-13</date>
- <notes>
- Fixed a few PHP5-specific bugs when working with node objects.
- </notes>
- <configureoptions>
- <configureoption name="with-tidy" default="autodetect" prompt="Tidy library installation dir?"/>
- </configureoptions>
- <filelist>
- <file role="src" name="config.m4"/>
- <file role="src" name="tidy.c"/>
- <file role="src" name="php_tidy.h"/>
-
- <file role="doc" name="CREDITS"/>
- <file role="doc" name="README"/>
- <file role="doc" name="TODO"/>
- <file role="doc" name="examples/cleanhtml.php"/>
- <file role="doc" name="examples/dumpit.php"/>
- <file role="doc" name="examples/urlgrab.php"/>
-
- <file role="test" name="tests/001.phpt"/>
- <file role="test" name="tests/002.phpt"/>
- <file role="test" name="tests/003.phpt"/>
- <file role="test" name="tests/004.phpt"/>
- <file role="test" name="tests/005.phpt"/>
- <file role="test" name="tests/005.html"/>
- <file role="test" name="tests/006.phpt"/>
- <file role="test" name="tests/007.phpt"/>
- </filelist>
- <deps>
- <dep type="php" rel="ge">4.3.0</dep>
- </deps>
- </release>
-</package>
-<!--
-vim:et:ts=1:sw=1
--->
diff --git a/ext/tidy/php_tidy.h b/ext/tidy/php_tidy.h
deleted file mode 100644
index e170d37086..0000000000
--- a/ext/tidy/php_tidy.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 4 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2003 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: John Coggeshall <john@php.net> |
- | Ilia Alshanetsky <ilia@php.net> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id$ */
-
-#ifndef PHP_TIDY_H
-#define PHP_TIDY_H
-
-extern zend_module_entry tidy_module_entry;
-#define phpext_tidy_ptr &tidy_module_entry
-
-#ifdef PHP_WIN32
-#define PHP_TIDY_API __declspec(dllexport)
-#else
-#define PHP_TIDY_API
-#endif
-
-#ifdef ZTS
-#include "TSRM.h"
-#endif
-
-#include "tidyenum.h"
-#include "tidy.h"
-#include "buffio.h"
-
-#ifdef ZTS
-#define TG(v) TSRMG(tidy_globals_id, zend_tidy_globals *, v)
-#else
-#define TG(v) (tidy_globals.v)
-#endif
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#define TIDY_RV_FALSE(__t) __t->type = IS_BOOL; __t->value.lval = FALSE
-#define TIDY_RV_TRUE(__t) __t->type = IS_BOOL; __t->value.lval = TRUE
-
-#define REMOVE_NEWLINE(_z) _z->value.str.val[_z->value.str.len-1] = '\0'; _z->value.str.len--;
-
-#define TIDY_TAG_CONST(tag) REGISTER_LONG_CONSTANT("TIDY_TAG_" #tag, TidyTag_##tag, CONST_CS | CONST_PERSISTENT)
-#define TIDY_ATTR_CONST(attr) REGISTER_LONG_CONSTANT("TIDY_ATTR_" #attr, TidyAttr_##attr, CONST_CS | CONST_PERSISTENT)
-#define TIDY_NODE_CONST(name, type) REGISTER_LONG_CONSTANT("TIDY_NODETYPE_" #name, TidyNode_##type, CONST_CS | CONST_PERSISTENT)
-
-#define PHP_ME_MAPPING(name, func_name, arg_types) \
- ZEND_NAMED_FE(name, ZEND_FN(func_name), arg_types)
-
-#define PHP_NODE_METHOD(name) PHP_FUNCTION(tnm_ ##name)
-#define PHP_ATTR_METHOD(name) PHP_FUNCTION(tam_ ##name)
-#define PHP_NODE_ME(name, param) PHP_ME_MAPPING(name, tnm_ ##name, param)
-#define PHP_ATTR_ME(name, param) PHP_ME_MAPPING(name, tam_ ##name, param)
-
-
-
-#define TIDY_REGISTER_OBJECT(_type, _object, _ptr) \
- { \
- tidy_object *obj; \
- obj = (tidy_object*)zend_object_store_get_object(_object TSRMLS_CC); \
- obj->type = is_ ## _type; \
- obj->u._type = _ptr; \
- }
-
-#define REGISTER_TIDY_CLASS(name, parent) \
- { \
- zend_class_entry ce; \
- INIT_CLASS_ENTRY(ce, "tidy_" # name, tidy_funcs_ ## name); \
- ce.create_object = tidy_object_new_ ## name; \
- tidy_ce_ ## name = zend_register_internal_class_ex(&ce, parent, NULL TSRMLS_CC); \
- tidy_ce_ ## name->ce_flags |= ZEND_ACC_FINAL_CLASS; \
- memcpy(&tidy_object_handlers_ ## name, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \
- tidy_object_handlers_ ## name.clone_obj = NULL; \
- }
-
-#define GET_THIS_CONTAINER() \
- PHPTidyObj *obj; \
- { \
- zval *object = getThis(); \
- obj = (PHPTidyObj *)zend_object_store_get_object(object TSRMLS_CC); \
- }
-
-#define INSTANCIATE_NODE(_zval, _container, _node) \
- tidy_instanciate(tidy_ce_node, _zval TSRMLS_CC); \
- _container = (PHPTidyObj *) zend_object_store_get_object(_zval TSRMLS_CC); \
- _container->node = _node; \
- _container->attr = NULL; \
- _container->type = is_node; \
- tidy_add_default_properities(_container, is_node TSRMLS_CC);
-
-#define INSTANCIATE_ATTR(_zval, _container, _attr) \
- tidy_instanciate(tidy_ce_attr, _zval TSRMLS_CC); \
- _container = (PHPTidyObj *) zend_object_store_get_object(_zval TSRMLS_CC); \
- _container->node = NULL; \
- _container->attr = _attr; \
- _container->type = is_attr; \
- tidy_add_default_properities(_container, is_attr TSRMLS_CC);
-
-#define PHP_NODE_METHOD_IS_TYPE(_type, _const) \
-PHP_NODE_METHOD(is_ ##_type) \
-{ \
- GET_THIS_CONTAINER(); \
- if(tidyNodeGetType(obj->node) == _const) {\
- RETURN_TRUE; \
- } else { \
- RETURN_FALSE; \
- } \
-}
-
-typedef enum {
- is_node,
- is_attr
-} tidy_obj_type;
-
-struct _PHPTidyDoc {
-
- TidyDoc doc;
- TidyBuffer *errbuf;
- zend_bool parsed;
-};
-
-typedef struct _PHPTidyDoc PHPTidyDoc;
-typedef struct _PHPTidyObj PHPTidyObj;
-
-struct _PHPTidyObj {
- zend_object std;
- TidyNode node;
- TidyAttr attr;
- tidy_obj_type type;
-};
-
-
-PHP_MINIT_FUNCTION(tidy);
-PHP_MSHUTDOWN_FUNCTION(tidy);
-PHP_RINIT_FUNCTION(tidy);
-PHP_RSHUTDOWN_FUNCTION(tidy);
-PHP_MINFO_FUNCTION(tidy);
-
-PHP_FUNCTION(tidy_setopt);
-PHP_FUNCTION(tidy_getopt);
-PHP_FUNCTION(tidy_parse_string);
-PHP_FUNCTION(tidy_parse_file);
-PHP_FUNCTION(tidy_clean_repair);
-PHP_FUNCTION(tidy_repair_string);
-PHP_FUNCTION(tidy_repair_file);
-PHP_FUNCTION(tidy_diagnose);
-PHP_FUNCTION(tidy_get_output);
-PHP_FUNCTION(tidy_get_error_buffer);
-PHP_FUNCTION(tidy_get_release);
-PHP_FUNCTION(tidy_reset_config);
-PHP_FUNCTION(tidy_get_config);
-PHP_FUNCTION(tidy_get_status);
-PHP_FUNCTION(tidy_get_html_ver);
-PHP_FUNCTION(tidy_is_xhtml);
-PHP_FUNCTION(tidy_is_xml);
-PHP_FUNCTION(tidy_error_count);
-PHP_FUNCTION(tidy_warning_count);
-PHP_FUNCTION(tidy_access_count);
-PHP_FUNCTION(tidy_config_count);
-PHP_FUNCTION(tidy_load_config);
-PHP_FUNCTION(tidy_load_config_enc);
-PHP_FUNCTION(tidy_set_encoding);
-PHP_FUNCTION(tidy_save_config);
-
-PHP_FUNCTION(tidy_get_root);
-PHP_FUNCTION(tidy_get_html);
-PHP_FUNCTION(tidy_get_head);
-PHP_FUNCTION(tidy_get_body);
-
-PHP_NODE_METHOD(__construct);
-PHP_NODE_METHOD(attributes);
-PHP_NODE_METHOD(children);
-
-PHP_NODE_METHOD(has_children);
-PHP_NODE_METHOD(has_siblings);
-PHP_NODE_METHOD(is_comment);
-PHP_NODE_METHOD(is_html);
-PHP_NODE_METHOD(is_xhtml);
-PHP_NODE_METHOD(is_xml);
-PHP_NODE_METHOD(is_text);
-PHP_NODE_METHOD(is_jste);
-PHP_NODE_METHOD(is_asp);
-PHP_NODE_METHOD(is_php);
-
-PHP_NODE_METHOD(next);
-PHP_NODE_METHOD(prev);
-PHP_NODE_METHOD(get_attr);
-PHP_NODE_METHOD(get_nodes);
-
-/* resource dtor */
-void dtor_TidyDoc(zend_rsrc_list_entry * TSRMLS_DC);
-
-/* constant register helpers */
-void _php_tidy_register_nodetypes(INIT_FUNC_ARGS);
-void _php_tidy_register_tags(INIT_FUNC_ARGS);
-void _php_tidy_register_attributes(INIT_FUNC_ARGS);
-
-ZEND_BEGIN_MODULE_GLOBALS(tidy)
- PHPTidyDoc *tdoc;
- zend_bool used;
- char *default_config;
-ZEND_END_MODULE_GLOBALS(tidy)
-
-#ifdef ZTS
-#define TG(v) TSRMG(tidy_globals_id, zend_tidy_globals *, v)
-#else
-#define TG(v) (tidy_globals.v)
-#endif
-
-
-
-
-#endif
-
-
-/*
- * 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
- */
diff --git a/ext/tidy/tests/001.phpt b/ext/tidy/tests/001.phpt
deleted file mode 100644
index 17da6f9874..0000000000
--- a/ext/tidy/tests/001.phpt
+++ /dev/null
@@ -1,24 +0,0 @@
---TEST--
-Check for tidy presence
---SKIPIF--
-<?php if (!extension_loaded("tidy")) print "skip"; ?>
---POST--
---GET--
---INI--
---FILE--
-<?php
-echo "tidy extension is available";
-/*
- you can add regression tests for your extension here
-
- the output of your test code has to be equal to the
- text in the --EXPECT-- section below for the tests
- to pass, differences between the output and the
- expected text are interpreted as failure
-
- see php4/README.TESTING for further information on
- writing regression tests
-*/
-?>
---EXPECT--
-tidy extension is available
diff --git a/ext/tidy/tests/002.phpt b/ext/tidy/tests/002.phpt
deleted file mode 100644
index 83456091f7..0000000000
--- a/ext/tidy/tests/002.phpt
+++ /dev/null
@@ -1,22 +0,0 @@
---TEST--
-tidy_parse_string()
---SKIPIF--
-<?php if (!extension_loaded("tidy")) print "skip"; ?>
---POST--
---GET--
---INI--
---FILE--
-<?php
- tidy_parse_string("<HTML></HTML>");
-
- echo tidy_get_output();
-
-?>
---EXPECT--
-<html>
-<head>
-<title></title>
-</head>
-<body>
-</body>
-</html> \ No newline at end of file
diff --git a/ext/tidy/tests/003.phpt b/ext/tidy/tests/003.phpt
deleted file mode 100644
index b008acecdb..0000000000
--- a/ext/tidy/tests/003.phpt
+++ /dev/null
@@ -1,25 +0,0 @@
---TEST--
-tidy_clean_repair()
---SKIPIF--
-<?php if (!extension_loaded("tidy")) print "skip"; ?>
---POST--
---GET--
---INI--
---FILE--
-<?php
-
- tidy_parse_string("<HTML></HTML>");
- tidy_clean_repair();
-
- echo tidy_get_output();
-
-?>
---EXPECT--
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<title></title>
-</head>
-<body>
-</body>
-</html>
diff --git a/ext/tidy/tests/004.phpt b/ext/tidy/tests/004.phpt
deleted file mode 100644
index ed60a39b27..0000000000
--- a/ext/tidy/tests/004.phpt
+++ /dev/null
@@ -1,21 +0,0 @@
---TEST--
-tidy_diagnose()
---SKIPIF--
-<?php if (!extension_loaded("tidy")) print "skip"; ?>
---POST--
---GET--
---INI--
---FILE--
-<?php
- tidy_parse_string("<HTML></HTML>");
- tidy_diagnose();
- echo tidy_get_error_buffer();
-
-?>
---EXPECT--
-
-line 1 column 1 - Warning: missing <!DOCTYPE> declaration
-line 1 column 7 - Warning: discarding unexpected </html>
-line 1 column 14 - Warning: inserting missing 'title' element
-Info: Document content looks like HTML 3.2
-3 warnings, 0 errors were found! \ No newline at end of file
diff --git a/ext/tidy/tests/005.html b/ext/tidy/tests/005.html
deleted file mode 100644
index 8c17451f91..0000000000
--- a/ext/tidy/tests/005.html
+++ /dev/null
@@ -1 +0,0 @@
-<HTML></HTML>
diff --git a/ext/tidy/tests/005.phpt b/ext/tidy/tests/005.phpt
deleted file mode 100644
index d69a726c8f..0000000000
--- a/ext/tidy/tests/005.phpt
+++ /dev/null
@@ -1,23 +0,0 @@
---TEST--
-tidy_parse_file()
---SKIPIF--
-<?php if (!extension_loaded("tidy")) print "skip"; ?>
---POST--
---GET--
---INI--
---FILE--
-<?php
-
- tidy_parse_file("ext/tidy/tests/005.html");
-
- echo tidy_get_output();
-
-?>
---EXPECT--
-<html>
-<head>
-<title></title>
-</head>
-<body>
-</body>
-</html> \ No newline at end of file
diff --git a/ext/tidy/tests/006.phpt b/ext/tidy/tests/006.phpt
deleted file mode 100644
index 7ea28e79c5..0000000000
--- a/ext/tidy/tests/006.phpt
+++ /dev/null
@@ -1,21 +0,0 @@
---TEST--
-Verbose tidy_get_error_buffer()
---SKIPIF--
-<?php if (!extension_loaded("tidy")) print "skip"; ?>
---POST--
---GET--
---INI--
---FILE--
-<?php
-
- tidy_parse_string("<HTML><asd asdf></HTML>");
-
- echo tidy_get_error_buffer(true);
-
-?>
---EXPECT--
-line 1 column 1 - Warning: missing <!DOCTYPE> declaration
-line 1 column 7 - Error: <asd> is not recognized!
-line 1 column 7 - Warning: discarding unexpected <asd>
-line 1 column 17 - Warning: discarding unexpected </html>
-line 1 column 7 - Warning: inserting missing 'title' element \ No newline at end of file
diff --git a/ext/tidy/tests/007.phpt b/ext/tidy/tests/007.phpt
deleted file mode 100644
index 9987677df6..0000000000
--- a/ext/tidy/tests/007.phpt
+++ /dev/null
@@ -1,36 +0,0 @@
---TEST--
-Verbose tidy_setopt() / tidy_getopt()
---SKIPIF--
-<?php if (!extension_loaded("tidy")) print "skip"; ?>
---POST--
---GET--
---INI--
---FILE--
-<?php
-
- echo "Current Value of 'tidy-mark': ";
- var_dump(tidy_getopt("tidy-mark"));
- tidy_setopt($tidy, "tidy-mark", true);
- echo "\nNew Value of 'tidy-mark': ";
- var_dump(tidy_getopt("tidy-mark"));
- echo "Current Value of 'error-file': ";
- var_dump(tidy_getopt("error-file"));
- tidy_setopt($tidy, "error-file", "foobar");
- echo "\nNew Value of 'error-file': ";
- var_dump(tidy_getopt("error-file"));
- echo "Current Value of 'tab-size': ";
- var_dump(tidy_getopt("tab-size"));
- tidy_setopt($tidy, "tab-size", 10);
- echo "\nNew Value of 'tab-size': ";
- var_dump(tidy_getopt("tab-size"));
-?>
---EXPECT--
-Current Value of 'tidy-mark': bool(false)
-
-New Value of 'tidy-mark': bool(true)
-Current Value of 'error-file': string(0) ""
-
-New Value of 'error-file': string(6) "foobar"
-Current Value of 'tab-size': int(8)
-
-New Value of 'tab-size': int(10) \ No newline at end of file
diff --git a/ext/tidy/tidy.c b/ext/tidy/tidy.c
deleted file mode 100644
index c67e29c271..0000000000
--- a/ext/tidy/tidy.c
+++ /dev/null
@@ -1,1689 +0,0 @@
-/*
- +----------------------------------------------------------------------+
- | PHP Version 4 |
- +----------------------------------------------------------------------+
- | Copyright (c) 1997-2003 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: John Coggeshall <john@php.net> |
- | Ilia Alshanetsky <ilia@php.net> |
- +----------------------------------------------------------------------+
-*/
-
-/* $Id$ */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "php.h"
-#include "php_tidy.h"
-#include "php_ini.h"
-#include "ext/standard/info.h"
-#include "Zend/zend_API.h"
-#include "Zend/zend_hash.h"
-#include "safe_mode.h"
-
-ZEND_DECLARE_MODULE_GLOBALS(tidy);
-
-#define TIDY_PARSED_CHECK() \
-if(!TG(tdoc)->parsed) { \
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "A document must be parsed before executing this function."); \
- RETURN_FALSE; \
-} \
-
-#define TIDY_SAFE_MODE_CHECK(filename) \
-if ((PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)) { \
- RETURN_FALSE; \
-} \
-
-function_entry tidy_functions[] = {
- PHP_FE(tidy_setopt, NULL)
- PHP_FE(tidy_getopt, NULL)
- PHP_FE(tidy_parse_string, NULL)
- PHP_FE(tidy_parse_file, NULL)
- PHP_FE(tidy_get_output, NULL)
- PHP_FE(tidy_get_error_buffer, NULL)
- PHP_FE(tidy_clean_repair, NULL)
- PHP_FE(tidy_repair_string, NULL)
- PHP_FE(tidy_repair_file, NULL)
- PHP_FE(tidy_diagnose, NULL)
- PHP_FE(tidy_get_release, NULL)
- PHP_FE(tidy_get_config, NULL)
- PHP_FE(tidy_get_status, NULL)
- PHP_FE(tidy_get_html_ver, NULL)
- PHP_FE(tidy_is_xhtml, NULL)
- PHP_FE(tidy_is_xml, NULL)
- PHP_FE(tidy_error_count, NULL)
- PHP_FE(tidy_warning_count, NULL)
- PHP_FE(tidy_access_count, NULL)
- PHP_FE(tidy_config_count, NULL)
- PHP_FE(tidy_load_config, NULL)
- PHP_FE(tidy_load_config_enc, NULL)
- PHP_FE(tidy_set_encoding, NULL)
- PHP_FE(tidy_save_config, NULL)
-
-#ifdef ZEND_ENGINE_2
- PHP_FE(tidy_get_root, NULL)
- PHP_FE(tidy_get_head, NULL)
- PHP_FE(tidy_get_html, NULL)
- PHP_FE(tidy_get_body, NULL)
-#endif
-
- {NULL, NULL, NULL}
-};
-
-#ifdef ZEND_ENGINE_2
-#include "zend_default_classes.h"
-
-static void tidy_object_dtor(void *object, zend_object_handle handle TSRMLS_DC);
-static void tidy_object_new(zend_class_entry *class_type, zend_object_handlers *handlers, zend_object_value *retval TSRMLS_DC);
-
-static zend_object_value tidy_object_new_node(zend_class_entry *class_type TSRMLS_DC);
-static zend_object_value tidy_object_new_attr(zend_class_entry *class_type TSRMLS_DC);
-static zend_object_value tidy_object_new_exception(zend_class_entry *class_type TSRMLS_DC);
-
-static zend_class_entry *tidy_get_ce_node(zval *object TSRMLS_DC);
-static zend_class_entry *tidy_get_ce_attr(zval *object TSRMLS_DC);
-
-static zval * tidy_instanciate(zend_class_entry *pce, zval *object TSRMLS_DC);
-
-zend_class_entry *tidy_ce_node, *tidy_ce_attr,
- *tidy_ce_exception;
-
-static zend_object_handlers tidy_object_handlers_node;
-static zend_object_handlers tidy_object_handlers_attr;
-static zend_object_handlers tidy_object_handlers_exception;
-
-function_entry tidy_funcs_node[] = {
-
- PHP_NODE_ME(__construct, NULL)
- PHP_NODE_ME(attributes, NULL)
- PHP_NODE_ME(children, NULL)
-
- PHP_NODE_ME(has_children, NULL)
- PHP_NODE_ME(has_siblings, NULL)
- PHP_NODE_ME(is_comment, NULL)
- PHP_NODE_ME(is_html, NULL)
- PHP_NODE_ME(is_text, NULL)
- PHP_NODE_ME(is_jste, NULL)
- PHP_NODE_ME(is_asp, NULL)
- PHP_NODE_ME(is_php, NULL)
-
- PHP_NODE_ME(next, NULL)
- PHP_NODE_ME(prev, NULL)
- PHP_NODE_ME(get_attr, NULL)
- /*PHP_NODE_ME(get_nodes, NULL) TODO */
- {NULL, NULL, NULL}
-};
-
-function_entry tidy_funcs_attr[] = {
- {NULL, NULL, NULL}
-};
-
-function_entry tidy_funcs_exception[] = {
- {NULL, NULL, NULL}
-};
-
-#endif
-
-zend_module_entry tidy_module_entry = {
-#if ZEND_MODULE_API_NO >= 20010901
- STANDARD_MODULE_HEADER,
-#endif
- "tidy",
- tidy_functions,
- PHP_MINIT(tidy),
- PHP_MSHUTDOWN(tidy),
- PHP_RINIT(tidy),
- NULL,
- PHP_MINFO(tidy),
-#if ZEND_MODULE_API_NO >= 20010901
- "1.0",
-#endif
- STANDARD_MODULE_PROPERTIES
-};
-
-#ifdef COMPILE_DL_TIDY
-ZEND_GET_MODULE(tidy)
-#endif
-
-/* {{{ PHP_INI
- */
-PHP_INI_BEGIN()
-STD_PHP_INI_ENTRY("tidy.default_config", "", PHP_INI_SYSTEM, OnUpdateString, default_config, zend_tidy_globals, tidy_globals)
-PHP_INI_END()
-/* }}} */
-
-static void tidy_globals_ctor(zend_tidy_globals *g TSRMLS_DC)
-{
- g->used = 0;
- g->tdoc = pemalloc(sizeof(PHPTidyDoc), 1);
- g->tdoc->doc = tidyCreate();
- g->tdoc->parsed = 0;
- g->tdoc->errbuf = pemalloc(sizeof(TidyBuffer), 1);
- tidyBufInit(g->tdoc->errbuf);
-
- if(tidySetErrorBuffer(g->tdoc->doc, g->tdoc->errbuf) != 0) {
- zend_error(E_ERROR, "Could not set Tidy error buffer");
- }
-
- tidyOptSetBool(g->tdoc->doc, TidyForceOutput, yes);
- tidyOptSetBool(g->tdoc->doc, TidyMark, no);
-
- /* remember settings so that we can restore them */
- tidyOptSnapshot(g->tdoc->doc);
-}
-
-static void tidy_globals_dtor(zend_tidy_globals *g TSRMLS_DC)
-{
- tidyBufFree(g->tdoc->errbuf);
- pefree(g->tdoc->errbuf, 1);
- tidyRelease(g->tdoc->doc);
- pefree(g->tdoc, 1);
- g->used = 0;
-}
-
-static void *php_tidy_get_opt_val(TidyOption opt, TidyOptionType *type TSRMLS_DC)
-{
- *type = tidyOptGetType(opt);
-
- switch (*type) {
- case TidyString: {
- char *val = (char *) tidyOptGetValue(TG(tdoc)->doc, tidyOptGetId(opt));
- if (val) {
- return (void *) estrdup(val);
- } else {
- return (void *) estrdup("");
- }
- }
- break;
-
- case TidyInteger:
- return (void *) tidyOptGetInt(TG(tdoc)->doc, tidyOptGetId(opt));
- break;
-
- case TidyBoolean:
- return (void *) tidyOptGetBool(TG(tdoc)->doc, tidyOptGetId(opt));
- break;
- }
-
- /* should not happen */
- return NULL;
-}
-
-static char *php_tidy_file_to_mem(char *filename, zend_bool use_include_path TSRMLS_DC)
-{
- php_stream *stream;
- int len;
- char *data = NULL;
-
- if (!(stream = php_stream_open_wrapper(filename, "rb", (use_include_path ? USE_PATH : 0) | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL))) {
- return NULL;
- }
- if ((len = php_stream_copy_to_mem(stream, &data, PHP_STREAM_COPY_ALL, 0)) > 0) {
- /* noop */
- } else if (len == 0) {
- data = estrdup("");
- }
- php_stream_close(stream);
-
- return data;
-}
-
-static void php_tidy_quick_repair(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_file)
-{
- char *data=NULL, *cfg_file=NULL, *arg1;
- int cfg_file_len, arg1_len;
- zend_bool use_include_path = 0;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sb", &arg1, &arg1_len, &cfg_file, &cfg_file_len, &use_include_path) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (is_file) {
- if (!(data = php_tidy_file_to_mem(arg1, use_include_path TSRMLS_CC))) {
- RETURN_FALSE;
- }
- } else {
- data = arg1;
- }
-
- if (cfg_file && cfg_file[0]) {
- TIDY_SAFE_MODE_CHECK(cfg_file);
- if(tidyLoadConfig(TG(tdoc)->doc, cfg_file) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not load configuration file '%s'", cfg_file);
- RETVAL_FALSE;
- }
- TG(used) = 1;
- }
-
- if (data) {
- if(tidyParseString(TG(tdoc)->doc, data) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "[Tidy error] %s", TG(tdoc)->errbuf->bp);
- RETVAL_FALSE;
- } else {
- TG(tdoc)->parsed = TRUE;
- if (tidyCleanAndRepair(TG(tdoc)->doc) >= 0) {
- TidyBuffer output = {0};
-
- tidySaveBuffer (TG(tdoc)->doc, &output);
- RETVAL_STRING(output.bp, 1);
- tidyBufFree(&output);
- } else {
- RETVAL_FALSE;
- }
- }
- }
-
- if (is_file) {
- efree(data);
- }
-}
-
-PHP_MINIT_FUNCTION(tidy)
-{
- REGISTER_INI_ENTRIES();
-
-#ifdef ZEND_ENGINE_2
- REGISTER_TIDY_CLASS(node, NULL);
- REGISTER_TIDY_CLASS(attr, NULL);
- REGISTER_TIDY_CLASS(exception, zend_exception_get_default());
-
- tidy_object_handlers_node.get_class_entry = tidy_get_ce_node;
- tidy_object_handlers_attr.get_class_entry = tidy_get_ce_attr;
-#endif
-
- _php_tidy_register_tags(INIT_FUNC_ARGS_PASSTHRU);
- _php_tidy_register_attributes(INIT_FUNC_ARGS_PASSTHRU);
- _php_tidy_register_nodetypes(INIT_FUNC_ARGS_PASSTHRU);
-
- ZEND_INIT_MODULE_GLOBALS(tidy, tidy_globals_ctor, tidy_globals_dtor);
-
- return SUCCESS;
-}
-
-PHP_MSHUTDOWN_FUNCTION(tidy)
-{
-#ifndef ZTS
- tidy_globals_dtor(&tidy_globals TSRMLS_CC);
-#endif
- return SUCCESS;
-}
-
-PHP_RINIT_FUNCTION(tidy)
-{
- if (TG(used) && tidyOptDiffThanSnapshot((TG(tdoc))->doc)) {
- tidyOptResetToSnapshot((TG(tdoc))->doc);
- TG(used) = 0;
- }
- /* if a user provided a default configuration file, use it */
- if (TG(default_config) && TG(default_config)[0]) {
- if (tidyLoadConfig((TG(tdoc))->doc, TG(default_config)) < 0) {
- zend_error(E_ERROR, "Unable to load Tidy configuration file at '%s'.", TG(default_config));
- }
- TG(used) = 1;
- }
- return SUCCESS;
-}
-
-PHP_MINFO_FUNCTION(tidy)
-{
- TidyIterator itOpt = tidyGetOptionList(TG(tdoc)->doc);
- void *opt_value;
- TidyOptionType optt;
- char buf[255];
-
- php_info_print_table_start();
- php_info_print_table_header(2, "Tidy support", "enabled");
- php_info_print_table_row(2, "libTidy Build Date", (char *)tidyReleaseDate());
- php_info_print_table_end();
-
- DISPLAY_INI_ENTRIES();
-
- php_info_print_table_start();
- php_info_print_table_header(2, "Tidy Configuration Directive", "Value");
- while (itOpt) {
- TidyOption opt = tidyGetNextOption(TG(tdoc)->doc, &itOpt);
-
- opt_value = php_tidy_get_opt_val(opt, &optt TSRMLS_CC);
- switch (optt) {
- case TidyString:
- php_info_print_table_row(2, (char *)tidyOptGetName(opt), (char*)opt_value);
- efree(opt_value);
- break;
-
- case TidyInteger:
- sprintf(buf, "%d", (int)opt_value);
- php_info_print_table_row(2, (char *)tidyOptGetName(opt), (char*)buf);
- break;
-
- case TidyBoolean:
- php_info_print_table_row(2, (char *)tidyOptGetName(opt), (opt_value ? "TRUE" : "FALSE"));
- break;
- }
- }
- php_info_print_table_end();
-}
-
-/* {{{ proto bool tidy_parse_string(string input)
- Parse a document stored in a string */
-PHP_FUNCTION(tidy_parse_string)
-{
- char *input;
- int input_len;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &input, &input_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- if(tidyParseString(TG(tdoc)->doc, input) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "[Tidy error] %s", TG(tdoc)->errbuf->bp);
- RETURN_FALSE;
- }
-
- TG(tdoc)->parsed = TRUE;
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto string tidy_get_error_buffer([boolean detailed])
- Return warnings and errors which occured parsing the specified document*/
-PHP_FUNCTION(tidy_get_error_buffer)
-{
- zend_bool detailed = 0;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &detailed) == FAILURE) {
- RETURN_FALSE;
- }
-
- TIDY_PARSED_CHECK();
-
- if (detailed) {
- tidyErrorSummary(TG(tdoc)->doc);
- }
-
- RETVAL_STRING(TG(tdoc)->errbuf->bp, 1);
- tidyBufClear(TG(tdoc)->errbuf);
-}
-/* }}} */
-
-/* {{{ proto string tidy_get_output()
- Return a string representing the parsed tidy markup */
-PHP_FUNCTION(tidy_get_output)
-{
- TidyBuffer output = {0};
-
- if (ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- tidySaveBuffer (TG(tdoc)->doc, &output);
-
- RETVAL_STRING(output.bp, 1);
-
- tidyBufFree(&output);
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_parse_file(string file [, bool use_include_path])
- Parse markup in file or URI */
-PHP_FUNCTION(tidy_parse_file)
-{
- char *inputfile;
- int input_len;
- zend_bool use_include_path = 0;
- char *contents;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &inputfile, &input_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- if (!(contents = php_tidy_file_to_mem(inputfile, use_include_path TSRMLS_CC))) {
- RETURN_FALSE;
- }
-
- if(tidyParseString(TG(tdoc)->doc, contents) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "[Tidy error] %s", TG(tdoc)->errbuf->bp);
- RETVAL_FALSE;
- } else {
- TG(tdoc)->parsed = TRUE;
- RETVAL_TRUE;
- }
-
- efree(contents);
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_clean_repair()
- Execute configured cleanup and repair operations on parsed markup */
-PHP_FUNCTION(tidy_clean_repair)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- if (tidyCleanAndRepair(TG(tdoc)->doc) >= 0) {
- RETURN_TRUE;
- }
-
- RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_repair_string(string data [, string config_file])
- Repair a string using an optionally provided configuration file */
-PHP_FUNCTION(tidy_repair_string)
-{
- php_tidy_quick_repair(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_repair_file(string filename [, string config_file [, bool use_include_path]])
- Repair a file using an optionally provided configuration file */
-PHP_FUNCTION(tidy_repair_file)
-{
- php_tidy_quick_repair(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_diagnose()
- Run configured diagnostics on parsed and repaired markup. */
-PHP_FUNCTION(tidy_diagnose)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- if (tidyRunDiagnostics(TG(tdoc)->doc) >= 0) {
- RETURN_TRUE;
- }
-
- RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto string tidy_get_release()
- Get release date (version) for Tidy library */
-PHP_FUNCTION(tidy_get_release)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- RETURN_STRING((char *)tidyReleaseDate(), 1);
-}
-/* }}} */
-
-/* {{{ proto string tidy_reset_config()
- Restore Tidy configuration to default values */
-PHP_FUNCTION(tidy_reset_config)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- RETURN_BOOL(tidyOptResetToSnapshot(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto array tidy_get_config()
- Get current Tidy configuarion */
-PHP_FUNCTION(tidy_get_config)
-{
- TidyIterator itOpt = tidyGetOptionList(TG(tdoc)->doc);
- char *opt_name;
- void *opt_value;
- TidyOptionType optt;
-
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- array_init(return_value);
-
- while (itOpt) {
- TidyOption opt = tidyGetNextOption(TG(tdoc)->doc, &itOpt);
-
- opt_name = (char *)tidyOptGetName(opt);
- opt_value = php_tidy_get_opt_val(opt, &optt TSRMLS_CC);
- switch (optt) {
- case TidyString:
- add_assoc_string(return_value, opt_name, (char*)opt_value, 0);
- break;
-
- case TidyInteger:
- add_assoc_long(return_value, opt_name, (long)opt_value);
- break;
-
- case TidyBoolean:
- add_assoc_bool(return_value, opt_name, (long)opt_value);
- break;
- }
- }
-
- return;
-}
-/* }}} */
-
-
-/* {{{ proto int tidy_get_status()
- Get status of specfied document. */
-PHP_FUNCTION(tidy_get_status)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- RETURN_LONG(tidyStatus(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto int tidy_get_html_ver()
- Get the Detected HTML version for the specified document. */
-PHP_FUNCTION(tidy_get_html_ver)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- RETURN_LONG(tidyDetectedHtmlVersion(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_is_xhtml()
- Indicates if the document is a XHTML document. */
-PHP_FUNCTION(tidy_is_xhtml)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- RETURN_BOOL(tidyDetectedXhtml(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_is_xhtml()
- Indicates if the document is a generic (non HTML/XHTML) XML document. */
-PHP_FUNCTION(tidy_is_xml)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- RETURN_BOOL(tidyDetectedGenericXml(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto int tidy_error_count()
- Returns the Number of Tidy errors encountered for specified document. */
-PHP_FUNCTION(tidy_error_count)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- RETURN_LONG(tidyErrorCount(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto int tidy_warning_count()
- Returns the Number of Tidy warnings encountered for specified document. */
-PHP_FUNCTION(tidy_warning_count)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- RETURN_LONG(tidyWarningCount(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto int tidy_access_count()
- Returns the Number of Tidy accessibility warnings encountered for specified document. */
-PHP_FUNCTION(tidy_access_count)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- RETURN_LONG(tidyAccessWarningCount(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto int tidy_config_count()
- Returns the Number of Tidy configuration errors encountered for specified document. */
-PHP_FUNCTION(tidy_config_count)
-{
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- RETURN_LONG(tidyConfigErrorCount(TG(tdoc)->doc));
-}
-/* }}} */
-
-/* {{{ proto void tidy_load_config(string filename)
- Load an ASCII Tidy configuration file */
-PHP_FUNCTION(tidy_load_config)
-{
- char *filename;
- int filename_len;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- TIDY_SAFE_MODE_CHECK(filename);
-
- if(tidyLoadConfig(TG(tdoc)->doc, filename) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not load configuration file '%s'", filename);
- RETURN_FALSE;
- }
-
- TG(used) = 1;
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto void tidy_load_config(string filename, string encoding)
- Load an ASCII Tidy configuration file with the specified encoding */
-PHP_FUNCTION(tidy_load_config_enc)
-{
- char *filename, *encoding;
- int enc_len, file_len;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &filename, &file_len, &encoding, &enc_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- TIDY_SAFE_MODE_CHECK(filename);
-
- if(tidyLoadConfigEnc(TG(tdoc)->doc, filename, encoding) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not load configuration file '%s' using encoding '%s'", filename, encoding);
- RETURN_FALSE;
- }
-
- TG(used) = 1;
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_set_encoding(string encoding)
- Set the input/output character encoding for parsing markup.
- Values include: ascii, latin1, raw, utf8, iso2022, mac, win1252, utf16le,
- utf16be, utf16, big5 and shiftjis. */
-PHP_FUNCTION(tidy_set_encoding)
-{
- char *encoding;
- int enc_len;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &encoding, &enc_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- if(tidySetCharEncoding(TG(tdoc)->doc, encoding) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not set encoding '%s'", encoding);
- RETURN_FALSE;
- }
-
- TG(used) = 1;
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_save_config(string filename)
- Save current settings to named file. Only non-default values are written. */
-PHP_FUNCTION(tidy_save_config)
-{
- char *filename;
- int file_len;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &file_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- TIDY_SAFE_MODE_CHECK(filename);
-
- if(tidyOptSaveFile(TG(tdoc)->doc, filename) < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not write tidy configuration file '%s'", filename);
- RETURN_FALSE;
- }
-
- RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_setopt(string option, mixed newvalue)
- Updates the configuration settings for the specified tidy document. */
-PHP_FUNCTION(tidy_setopt)
-{
- zval *value;
- char *optname;
- int optname_len;
- TidyOption opt;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &optname, &optname_len, &value) == FAILURE) {
- RETURN_FALSE;
- }
-
- opt = tidyGetOptionByName(TG(tdoc)->doc, optname);
- if (!opt) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown Tidy Configuration Option '%s'", optname);
- RETURN_FALSE;
- }
-
- switch(tidyOptGetType(opt)) {
- case TidyString:
- convert_to_string_ex(&value);
- if(tidyOptSetValue(TG(tdoc)->doc, tidyOptGetId(opt), Z_STRVAL_P(value))) {
- TG(used) = 1;
- RETURN_TRUE;
- }
- break;
-
- case TidyInteger:
- convert_to_long_ex(&value);
- if(tidyOptSetInt(TG(tdoc)->doc, tidyOptGetId(opt), Z_LVAL_P(value))) {
- TG(used) = 1;
- RETURN_TRUE;
- }
- break;
-
- case TidyBoolean:
- convert_to_long_ex(&value);
- if(tidyOptSetBool(TG(tdoc)->doc, tidyOptGetId(opt), Z_LVAL_P(value))) {
- TG(used) = 1;
- RETURN_TRUE;
- }
- break;
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to determine type of Tidy configuration constant to set");
- break;
- }
- RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto mixed tidy_getopt(string option)
- Returns the value of the specified configuration option for the tidy document. */
-PHP_FUNCTION(tidy_getopt)
-{
- char *optname;
- void *optval;
- int optname_len;
- TidyOption opt;
- TidyOptionType optt;
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &optname, &optname_len) == FAILURE) {
- RETURN_FALSE;
- }
-
- opt = tidyGetOptionByName(TG(tdoc)->doc, optname);
- if (!opt) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown Tidy Configuration Option '%s'", optname);
- RETURN_FALSE;
- }
-
- optval = php_tidy_get_opt_val(opt, &optt TSRMLS_CC);
- switch (optt) {
- case TidyString:
- RETVAL_STRING((char *)optval, 0);
- break;
-
- case TidyInteger:
- RETURN_LONG((long)optval);
- break;
-
- case TidyBoolean:
- if (optval) {
- RETURN_TRUE;
- } else {
- RETURN_NULL();
- }
- break;
-
- default:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to determine type of Tidy configuration constant to get");
- break;
- }
-
- RETURN_FALSE;
-}
-/* }}} */
-
-#ifdef ZEND_ENGINE_2
-static void tidy_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
-{
- PHPTidyObj *intern = (PHPTidyObj *)object;
-
- zend_hash_destroy(intern->std.properties);
- FREE_HASHTABLE(intern->std.properties);
-
- efree(object);
-}
-
-static void tidy_object_new(zend_class_entry *class_type, zend_object_handlers *handlers, zend_object_value *retval TSRMLS_DC)
-{
- PHPTidyObj *intern;
- zval *tmp;
-
- intern = emalloc(sizeof(PHPTidyObj));
- memset(intern, 0, sizeof(PHPTidyObj));
- intern->std.ce = class_type;
-
- ALLOC_HASHTABLE(intern->std.properties);
- zend_hash_init(intern->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
- zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
-
- retval->handle = zend_objects_store_put(intern, tidy_object_dtor, NULL TSRMLS_CC);
- retval->handlers = handlers;
-}
-
-static zend_object_value tidy_object_new_node(zend_class_entry *class_type TSRMLS_DC)
-{
- zend_object_value retval;
- tidy_object_new(class_type, &tidy_object_handlers_node, &retval TSRMLS_CC);
- return retval;
-}
-
-static zend_object_value tidy_object_new_attr(zend_class_entry *class_type TSRMLS_DC)
-{
- zend_object_value retval;
- tidy_object_new(class_type, &tidy_object_handlers_attr, &retval TSRMLS_CC);
- return retval;
-
-}
-
-static zend_object_value tidy_object_new_exception(zend_class_entry *class_type TSRMLS_DC)
-{
- zend_object_value retval;
- tidy_object_new(class_type, &tidy_object_handlers_exception, &retval TSRMLS_CC);
- return retval;
-
-}
-
-static zend_class_entry *tidy_get_ce_node(zval *object TSRMLS_DC)
-{
- return tidy_ce_node;
-}
-
-static zend_class_entry *tidy_get_ce_attr(zval *object TSRMLS_DC)
-{
- return tidy_ce_attr;
-}
-
-static zval * tidy_instanciate(zend_class_entry *pce, zval *object TSRMLS_DC)
-{
- if (!object) {
- ALLOC_ZVAL(object);
- }
- Z_TYPE_P(object) = IS_OBJECT;
- object_init_ex(object, pce);
- object->refcount = 1;
- object->is_ref = 1;
- return object;
-}
-
-#define ADD_PROPERITY_STRING(_table, _key, _string) \
- { \
- zval *tmp; \
- MAKE_STD_ZVAL(tmp); \
- if(_string) { \
- ZVAL_STRING(tmp, (char *)_string, 1); \
- } else { \
- ZVAL_EMPTY_STRING(tmp); \
- } \
- zend_hash_update(_table, #_key, sizeof(#_key), (void *)&tmp, sizeof(zval *), NULL); \
- }
-
-#define ADD_PROPERITY_LONG(_table, _key, _long) \
- { \
- zval *tmp; \
- MAKE_STD_ZVAL(tmp); \
- ZVAL_LONG(tmp, _long); \
- zend_hash_update(_table, #_key, sizeof(#_key), (void *)&tmp, sizeof(zval *), NULL); \
- }
-
-static void tidy_add_default_properities(PHPTidyObj *obj, tidy_obj_type type TSRMLS_DC) {
-
- TidyBuffer buf;
-
- switch(type) {
-
- case is_node:
- memset(&buf, 0, sizeof(buf));
- tidyNodeGetText(TG(tdoc)->doc, obj->node, &buf);
- ADD_PROPERITY_STRING(obj->std.properties, value, buf.bp);
- tidyBufFree(&buf);
-
- fprintf(stderr, "type: %d\n",tidyNodeGetType(obj->node));
- ADD_PROPERITY_STRING(obj->std.properties, name, tidyNodeGetName(obj->node));
- ADD_PROPERITY_LONG(obj->std.properties, type, tidyNodeGetType(obj->node));
- switch(tidyNodeGetType(obj->node)) {
-
- case TidyNode_Root:
- case TidyNode_DocType:
- case TidyNode_Text:
- case TidyNode_Comment:
- break;
- default:
- ADD_PROPERITY_LONG(obj->std.properties, id, tidyNodeGetId(obj->node));
- }
-
- break;
- case is_attr:
- ADD_PROPERITY_STRING(obj->std.properties, name, tidyAttrName(obj->attr));
- ADD_PROPERITY_STRING(obj->std.properties, value, tidyAttrValue(obj->attr));
- ADD_PROPERITY_LONG(obj->std.properties, id, tidyAttrGetId(obj->attr));
- break;
- }
-
-}
-/* {{{ proto TidyNode tidy_get_root()
- Returns a TidyNode Object representing the root of the tidy parse tree */
-PHP_FUNCTION(tidy_get_root)
-{
- PHPTidyObj *obj;
-
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- tidy_instanciate(tidy_ce_node, return_value TSRMLS_CC);
- obj = (PHPTidyObj *) zend_object_store_get_object(return_value TSRMLS_CC);
- obj->node = tidyGetRoot(TG(tdoc)->doc);
- obj->attr = NULL;
- obj->type = is_node;
-
- tidy_add_default_properities(obj, is_node TSRMLS_CC);
-
-}
-/* }}} */
-
-/* {{{ proto TidyNode tidy_get_html()
- Returns a TidyNode Object starting from the <HTML> tag of the tidy parse tree */
-PHP_FUNCTION(tidy_get_html)
-{
- PHPTidyObj *obj;
-
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- tidy_instanciate(tidy_ce_node, return_value TSRMLS_CC);
- obj = (PHPTidyObj *) zend_object_store_get_object(return_value TSRMLS_CC);
- obj->node = tidyGetHtml(TG(tdoc)->doc);
- obj->attr = NULL;
- obj->type = is_node;
-
- tidy_add_default_properities(obj, is_node TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ proto TidyNode tidy_get_head()
- Returns a TidyNode Object starting from the <HEAD> tag of the tidy parse tree */
-PHP_FUNCTION(tidy_get_head)
-{
- PHPTidyObj *obj;
-
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- tidy_instanciate(tidy_ce_node, return_value TSRMLS_CC);
- obj = (PHPTidyObj *) zend_object_store_get_object(return_value TSRMLS_CC);
- obj->node = tidyGetHead(TG(tdoc)->doc);
- obj->attr = NULL;
- obj->type = is_node;
-
- tidy_add_default_properities(obj, is_node TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ proto TidyNode tidy_get_body(resource tidy)
- Returns a TidyNode Object starting from the <BODY> tag of the tidy parse tree */
-PHP_FUNCTION(tidy_get_body)
-{
- PHPTidyObj *obj;
-
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- tidy_instanciate(tidy_ce_node, return_value TSRMLS_CC);
- obj = (PHPTidyObj *) zend_object_store_get_object(return_value TSRMLS_CC);
- obj->node = tidyGetBody(TG(tdoc)->doc);
- obj->attr = NULL;
- obj->type = is_node;
-
- tidy_add_default_properities(obj, is_node TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ proto void tidy_node::tidy_node()
- Constructor. */
-PHP_NODE_METHOD(__construct)
-{
-}
-/* }}} */
-
-/* {{{ proto tidy_attr tidy_node::attributes()
- Returns an array of attribute objects for node */
-PHP_NODE_METHOD(attributes)
-{
- TidyAttr tempattr;
- zval *object;
- PHPTidyObj *objtemp;
- GET_THIS_CONTAINER();
-
- tempattr = tidyAttrFirst(obj->node);
-
- if(tempattr) {
- array_init(return_value);
-
- do {
-
- MAKE_STD_ZVAL(object);
- INSTANCIATE_ATTR(object, objtemp, tempattr);
- add_next_index_zval(return_value, object);
-
- } while((tempattr = tidyAttrNext(tempattr)));
- }
-}
-/* }}} */
-
-
-
-/* {{{ proto tidy_node tidy_node::children()
- Returns an array of child nodes */
-PHP_NODE_METHOD(children)
-{
- TidyNode tempnode;
- zval *object;
- PHPTidyObj *objtemp;
- GET_THIS_CONTAINER();
-
- tempnode = tidyGetChild(obj->node);
-
- if(tempnode) {
- array_init(return_value);
- do {
-
- MAKE_STD_ZVAL(object);
- INSTANCIATE_NODE(object, objtemp, tempnode);
- add_next_index_zval(return_value, object);
-
- } while((tempnode = tidyGetNext(tempnode)));
- }
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::has_children()
- Returns true if this node has children */
-PHP_NODE_METHOD(has_children)
-{
- GET_THIS_CONTAINER();
-
- if(tidyGetChild(obj->node)) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::has_siblings()
- Returns true if this node has siblings */
-PHP_NODE_METHOD(has_siblings)
-{
- GET_THIS_CONTAINER();
-
- if(tidyGetNext(obj->node)) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_comment()
- Returns true if this node represents a comment */
-PHP_NODE_METHOD(is_comment)
-{
- GET_THIS_CONTAINER();
- if(tidyNodeGetType(obj->node) == TidyNode_Comment) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_html()
- Returns true if this node is part of a HTML document */
-PHP_NODE_METHOD(is_html)
-{
- GET_THIS_CONTAINER();
-
- if(tidyNodeGetType(obj->node) & (TidyNode_Start | TidyNode_End | TidyNode_StartEnd)) {
- RETURN_TRUE;
- }
- RETURN_FALSE;
-
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_xhtml()
- Returns true if this node is part of a XHTML document */
-PHP_NODE_METHOD(is_xhtml)
-{
- GET_THIS_CONTAINER();
- if(tidyDetectedXhtml(TG(tdoc)->doc)) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_xml()
- Returns true if this node is part of a XML document */
-PHP_NODE_METHOD(is_xml)
-{
- GET_THIS_CONTAINER();
- if(tidyDetectedGenericXml(TG(tdoc)->doc)) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_text()
- Returns true if this node represents text (no markup) */
-PHP_NODE_METHOD(is_text)
-{
- GET_THIS_CONTAINER();
- if(tidyNodeGetType(obj->node) == TidyNode_Text) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_jste()
- Returns true if this node is JSTE */
-PHP_NODE_METHOD(is_jste)
-{
- GET_THIS_CONTAINER();
- if(tidyNodeGetType(obj->node) == TidyNode_Jste) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_asp()
- Returns true if this node is ASP */
-PHP_NODE_METHOD(is_asp)
-{
- GET_THIS_CONTAINER();
- if(tidyNodeGetType(obj->node) == TidyNode_Asp) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-}
-/* }}} */
-
-/* {{{ proto boolean tidy_node::is_jsp()
- Returns true if this node is JSP */
-PHP_NODE_METHOD(is_php)
-{
- GET_THIS_CONTAINER();
- if(tidyNodeGetType(obj->node) == TidyNode_Php) {
- RETURN_TRUE;
- } else {
- RETURN_FALSE;
- }
-}
-/* }}} */
-
-/* {{{ proto tidy_node tidy_node::next()
- Returns the next sibling to this node */
-PHP_NODE_METHOD(next)
-{
- PHPTidyObj *obj;
-
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- tidy_instanciate(tidy_ce_node, return_value TSRMLS_CC);
- obj = (PHPTidyObj *) zend_object_store_get_object(return_value TSRMLS_CC);
- obj->node = tidyGetNext(obj->node);
- obj->attr = NULL;
- obj->type = is_node;
-
- tidy_add_default_properities(obj, is_node TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ proto tidy_node tidy_node::prev()
- Returns the previous sibiling to this node */
-PHP_NODE_METHOD(prev)
-{
- PHPTidyObj *obj;
-
- if(ZEND_NUM_ARGS()) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- tidy_instanciate(tidy_ce_node, return_value TSRMLS_CC);
- obj = (PHPTidyObj *) zend_object_store_get_object(return_value TSRMLS_CC);
- obj->node = tidyGetPrev(obj->node);
- obj->attr = NULL;
- obj->type = is_node;
-
- tidy_add_default_properities(obj, is_node TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ proto tidy_attr tidy_node::get_attr(int attrib_id)
- Return the attribute with the provided attribute id */
-PHP_NODE_METHOD(get_attr)
-{
- TidyAttr tempattr;
- long param;
- GET_THIS_CONTAINER();
-
- if(ZEND_NUM_ARGS() != 1) {
- WRONG_PARAM_COUNT;
- }
-
- TIDY_PARSED_CHECK();
-
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &param) == FAILURE) {
- RETURN_FALSE;
- }
-
- for(tempattr = tidyAttrFirst(obj->node); tempattr; tempattr = tidyAttrNext(tempattr)) {
-
- if(tidyAttrGetId(tempattr) == param) {
-
- tidy_instanciate(tidy_ce_node, return_value TSRMLS_CC);
-
- obj = (PHPTidyObj *) zend_object_store_get_object(return_value TSRMLS_CC);
- obj->node = NULL;
- obj->attr = tempattr;
- obj->type = is_attr;
-
- tidy_add_default_properities(obj, is_attr TSRMLS_CC);
- }
- }
-
-}
-/* }}} */
-
-/* {{{ proto tidy_node tidy_node::get_nodes(int node_id)
- Return an array of nodes under this node with the specified id */
-PHP_NODE_METHOD(get_nodes)
-{
- /* TODO */
-}
-/* }}} */
-
-#endif /* ZEND_ENGINE_2 */
-
-void _php_tidy_register_nodetypes(INIT_FUNC_ARGS)
-{
-
- TIDY_NODE_CONST(ROOT, Root);
- TIDY_NODE_CONST(DOCTYPE, DocType);
- TIDY_NODE_CONST(COMMENT, Comment);
- TIDY_NODE_CONST(PROCINS, ProcIns);
- TIDY_NODE_CONST(TEXT, Text);
- TIDY_NODE_CONST(START, Start);
- TIDY_NODE_CONST(END, End);
- TIDY_NODE_CONST(STARTEND, StartEnd);
- TIDY_NODE_CONST(CDATA, CDATA);
- TIDY_NODE_CONST(SECTION, Section);
- TIDY_NODE_CONST(ASP, Asp);
- TIDY_NODE_CONST(JSTE, Jste);
- TIDY_NODE_CONST(PHP, Php);
- TIDY_NODE_CONST(XMLDECL, XmlDecl);
-
-}
-
-void _php_tidy_register_tags(INIT_FUNC_ARGS)
-{
-
- TIDY_TAG_CONST(UNKNOWN);
- TIDY_TAG_CONST(A);
- TIDY_TAG_CONST(ABBR);
- TIDY_TAG_CONST(ACRONYM);
- TIDY_TAG_CONST(ADDRESS);
- TIDY_TAG_CONST(ALIGN);
- TIDY_TAG_CONST(APPLET);
- TIDY_TAG_CONST(AREA);
- TIDY_TAG_CONST(B);
- TIDY_TAG_CONST(BASE);
- TIDY_TAG_CONST(BASEFONT);
- TIDY_TAG_CONST(BDO);
- TIDY_TAG_CONST(BGSOUND);
- TIDY_TAG_CONST(BIG);
- TIDY_TAG_CONST(BLINK);
- TIDY_TAG_CONST(BLOCKQUOTE);
- TIDY_TAG_CONST(BODY);
- TIDY_TAG_CONST(BR);
- TIDY_TAG_CONST(BUTTON);
- TIDY_TAG_CONST(CAPTION);
- TIDY_TAG_CONST(CENTER);
- TIDY_TAG_CONST(CITE);
- TIDY_TAG_CONST(CODE);
- TIDY_TAG_CONST(COL);
- TIDY_TAG_CONST(COLGROUP);
- TIDY_TAG_CONST(COMMENT);
- TIDY_TAG_CONST(DD);
- TIDY_TAG_CONST(DEL);
- TIDY_TAG_CONST(DFN);
- TIDY_TAG_CONST(DIR);
- TIDY_TAG_CONST(DIV);
- TIDY_TAG_CONST(DL);
- TIDY_TAG_CONST(DT);
- TIDY_TAG_CONST(EM);
- TIDY_TAG_CONST(EMBED);
- TIDY_TAG_CONST(FIELDSET);
- TIDY_TAG_CONST(FONT);
- TIDY_TAG_CONST(FORM);
- TIDY_TAG_CONST(FRAME);
- TIDY_TAG_CONST(FRAMESET);
- TIDY_TAG_CONST(H1);
- TIDY_TAG_CONST(H2);
- TIDY_TAG_CONST(H3);
- TIDY_TAG_CONST(H4);
- TIDY_TAG_CONST(H5);
- TIDY_TAG_CONST(H6);
- TIDY_TAG_CONST(HEAD);
- TIDY_TAG_CONST(HR);
- TIDY_TAG_CONST(HTML);
- TIDY_TAG_CONST(I);
- TIDY_TAG_CONST(IFRAME);
- TIDY_TAG_CONST(ILAYER);
- TIDY_TAG_CONST(IMG);
- TIDY_TAG_CONST(INPUT);
- TIDY_TAG_CONST(INS);
- TIDY_TAG_CONST(ISINDEX);
- TIDY_TAG_CONST(KBD);
- TIDY_TAG_CONST(KEYGEN);
- TIDY_TAG_CONST(LABEL);
- TIDY_TAG_CONST(LAYER);
- TIDY_TAG_CONST(LEGEND);
- TIDY_TAG_CONST(LI);
- TIDY_TAG_CONST(LINK);
- TIDY_TAG_CONST(LISTING);
- TIDY_TAG_CONST(MAP);
- TIDY_TAG_CONST(MARQUEE);
- TIDY_TAG_CONST(MENU);
- TIDY_TAG_CONST(META);
- TIDY_TAG_CONST(MULTICOL);
- TIDY_TAG_CONST(NOBR);
- TIDY_TAG_CONST(NOEMBED);
- TIDY_TAG_CONST(NOFRAMES);
- TIDY_TAG_CONST(NOLAYER);
- TIDY_TAG_CONST(NOSAVE);
- TIDY_TAG_CONST(NOSCRIPT);
- TIDY_TAG_CONST(OBJECT);
- TIDY_TAG_CONST(OL);
- TIDY_TAG_CONST(OPTGROUP);
- TIDY_TAG_CONST(OPTION);
- TIDY_TAG_CONST(P);
- TIDY_TAG_CONST(PARAM);
- TIDY_TAG_CONST(PLAINTEXT);
- TIDY_TAG_CONST(PRE);
- TIDY_TAG_CONST(Q);
- TIDY_TAG_CONST(RB);
- TIDY_TAG_CONST(RBC);
- TIDY_TAG_CONST(RP);
- TIDY_TAG_CONST(RT);
- TIDY_TAG_CONST(RTC);
- TIDY_TAG_CONST(RUBY);
- TIDY_TAG_CONST(S);
- TIDY_TAG_CONST(SAMP);
- TIDY_TAG_CONST(SCRIPT);
- TIDY_TAG_CONST(SELECT);
- TIDY_TAG_CONST(SERVER);
- TIDY_TAG_CONST(SERVLET);
- TIDY_TAG_CONST(SMALL);
- TIDY_TAG_CONST(SPACER);
- TIDY_TAG_CONST(SPAN);
- TIDY_TAG_CONST(STRIKE);
- TIDY_TAG_CONST(STRONG);
- TIDY_TAG_CONST(STYLE);
- TIDY_TAG_CONST(SUB);
- TIDY_TAG_CONST(SUP);
- TIDY_TAG_CONST(TABLE);
- TIDY_TAG_CONST(TBODY);
- TIDY_TAG_CONST(TD);
- TIDY_TAG_CONST(TEXTAREA);
- TIDY_TAG_CONST(TFOOT);
- TIDY_TAG_CONST(TH);
- TIDY_TAG_CONST(THEAD);
- TIDY_TAG_CONST(TITLE);
- TIDY_TAG_CONST(TR);
- TIDY_TAG_CONST(TT);
- TIDY_TAG_CONST(U);
- TIDY_TAG_CONST(UL);
- TIDY_TAG_CONST(VAR);
- TIDY_TAG_CONST(WBR);
- TIDY_TAG_CONST(XMP);
-
-}
-
-void _php_tidy_register_attributes(INIT_FUNC_ARGS)
-{
-
- TIDY_ATTR_CONST(UNKNOWN);
- TIDY_ATTR_CONST(ABBR);
- TIDY_ATTR_CONST(ACCEPT);
- TIDY_ATTR_CONST(ACCEPT_CHARSET);
- TIDY_ATTR_CONST(ACCESSKEY);
- TIDY_ATTR_CONST(ACTION);
- TIDY_ATTR_CONST(ADD_DATE);
- TIDY_ATTR_CONST(ALIGN);
- TIDY_ATTR_CONST(ALINK);
- TIDY_ATTR_CONST(ALT);
- TIDY_ATTR_CONST(ARCHIVE);
- TIDY_ATTR_CONST(AXIS);
- TIDY_ATTR_CONST(BACKGROUND);
- TIDY_ATTR_CONST(BGCOLOR);
- TIDY_ATTR_CONST(BGPROPERTIES);
- TIDY_ATTR_CONST(BORDER);
- TIDY_ATTR_CONST(BORDERCOLOR);
- TIDY_ATTR_CONST(BOTTOMMARGIN);
- TIDY_ATTR_CONST(CELLPADDING);
- TIDY_ATTR_CONST(CELLSPACING);
- TIDY_ATTR_CONST(CHAR);
- TIDY_ATTR_CONST(CHAROFF);
- TIDY_ATTR_CONST(CHARSET);
- TIDY_ATTR_CONST(CHECKED);
- TIDY_ATTR_CONST(CITE);
- TIDY_ATTR_CONST(CLASS);
- TIDY_ATTR_CONST(CLASSID);
- TIDY_ATTR_CONST(CLEAR);
- TIDY_ATTR_CONST(CODE);
- TIDY_ATTR_CONST(CODEBASE);
- TIDY_ATTR_CONST(CODETYPE);
- TIDY_ATTR_CONST(COLOR);
- TIDY_ATTR_CONST(COLS);
- TIDY_ATTR_CONST(COLSPAN);
- TIDY_ATTR_CONST(COMPACT);
- TIDY_ATTR_CONST(CONTENT);
- TIDY_ATTR_CONST(COORDS);
- TIDY_ATTR_CONST(DATA);
- TIDY_ATTR_CONST(DATAFLD);
- /* TIDY_ATTR_CONST(DATAFORMATSAS); */
- TIDY_ATTR_CONST(DATAPAGESIZE);
- TIDY_ATTR_CONST(DATASRC);
- TIDY_ATTR_CONST(DATETIME);
- TIDY_ATTR_CONST(DECLARE);
- TIDY_ATTR_CONST(DEFER);
- TIDY_ATTR_CONST(DIR);
- TIDY_ATTR_CONST(DISABLED);
- TIDY_ATTR_CONST(ENCODING);
- TIDY_ATTR_CONST(ENCTYPE);
- TIDY_ATTR_CONST(FACE);
- TIDY_ATTR_CONST(FOR);
- TIDY_ATTR_CONST(FRAME);
- TIDY_ATTR_CONST(FRAMEBORDER);
- TIDY_ATTR_CONST(FRAMESPACING);
- TIDY_ATTR_CONST(GRIDX);
- TIDY_ATTR_CONST(GRIDY);
- TIDY_ATTR_CONST(HEADERS);
- TIDY_ATTR_CONST(HEIGHT);
- TIDY_ATTR_CONST(HREF);
- TIDY_ATTR_CONST(HREFLANG);
- TIDY_ATTR_CONST(HSPACE);
- TIDY_ATTR_CONST(HTTP_EQUIV);
- TIDY_ATTR_CONST(ID);
- TIDY_ATTR_CONST(ISMAP);
- TIDY_ATTR_CONST(LABEL);
- TIDY_ATTR_CONST(LANG);
- TIDY_ATTR_CONST(LANGUAGE);
- TIDY_ATTR_CONST(LAST_MODIFIED);
- TIDY_ATTR_CONST(LAST_VISIT);
- TIDY_ATTR_CONST(LEFTMARGIN);
- TIDY_ATTR_CONST(LINK);
- TIDY_ATTR_CONST(LONGDESC);
- TIDY_ATTR_CONST(LOWSRC);
- TIDY_ATTR_CONST(MARGINHEIGHT);
- TIDY_ATTR_CONST(MARGINWIDTH);
- TIDY_ATTR_CONST(MAXLENGTH);
- TIDY_ATTR_CONST(MEDIA);
- TIDY_ATTR_CONST(METHOD);
- TIDY_ATTR_CONST(MULTIPLE);
- TIDY_ATTR_CONST(NAME);
- TIDY_ATTR_CONST(NOHREF);
- TIDY_ATTR_CONST(NORESIZE);
- TIDY_ATTR_CONST(NOSHADE);
- TIDY_ATTR_CONST(NOWRAP);
- TIDY_ATTR_CONST(OBJECT);
- TIDY_ATTR_CONST(OnAFTERUPDATE);
- TIDY_ATTR_CONST(OnBEFOREUNLOAD);
- TIDY_ATTR_CONST(OnBEFOREUPDATE);
- TIDY_ATTR_CONST(OnBLUR);
- TIDY_ATTR_CONST(OnCHANGE);
- TIDY_ATTR_CONST(OnCLICK);
- TIDY_ATTR_CONST(OnDATAAVAILABLE);
- TIDY_ATTR_CONST(OnDATASETCHANGED);
- TIDY_ATTR_CONST(OnDATASETCOMPLETE);
- TIDY_ATTR_CONST(OnDBLCLICK);
- TIDY_ATTR_CONST(OnERRORUPDATE);
- TIDY_ATTR_CONST(OnFOCUS);
- TIDY_ATTR_CONST(OnKEYDOWN);
- TIDY_ATTR_CONST(OnKEYPRESS);
- TIDY_ATTR_CONST(OnKEYUP);
- TIDY_ATTR_CONST(OnLOAD);
- TIDY_ATTR_CONST(OnMOUSEDOWN);
- TIDY_ATTR_CONST(OnMOUSEMOVE);
- TIDY_ATTR_CONST(OnMOUSEOUT);
- TIDY_ATTR_CONST(OnMOUSEOVER);
- TIDY_ATTR_CONST(OnMOUSEUP);
- TIDY_ATTR_CONST(OnRESET);
- TIDY_ATTR_CONST(OnROWENTER);
- TIDY_ATTR_CONST(OnROWEXIT);
- TIDY_ATTR_CONST(OnSELECT);
- TIDY_ATTR_CONST(OnSUBMIT);
- TIDY_ATTR_CONST(OnUNLOAD);
- TIDY_ATTR_CONST(PROFILE);
- TIDY_ATTR_CONST(PROMPT);
- TIDY_ATTR_CONST(RBSPAN);
- TIDY_ATTR_CONST(READONLY);
- TIDY_ATTR_CONST(REL);
- TIDY_ATTR_CONST(REV);
- TIDY_ATTR_CONST(RIGHTMARGIN);
- TIDY_ATTR_CONST(ROWS);
- TIDY_ATTR_CONST(ROWSPAN);
- TIDY_ATTR_CONST(RULES);
- TIDY_ATTR_CONST(SCHEME);
- TIDY_ATTR_CONST(SCOPE);
- TIDY_ATTR_CONST(SCROLLING);
- TIDY_ATTR_CONST(SELECTED);
- TIDY_ATTR_CONST(SHAPE);
- TIDY_ATTR_CONST(SHOWGRID);
- TIDY_ATTR_CONST(SHOWGRIDX);
- TIDY_ATTR_CONST(SHOWGRIDY);
- TIDY_ATTR_CONST(SIZE);
- TIDY_ATTR_CONST(SPAN);
- TIDY_ATTR_CONST(SRC);
- TIDY_ATTR_CONST(STANDBY);
- TIDY_ATTR_CONST(START);
- TIDY_ATTR_CONST(STYLE);
- TIDY_ATTR_CONST(SUMMARY);
- TIDY_ATTR_CONST(TABINDEX);
- TIDY_ATTR_CONST(TARGET);
- TIDY_ATTR_CONST(TEXT);
- TIDY_ATTR_CONST(TITLE);
- TIDY_ATTR_CONST(TOPMARGIN);
- TIDY_ATTR_CONST(TYPE);
- TIDY_ATTR_CONST(USEMAP);
- TIDY_ATTR_CONST(VALIGN);
- TIDY_ATTR_CONST(VALUE);
- TIDY_ATTR_CONST(VALUETYPE);
- TIDY_ATTR_CONST(VERSION);
- TIDY_ATTR_CONST(VLINK);
- TIDY_ATTR_CONST(VSPACE);
- TIDY_ATTR_CONST(WIDTH);
- TIDY_ATTR_CONST(WRAP);
- TIDY_ATTR_CONST(XML_LANG);
- TIDY_ATTR_CONST(XML_SPACE);
- TIDY_ATTR_CONST(XMLNS);
-
-}