php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login

Patch bug45259_sqlite-bind-params-autodetect_v308350 for PDO SQLite Bug #54023

Patch version 2011-02-15 10:47 UTC

Return to Bug #54023 | Download this patch
Patch Revisions:

Developer: sl9@gmx.net

Index: ext/pdo_sqlite/tests/bug45259_bool.phpt
===================================================================
--- ext/pdo_sqlite/tests/bug45259_bool.phpt	(revision 0)
+++ ext/pdo_sqlite/tests/bug45259_bool.phpt	(revision 0)
@@ -0,0 +1,31 @@
+--TEST--
+Bug #45259 (SQLite PDO prepared statements don't bind values - boolean)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$testGroups = array(
+	// sqlite3_bind_int
+	'Boolean' => array(
+		'concrete true = true    ' => array('SELECT 1 = 1 AS test', array()),
+		'concrete true = false   ' => array('SELECT 1 = 0 AS test', array()),
+		'bound    true = true    ' => array('SELECT 1 = ? AS test', array(true)),
+		'bound    true = false   ' => array('SELECT 1 = ? AS test', array(false)),
+	),
+);
+
+require dirname(__FILE__) . '/bug45259_common.inc';
+
+?>
+--EXPECT--
+Boolean:
+ concrete true = true    : 1
+ concrete true = false   : 0
+ bound    true = true    : 1
+ bound    true = false   : 0
Index: ext/pdo_sqlite/tests/bug45259_double.phpt
===================================================================
--- ext/pdo_sqlite/tests/bug45259_double.phpt	(revision 0)
+++ ext/pdo_sqlite/tests/bug45259_double.phpt	(revision 0)
@@ -0,0 +1,31 @@
+--TEST--
+Bug #45259 (SQLite PDO prepared statements don't bind values - double)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$testGroups = array(
+	// sqlite3_bind_double
+	'Double' => array(
+		'concrete 12.34 = 12.34  ' => array('SELECT 12.34 = 12.34 AS test', array()),
+		'concrete 12.34 = 43.21  ' => array('SELECT 12.34 = 43.21 AS test', array()),
+		'bound    12.34 = 12.34  ' => array('SELECT 12.34 = ? AS test', array(12.34)),
+		'bound    12.34 = 43.21  ' => array('SELECT 12.34 = ? AS test', array(43.21)),
+	),
+);
+
+require dirname(__FILE__) . '/bug45259_common.inc';
+
+?>
+--EXPECT--
+Double:
+ concrete 12.34 = 12.34  : 1
+ concrete 12.34 = 43.21  : 0
+ bound    12.34 = 12.34  : 1
+ bound    12.34 = 43.21  : 0
Index: ext/pdo_sqlite/tests/bug45259_int-big.phpt
===================================================================
--- ext/pdo_sqlite/tests/bug45259_int-big.phpt	(revision 0)
+++ ext/pdo_sqlite/tests/bug45259_int-big.phpt	(revision 0)
@@ -0,0 +1,31 @@
+--TEST--
+Bug #45259 (SQLite PDO prepared statements don't bind values - int big)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$testGroups = array(
+	// sqlite3_bind_int
+	'Integer (big)' => array(
+		'concrete PHP_INT_MAX = PHP_INT_MAX    ' => array('SELECT ' . PHP_INT_MAX . ' = ' . PHP_INT_MAX . ' AS test', array()),
+		'concrete PHP_INT_MAX = PHP_INT_MAX - 1' => array('SELECT ' . PHP_INT_MAX . ' = ' . (PHP_INT_MAX - 1) . ' AS test', array()),
+		'bound    PHP_INT_MAX = PHP_INT_MAX    ' => array('SELECT ' . PHP_INT_MAX . ' = ? AS test', array(PHP_INT_MAX)),
+		'bound    PHP_INT_MAX = PHP_INT_MAX - 1' => array('SELECT ' . PHP_INT_MAX . ' = ? AS test', array(PHP_INT_MAX - 1)),
+	),
+);
+
+require dirname(__FILE__) . '/bug45259_common.inc';
+
+?>
+--EXPECT--
+Integer (big):
+ concrete PHP_INT_MAX = PHP_INT_MAX    : 1
+ concrete PHP_INT_MAX = PHP_INT_MAX - 1: 0
+ bound    PHP_INT_MAX = PHP_INT_MAX    : 1
+ bound    PHP_INT_MAX = PHP_INT_MAX - 1: 0
\ No newline at end of file
Index: ext/pdo_sqlite/tests/bug45259_int-small.phpt
===================================================================
--- ext/pdo_sqlite/tests/bug45259_int-small.phpt	(revision 0)
+++ ext/pdo_sqlite/tests/bug45259_int-small.phpt	(revision 0)
@@ -0,0 +1,31 @@
+--TEST--
+Bug #45259 (SQLite PDO prepared statements don't bind values - int small)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$testGroups = array(
+	// sqlite3_bind_int
+	'Integer (small)' => array(
+		'concrete 100 = 100      ' => array('SELECT 100 = 100 AS test', array()),
+		'concrete 100 = 50       ' => array('SELECT 100 = 50 AS test', array()),
+		'bound    100 = 100      ' => array('SELECT 100 = ? AS test', array(100)),
+		'bound    100 = 50       ' => array('SELECT 100 = ? AS test', array(50)),
+	),
+);
+
+require dirname(__FILE__) . '/bug45259_common.inc';
+
+?>
+--EXPECT--
+Integer (small):
+ concrete 100 = 100      : 1
+ concrete 100 = 50       : 0
+ bound    100 = 100      : 1
+ bound    100 = 50       : 0
Index: ext/pdo_sqlite/tests/bug45259_null.phpt
===================================================================
--- ext/pdo_sqlite/tests/bug45259_null.phpt	(revision 0)
+++ ext/pdo_sqlite/tests/bug45259_null.phpt	(revision 0)
@@ -0,0 +1,31 @@
+--TEST--
+Bug #45259 (SQLite PDO prepared statements don't bind values - null)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$testGroups = array(
+	// sqlite3_bind_null
+	'Null' => array(
+		'concrete IFNULL(null)   ' => array('SELECT IFNULL(null,"null") AS test', array()),
+		'concrete IFNULL(ifail)  ' => array('SELECT IFNULL("ifail","null") AS test', array()),
+		'bound    IFNULL(null)   ' => array('SELECT IFNULL(?,"null") AS test', array(null)),
+		'bound    IFNULL(ifail)  ' => array('SELECT IFNULL(?,"null") AS test', array('ifail')),
+	),
+);
+
+require dirname(__FILE__) . '/bug45259_common.inc';
+
+?>
+--EXPECT--
+Null:
+ concrete IFNULL(null)   : null
+ concrete IFNULL(ifail)  : ifail
+ bound    IFNULL(null)   : null
+ bound    IFNULL(ifail)  : ifail
Index: ext/pdo_sqlite/tests/bug45259_text.phpt
===================================================================
--- ext/pdo_sqlite/tests/bug45259_text.phpt	(revision 0)
+++ ext/pdo_sqlite/tests/bug45259_text.phpt	(revision 0)
@@ -0,0 +1,31 @@
+--TEST--
+Bug #45259 (SQLite PDO prepared statements don't bind values - text)
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$testGroups = array(
+	// sqlite3_bind_text
+	'String' => array(
+		'concrete testme = testme' => array('SELECT "testme" = "testme" AS test', array()),
+		'concrete testme = ifail ' => array('SELECT "testme" = "ifail" AS test', array()),
+		'bound    testme = testme' => array('SELECT "testme" = ? AS test', array('testme')),
+		'bound    testme = ifail ' => array('SELECT "testme" = ? AS test', array('ifail')),
+	),
+);
+
+require dirname(__FILE__) . '/bug45259_common.inc';
+
+?>
+--EXPECT--
+String:
+ concrete testme = testme: 1
+ concrete testme = ifail : 0
+ bound    testme = testme: 1
+ bound    testme = ifail : 0
Index: ext/pdo_sqlite/tests/bug45259_common.inc
===================================================================
--- ext/pdo_sqlite/tests/bug45259_common.inc	(revision 0)
+++ ext/pdo_sqlite/tests/bug45259_common.inc	(revision 0)
@@ -0,0 +1,15 @@
+<?php
+
+$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+foreach($testGroups as $testGroupName => $testCases){
+	echo $testGroupName, ':', PHP_EOL;
+	foreach($testCases as $testCaseName => $testCase){
+		$query = $testCase[0];
+		$param = $testCase[1];
+		$stmt = $db->prepare($query);
+		$stmt->execute($param);
+		$row = $stmt->fetch();
+		echo ' ', $testCaseName, ': ', $row['test'], PHP_EOL;
+	}
+}
Index: ext/pdo_sqlite/sqlite_statement.c
===================================================================
--- ext/pdo_sqlite/sqlite_statement.c	(revision 308350)
+++ ext/pdo_sqlite/sqlite_statement.c	(working copy)
@@ -78,6 +78,8 @@
 static int pdo_sqlite_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
 		enum pdo_param_event event_type TSRMLS_DC)
 {
+	int hookResult = 0; // failure
+
 	pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
 
 	switch (event_type) {
@@ -86,39 +88,97 @@
 				sqlite3_reset(S->stmt);
 				S->done = 1;
 			}
-			
+
 			if (param->is_param) {
-				
 				if (param->paramno == -1) {
 					param->paramno = sqlite3_bind_parameter_index(S->stmt, param->name) - 1;
 				}
 
+				if(PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_ZVAL){
+					// XXX: User didn't specify a PDO_PARAM_* value, so let's do autodetect using the ZVAL type
+					switch(Z_TYPE_P(param->parameter)){
+						case IS_STRING:
+							param->param_type = PDO_PARAM_STR;
+						break;
+						case IS_LONG:
+							param->param_type = PDO_PARAM_INT;
+						break;
+						case IS_NULL:
+							param->param_type = PDO_PARAM_NULL;
+						break;
+						case IS_BOOL:
+							param->param_type = PDO_PARAM_BOOL;
+						break;
+						case IS_DOUBLE:
+							param->param_type = PDO_PARAM_INT;
+						break;
+						case IS_RESOURCE:
+							param->param_type = PDO_PARAM_LOB;
+						break;
+						default:
+							pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Invalid parameter type" TSRMLS_CC);
+					}
+				}
+
 				switch (PDO_PARAM_TYPE(param->param_type)) {
 					case PDO_PARAM_STMT:
-						return 0;
-
+						pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Invalid parameter type" TSRMLS_CC);
+					break;
 					case PDO_PARAM_NULL:
-						if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
-							return 1;
+						if(sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+							hookResult = 1; // success
+						}else{
+							pdo_sqlite_error_stmt(stmt);
 						}
-						pdo_sqlite_error_stmt(stmt);
-						return 0;
-					
+					break;
 					case PDO_PARAM_INT:
-					case PDO_PARAM_BOOL:
-						if (Z_TYPE_P(param->parameter) == IS_NULL) {
+						if (Z_TYPE_P(param->parameter) == IS_LONG) {
+							// no conversion
+						}else if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
+							if (sqlite3_bind_double(S->stmt, param->paramno + 1, Z_DVAL_P(param->parameter)) == SQLITE_OK) {
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
+							}
+						}else if (Z_TYPE_P(param->parameter) == IS_NULL) {
 							if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
-								return 1;
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
 							}
-						} else {
+						}else{
 							convert_to_long(param->parameter);
-							if (SQLITE_OK == sqlite3_bind_int(S->stmt, param->paramno + 1, Z_LVAL_P(param->parameter))) {
-								return 1;
+						}
+
+						if (Z_TYPE_P(param->parameter) == IS_LONG) {
+							if (sqlite3_bind_int(S->stmt, param->paramno + 1, Z_LVAL_P(param->parameter)) == SQLITE_OK) {
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
 							}
 						}
-						pdo_sqlite_error_stmt(stmt);
-						return 0;
-					
+					break;
+					case PDO_PARAM_BOOL:
+						if (Z_TYPE_P(param->parameter) == IS_BOOL) {
+							// no conversion
+						}else if (Z_TYPE_P(param->parameter) == IS_NULL) {
+							if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
+							}
+						}else{
+							convert_to_boolean(param->parameter);
+						}
+
+						if (Z_TYPE_P(param->parameter) == IS_BOOL) {
+							if (sqlite3_bind_int(S->stmt, param->paramno + 1, Z_LVAL_P(param->parameter)) == SQLITE_OK) {
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
+							}
+						}
+					break;
 					case PDO_PARAM_LOB:
 						if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
 							php_stream *stm;
@@ -128,54 +188,70 @@
 								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 {
+							}else{
 								pdo_raise_impl_error(stmt->dbh, stmt, "HY105", "Expected a stream resource" TSRMLS_CC);
-								return 0;
 							}
 						} else if (Z_TYPE_P(param->parameter) == IS_NULL) {
 							if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
-								return 1;
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
 							}
-							pdo_sqlite_error_stmt(stmt);
-							return 0;
 						} else {
 							convert_to_string(param->parameter);
+							if(
+								sqlite3_bind_blob(
+									S->stmt, param->paramno + 1,
+									Z_STRVAL_P(param->parameter),
+									Z_STRLEN_P(param->parameter),
+									SQLITE_STATIC
+								) == SQLITE_OK
+							){
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
+							}
 						}
-						
-						if (SQLITE_OK == sqlite3_bind_blob(S->stmt, param->paramno + 1,
-								Z_STRVAL_P(param->parameter),
-								Z_STRLEN_P(param->parameter),
-								SQLITE_STATIC)) {
-							return 1;	
-						}
-						pdo_sqlite_error_stmt(stmt);
-						return 0;
-							
+					break;
+
 					case PDO_PARAM_STR:
 					default:
-						if (Z_TYPE_P(param->parameter) == IS_NULL) {
+						if (Z_TYPE_P(param->parameter) == IS_STRING) {
+							// no conversion
+						} else if (Z_TYPE_P(param->parameter) == IS_NULL) {
 							if (sqlite3_bind_null(S->stmt, param->paramno + 1) == SQLITE_OK) {
-								return 1;
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
 							}
 						} else {
 							convert_to_string(param->parameter);
-							if(SQLITE_OK == sqlite3_bind_text(S->stmt, param->paramno + 1,
+						}
+
+						if(Z_TYPE_P(param->parameter) == IS_STRING){
+							if(
+								sqlite3_bind_text(
+									S->stmt, param->paramno + 1,
 									Z_STRVAL_P(param->parameter),
 									Z_STRLEN_P(param->parameter),
-									SQLITE_STATIC)) {
-								return 1;	
+									SQLITE_STATIC
+								) == SQLITE_OK
+							){
+								hookResult = 1; // success
+							}else{
+								pdo_sqlite_error_stmt(stmt);
 							}
 						}
-						pdo_sqlite_error_stmt(stmt);
-						return 0;
+					break;
 				}
+			}else{
+				hookResult = 1; // success
 			}
-			break;
-
+		break;
 		default:
-			;
+			hookResult = 1; // success
 	}
-	return 1;
+	return hookResult;
 }
 
 static int pdo_sqlite_stmt_fetch(pdo_stmt_t *stmt,
Index: ext/pdo/pdo_stmt.c
===================================================================
--- ext/pdo/pdo_stmt.c	(revision 308350)
+++ ext/pdo/pdo_stmt.c	(working copy)
@@ -468,6 +468,13 @@
 			}
 
 			param.param_type = PDO_PARAM_STR;
+			if(strcmp(stmt->dbh->driver->driver_name, "sqlite") == 0){
+				// Sqlite does own mapping of zvals to pdo params now.
+				// Setting param type to a constant to signal that no explicit type was set
+				// gives the driver the opportunity to autodetect the type from the zval itself
+				param.param_type = PDO_PARAM_ZVAL;
+			}
+
 			MAKE_STD_ZVAL(param.parameter);
 			MAKE_COPY_ZVAL(tmp, param.parameter);
 
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 21:01:30 2024 UTC