Initial Release

This commit is contained in:
Sara Golemon
2006-05-03 23:42:24 +00:00
parent b24bc05012
commit 5bf48ba638
13 changed files with 2238 additions and 0 deletions

3
CREDITS Normal file
View File

@@ -0,0 +1,3 @@
Userspace driver for PDO
Sara Golemon

0
EXPERIMENTAL Normal file
View File

264
README.OBJECTS Normal file
View File

@@ -0,0 +1,264 @@
PDO Userspace Driver
--------------------
This extension exports three class definitions (two interfaces plus one static class):
interface PDO_User_Driver {
function __construct($dsn, $user, $pass, $options) {
/* new PDO('user:driver=classname;...') */
}
function pdo_prepare($sql, $options) {
/* PDO::prepare() or PDO::query() */
if (SUCCESS) {
return new Object_Implementing_PDO_User_Statement($optional, $parameters);
} else {
/* If your class will be unable to perform the query, return false here to indicate failure */
return false;
}
}
function pdo_do($sql) {
/* PDO::exec() */
if (SUCCESS) {
return $rowsAffected;
} else {
return FALSE; /* NULL or a negative number may also be used to indicate failure */
}
}
function pdo_quote($string) {
/* PDO::quote() */
/* There is no "failure" mode for this method, you must return something */
return $modifiedString;
}
function pdo_begin() {
/* PDO::beginTransaction() */
if (SUCCESS) {
return true;
} else {
return false;
}
}
function pdo_commit() {
/* PDO::commit() */
if (SUCCESS) {
return true;
} else {
return false;
}
}
function pdo_rollback() {
/* PDO::rollBack() */
if (SUCCESS) {
return true;
} else {
return false;
}
}
function pdo_lastInsertID($seq) {
/* PDO::lastInsertID() */
/* There is no "failure" mode for this method, you must return something */
return $lastIDString;
}
function pdo_checkLiveness() {
/* Called by PDO internally */
return $driverIsAliveBool;
}
function pdo_setAttribute($attr, $val) {
/* PDO::setAttribute($attr, $val) */
/* $attr == PDO::ATTR_* */
if (SUCCESS) {
return true;
} else {
return false;
}
}
function pdo_getAttribute($attr) {
/* PDO::getAttribute($attr) */
/* $attr == PDO::ATTR_* */
if (SUCCESS) {
return $attributeValue;
} else {
return false;
}
}
function pdo_close() {
/* Called when shutting down a database handle - e.g. unset($pdoHandle); */
/* Return value ignored */
}
function pdo_fetchError() {
/* PDO::errorInfo */
return array(0 => 12345, 1 => 'Error 12345 has occured...blah...blah...blah');
}
}
interface PDO_User_Statement {
function pdo_execute() {
/* PDO_Statement::execute() */
/* The result of emulated bound parameters may be retreived via: */
$resultQuery = PDO_User::statementParam($this, PDO_User::STATEMENT_PARAM_ACTIVE_QUERY);
if (SUCCESS) {
return array('rows' => $numberOfRowsInSet, 'cols' => $numberOfColsInSet);
} else {
return false;
}
}
function pdo_fetch($orientation, $offset) {
/* PDO_Statement::fetch() and family */
/* This method should only adjust the current cursor's position,
* getcol() will be used to actually retreive the data */
/* $orientation is one of PDO::FETCH_ORI_*
* $offset is a relative position to the location tagged by $orientation */
if (SUCCESS) {
return true;
} else {
/* e.g. - No more rows */
return false;
}
}
function pdo_nextRowset() {
/* PDO_Statement::nextRowset() */
if (SUCCESS) {
return true;
} else {
return false;
}
}
function pdo_describe($columnNumber) {
/* Called after PDO_Statement::execute() to determine column names,
* also used by PDO_Statement::getColumnMeta() */
return array('name' => $nameOfColumn, 'maxlen' => $maximumLengthOfDataInColumn);
}
function pdo_colmeta($columnNumber) {
/* PDO_Statement::getColumnMeta() */
/* Return as many of the supported fields as possible,
* custom fields may also be returned by prefixing with user: */
return array('scale' => $floatingPointScale,
'table' => $sourceTable,
'type' => $phpTypeName, /* e.g. 'string', 'integer', 'bool' */
'native_type' => $dbTypeName, /* e.g. 'char', 'blog', 'double' */
'flags' => array( 'primary_key',
'not_null',
'unique_key',
'multiple_key',
'unsigned',
'auto_increment',
'blob',
'user:foo', /* custom flag(s) */
),
'user:bar' => 'baz' /* custom metadata(s) */
);
}
function pdo_getcol($columnNumber) {
/* Called by PDO_Statement::fetch() family of functions */
return $contentsOfColumnForCurrentRow;
}
function pdo_paramhook($event, $columnNumber, $columnName, $isParam, &$parameter) {
/* Called before and after EXEC and FETCH events */
/* $event is one of PDO::PARAM_EVT_EXEC_* or PDO_PARAM_EVT_FETCH_*
* $columnNumber / $columnName are the identifiers of the column, either or both may be available
* $isParam is TRUE for placeholder parameters (e.g. WHERE foo = ?), it is FALSE for result parameters (e.g. SELECT col1)
* $parameter is the actual bound variable and is always passed by reference */
/* Return value is ignored */
}
function pdo_setAttribute($attr, $val) {
/* PDO_Statement::setAttribute($attr, $val) */
/* $attr == PDO::ATTR_* */
if (SUCCESS) {
return true;
} else {
return false;
}
}
function pdo_getAttribute($attr) {
/* PDO_Statement::getAttribute($attr) */
/* $attr == PDO::ATTR_* */
if (SUCCESS) {
return $attributeValue;
} else {
return false;
}
}
function pdo_closeCursor() {
/* PDO_Statement::closeCursor() */
if (SUCCESS) {
return true;
} else {
return false;
}
}
function pdo_close() {
/* Called with shutting down a statement */
/* Return value ignored */
}
}
class PDO_User {
function parseDSN($dsn, $params) {
/* Parses a DSN string in the format: var1=val1;var2=val2;var3=val3;...
* For the variables named in $params, For example:
$result = PDO_User::parseDSN('host=localhost;port=3306', array('host','port'));
print_r($result);
* Results in:
Array(2) {
[host] => localhost
[port] => 3306
}
*/
}
function driverParam($attribute[, $value]) {
/* $attribute is one of:
PDO_User::DRIVER_PARAM_MAX_ESCAPSED_CHAR_LENGTH (used by emulated prepared statement routines internally)
PDO_User::DRIVER_PARAM_DATA_SOURCE (refers to the $dsn passed to the driver class' constructor)
PDO_User::DRIVER_PARAM_SQLSTATE (Driver's current SQLSTATE value)
PDO_User::STATEMENT_PARAM_ACTIVE_QUERY (Post-transformation emulated prepared statement result)
PDO_User::STATEMENT_PARAM_SQLSTATE (Statement's current SQLSTATE value)
* When $value is passed, the parameter will be set to this new value
* Whether or not $value is passed, the current value will be returned */
}
}

40
config.m4 Normal file
View File

