[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pecl-cvs
Subject:    [PECL-CVS] com =?UTF-8?Q?pecl/database/mysql=5Fxdevapi=3A=20orabug=20=23=33=30=32=32?= =?UTF-8?Q?=36
From:       hery ramilison <mysqlre () php ! net>
Date:       2019-08-26 17:31:08
Message-ID: php-mail-984e041fe177b6a6338955279439f390423642128 () git ! php ! net
[Download RAW message or body]

Commit:    9110609c57833ab43cb40325aa3c17720102b048
Author:    Darek Slusarczyk <dariusz.slusarczyk@oracle.com>         Mon, 26 Aug 2019 \
                19:30:25 +0200
Parents:   cba371016cff36efbe32a0705d4f5bcd0fb2fa15
Branches:  release/8.0.18

Link:       http://git.php.net/?p=pecl/database/mysql_xdevapi.git;a=commitdiff;h=9110609c57833ab43cb40325aa3c17720102b048


Log:
orabug #30226232: incorrect behaviour of chained CRUD ops in webserver mode
- CRUD Collection.Add: fix wrong management of raw zvals which was the main reason of \
                incorrect behaviour (in Collection_add there was kept zval* \
                object_zv;)
- fix related tests/add_with_empty_arg_is_noop.phpt
- add json_api.h header to safely include <ext/json/...> headers
- improvements in util::zvalue

Bugs:
https://bugs.php.net/30226232

Changed paths:
  A  json_api.h
  M  mysqlx_collection.cc
  M  mysqlx_collection__add.cc
  M  mysqlx_collection__add.h
  M  mysqlx_table__insert.cc
  M  php_api.h
  M  tests/add_with_empty_arg_is_noop.phpt
  M  util/json_utils.cc
  M  util/json_utils.h
  M  util/value.cc
  M  util/value.h
  M  util/value.inl


["diff_9110609c57833ab43cb40325aa3c17720102b048.txt" (text/plain)]

diff --git a/json_api.h b/json_api.h
new file mode 100644
index 0000000..ea1e47d
--- /dev/null
+++ b/json_api.h
@@ -0,0 +1,27 @@
+/*
+  +----------------------------------------------------------------------+
+  | PHP Version 7                                                        |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2006-2019 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: Darek Slusarczyk <marines@php.net>                          |
+  +----------------------------------------------------------------------+
+*/
+#ifndef MYSQL_XDEVAPI_JSON_API_H
+#define MYSQL_XDEVAPI_JSON_API_H
+
+extern "C" {
+#include <ext/json/php_json.h>
+#include <ext/json/php_json_parser.h>
+#include <zend_smart_str.h>
+}
+
+#endif // MYSQL_XDEVAPI_JSON_API_H
diff --git a/mysqlx_collection.cc b/mysqlx_collection.cc
index c006bca..c0911b3 100644
--- a/mysqlx_collection.cc
+++ b/mysqlx_collection.cc
@@ -562,7 +562,7 @@ MYSQL_XDEVAPI_PHP_METHOD(mysqlx_collection, addOrReplaceOne)
 	Collection_add coll_add;
 	zval doc_with_id;
 	util::json::ensure_doc_id(doc, id, &doc_with_id);
-	if (!coll_add.add_docs(object_zv, data_object.collection, id, &doc_with_id)) {
+	if (!coll_add.add_docs(data_object.collection, id, &doc_with_id)) {
 		DBG_VOID_RETURN;
 	}
 
diff --git a/mysqlx_collection__add.cc b/mysqlx_collection__add.cc
index 4161c7a..5a9a6ee 100644
--- a/mysqlx_collection__add.cc
+++ b/mysqlx_collection__add.cc
@@ -17,10 +17,7 @@
 */
 #include "php_api.h"
 #include "mysqlnd_api.h"
-extern "C" {
-#include <ext/json/php_json.h>
-#include <ext/json/php_json_parser.h>
-}
+#include "json_api.h"
 #include "xmysqlnd/xmysqlnd.h"
 #include "xmysqlnd/xmysqlnd_session.h"
 #include "xmysqlnd/xmysqlnd_schema.h"
@@ -61,40 +58,20 @@ ZEND_END_ARG_INFO()
 
 //------------------------------------------------------------------------------
 
-
 /* {{{ execute_statement */
 enum_func_status
-execute_statement(xmysqlnd_stmt* stmt,zval* return_value)
+execute_statement(xmysqlnd_stmt& stmt, zval* resultset)
 {
-	enum_func_status ret{FAIL};
-	if (stmt) {
-		zval stmt_zv;
-		ZVAL_UNDEF(&stmt_zv);
-		mysqlx_new_stmt(&stmt_zv, stmt);
-		if (Z_TYPE(stmt_zv) == IS_NULL) {
-			xmysqlnd_stmt_free(stmt, nullptr, nullptr);
-		}
-		if (Z_TYPE(stmt_zv) == IS_OBJECT) {
-			zval zv;
-			ZVAL_UNDEF(&zv);
-			zend_long flags{0};
-			mysqlx_statement_execute_read_response(Z_MYSQLX_P(&stmt_zv),
-								flags, MYSQLX_RESULT, &zv);
-			ZVAL_COPY(return_value, &zv);
-			zval_dtor(&zv);
-			ret = PASS;
-		}
-		zval_ptr_dtor(&stmt_zv);
-	}
-	return ret;
+	util::zvalue stmt_zv;
+	mysqlx_new_stmt(stmt_zv.ptr(), &stmt);
+	if (!stmt_zv.is_object()) return FAIL;
+	zend_long flags{0};
+	mysqlx_statement_execute_read_response(Z_MYSQLX_P(stmt_zv.ptr()),
+						flags, MYSQLX_RESULT, resultset);
+	return PASS;
 }
 /* }}} */
 
-
-#define ID_COLUMN_NAME		"_id"
-#define ID_TEMPLATE_PREFIX	"\"" ID_COLUMN_NAME "\":\""
-#define ID_TEMPLATE_SUFFIX	"\"}"
-
 enum class Add_op_status
 {
 	success,
@@ -112,10 +89,9 @@ struct doc_add_op_return_status
 Add_op_status
 collection_add_string(
 	st_xmysqlnd_crud_collection_op__add* add_op,
-	zval* doc,
-	zval* /*return_value*/)
+	util::zvalue& doc)
 {
-	if( PASS == xmysqlnd_crud_collection_add__add_doc(add_op,doc) ) {
+	if( PASS == xmysqlnd_crud_collection_add__add_doc(add_op, doc.ptr()) ) {
 		return Add_op_status::success;
 	}
 	return Add_op_status::fail;
@@ -125,49 +101,32 @@ collection_add_string(
 
 /* {{{ collection_add_object*/
 Add_op_status
-collection_add_object_impl(
+collection_add_object(
 	st_xmysqlnd_crud_collection_op__add* add_op,
-	zval* doc,
-	zval* /*return_value*/)
+	util::zvalue& doc)
 {
-	zval new_doc;
+	util::zvalue new_doc;
 	Add_op_status ret = Add_op_status::fail;
-	util::json::to_zv_string(doc, &new_doc);
-	if( PASS == xmysqlnd_crud_collection_add__add_doc(add_op, &new_doc) ) {
+	util::json::to_zv_string(doc, new_doc);
+	if( PASS == xmysqlnd_crud_collection_add__add_doc(add_op, new_doc.ptr()) ) {
 		ret = Add_op_status::success;
 	}
-	zval_dtor(&new_doc);
 	return ret;
 }
 /* }}} */
 
 
-/* {{{ collection_add_object*/
-Add_op_status
-collection_add_object(
-	st_xmysqlnd_crud_collection_op__add* add_op,
-	zval* doc,
-	zval* return_value)
-{
-	return collection_add_object_impl(
-				add_op, doc, return_value);
-}
-/* }}} */
-
-
 /* {{{ collection_add_array*/
 Add_op_status
 collection_add_array(
 	st_xmysqlnd_crud_collection_op__add* add_op,
-	zval* doc,
-	zval* return_value)
+	util::zvalue& doc)
 {
 	Add_op_status ret = Add_op_status::fail;
-	if( zend_hash_num_elements(Z_ARRVAL_P(doc)) == 0 ) {
+	if( doc.empty() ) {
 		ret = Add_op_status::noop;
 	} else {
-		ret = collection_add_object_impl(
-			add_op, doc, return_value);
+		ret = collection_add_object(add_op, doc);
 	}
 	return ret;
 }
@@ -180,12 +139,11 @@ collection_add_array(
 
 /* {{{ Collection_add::init() */
 bool Collection_add::add_docs(
-	zval* obj_zv,
 	xmysqlnd_collection* coll,
 	zval* documents,
 	int num_of_documents)
 {
-	if (!obj_zv || !documents || !num_of_documents) return false;
+	if (!documents || !num_of_documents) return false;
 
 	for (int i{0}; i < num_of_documents; ++i) {
 		if (Z_TYPE(documents[i]) != IS_STRING &&
@@ -198,20 +156,15 @@ bool Collection_add::add_docs(
 
 	if( !add_op ) {
 		if( !coll ) return false;
-		object_zv = obj_zv;
 		collection = coll->get_reference();
 		add_op = xmysqlnd_crud_collection_add__create(
 			mnd_str2c(collection->get_schema()->get_name()),
 			mnd_str2c(collection->get_name()));
 		if (!add_op) return false;
-	} else {
-		ZVAL_COPY(obj_zv, object_zv);
 	}
 
-	zval doc;
 	for (int i{0}; i < num_of_documents; ++i) {
-		ZVAL_DUP(&doc, &documents[i]);
-		docs.push_back( doc );
+		docs.push_back(util::zvalue::clone_from(&documents[i]));
 	}
 
 	return true;
@@ -221,13 +174,12 @@ bool Collection_add::add_docs(
 
 /* {{{ Collection_add::init() */
 bool Collection_add::add_docs(
-	zval* obj_zv,
 	xmysqlnd_collection* coll,
 	const util::string_view& /*doc_id*/,
 	zval* doc)
 {
 	const int num_of_documents = 1;
-	if (!add_docs(obj_zv, coll, doc, num_of_documents)) return false;
+	if (!add_docs(coll, doc, num_of_documents)) return false;
 	return xmysqlnd_crud_collection_add__set_upsert(add_op) == PASS;
 }
 /* }}} */
@@ -236,11 +188,6 @@ bool Collection_add::add_docs(
 /* {{{ Collection_add::~Collection_add() */
 Collection_add::~Collection_add()
 {
-	for (size_t i{0}; i < docs.size(); ++i) {
-		zval_ptr_dtor(&docs[i]);
-		ZVAL_UNDEF(&docs[i]);
-	}
-
 	if (add_op) {
 		xmysqlnd_crud_collection_add__destroy(add_op);
 	}
@@ -253,30 +200,24 @@ Collection_add::~Collection_add()
 
 
 /* {{{ Collection_add::execute() */
-void Collection_add::execute(zval* return_value)
+void Collection_add::execute(zval* resultset)
 {
-	enum_func_status execute_ret_status{PASS};
-	size_t noop_cnt{0};
-
 	DBG_ENTER("Collection_add::execute");
 
-	RETVAL_FALSE;
-
+	size_t noop_cnt{0};
 	Add_op_status ret = Add_op_status::success;
-	for (size_t i{0}; i < docs.size() && ret != Add_op_status::fail ; ++i) {
+	for (auto it{docs.begin()}; it != docs.end() && ret != Add_op_status::fail ; ++it) \
{  ret = Add_op_status::fail;
-		switch(Z_TYPE(docs[i])) {
-		case IS_STRING:
-			ret = collection_add_string(
-				add_op, &docs[i], return_value);
+		auto& doc{ *it };
+		switch(doc.type()) {
+		case util::zvalue::Type::String:
+			ret = collection_add_string(add_op, doc);
 			break;
-		case IS_ARRAY:
-			ret = collection_add_array(
-				add_op, &docs[i], return_value);
+		case util::zvalue::Type::Array:
+			ret = collection_add_array(add_op, doc);
 			break;
-		case IS_OBJECT:
-			ret = collection_add_object(
-				add_op, &docs[i], return_value);
+		case util::zvalue::Type::Object:
+			ret = collection_add_object(add_op, doc);
 			break;
 		}
 		if( ret == Add_op_status::noop ) {
@@ -284,10 +225,11 @@ void Collection_add::execute(zval* return_value)
 		}
 	}
 
-	if ( execute_ret_status != FAIL && docs.size() > noop_cnt ) {
+	enum_func_status execute_ret_status{PASS};
+	if ( docs.size() > noop_cnt ) {
 		xmysqlnd_stmt* stmt = collection->add(add_op);
 		if( nullptr != stmt ) {
-			execute_ret_status =  execute_statement(stmt,return_value);
+			execute_ret_status = execute_statement(*stmt, resultset);
 		} else {
 			execute_ret_status = FAIL;
 		}
@@ -314,10 +256,9 @@ MYSQL_XDEVAPI_PHP_METHOD(mysqlx_collection__add, __construct)
 /* {{{ proto mixed mysqlx_collection__add::execute() */
 MYSQL_XDEVAPI_PHP_METHOD(mysqlx_collection__add, execute)
 {
-	zval* object_zv{nullptr};
-
 	DBG_ENTER("mysqlx_collection__add::execute");
 
+	zval* object_zv{nullptr};
 	if (FAILURE == util::zend::parse_method_parameters(execute_data, getThis(), "O",
 												&object_zv,
 												collection_add_class_entry))
@@ -355,7 +296,9 @@ MYSQL_XDEVAPI_PHP_METHOD(mysqlx_collection__add, add)
 	 * For subsequent calls to add_docs, the xmysqlnd_collection is set to NULL
 	 */
 	Collection_add& coll_add = util::fetch_data_object<Collection_add>(object_zv);
-	coll_add.add_docs(return_value, nullptr, docs, num_of_docs);
+	if (coll_add.add_docs(nullptr, docs, num_of_docs)) {
+		util::zvalue::copy_to(object_zv, return_value);
+	}
 
 	DBG_VOID_RETURN;
 }
@@ -477,7 +420,7 @@ mysqlx_new_collection__add(
 	if (SUCCESS == object_init_ex(return_value, collection_add_class_entry) && \
IS_OBJECT == Z_TYPE_P(return_value)) {  const st_mysqlx_object* const mysqlx_object = \
Z_MYSQLX_P(return_value);  Collection_add* const coll_add = \
                static_cast<Collection_add*>(mysqlx_object->ptr);
-		if (!coll_add || !coll_add->add_docs(return_value, collection, docs, num_of_docs)) \
{ +		if (!coll_add || !coll_add->add_docs(collection, docs, num_of_docs)) {
 			php_error_docref(nullptr, E_WARNING, "invalid object of class %s", \
ZSTR_VAL(mysqlx_object->zo.ce->name));  zval_ptr_dtor(return_value);
 			ZVAL_NULL(return_value);
diff --git a/mysqlx_collection__add.h b/mysqlx_collection__add.h
index eb9d0f3..86be291 100644
--- a/mysqlx_collection__add.h
+++ b/mysqlx_collection__add.h
@@ -18,6 +18,8 @@
 #ifndef MYSQLX_COLLECTION__ADD_H
 #define MYSQLX_COLLECTION__ADD_H
 
+#include "util/value.h"
+
 namespace mysqlx {
 
 namespace drv {
@@ -39,24 +41,21 @@ public:
 	~Collection_add();
 
 	bool add_docs(
-		zval* object_zv,
 		drv::xmysqlnd_collection* collection,
 		zval* docs,
 		int num_of_docs);
 	bool add_docs(
-		zval* object_zv,
 		drv::xmysqlnd_collection* collection,
 		const util::string_view& single_doc_id,
 		zval* doc);
 
 public:
-	void execute(zval* return_value);
+	void execute(zval* resultset);
 
 private:
-	zval* object_zv{nullptr};
 	drv::xmysqlnd_collection* collection{nullptr};
 	drv::st_xmysqlnd_crud_collection_op__add* add_op{nullptr};
-	std::vector<zval> docs;
+	std::vector<util::zvalue> docs;
 };
 /* }}} */
 
diff --git a/mysqlx_table__insert.cc b/mysqlx_table__insert.cc
index 632fcf0..dc99dcf 100644
--- a/mysqlx_table__insert.cc
+++ b/mysqlx_table__insert.cc
@@ -17,10 +17,7 @@
 */
 #include "php_api.h"
 #include "mysqlnd_api.h"
-extern "C" {
-#include <ext/json/php_json.h>
-#include <zend_smart_str.h>
-}
+#include "json_api.h"
 #include "xmysqlnd/xmysqlnd.h"
 #include "xmysqlnd/xmysqlnd_session.h"
 #include "xmysqlnd/xmysqlnd_schema.h"
diff --git a/php_api.h b/php_api.h
index 716a9c8..1d5590c 100644
--- a/php_api.h
+++ b/php_api.h
@@ -62,7 +62,7 @@ extern "C" {
 	ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val) \
 	MYSQLX_RESTORE_WARNINGS()
 
-#else
+#else // UNIX OSes
 
 #define MYSQLX_HASH_FOREACH_VAL ZEND_HASH_FOREACH_VAL
 #define MYSQLX_HASH_FOREACH_PTR	ZEND_HASH_FOREACH_PTR
@@ -70,5 +70,4 @@ extern "C" {
 
 #endif
 
-
 #endif // MYSQL_XDEVAPI_PHP_API_H
diff --git a/tests/add_with_empty_arg_is_noop.phpt \
b/tests/add_with_empty_arg_is_noop.phpt index ed95fc0..5c04761 100644
--- a/tests/add_with_empty_arg_is_noop.phpt
+++ b/tests/add_with_empty_arg_is_noop.phpt
@@ -16,7 +16,7 @@ error_reporting=0
 
 		$result = $coll->add([])->execute();//Single noop
 
-		expect_false($result);
+		expect_null($result);
 
 		$res = $coll->find()->execute()->fetchAll();
 		expect_empty_array($res);
@@ -30,13 +30,13 @@ error_reporting=0
 		expect_eq($result->getAffectedItemsCount(), 2);
 
 		$result = $coll->add([])->execute();//Again noop
-		expect_false($result);
+		expect_null($result);
 
 		$res = $coll->find()->execute()->fetchAll();
 		expect_eq(count($res),2);
 
 		$result = $coll->add([],[],[])->execute(); //Perverted case...
-		expect_false($result);
+		expect_null($result);
 		$res = $coll->find()->execute()->fetchAll();
 		expect_eq(count($res),2);
 
diff --git a/util/json_utils.cc b/util/json_utils.cc
index 051a8e1..647527a 100644
--- a/util/json_utils.cc
+++ b/util/json_utils.cc
@@ -59,6 +59,11 @@ void to_zv_string(zval* src, zval* dest)
 }
 /* }}} */
 
+void to_zv_string(util::zvalue& src, util::zvalue& dest)
+{
+	to_zv_string(src.ptr(), dest.ptr());
+}
+
 namespace {
 
 class Ensure_doc_id
diff --git a/util/json_utils.h b/util/json_utils.h
index 9f85722..7a1b049 100644
--- a/util/json_utils.h
+++ b/util/json_utils.h
@@ -27,9 +27,12 @@ namespace mysqlx {
 
 namespace util {
 
+class zvalue;
+
 namespace json {
 
 void to_zv_string(zval* src, zval* dest);
+void to_zv_string(util::zvalue& src, util::zvalue& dest);
 
 void ensure_doc_id(
 	zval* raw_doc,
diff --git a/util/value.cc b/util/value.cc
index 159ec95..f764cb2 100644
--- a/util/value.cc
+++ b/util/value.cc
@@ -512,27 +512,47 @@ zvalue zvalue::clone() const
 	return result;
 }
 
-void zvalue::acquire(zval* other)
+zvalue zvalue::clone_from(zval* src)
 {
-	assert(other);
+	zvalue result;
+	ZVAL_DUP(&result.zv, src);
+	return result;
+}
+
+void zvalue::acquire(zval* src)
+{
+	assert(src);
 	zval_ptr_dtor(&zv);
-	ZVAL_ZVAL(&zv, other, 1, 1);
-	ZVAL_UNDEF(other);
+	ZVAL_ZVAL(&zv, src, 1, 1);
+	ZVAL_UNDEF(src);
 }
 
-void zvalue::copy_to(zval* other)
+void zvalue::copy_to(zval* dst)
 {
-	assert(other);
-	ZVAL_ZVAL(other, &zv, 1, 0);
+	assert(dst);
+	ZVAL_ZVAL(dst, &zv, 1, 0);
 }
 
-void zvalue::move_to(zval* other)
+void zvalue::copy_to(zval* src, zval* dst)
 {
-	assert(other);
-	ZVAL_ZVAL(other, &zv, 1, 1);
+	assert(src && dst);
+	ZVAL_ZVAL(dst, src, 1, 0);
+}
+
+void zvalue::move_to(zval* dst)
+{
+	assert(dst);
+	ZVAL_ZVAL(dst, &zv, 1, 1);
 	ZVAL_UNDEF(&zv);
 }
 
+void zvalue::move_to(zval* src, zval* dst)
+{
+	assert(src && dst);
+	ZVAL_ZVAL(dst, src, 1, 1);
+	ZVAL_UNDEF(src);
+}
+
 zval zvalue::release()
 {
 	zval other;
diff --git a/util/value.h b/util/value.h
index 48e6cf7..7167406 100644
--- a/util/value.h
+++ b/util/value.h
@@ -187,6 +187,8 @@ class zvalue
 		// new fully separated item, not just next reference incremented
 		zvalue clone() const;
 
+		static zvalue clone_from(zval* src);
+
 		// take over ownership of passed zval
 		void acquire(zval* zv);
 		void acquire(zval& zv);
@@ -195,10 +197,14 @@ class zvalue
 		void copy_to(zval* zv);
 		void copy_to(zval& zv);
 
+		static void copy_to(zval* src, zval* dst);
+
 		// moves value to zv, and sets type to undefined
 		void move_to(zval* zv);
 		void move_to(zval& zv);
 
+		static void move_to(zval* src, zval* dst);
+
 		// increment / decrement reference counter if type is refcounted, else does \
nothing  void inc_ref() const;
 		void dec_ref() const;
diff --git a/util/value.inl b/util/value.inl
index 5d8666a..0f0f980 100644
--- a/util/value.inl
+++ b/util/value.inl
@@ -260,19 +260,19 @@ inline bool zvalue::empty() const
 	return size() == 0;
 }
 
-inline void zvalue::acquire(zval& zv)
+inline void zvalue::acquire(zval& src)
 {
-	acquire(&zv);
+	acquire(&src);
 }
 
-inline void zvalue::copy_to(zval& zv)
+inline void zvalue::copy_to(zval& dst)
 {
-	copy_to(&zv);
+	copy_to(&dst);
 }
 
-inline void zvalue::move_to(zval& zv)
+inline void zvalue::move_to(zval& dst)
 {
-	move_to(&zv);
+	move_to(&dst);
 }
 
 inline void zvalue::inc_ref() const



-- 
PECL CVS Mailing List 
To unsubscribe, visit: http://www.php.net/unsub.php

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic