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

Patch oci8-php7-bind for OCI8 related Bug #71148

Patch version 2016-10-13 03:56 UTC

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

Developer: sixd@php.net

diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c
index 0527b55..59f9931 100644
--- a/ext/oci8/oci8.c
+++ b/ext/oci8/oci8.c
@@ -1387,6 +1387,11 @@ void php_oci_bind_hash_dtor(zval *data)
 {
 	php_oci_bind *bind = (php_oci_bind *) Z_PTR_P(data);
 
+	if (!Z_ISUNDEF(bind->parameter)) {
+		zval_ptr_dtor(&bind->parameter);
+		ZVAL_UNDEF(&bind->parameter);
+	}
+
 	if (bind->array.elements) {
 		efree(bind->array.elements);
 		bind->array.elements = NULL;
diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c
index 727ec3e..18714d1 100644
--- a/ext/oci8/oci8_interface.c
+++ b/ext/oci8/oci8_interface.c
@@ -110,7 +110,7 @@ PHP_FUNCTION(oci_bind_by_name)
 	zval *bind_var = NULL;
 	php_oci_statement *statement;
 	
-	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz/|ll", &z_statement, &name, &name_len, &bind_var, &maxlen, &type) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz|ll", &z_statement, &name, &name_len, &bind_var, &maxlen, &type) == FAILURE) {
 		return;
 	}
 
diff --git a/ext/oci8/oci8_statement.c b/ext/oci8/oci8_statement.c
index d4f0815..0d751a8 100644
--- a/ext/oci8/oci8_statement.c
+++ b/ext/oci8/oci8_statement.c
@@ -1094,13 +1094,20 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 	int mode = OCI_DATA_AT_EXEC;
 	sb4 value_sz = -1;
 	sword errstatus;
+	zval *param = NULL;
+
+	if (!Z_ISREF_P(var)) {
+		param = var;
+	} else {
+		param = Z_REFVAL_P(var);
+	}
 
 	switch (type) {
 		case SQLT_NTY:
 		{
 			zval *tmp;
 			
-			if (Z_TYPE_P(var) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(var), "collection", sizeof("collection")-1)) == NULL) {
+			if (Z_TYPE_P(param) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(param), "collection", sizeof("collection")-1)) == NULL) {
 				php_error_docref(NULL, E_WARNING, "Unable to find collection property");
 				return 1;
 			}