@@ -0,0 +1,40 @@
dnl
dnl $Id$
dnl
if test "$PHP_PDO" != "no"; then
PHP_ARG_ENABLE(pdo-user, for Userdriver support for PDO,
[ --enable-pdo-user PDO: Userdriver support.])
if test "$PHP_PDO_USER" != "no"; then
AC_DEFINE(HAVE_USER, 1, [Whether you have Userdriver Support])
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_user, pdo_user.c pdo_user_driver.c pdo_user_statement.c pdo_user_object.c, $ext_shared,,-I$pdo_inc_path)
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(pdo_user, pdo)
])
PHP_SUBST(PDO_USER_SHARED_LIBADD)
fi
fi
dnl vim: se ts=2 sw=2 et:

11
config.w32 Normal file
View File

@@ -0,0 +1,11 @@
// $Id$
// vim:ft=javascript
ARG_ENABLE("pdo-sqlite", "for pdo_user support", "no");
if (PHP_PDO_USER != "no") {
EXTENSION("pdo_user", "pdo_user.c pdo_user_driver.c pdo_user_statement.c pdo_user_object.c");
ADD_EXTENSION_DEP('pdo_user', 'pdo');
}

66
package2.xml Normal file
View File

@@ -0,0 +1,66 @@
<?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_USER</name>
<channel>pecl.php.net</channel>
<summary>Userspace driver for PDO</summary>
<description>This extension provides a Userspace interface for PDO drivers</description>
<lead>
<name>Sara Golemon</name>
<user>pollita</user>
<email>pollita@php.net</email>
<active>yes</active>
</lead>
<date>2006-05-03</date>
<version>
<release>0.1.0</release>
<api>0.1.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://www.php.net/license">PHP</license>
<notes>Initial Release</notes>
<contents>
<dir name="/">
<file name="config.m4" role="src" />
<file name="config.w32" role="src" />
<file name="CREDITS" role="doc" />
<file name="EXPERIMENTAL" role="doc" />
<file name="README.OBJECTS" role="doc" />
<file name="pdo_user.c" role="src" />
<file name="pdo_user_driver.c" role="src" />
<file name="pdo_user_statement.c" role="src" />
<file name="pdo_user_object.c" role="src" />
<file name="php_pdo_user.h" role="src" />
<file name="php_pdo_user_int.h" role="src" />
<dir name="tests/">
<file name="globals.phpt" role="test" />
</dir> <!-- tests/ -->
</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_USER</providesextension>
<extsrcrelease />
</package>

216
pdo_user.c Normal file
View File

@@ -0,0 +1,216 @@
/*
+----------------------------------------------------------------------+
| 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: Sara Golemon <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php_pdo_user_int.h"
#include "ext/standard/info.h"
ZEND_DECLARE_MODULE_GLOBALS(pdo_user)
extern pdo_driver_t pdo_user_driver;
/* *********************************
* PtrMap linked list management *
********************************* */
struct _php_pdo_user_llist {
php_pdo_user_llist *next, *prev;
php_pdo_user_data *data;
};
int php_pdo_user_ptrmap_map(php_pdo_user_data *data TSRMLS_DC)
{
php_pdo_user_llist *el = emalloc(sizeof(php_pdo_user_llist));
el->next = PDO_USER_G(ptr_map);
el->prev = NULL;
el->data = data;
if (PDO_USER_G(ptr_map)) {
PDO_USER_G(ptr_map)->prev = el;
}
PDO_USER_G(ptr_map) = el;
return SUCCESS;
}
int php_pdo_user_ptrmap_unmap(php_pdo_user_data *data TSRMLS_DC)
{
php_pdo_user_llist *el = PDO_USER_G(ptr_map);
if (!el) {
/* Nothing to unmap, not normal codepath... */
return FAILURE;
}
while (el) {
if (el->data == data) {
if (el->prev) {
el->prev->next = el->next;
} else {
PDO_USER_G(ptr_map) = el->next;
}
if (el->next) {
el->next->prev = el->prev;
}
efree(el);
return SUCCESS;
}
el = el->next;
}
return FAILURE;
}
void *php_pdo_user_ptrmap_locate(zval *object TSRMLS_DC)
{
php_pdo_user_llist *el = PDO_USER_G(ptr_map);
if (!el) {
/* Nothing to find */
return NULL;
}
while (el) {
if (el->data->object == object) {
return el->data;
}
el = el->next;
}
return NULL;
}
void php_pdo_user_ptrmap_destroy(TSRMLS_D)
{
php_pdo_user_llist *el = PDO_USER_G(ptr_map);
while (el) {
php_pdo_user_llist *next = el->next;
efree(el);
el = next;
}
PDO_USER_G(ptr_map) = NULL;
}
/* ***********************
* Module Housekeeping *
*********************** */
/* {{{ pdo_user_functions[] */
#if ZEND_MODULE_API_NO >= 20050922
static zend_module_dep pdo_user_deps[] = {
ZEND_MOD_REQUIRED("pdo")
{NULL, NULL, NULL}
};
#endif
/* }}} */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(pdo_user)
{
#ifdef ZTS
ts_allocate_id(&pdo_user_globals_id, sizeof(zend_pdo_user_globals), NULL, NULL);
#endif
if (FAILURE == PHP_MINIT(php_pdo_user_class)(INIT_FUNC_ARGS_PASSTHRU)) {
return FAILURE;
}
return php_pdo_register_driver(&pdo_user_driver);
}
/* }}} */
/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(pdo_user)
{
PDO_USER_G(ptr_map) = NULL;
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
PHP_RSHUTDOWN_FUNCTION(pdo_user)
{
if (PDO_USER_G(ptr_map)) {
php_pdo_user_ptrmap_destroy(TSRMLS_C);
}
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(pdo_user)
{
php_pdo_unregister_driver(&pdo_user_driver);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(pdo_user)
{
php_info_print_table_start();
php_info_print_table_header(2, "PDO Driver for Userspace data sources", "enabled");
php_info_print_table_end();
}
/* }}} */
/* {{{ pdo_user_module_entry */
zend_module_entry pdo_user_module_entry = {
#if ZEND_MODULE_API_NO >= 20050922
STANDARD_MODULE_HEADER_EX, NULL,
pdo_user_deps,
#else
STANDARD_MODULE_HEADER,
#endif
PHP_PDO_USER_EXTNAME,
NULL, /* procedural functions */
PHP_MINIT(pdo_user),
PHP_MSHUTDOWN(pdo_user),
PHP_RINIT(pdo_user),
PHP_RSHUTDOWN(pdo_user),
PHP_MINFO(pdo_user),
PHP_PDO_USER_EXTVER,
STANDARD_MODULE_PROPERTIES
};
/* }}} */
#ifdef COMPILE_DL_PDO_USER
ZEND_GET_MODULE(pdo_user)
#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
*/

474
pdo_user_driver.c Normal file
View File

@@ -0,0 +1,474 @@
/*
+----------------------------------------------------------------------+
| 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: Sara Golemon <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php_pdo_user_int.h"
#include "zend_exceptions.h"
#include <stdarg.h>
/* ******************
* Driver Methods *
****************** */
#define PHP_PDO_USER_DRV_CLOSER "pdo_close"
#define PHP_PDO_USER_DRV_PREPARER "pdo_prepare"
#define PHP_PDO_USER_DRV_DOER "pdo_do"
#define PHP_PDO_USER_DRV_QUOTER "pdo_quote"
#define PHP_PDO_USER_DRV_BEGIN "pdo_begin"
#define PHP_PDO_USER_DRV_COMMIT "pdo_commit"
#define PHP_PDO_USER_DRV_ROLLBACK "pdo_rollback"
#define PHP_PDO_USER_DRV_SET_ATTRIBUTE "pdo_setattribute"
#define PHP_PDO_USER_DRV_LAST_INSERT_ID "pdo_lastinsertid"
#define PHP_PDO_USER_DRV_FETCH_ERROR_FUNC "pdo_fetcherror"
#define PHP_PDO_USER_DRV_GET_ATTRIBUTE "pdo_getattribute"
#define PHP_PDO_USER_DRV_CHECK_LIVENESS "pdo_checkliveness"
static int php_pdo_user_closer(pdo_dbh_t *dbh TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
if (data) {
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_CLOSER, sizeof(PHP_PDO_USER_DRV_CLOSER) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == SUCCESS) {
/* Ignore retval */
zval_dtor(&retval);
}
php_pdo_user_ptrmap_unmap(data TSRMLS_CC);
zval_ptr_dtor(&(data->object));
efree(data);
dbh->driver_data = NULL;
}
return 0;
}
static int php_pdo_user_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
php_pdo_user_data *stmtdata = NULL;
zval *args[2], fname, *retval;
stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_PREPARER, sizeof(PHP_PDO_USER_DRV_PREPARER) - 1, 0);
MAKE_STD_ZVAL(args[0]);
ZVAL_STRINGL(args[0], sql, sql_len, 1);
args[1] = driver_options ? driver_options : EG(uninitialized_zval_ptr);
ALLOC_INIT_ZVAL(retval);
if (call_user_function(EG(function_table), &data->object, &fname, retval, 2, args TSRMLS_CC) == FAILURE) {
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&retval);
return 0; /* FAILURE */
}
zval_ptr_dtor(&args[0]);
if (Z_TYPE_P(retval) != IS_OBJECT ||
!php_pdo_user_implements_statement(Z_OBJCE_P(retval))) {
/* TODO: Throw exception */
zval_ptr_dtor(&retval);
return 0; /* FAILURE */
}
stmtdata = emalloc(sizeof(php_pdo_user_data));
stmtdata->object = retval;
stmtdata->dbh = dbh;
stmtdata->stmt = stmt;
php_pdo_user_ptrmap_map(stmtdata TSRMLS_CC);
stmt->driver_data = stmtdata;
stmt->methods = &php_pdo_user_stmt_methods;
/* TODO: Allow a way to expose native prepared statements */
return 1; /* SUCCESS */
}
static long php_pdo_user_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, *zsql, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_DOER, sizeof(PHP_PDO_USER_DRV_DOER) - 1, 0);
MAKE_STD_ZVAL(zsql);
ZVAL_STRINGL(zsql, (char*)sql, sql_len, 1);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 1, &zsql TSRMLS_CC) == SUCCESS) {
if (Z_TYPE(retval) == IS_NULL ||
(Z_TYPE(retval) == IS_BOOL && Z_BVAL(retval) == 0)) {
/* Convert NULL or FALSE to an error condition */
ZVAL_LONG(&retval, -1);
} else {
/* Anything else is just a number of rows affected */
convert_to_long(&retval);
}
} else {
ZVAL_LONG(&retval, -1);
}
zval_ptr_dtor(&zsql);
if (Z_LVAL(retval) < 0) {
Z_LVAL(retval) = -1;
}
return Z_LVAL(retval);
}
static int php_pdo_user_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, *zunq, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_QUOTER, sizeof(PHP_PDO_USER_DRV_QUOTER) - 1, 0);
MAKE_STD_ZVAL(zunq);
ZVAL_STRINGL(zunq, (char*)unquoted, unquotedlen, 1);
/* TODO: paramtype */
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 1, &zunq TSRMLS_CC) == SUCCESS) {
convert_to_string(&retval);
} else {
ZVAL_STRINGL(&retval, "", 0, 1);
}
zval_ptr_dtor(&zunq);
*quoted = Z_STRVAL(retval);
*quotedlen = Z_STRLEN(retval);
return 1;
}
static int php_pdo_user_begin(pdo_dbh_t *dbh TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_BEGIN, sizeof(PHP_PDO_USER_DRV_BEGIN) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == SUCCESS) {
convert_to_boolean(&retval);
} else {
ZVAL_FALSE(&retval);
}
return Z_BVAL(retval);
}
static int php_pdo_user_commit(pdo_dbh_t *dbh TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_COMMIT, sizeof(PHP_PDO_USER_DRV_COMMIT) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == SUCCESS) {
convert_to_boolean(&retval);
} else {
ZVAL_FALSE(&retval);
}
return Z_BVAL(retval);
}
static int php_pdo_user_rollback(pdo_dbh_t *dbh TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_ROLLBACK, sizeof(PHP_PDO_USER_DRV_ROLLBACK) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == SUCCESS) {
convert_to_boolean(&retval);
} else {
ZVAL_FALSE(&retval);
}
return Z_BVAL(retval);
}
static int php_pdo_user_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, *zargs[2], retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_SET_ATTRIBUTE, sizeof(PHP_PDO_USER_DRV_SET_ATTRIBUTE) - 1, 0);
MAKE_STD_ZVAL(zargs[0]);
ZVAL_LONG(zargs[0], attr);
zargs[1] = val;
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 2, zargs TSRMLS_CC) == SUCCESS) {
convert_to_boolean(&retval);
} else {
ZVAL_FALSE(&retval);
}
zval_ptr_dtor(&zargs[0]);
return Z_BVAL(retval);
}
static char *php_pdo_user_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, *zname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_LAST_INSERT_ID, sizeof(PHP_PDO_USER_DRV_LAST_INSERT_ID) - 1, 0);
MAKE_STD_ZVAL(zname);
ZVAL_STRING(zname, (char*)name, 1);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 1, &zname TSRMLS_CC) == SUCCESS) {
convert_to_string(&retval);
} else {
ZVAL_STRINGL(&retval, "", 0, 1);
}
*len = Z_STRLEN(retval);
return Z_STRVAL(retval);
}
static int php_pdo_user_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_FETCH_ERROR_FUNC, sizeof(PHP_PDO_USER_DRV_FETCH_ERROR_FUNC) - 1, 0);
/* TODO: Include statement object (if it exists) */
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == SUCCESS) {
if (Z_TYPE(retval) == IS_ARRAY) {
zval **tmpzval;
if (zend_hash_index_find(Z_ARRVAL(retval), 0, (void**)&tmpzval) == SUCCESS) {
zval *copyval;
MAKE_STD_ZVAL(copyval);
*copyval = **tmpzval;
INIT_PZVAL(copyval);
zval_copy_ctor(copyval);
convert_to_long(copyval);
add_next_index_zval(info, copyval);
} else {
add_next_index_long(info, 0);
}
if (zend_hash_index_find(Z_ARRVAL(retval), 0, (void**)&tmpzval) == SUCCESS) {
zval *copyval;
MAKE_STD_ZVAL(copyval);
*copyval = **tmpzval;
INIT_PZVAL(copyval);
zval_copy_ctor(copyval);
convert_to_string(copyval);
add_next_index_zval(info, copyval);
} else {
add_next_index_string(info, "", 1);
}
} else {
add_next_index_long(info, 0);
add_next_index_string(info, "", 1);
}
zval_dtor(&retval);
} else {
add_next_index_long(info, 0);
add_next_index_string(info, "", 1);
}
return 1;
}
static int php_pdo_user_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, *zattr;
int ret = 1; /* SUCCESS */
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_GET_ATTRIBUTE, sizeof(PHP_PDO_USER_DRV_GET_ATTRIBUTE) - 1, 0);
MAKE_STD_ZVAL(zattr);
ZVAL_LONG(zattr, attr);
if (call_user_function(EG(function_table), &(data->object), &fname, return_value, 1, &zattr TSRMLS_CC) == FAILURE) {
ZVAL_NULL(return_value);
ret = 0; /* FAILURE */
}
zval_ptr_dtor(&zattr);
return ret;
}
static int php_pdo_user_check_liveness(pdo_dbh_t *dbh TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)dbh->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_DRV_CHECK_LIVENESS, sizeof(PHP_PDO_USER_DRV_CHECK_LIVENESS) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == SUCCESS) {
convert_to_boolean(&retval);
} else {
ZVAL_FALSE(&retval);
}
return Z_BVAL(retval);
}
static struct pdo_dbh_methods php_pdo_user_drv_methods = {
php_pdo_user_closer,
php_pdo_user_preparer,
php_pdo_user_doer,
php_pdo_user_quoter,
php_pdo_user_begin,
php_pdo_user_commit,
php_pdo_user_rollback,
php_pdo_user_set_attribute,
php_pdo_user_last_insert_id,
php_pdo_user_fetch_error_func,
php_pdo_user_get_attribute,
php_pdo_user_check_liveness,
};
/* ***********
* FACTORY *
*********** */
static void php_pdo_factory_error(int errcode TSRMLS_DC, const char *format, ...)
{
va_list args;
char *message;
va_start(args, format);
vspprintf(&message, 0, format, args);
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE[HY000] [%d] %s", errcode, message);
va_end(args);
efree(message);
}
/* {{{ pdo_user_driver_factory */
static int pdo_user_driver_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC)
{
zend_class_entry *ce;
php_pdo_user_data *data = NULL;
zval *object = NULL;
zend_function *constructor;
struct pdo_data_src_parser vars[] = {
{ "driver", NULL, 0 }
};
php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 1);
if (!vars[0].optval) {
php_pdo_factory_error(-1 TSRMLS_CC, "No driver class specified.");
return 0; /* FAILURE */
}
ce = zend_fetch_class(vars[0].optval, strlen(vars[0].optval), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
if (!ce) {
php_pdo_factory_error(-2 TSRMLS_CC, "Class %s not found.", vars[0].optval);
efree(vars[0].optval);
return 0; /* FAILURE */
}
if (!php_pdo_user_implements_driver(ce)) {
php_pdo_factory_error(-3 TSRMLS_CC, "Class %s does not implement PDO_User_Driver interface.", vars[0].optval);
efree(vars[0].optval);
return 0; /* FAILURE */
}
ALLOC_INIT_ZVAL(object);
if (object_init_ex(object, ce) == FAILURE) {
php_pdo_factory_error(-4 TSRMLS_CC, "Failure instantiating class %s", vars[0].optval);
efree(vars[0].optval);
zval_ptr_dtor(&object);
return 0; /* FAILURE */
}
efree(vars[0].optval);
data = emalloc(sizeof(php_pdo_user_data));
data->object = object;
data->dbh = dbh;
data->stmt = NULL;
php_pdo_user_ptrmap_map(data TSRMLS_CC);
dbh->driver_data = data;
dbh->alloc_own_columns = 1;
dbh->max_escaped_char_length = 2;
dbh->methods = &php_pdo_user_drv_methods;
constructor = Z_OBJ_HT_P(object)->get_constructor(object TSRMLS_CC);
if (constructor) {
zval fname, retval, *args[4];
/* Lazy, but also less problematic */
ZVAL_STRING(&fname, constructor->common.function_name, 0);
/* $dsn */
MAKE_STD_ZVAL(args[0]);
ZVAL_STRINGL(args[0], dbh->data_source, dbh->data_source_len, 1);
/* $user */
MAKE_STD_ZVAL(args[1]);
ZVAL_STRING(args[1], dbh->username ? dbh->username : "", 1);
/* $pass */
MAKE_STD_ZVAL(args[2]);
ZVAL_STRING(args[2], dbh->password ? dbh->password : "", 1);
/* $params */
args[3] = driver_options ? driver_options : EG(uninitialized_zval_ptr);
if (SUCCESS == call_user_function(EG(function_table), &object, &fname, &retval, 4, args TSRMLS_CC)) {
zval_dtor(&retval);
}
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&args[1]);
zval_ptr_dtor(&args[2]);
}
return 1; /* SUCCESS */
}
/* }}} */
/* {{{ pdo_user_driver */
pdo_driver_t pdo_user_driver = {
PDO_DRIVER_HEADER(user),
pdo_user_driver_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
*/

344
pdo_user_object.c Normal file
View File

@@ -0,0 +1,344 @@
/*
+----------------------------------------------------------------------+
| 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: Sara Golemon <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php_pdo_user_int.h"
/* ******************
* PDO_User Class *
****************** */
/* PDO_User::CONSTANTS */
#define PHP_PDO_USER_DRIVER_PARAM_MAX_ESCAPSED_CHAR_LENGTH 0x00000001
#define PHP_PDO_USER_DRIVER_PARAM_DATA_SOURCE 0x00000002
#define PHP_PDO_USER_DRIVER_PARAM_SQLSTATE 0x00000003
#define PHP_PDO_USER_STATEMENT_PARAM_ACTIVE_QUERY 0x00010000
#define PHP_PDO_USER_STATEMENT_PARAM_SQLSTATE 0x00010003
/* {{{ mixed PDO_User::driverParam(object dbh, integer param[, mixed value])
- aka mixed PDO_User::statementParam(object stmt, integer param[, mixed value])
Get/Set a PDO option on a driver or statement handle
Passign value == NULL does a get-only, without changing the original value
Returns original value (or NULL on failure) */
PHP_METHOD(pdo_user, driverparam)
{
php_pdo_user_data *data;
zval *zobj;
long param;
zval *val = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ol|z", &zobj, &param, &val) == FAILURE) {
return;
}
data = php_pdo_user_ptrmap_locate(zobj TSRMLS_CC);
if (!data) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter 1 must be an active PDO_User driver or statement object");
RETURN_NULL();
}
switch (param) {
case PHP_PDO_USER_DRIVER_PARAM_MAX_ESCAPSED_CHAR_LENGTH:
{
zval *longval = val, tmpval;
RETVAL_LONG(data->dbh->max_escaped_char_length);
if (longval) {
/* Set a new value */
if (Z_TYPE_P(longval) != IS_LONG) {
tmpval = *longval;
zval_copy_ctor(&tmpval);
convert_to_long(&tmpval);
longval = &tmpval;
}
if (Z_LVAL_P(longval) < 1) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "max_escaped_character_length must be a positive integer");
RETVAL_NULL();
} else {
data->dbh->max_escaped_char_length = Z_LVAL_P(longval);
}
}
break;
}
case PHP_PDO_USER_DRIVER_PARAM_DATA_SOURCE:
{
if (val) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot override data source");
}
RETVAL_STRINGL(data->dbh->data_source, data->dbh->data_source_len, 1);
break;
}
case PHP_PDO_USER_DRIVER_PARAM_SQLSTATE:
{
RETVAL_STRING(data->dbh->error_code, 1);
if (val) {
zval *strval = val, tmpval;
if (Z_TYPE_P(strval) != IS_STRING) {
tmpval = *strval;
zval_copy_ctor(&tmpval);
convert_to_string(&tmpval);
strval = &tmpval;
}
strcpy(data->dbh->error_code, " ");
memcpy(data->dbh->error_code, Z_STRVAL_P(strval), Z_STRLEN_P(strval) > 5 ? 5 : Z_STRLEN_P(strval));
if (strval == &tmpval) {
zval_dtor(&tmpval);
}
}
break;
}
/* Statement params (don't forget to check for data->stmt) */
case PHP_PDO_USER_STATEMENT_PARAM_ACTIVE_QUERY:
{
if (val) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot override data source");
}
if (!data->stmt) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot return statement params from a driver object");
break;
}
if (data->stmt->active_query_string) {
RETVAL_STRINGL(data->stmt->active_query_string, data->stmt->active_query_stringlen, 1);
} else {
RETVAL_NULL();
}
break;
}
case PHP_PDO_USER_STATEMENT_PARAM_SQLSTATE:
{
if (!data->stmt) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot return statement params from a driver object");
break;
}
RETVAL_STRING(data->stmt->error_code, 1);
if (val) {
zval *strval = val, tmpval;
if (Z_TYPE_P(strval) != IS_STRING) {
tmpval = *strval;
zval_copy_ctor(&tmpval);
convert_to_string(&tmpval);
strval = &tmpval;
}
strcpy(data->stmt->error_code, " ");
memcpy(data->stmt->error_code, Z_STRVAL_P(strval), Z_STRLEN_P(strval) > 5 ? 5 : Z_STRLEN_P(strval));
if (strval == &tmpval) {
zval_dtor(&tmpval);
}
}
break;
}
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown parameter (%ld)", param);
}
}
/* }}} */
/* {{{ array PDO_User::parsedsn(string dsn, array params)
Parse a DSN string ( var1=val;var2=val;var3=val )
Into an associative array */
PHP_METHOD(pdo_user,parsedsn)
{
char *dsn;
int dsn_len, num_opts, i;
zval *opts, **opt = NULL;
struct pdo_data_src_parser *vars;
HashPosition pos;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &dsn, &dsn_len, &opts) == FAILURE) {
return;
}
array_init(return_value);
if (!dsn_len || !(num_opts = zend_hash_num_elements(Z_ARRVAL_P(opts)))) {
return;
}
vars = safe_emalloc(num_opts, sizeof(struct pdo_data_src_parser), 0);
for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(opts), &pos), num_opts =0;
zend_hash_get_current_data_ex(Z_ARRVAL_P(opts), (void**)&opt, &pos) == SUCCESS;
zend_hash_move_forward_ex(Z_ARRVAL_P(opts), &pos)) {
zval copyval = **opt;
/* Some data gets copied here that doesn't need to be (typically all of it I'd think)
* But it's more convenient[lazy] than tracking what does... */
zval_copy_ctor(&copyval);
convert_to_string(&copyval);
vars[num_opts].optname = Z_STRVAL(copyval);
vars[num_opts].optval = NULL;
vars[num_opts].freeme = 0;
num_opts++;
}
php_pdo_parse_data_source(dsn, dsn_len, vars, num_opts);
for(i = 0; i < num_opts; i++) {
if (vars[i].optval) {
add_assoc_string(return_value, (char*)vars[i].optname, vars[i].optval, !vars[i].freeme);
} else {
add_assoc_null(return_value, (char*)vars[i].optname);
}
/* This makes that unnecessary copying hurt twice as much...
* Must refactor this to track dups and only do them when actually needed */
efree((void*)vars[i].optname);
}
efree(vars);
}
/* }}} */
static zend_class_entry *php_pdo_user_ce;
static zend_class_entry *php_pdo_user_driver_interface;
static zend_class_entry *php_pdo_user_statement_interface;
static zend_function_entry php_pdo_user_class_functions[] = {
PHP_ME(pdo_user, driverparam, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_MALIAS(pdo_user, statementparam, driverparam, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_ME(pdo_user, parsedsn, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
{ NULL, NULL, NULL }
};
static zend_function_entry php_pdo_user_driver_interface_functions[] = {
PHP_ABSTRACT_ME(pdo_user_driver, __construct, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_close, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_prepare, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_do, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_quote, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_begin, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_commit, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_rollback, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_setattribute, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_lastinsertid, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_fetcherror, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_getattribute, NULL)
PHP_ABSTRACT_ME(pdo_user_driver, pdo_checkliveness, NULL)
{ NULL, NULL, NULL }
};
static zend_function_entry php_pdo_user_statement_interface_functions[] = {
PHP_ABSTRACT_ME(pdo_user_statement, pdo_close, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_execute, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_fetch, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_describe, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_getcol, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_paramhook, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_setattribute, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_getattribute, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_colmeta, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_nextrowset, NULL)
PHP_ABSTRACT_ME(pdo_user_statement, pdo_closecursor, NULL)
{ NULL, NULL, NULL }
};
static inline void _php_pdo_user_declare_long_constant(zend_class_entry *ce, 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(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(&ce->constants_table, (char*)const_name, name_len+1, &constant, sizeof(zval*), NULL);
#endif
}
#define PHP_PDO_USER_DECLARE_LONG_CONSTANT(cnst) \
_php_pdo_user_declare_long_constant(php_pdo_user_ce, #cnst , sizeof( #cnst ) - 1, PHP_PDO_USER_##cnst TSRMLS_CC)
PHP_MINIT_FUNCTION(php_pdo_user_class)
{
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "PDO_User", php_pdo_user_class_functions);
php_pdo_user_ce = zend_register_internal_class(&ce TSRMLS_CC);
php_pdo_user_ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; /* Prevents instantiation */
PHP_PDO_USER_DECLARE_LONG_CONSTANT(DRIVER_PARAM_MAX_ESCAPSED_CHAR_LENGTH);
PHP_PDO_USER_DECLARE_LONG_CONSTANT(DRIVER_PARAM_DATA_SOURCE);
PHP_PDO_USER_DECLARE_LONG_CONSTANT(DRIVER_PARAM_SQLSTATE);
PHP_PDO_USER_DECLARE_LONG_CONSTANT(STATEMENT_PARAM_ACTIVE_QUERY);
PHP_PDO_USER_DECLARE_LONG_CONSTANT(STATEMENT_PARAM_SQLSTATE);
INIT_CLASS_ENTRY(ce, "PDO_User_Driver", php_pdo_user_driver_interface_functions);
php_pdo_user_driver_interface = zend_register_internal_interface(&ce TSRMLS_CC);
INIT_CLASS_ENTRY(ce, "PDO_User_Statement", php_pdo_user_statement_interface_functions);
php_pdo_user_statement_interface = zend_register_internal_interface(&ce TSRMLS_CC);
return SUCCESS;
}
int php_pdo_user_implements_driver(zend_class_entry *ce)
{
int i;
if (!ce) {
return 0;
}
for(i = 0; i < ce->num_interfaces; i++) {
if (ce->interfaces[i] == php_pdo_user_driver_interface) {
return 1;
}
}
return 0;
}
int php_pdo_user_implements_statement(zend_class_entry *ce)
{
int i;
if (!ce) {
return 0;
}
for(i = 0; i < ce->num_interfaces; i++) {
if (ce->interfaces[i] == php_pdo_user_statement_interface) {
return 1;
}
}
return 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
*/

387
pdo_user_statement.c Normal file
View File

@@ -0,0 +1,387 @@
/*
+----------------------------------------------------------------------+
| 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: Sara Golemon <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php_pdo_user_int.h"
/* Even if the userspace describe method doesn't return a proper array
* we still need to populate the column metadata with *something*
* Generate a name using this prefix and a numeric (colno) suffix */
#define PHP_PDO_USER_STMT_UNKNOWN_COL_PREFIX "column_"
#define PHP_PDO_USER_STMT_CLOSER "pdo_close"
#define PHP_PDO_USER_STMT_EXECUTE "pdo_execute"
#define PHP_PDO_USER_STMT_FETCH "pdo_fetch"
#define PHP_PDO_USER_STMT_DESCRIBE "pdo_describe"
#define PHP_PDO_USER_STMT_GET_COL "pdo_getcol"
#define PHP_PDO_USER_STMT_PARAM_HOOK "pdo_paramhook"
#define PHP_PDO_USER_STMT_SET_ATTR "pdo_setattribute"
#define PHP_PDO_USER_STMT_GET_ATTR "pdo_getattribute"
#define PHP_PDO_USER_STMT_COL_META "pdo_colmeta"
#define PHP_PDO_USER_STMT_NEXT_ROWSET "pdo_nextrowset"
#define PHP_PDO_USER_STMT_CURSOR_CLOSER "pdo_closecursor"
static inline long php_pdo_user_long_from_assoc(HashTable *ht, char *key, size_t key_len)
{
long ret = 0;
zval **tmp;
if (zend_hash_find(ht, key, key_len, (void**)&tmp) == SUCCESS) {
switch (Z_TYPE_PP(tmp)) {
case IS_NULL: ret = 0; break;
case IS_BOOL: ret = Z_BVAL_PP(tmp) ? 1 : 0; break;
case IS_LONG: ret = Z_LVAL_PP(tmp); break;
case IS_DOUBLE: ret = (long)Z_DVAL_PP(tmp); break;
default:
{
zval copyval = **tmp;
zval_copy_ctor(&copyval);
convert_to_long(&copyval);
ret = Z_LVAL(copyval);
}
}
}
return ret;
}
static inline char *php_pdo_user_string_from_assoc(HashTable *ht, char *key, size_t key_len, int *len)
{
zval **tmp;
if (zend_hash_find(ht, key, key_len, (void**)&tmp) == SUCCESS) {
if (Z_TYPE_PP(tmp) == IS_STRING) {
*len = Z_STRLEN_PP(tmp);
return estrndup(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
} else {
zval copyval = **tmp;
zval_copy_ctor(&copyval);
convert_to_string(&copyval);
*len = Z_STRLEN(copyval);
return Z_STRVAL(copyval);
}
}
*len = 0;
return estrndup("", 0);
}
static int php_pdo_user_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
if (data) {
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_CLOSER, sizeof(PHP_PDO_USER_STMT_CLOSER) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == SUCCESS) {
/* Ignore retval */
zval_dtor(&retval);
}
php_pdo_user_ptrmap_unmap(data TSRMLS_CC);
zval_ptr_dtor(&(data->object));
efree(data);
stmt->driver_data = NULL;
}
return 0;
}
static int php_pdo_user_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_EXECUTE, sizeof(PHP_PDO_USER_STMT_EXECUTE) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == FAILURE) {
return 0; /* FAILURE */
}
if (Z_TYPE(retval) != IS_ARRAY) {
/* throw an exception */
zval_dtor(&retval);
return 0; /* FAILURE */
}
stmt->row_count = php_pdo_user_long_from_assoc(Z_ARRVAL(retval), "rows", sizeof("rows"));
stmt->column_count = php_pdo_user_long_from_assoc(Z_ARRVAL(retval), "cols", sizeof("cols"));
zval_dtor(&retval);
if (!stmt->column_count) {
/* throw an exception */
stmt->row_count = 0;
return 0; /* FAILURE */
}
return 1; /* SUCCESS */
}
static int php_pdo_user_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, long offset TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, retval, *args[2];
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_FETCH, sizeof(PHP_PDO_USER_STMT_FETCH) - 1, 0);
MAKE_STD_ZVAL(args[0]);
ZVAL_LONG(args[0], ori);
MAKE_STD_ZVAL(args[1]);
ZVAL_LONG(args[1], offset);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 2, args TSRMLS_CC) == FAILURE) {
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&args[1]);
return 0; /* FAILURE */
}
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&args[1]);
convert_to_boolean(&retval);
return Z_BVAL(retval);
}
static int php_pdo_user_stmt_describe(pdo_stmt_t *stmt, int colno TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, retval, *zcolno;
int len;
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_DESCRIBE, sizeof(PHP_PDO_USER_STMT_DESCRIBE) - 1, 0);
MAKE_STD_ZVAL(zcolno);
ZVAL_LONG(zcolno, colno);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 1, &zcolno TSRMLS_CC) == FAILURE) {
zval_ptr_dtor(&zcolno);
return 0;
}
zval_ptr_dtor(&zcolno);
if (Z_TYPE(retval) != IS_ARRAY) {
/* throw an exception */
zval_dtor(&retval);
stmt->columns[colno].namelen = spprintf(&stmt->columns[colno].name, 0, PHP_PDO_USER_STMT_UNKNOWN_COL_PREFIX "%d", colno);
stmt->columns[colno].maxlen = 0xffffffff;
stmt->columns[colno].precision = 0;
stmt->columns[colno].param_type = PDO_PARAM_STR;
return 0;
}
stmt->columns[colno].name = php_pdo_user_string_from_assoc(Z_ARRVAL(retval), "name", sizeof("name"), &len);
stmt->columns[colno].namelen = len;
stmt->columns[colno].maxlen = php_pdo_user_long_from_assoc(Z_ARRVAL(retval), "maxlen", sizeof("maxlen"));
stmt->columns[colno].precision = php_pdo_user_long_from_assoc(Z_ARRVAL(retval), "precision", sizeof("precision"));
stmt->columns[colno].param_type = PDO_PARAM_STR;
zval_dtor(&retval);
return 1; /* SUCCESS */
}
static int php_pdo_user_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, unsigned long *len, int *caller_frees TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, retval, *zcolno;
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_GET_COL, sizeof(PHP_PDO_USER_STMT_GET_COL) - 1, 0);
MAKE_STD_ZVAL(zcolno);
ZVAL_LONG(zcolno, colno);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 1, &zcolno TSRMLS_CC) == FAILURE) {
zval_ptr_dtor(&zcolno);
return 0;
}
zval_ptr_dtor(&zcolno);
convert_to_string(&retval);
*ptr = Z_STRVAL(retval);
*len = Z_STRLEN(retval);
*caller_frees = 1;
return 1; /* SUCCESS */
}
static int php_pdo_user_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param, enum pdo_param_event event_type TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, *args[5], retval;
switch(event_type) {
case PDO_PARAM_EVT_EXEC_PRE:
case PDO_PARAM_EVT_EXEC_POST:
case PDO_PARAM_EVT_FETCH_PRE:
case PDO_PARAM_EVT_FETCH_POST:
break;
default:
return 1; /* Don't handle other methods */
}
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_PARAM_HOOK, sizeof(PHP_PDO_USER_STMT_PARAM_HOOK) - 1, 0);
/* $event, $num, $name, $is_param, &$param */
MAKE_STD_ZVAL(args[0]);
ZVAL_LONG(args[0], event_type);
MAKE_STD_ZVAL(args[1]);
ZVAL_LONG(args[1], param->paramno);
ALLOC_INIT_ZVAL(args[2]);
if (param->name) {
ZVAL_STRINGL(args[2], param->name, param->namelen, 1);
}
MAKE_STD_ZVAL(args[3]);
ZVAL_BOOL(args[3], param->is_param);
args[4] = param->parameter;
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 5, args TSRMLS_CC) == FAILURE) {
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&args[1]);
zval_ptr_dtor(&args[2]);
zval_ptr_dtor(&args[3]);
return 1; /* Soft failure */
}
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&args[1]);
zval_ptr_dtor(&args[2]);
zval_ptr_dtor(&args[3]);
zval_dtor(&retval); /* Ignore */
return 1; /* SUCCESS */
}
static int php_pdo_user_stmt_set_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, *zargs[2], retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_SET_ATTR, sizeof(PHP_PDO_USER_STMT_SET_ATTR) - 1, 0);
MAKE_STD_ZVAL(zargs[0]);
ZVAL_LONG(zargs[0], attr);
zargs[1] = val;
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 2, zargs TSRMLS_CC) == SUCCESS) {
convert_to_boolean(&retval);
} else {
ZVAL_FALSE(&retval);
}
zval_ptr_dtor(&zargs[0]);
return Z_BVAL(retval);
}
static int php_pdo_user_stmt_get_attr(pdo_stmt_t *stmt, long attr, zval *val TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, *zattr;
int ret = 1; /* SUCCESS */
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_GET_ATTR, sizeof(PHP_PDO_USER_STMT_GET_ATTR) - 1, 0);
MAKE_STD_ZVAL(zattr);
ZVAL_LONG(zattr, attr);
if (call_user_function(EG(function_table), &(data->object), &fname, val, 1, &zattr TSRMLS_CC) == FAILURE) {
ZVAL_NULL(val);
ret = 0; /* FAILURE */
}
zval_ptr_dtor(&zattr);
return ret;
}
static int php_pdo_user_stmt_col_meta(pdo_stmt_t *stmt, long colno, zval *return_value TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, *zcolno;
int ret = 1; /* SUCCESS */
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_COL_META, sizeof(PHP_PDO_USER_STMT_COL_META) - 1, 0);
MAKE_STD_ZVAL(zcolno);
ZVAL_LONG(zcolno, colno);
if (call_user_function(EG(function_table), &(data->object), &fname, return_value, 1, &zcolno TSRMLS_CC) == FAILURE) {
ZVAL_NULL(return_value);
ret = 0; /* FAILURE */
}
zval_ptr_dtor(&zcolno);
return ret;
}
static int php_pdo_user_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_NEXT_ROWSET, sizeof(PHP_PDO_USER_STMT_NEXT_ROWSET) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == FAILURE) {
return 0; /* FAILURE */
}
convert_to_boolean(&retval);
return Z_BVAL(retval);
}
static int php_pdo_user_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
{
php_pdo_user_data *data = (php_pdo_user_data*)stmt->driver_data;
zval fname, retval;
ZVAL_STRINGL(&fname, PHP_PDO_USER_STMT_CURSOR_CLOSER, sizeof(PHP_PDO_USER_STMT_CURSOR_CLOSER) - 1, 0);
if (call_user_function(EG(function_table), &(data->object), &fname, &retval, 0, NULL TSRMLS_CC) == FAILURE) {
return 0; /* FAILURE */
}
convert_to_boolean(&retval);
return Z_BVAL(retval);
}
struct pdo_stmt_methods php_pdo_user_stmt_methods = {
php_pdo_user_stmt_dtor,
php_pdo_user_stmt_execute,
php_pdo_user_stmt_fetch,
php_pdo_user_stmt_describe,
php_pdo_user_stmt_get_col,
php_pdo_user_stmt_param_hook,
php_pdo_user_stmt_set_attr,
php_pdo_user_stmt_get_attr,
php_pdo_user_stmt_col_meta,
php_pdo_user_stmt_next_rowset,
php_pdo_user_stmt_cursor_closer
};