@@ -1122,7 +1129,7 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 		{
 			zval *tmp;
 			
-			if (Z_TYPE_P(var) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(var), "descriptor", sizeof("descriptor")-1)) == NULL) {
+			if (Z_TYPE_P(param) != IS_OBJECT || (tmp = zend_hash_str_find(Z_OBJPROP_P(param), "descriptor", sizeof("descriptor")-1)) == NULL) {
 				php_error_docref(NULL, E_WARNING, "Unable to find descriptor property");
 				return 1;
 			}
@@ -1141,17 +1148,17 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 			
 		case SQLT_INT:
 		case SQLT_NUM:
-			if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
+			if (Z_TYPE_P(param) == IS_RESOURCE || Z_TYPE_P(param) == IS_OBJECT) {
 				php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
 				return 1;
 			}
-			convert_to_long(var);
+			convert_to_long(param);
 #if defined(OCI_MAJOR_VERSION) && (OCI_MAJOR_VERSION > 10) &&			\
 	(defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || defined(_WIN64)) 
-			bind_data = (ub8 *)&Z_LVAL_P(var);
+			bind_data = (ub8 *)&Z_LVAL_P(param);
 			value_sz = sizeof(ub8);
 #else
-			bind_data = (ub4 *)&Z_LVAL_P(var);
+			bind_data = (ub4 *)&Z_LVAL_P(param);
 			value_sz = sizeof(ub4);
 #endif
 			mode = OCI_DEFAULT;
@@ -1162,20 +1169,20 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 		case SQLT_LNG:
 		case SQLT_AFC:
 		case SQLT_CHR: /* SQLT_CHR is the default value when type was not specified */
-			if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
+			if (Z_TYPE_P(param) == IS_RESOURCE || Z_TYPE_P(param) == IS_OBJECT) {
 				php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
 				return 1;
 			}
-			if (Z_TYPE_P(var) != IS_NULL) {
-				convert_to_string(var);
+			if (Z_TYPE_P(param) != IS_NULL) {
+				convert_to_string(param);
 			}
 			if ((maxlength == -1) || (maxlength == 0)) {
 				if (type == SQLT_LNG) {
 					value_sz = SB4MAXVAL;
-				} else if (Z_TYPE_P(var) == IS_STRING) {
-					value_sz = (sb4) Z_STRLEN_P(var);
+				} else if (Z_TYPE_P(param) == IS_STRING) {
+					value_sz = (sb4) Z_STRLEN_P(param);
 				} else {
-					/* Bug-72524: revert value_sz from PHP_OCI_PIECE_SIZE to 0. This restores PHP 5.6 behavior */
+                    /* Bug-72524: revert value_sz from PHP_OCI_PIECE_SIZE to 0 */
 					value_sz = 0;
 				}
 			} else {
@@ -1184,11 +1191,11 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 			break;
 
 		case SQLT_RSET:
-			if (Z_TYPE_P(var) != IS_RESOURCE) {
+			if (Z_TYPE_P(param) != IS_RESOURCE) {
 				php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
 				return 1;
 			}
-			PHP_OCI_ZVAL_TO_STATEMENT_EX(var, bind_statement);
+			PHP_OCI_ZVAL_TO_STATEMENT_EX(param, bind_statement);
 			value_sz = sizeof(void*);
 
 			oci_stmt = bind_statement->stmt;
@@ -1200,15 +1207,15 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 
 #if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12
 		case SQLT_BOL:
-			if (Z_TYPE_P(var) == IS_RESOURCE || Z_TYPE_P(var) == IS_OBJECT) {
+			if (Z_TYPE_P(param) == IS_RESOURCE || Z_TYPE_P(param) == IS_OBJECT) {
 				php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
 				return 1;
 			}
-			convert_to_boolean(var);
-			bind_data = (zend_long *)&Z_LVAL_P(var);
-			if (Z_TYPE_P(var) == IS_TRUE)
+			convert_to_boolean(param);
+			bind_data = (zend_long *)&Z_LVAL_P(param);
+			if (Z_TYPE_P(param) == IS_TRUE)
 				*(zend_long *)bind_data = 1;
-			else if (Z_TYPE_P(var) == IS_FALSE)
+			else if (Z_TYPE_P(param) == IS_FALSE)
 				*(zend_long *)bind_data = 0;
 			else {
 				php_error_docref(NULL, E_WARNING, "Invalid variable used for bind");
@@ -1234,6 +1241,10 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 
 	if ((old_bind = zend_hash_str_find_ptr(statement->binds, name, name_len)) != NULL) {
 		bindp = old_bind;
+		if (!Z_ISUNDEF(bindp->parameter)) {
+			zval_ptr_dtor(&bindp->parameter);
+			ZVAL_UNDEF(&bindp->parameter);
+		}
 	} else {
 		zend_string *zvtmp;
 		zvtmp = zend_string_init(name, name_len, 0);
@@ -1241,16 +1252,20 @@ int php_oci_bind_by_name(php_oci_statement *statement, char *name, size_t name_l
 		bindp = zend_hash_update_ptr(statement->binds, zvtmp, bindp);
 		zend_string_release(zvtmp);
 	}
-    /* Make sure the minimum of value_sz is 1 to avoid ORA-3149 
-     * when both in/out parameters are bound with empty strings
-     */
+
+	/* Keep a copy of bound variable in the bind hash */
+	ZVAL_COPY(&bindp->parameter, var);
+
+	/* Make sure the minimum of value_sz is 1 to avoid ORA-3149 
+	 * when both in/out parameters are bound with empty strings
+	 */
 	if (value_sz == 0)
 		value_sz = 1;
 	
 	bindp->descriptor = oci_desc;
 	bindp->statement = oci_stmt;
 	bindp->parent_statement = statement;
-	bindp->zval = var;
+	bindp->zval = param;
 	bindp->type = type;
 	/* Storing max length set in OCIBindByName() to check it later in
 	 * php_oci_bind_in_callback() function to avoid ORA-1406 error while
@@ -1510,7 +1525,7 @@ php_oci_out_column *php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAME
 		convert_to_long(&tmp);
 		column = php_oci_statement_get_column(statement, Z_LVAL(tmp), NULL, 0);
 		if (!column) {
-			php_error_docref(NULL, E_WARNING, "Invalid column index \"" ZEND_LONG_FMT "\"", Z_LVAL(tmp));
+			php_error_docref(NULL, E_WARNING, "Invalid column index \"%pd\"", Z_LVAL(tmp));
 			zval_dtor(&tmp);
 			return NULL;
 		}
@@ -1577,7 +1592,7 @@ int php_oci_bind_array_by_name(php_oci_statement *statement, char *name, size_t
 	convert_to_array(var);
 
 	if (maxlength < -1) {
-		php_error_docref(NULL, E_WARNING, "Invalid max length value (" ZEND_LONG_FMT ")", maxlength);
+		php_error_docref(NULL, E_WARNING, "Invalid max length value (%pd)", maxlength);
 		return 1;
 	}
 	
@@ -1608,7 +1623,7 @@ int php_oci_bind_array_by_name(php_oci_statement *statement, char *name, size_t
 			bind = php_oci_bind_array_helper_date(var, max_table_length, statement->connection);
 			break;
 		default:
-			php_error_docref(NULL, E_WARNING, "Unknown or unsupported datatype given: " ZEND_LONG_FMT, type);
+			php_error_docref(NULL, E_WARNING, "Unknown or unsupported datatype given: %pd", type);
 			return 1;
 			break;
 	}
diff --git a/ext/oci8/package.xml b/ext/oci8/package.xml
index 29b5d6d..9c243a9 100644
--- a/ext/oci8/package.xml
+++ b/ext/oci8/package.xml
@@ -46,12 +46,12 @@ Interoperability Support" (ID 207303.1) for details.
   <active>no</active>
  </lead>
 
- <date>2016-08-18</date>
+ <date>2016-09-14</date>
  <time>12:00:00</time>
 
   <version>
-   <release>2.1.2</release>
-   <api>2.1.2</api>
+   <release>2.1.3</release>
+   <api>2.1.3</api>
   </version>
   <stability>
    <release>stable</release>
@@ -60,8 +60,7 @@ Interoperability Support" (ID 207303.1) for details.
   <license uri="http://www.php.net/license">PHP</license>
   <notes>
 This version is for PHP 7 only.
-Fixed invalid handle error with Implicit Result Sets
-Fixed bug #72524 (Binding null values triggers ORA-24816 error)
+Fixed bug #71148 (Bind reference overwritten on PHP 7)
   </notes>
  <contents>
   <dir name="/">
@@ -471,6 +470,23 @@ Fixed bug #72524 (Binding null values triggers ORA-24816 error)
 
 <release>
   <version>
+   <release>2.1.2</release>
+   <api>2.1.2</api>
+  </version>
+  <stability>
+   <release>stable</release>
+   <api>stable</api>
+  </stability>
+  <license uri="http://www.php.net/license">PHP</license>
+  <notes>
+This version is for PHP 7 only.
+Fixed invalid handle error with Implicit Result Sets
+Fixed bug #72524 (Binding null values triggers ORA-24816 error)
+  </notes>
+</release>
+
+<release>
+  <version>
    <release>2.1.1</release>
    <api>2.1.1</api>
   </version>
diff --git a/ext/oci8/php_oci8.h b/ext/oci8/php_oci8.h
index 70200e4..ef9b35d 100644
--- a/ext/oci8/php_oci8.h
+++ b/ext/oci8/php_oci8.h
@@ -43,7 +43,7 @@
  */
 #undef PHP_OCI8_VERSION
 #endif
-#define PHP_OCI8_VERSION "2.1.2"
+#define PHP_OCI8_VERSION "2.1.3"
 
 extern zend_module_entry oci8_module_entry;
 #define phpext_oci8_ptr &oci8_module_entry
diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h
index 3a63504..1d66f05 100644
--- a/ext/oci8/php_oci8_int.h
+++ b/ext/oci8/php_oci8_int.h
@@ -243,6 +243,7 @@ typedef struct {
 typedef struct { 
 	OCIBind				*bind;					/* bind handle */
 	zval				*zval;					/* value */
+	zval				parameter;				/* a copy of bound variable used for oci_bind_by_name */
 	dvoid				*descriptor;			/* used for binding of LOBS etc */
 	OCIStmt				*statement;				/* used for binding REFCURSORs */
 	php_oci_statement	*parent_statement;		/* pointer to the parent statement */
diff --git a/ext/oci8/tests/driver_name.phpt b/ext/oci8/tests/driver_name.phpt
index 9814703..d24044e 100644
--- a/ext/oci8/tests/driver_name.phpt
+++ b/ext/oci8/tests/driver_name.phpt
@@ -57,11 +57,11 @@ function get_attr($conn)
 ?>
 --EXPECT--
 **Test 1.1 - Default values for the attribute **************
-The value of DRIVER_NAME is PHP OCI8 : 2.1.2
+The value of DRIVER_NAME is PHP OCI8 : 2.1.3
 
 ***Test 1.2 - Get the values from different connections **************
 Testing with oci_pconnect()
-The value of DRIVER_NAME is PHP OCI8 : 2.1.2
+The value of DRIVER_NAME is PHP OCI8 : 2.1.3
 Testing with oci_new_connect()
-The value of DRIVER_NAME is PHP OCI8 : 2.1.2
+The value of DRIVER_NAME is PHP OCI8 : 2.1.3
 Done
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue Mar 28 00:01:34 2017 UTC