46
php_pdo_user.h Normal file
View File

@@ -0,0 +1,46 @@
/*
+----------------------------------------------------------------------+
| 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: Sara Golemon <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_USER_H
#define PHP_PDO_USER_H
#define PHP_PDO_USER_EXTNAME "pdo_user"
#define PHP_PDO_USER_EXTVER "0.1"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
extern zend_module_entry pdo_user_module_entry;
#define phpext_pdo_user_ptr &pdo_user_module_entry
#endif /* PHP_PDO_USER_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
*/

68
php_pdo_user_int.h Normal file
View File

@@ -0,0 +1,68 @@
/*
+----------------------------------------------------------------------+
| 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: Sara Golemon <pollita@php.net> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef PHP_PDO_USER_INT_H
#define PHP_PDO_USER_INT_H
#include "php_pdo_user.h"
#include "pdo/php_pdo.h"
#include "pdo/php_pdo_driver.h"
typedef struct _php_pdo_user_llist php_pdo_user_llist;
ZEND_BEGIN_MODULE_GLOBALS(pdo_user)
php_pdo_user_llist *ptr_map;
ZEND_END_MODULE_GLOBALS(pdo_user)
extern ZEND_DECLARE_MODULE_GLOBALS(pdo_user);
#ifdef ZTS
#define PDO_USER_G(v) TSRMG(pdo_user_globals_id, zend_pdo_user_globals *, v)
#else
#define PDO_USER_G(v) (pdo_user_globals.v)
#endif
typedef struct _php_pdo_user_data {
zval *object;
pdo_dbh_t *dbh;
pdo_stmt_t *stmt;
} php_pdo_user_data;
int php_pdo_user_ptrmap_map(php_pdo_user_data *data TSRMLS_DC);
int php_pdo_user_ptrmap_unmap(php_pdo_user_data *data TSRMLS_DC);
void *php_pdo_user_ptrmap_locate(zval *object TSRMLS_DC);
void php_pdo_user_ptrmap_destroy(TSRMLS_D);
PHP_MINIT_FUNCTION(php_pdo_user_class);
int php_pdo_user_implements_driver(zend_class_entry *ce);
int php_pdo_user_implements_statement(zend_class_entry *ce);
extern struct pdo_stmt_methods php_pdo_user_stmt_methods;
#endif /* PHP_PDO_USER_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
*/

319
tests/globals.phpt Normal file
View File

@@ -0,0 +1,319 @@
--TEST--
Globals Driver
--SKIPIF--
<?php
if (!extension_loaded('pdo_user')) {
die('pdo_user not loaded');
}
?>
--FILE--
<?php
/* DON'T USE THIS IN THE WILD
* It's just a basic driver implementation meant to provide a test framework,
* It makes assumptions about the caller that would be unsafe in uncontrolled environments */
class PDO_User_Globals_Statement implements PDO_User_Statement {
private $cursor = NULL;
private $varname = NULL;
function pdo_close() { }
function pdo_execute() {
$query = PDO_User::statementParam($this, PDO_User::STATEMENT_PARAM_ACTIVE_QUERY);
if (preg_match('/^SELECT FROM "(.*?)"$/i', $query, $matches)) {
$this->fetched = false;
if (isset($GLOBALS[$matches[1]])) {
$this->varname = $matches[1];
$this->cursor = $GLOBALS[$matches[1]];
if (is_array($this->cursor)) {
reset($this->cursor);
return array('rows' => count($this->cursor), 'cols' => 1);
}
return array('rows' => 1, 'cols' => 1);
} else {
return false;
}
}
return false;
}
function pdo_fetch($ori, $fetch) {
switch ($ori) {
case PDO::FETCH_ORI_NEXT:
if ($this->fetched) {
if (is_array($this->cursor)) {
next($this->cursor);
return true;
} else {
$this->cursor = NULL;
return false;
}
} else {
$this->fetched = true;
return true;
}
break;
case PDO::FETCH_ORI_PRIOR:
if ($this->fetched) {
if (is_array($this->cursor)) {
prev($this->cursor);
return true;
} else {
$this->cursor = NULL;
return false;
}
} else {
$this->fetched = true;
return true;
}
break;
case PDO::FETCH_ORI_FIRST:
if ($this->fetched) {
if (is_array($this->cursor)) {
reset($this->cursor);
return true;
} else {
$this->cursor = NULL;
return false;
}
} else {
$this->fetched = true;
return true;
}
break;
case PDO::FETCH_ORI_LAST:
if ($this->fetched) {
if (is_array($this->cursor)) {
end($this->cursor);
return true;
} else {
$this->cursor = NULL;
return false;
}
} else {
$this->fetched = true;
return true;
}
break;
case PDO::FETCH_ORI_ABS:
if ($this->fetched) {
if (is_array($this->cursor)) {
reset($this->cursor);
while ($ofs--) next($this->cursor);
return true;
} else {
$this->cursor = NULL;
return false;
}
} else {
$this->fetched = true;
return true;
}
break;
case PDO::FETCH_ORI_REL:
if ($this->fetched) {
if (is_array($this->cursor)) {
if ($ofs > 0) {
while ($ofs--) prev($this->cursor);
} elseif ($ofs < 0) {
while ($ofs++) next($this->cursor);
}
return true;
} else {
$this->cursor = NULL;
return false;
}
} else {
$this->fetched = true;
return true;
}
break;
}
return false;
}
function pdo_describe($col) {
return array('name'=>$this->varname,'maxlen'=>0x7FFFFFFF, 'precision'=>0);
}
function pdo_getCol($col) {
if (is_array($this->cursor)) {
return current($this->cursor);
} else {
return $this->cursor;
}
}
function pdo_paramHook($type, $colno, $paramname, $is_param, &$param) { }
function pdo_getAttribute($attr) { return NULL; }
function pdo_setAttribute($attr, $val) { return false; }
function pdo_colMeta($col) {
return array('table'=>'global_symbol_table', 'type'=>gettype($this->cursor));
}
function pdo_nextRowset() {
return $this->fetch(PDO::FETCH_ORI_NEXT, 1);
}
function pdo_closeCursor() {
$this->cursor = NULL;
}
}
class PDO_User_Globals_Driver implements PDO_User_Driver {
private $errorCode = 0;
private $errorDesc = '';
private $lastInsert = NULL;
function insert($key, $value) {
if (isset($GLOBALS[$key])) {
return 0;
}
$GLOBALS[$key] = $value;
return 1;
}
function update($key, $value) {
if (!isset($GLOBALS[$key])) {
return 0;
}
$GLOBALS[$key] = $value;
return 1;
}
function delete($key) {
if (!isset($GLOBALS[$key])) {
return 0;
}
unset($GLOBALS[$key]);
return 1;
}
/* PDO Driver Implementation */
function __construct($dsn, $user, $pass, $options) { }
function pdo_close() { }
function pdo_prepare($sql, $options) {
return new PDO_User_Globals_Statement($sql, $options);
}
function pdo_do($sql) {
if (preg_match('/^INSERT "(.*?)" as "(.*?)"$/i', $sql, $matches)) {
return $this->insert($matches[1], $matches[2]);
} elseif (preg_match('/^UPDATE "(.*?)" to "(.*?)"$/i', $sql, $matches)) {
return $this->update($matches[1], $matches[2]);
} elseif (preg_match('/^DELETE "(.*?)"$/i', $sql, $matches)) {
return $this->delete($matches[1]);
}
$this->errorCode = 1000;
$this->errorDesc = 'Invalid query: ' . $sql;
return false;
}
function pdo_quote($str) {
return '"' . addslashes($str) . '"';
}
function pdo_begin() { return false; }
function pdo_commit() { return false; }
function pdo_rollback() { return false; }
function pdo_setAttribute($attr, $val) { return false; }
function pdo_getAttribute($attr) { return NULL; }
function pdo_lastInsertID($seq) { return $this->lastInsert; }
function pdo_fetchError() {
return array($this->errorCode, $this->errorDesc);
}
function pdo_checkLiveness() { return true; }
}
$preset = 'Some Value';
$drv = new PDO('user:driver=PDO_User_Globals_Driver');
var_dump($drv->exec('INSERT "newvar" as "newvalue"'), $newvar);
var_dump($drv->exec('UPDATE "preset" to "Other Value"'), $preset);
var_dump($drv->exec('DELETE "preset"'), @$preset);
var_dump($drv->exec('DELETE "preset"'));
var_dump($drv->exec('Invalid Query'), $drv->errorInfo());
echo "-*-\n";
var_dump($stmt = $drv->prepare('SELECT FROM "newvar"'));
var_dump($stmt->execute());
var_dump($stmt->columnCount());
var_dump($stmt->rowCount());
var_dump($stmt->getColumnMeta(0));
var_dump($stmt->fetchColumn(0));
unset($stmt);
echo "-*-\n";
$foo = 'bar';
$baz = NULL;
var_dump($stmt = $drv->prepare('SELECT FROM ?'));
var_dump($stmt->bindValue(1, 'foo'));
var_dump($stmt->bindColumn(1, $baz));
var_dump($stmt->execute());
var_dump($stmt->fetch(PDO::FETCH_BOUND), $baz);
unset($stmt);
echo "-*-\n";
var_dump($stmt = $drv->prepare('INVALID QUERY'));
var_dump($stmt->execute());
--EXPECTF--
int(1)
string(8) "newvalue"
int(1)
string(11) "Other Value"
int(1)
NULL
int(0)
bool(false)
array(3) {
[0]=>
string(5) "00000"
[1]=>
int(1000)
[2]=>
string(4) "1000"
}
-*-
object(PDOStatement)#%d (1) {
["queryString"]=>
string(20) "SELECT FROM "newvar""
}
bool(true)
int(1)
int(1)
array(6) {
["table"]=>
string(19) "global_symbol_table"
["type"]=>
string(6) "string"
["name"]=>
string(6) "newvar"
["len"]=>
int(2147483647)
["precision"]=>
int(0)
["pdo_type"]=>
int(2)
}
string(8) "newvalue"
-*-
object(PDOStatement)#%d (1) {
["queryString"]=>
string(13) "SELECT FROM ?"
}
bool(true)
bool(true)
bool(true)
bool(true)
string(3) "bar"
-*-
object(PDOStatement)#%d (1) {
["queryString"]=>
string(13) "INVALID QUERY"
}
bool(false)