summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-10-02 10:53:21 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-10-12 13:00:41 +0200
commite735de6eae4a60fb55fac6fc99b6b63f525c4b4b (patch)
tree667d76200945389a8a274dd061bd3fe5739a8f5b
parentd731b764e527e2dc6d9a297a80174296c960ed90 (diff)
downloadphp-git-e735de6eae4a60fb55fac6fc99b6b63f525c4b4b.tar.gz
Add GC support for PDO driver data
Add a get_gc method that can be implemented by drivers, which can be used to add additional zvals to the GC buffer. Implement GC support for PDO SQLite callbacks in particular. Closes GH-6262.
-rw-r--r--ext/pdo/pdo_dbh.c8
-rw-r--r--ext/pdo/php_pdo_driver.h5
-rw-r--r--ext/pdo_dblib/dblib_driver.c3
-rw-r--r--ext/pdo_firebird/firebird_driver.c6
-rw-r--r--ext/pdo_mysql/mysql_driver.c3
-rw-r--r--ext/pdo_oci/oci_driver.c7
-rw-r--r--ext/pdo_odbc/odbc_driver.c6
-rw-r--r--ext/pdo_pgsql/pgsql_driver.c1
-rw-r--r--ext/pdo_sqlite/sqlite_driver.c22
-rw-r--r--ext/pdo_sqlite/tests/gc.phpt24
10 files changed, 75 insertions, 10 deletions
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c
index 2e81db2bbf..25ee7afb2e 100644
--- a/ext/pdo/pdo_dbh.c
+++ b/ext/pdo/pdo_dbh.c
@@ -1291,8 +1291,12 @@ static int dbh_compare(zval *object1, zval *object2)
static HashTable *dbh_get_gc(zend_object *object, zval **gc_data, int *gc_count)
{
pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(object);
- *gc_data = &dbh->def_stmt_ctor_args;
- *gc_count = 1;
+ zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
+ zend_get_gc_buffer_add_zval(gc_buffer, &dbh->def_stmt_ctor_args);
+ if (dbh->methods->get_gc) {
+ dbh->methods->get_gc(dbh, gc_buffer);
+ }
+ zend_get_gc_buffer_use(gc_buffer, gc_data, gc_count);
return zend_std_get_properties(object);
}
diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h
index 960ddec4ef..974eb0bad0 100644
--- a/ext/pdo/php_pdo_driver.h
+++ b/ext/pdo/php_pdo_driver.h
@@ -286,6 +286,10 @@ typedef int (*pdo_dbh_check_liveness_func)(pdo_dbh_t *dbh);
* scope */
typedef void (*pdo_dbh_request_shutdown)(pdo_dbh_t *dbh);
+/* Called when the PDO handle is scanned for GC. Should populate the get_gc buffer
+ * with any zvals in the driver_data that would be freed if the handle is destroyed. */
+typedef void (*pdo_dbh_get_gc_func)(pdo_dbh_t *dbh, zend_get_gc_buffer *buffer);
+
/* for adding methods to the dbh or stmt objects
pointer to a list of driver specific functions. The convention is
to prefix the function names using the PDO driver name; this will
@@ -316,6 +320,7 @@ struct pdo_dbh_methods {
pdo_dbh_get_driver_methods_func get_driver_methods;
pdo_dbh_request_shutdown persistent_shutdown;
pdo_dbh_txn_func in_transaction;
+ pdo_dbh_get_gc_func get_gc;
};
/* }}} */
diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c
index 7f160a402f..e581642037 100644
--- a/ext/pdo_dblib/dblib_driver.c
+++ b/ext/pdo_dblib/dblib_driver.c
@@ -417,7 +417,8 @@ static const struct pdo_dbh_methods dblib_methods = {
NULL, /* check liveness */
NULL, /* get driver methods */
NULL, /* request shutdown */
- NULL /* in transaction */
+ NULL, /* in transaction */
+ NULL /* get gc */
};
static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c
index c27a9e2ed5..c299907f0f 100644
--- a/ext/pdo_firebird/firebird_driver.c
+++ b/ext/pdo_firebird/firebird_driver.c
@@ -1005,7 +1005,11 @@ static const struct pdo_dbh_methods firebird_methods = { /* {{{ */
NULL, /* last_id not supported */
pdo_firebird_fetch_error_func,
firebird_handle_get_attribute,
- NULL /* check_liveness */
+ NULL, /* check_liveness */
+ NULL, /* get driver methods */
+ NULL, /* request shutdown */
+ NULL, /* in transaction */
+ NULL /* get gc */
};
/* }}} */
diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
index a666489a50..19923464e4 100644
--- a/ext/pdo_mysql/mysql_driver.c
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -563,7 +563,8 @@ static const struct pdo_dbh_methods mysql_methods = {
pdo_mysql_check_liveness,
NULL,
pdo_mysql_request_shutdown,
- pdo_mysql_in_transaction
+ pdo_mysql_in_transaction,
+ NULL /* get_gc */
};
/* }}} */
diff --git a/ext/pdo_oci/oci_driver.c b/ext/pdo_oci/oci_driver.c
index 096a26575e..2c65fc973b 100644
--- a/ext/pdo_oci/oci_driver.c
+++ b/ext/pdo_oci/oci_driver.c
@@ -705,9 +705,10 @@ static const struct pdo_dbh_methods oci_methods = {
pdo_oci_fetch_error_func,
oci_handle_get_attribute,
pdo_oci_check_liveness, /* check_liveness */
- NULL, /* get_driver_methods */
- NULL,
- NULL
+ NULL, /* get_driver_methods */
+ NULL, /* request_shutdown */
+ NULL, /* in_transaction */
+ NULL /* get_gc */
};
static int pdo_oci_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */
diff --git a/ext/pdo_odbc/odbc_driver.c b/ext/pdo_odbc/odbc_driver.c
index 9a254553d5..81e4915da5 100644
--- a/ext/pdo_odbc/odbc_driver.c
+++ b/ext/pdo_odbc/odbc_driver.c
@@ -384,7 +384,11 @@ static const struct pdo_dbh_methods odbc_methods = {
NULL, /* last id */
pdo_odbc_fetch_error_func,
odbc_handle_get_attr, /* get attr */
- NULL, /* check_liveness */
+ NULL, /* check_liveness */
+ NULL, /* get_driver_methods */
+ NULL, /* request_shutdown */
+ NULL, /* in_transaction */
+ NULL /* get_gc */
};
static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */
diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c
index d800d65a2d..37680b8efa 100644
--- a/ext/pdo_pgsql/pgsql_driver.c
+++ b/ext/pdo_pgsql/pgsql_driver.c
@@ -1179,6 +1179,7 @@ static const struct pdo_dbh_methods pgsql_methods = {
pdo_pgsql_get_driver_methods, /* get_driver_methods */
NULL,
pgsql_handle_in_transaction,
+ NULL /* get_gc */
};
static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{ */
diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c
index 26fa1c00eb..a8a96c7a13 100644
--- a/ext/pdo_sqlite/sqlite_driver.c
+++ b/ext/pdo_sqlite/sqlite_driver.c
@@ -695,6 +695,25 @@ static void pdo_sqlite_request_shutdown(pdo_dbh_t *dbh)
}
}
+static void pdo_sqlite_get_gc(pdo_dbh_t *dbh, zend_get_gc_buffer *gc_buffer)
+{
+ pdo_sqlite_db_handle *H = dbh->driver_data;
+
+ struct pdo_sqlite_func *func = H->funcs;
+ while (func) {
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->func);
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->step);
+ zend_get_gc_buffer_add_zval(gc_buffer, &func->fini);
+ func = func->next;
+ }
+
+ struct pdo_sqlite_collation *collation = H->collations;
+ while (collation) {
+ zend_get_gc_buffer_add_zval(gc_buffer, &collation->callback);
+ collation = collation->next;
+ }
+}
+
static const struct pdo_dbh_methods sqlite_methods = {
sqlite_handle_closer,
sqlite_handle_preparer,
@@ -710,7 +729,8 @@ static const struct pdo_dbh_methods sqlite_methods = {
NULL, /* check_liveness: not needed */
get_driver_methods,
pdo_sqlite_request_shutdown,
- NULL
+ NULL, /* in_transaction */
+ pdo_sqlite_get_gc
};
static char *make_filename_safe(const char *filename)
diff --git a/ext/pdo_sqlite/tests/gc.phpt b/ext/pdo_sqlite/tests/gc.phpt
new file mode 100644
index 0000000000..25407697e6
--- /dev/null
+++ b/ext/pdo_sqlite/tests/gc.phpt
@@ -0,0 +1,24 @@
+--TEST--
+GC support for PDO Sqlite driver data
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+
+class Obj {
+ public $a;
+ public function callback() { }
+}
+
+$obj = new Obj;
+$obj->a = new PDO('sqlite::memory:');
+$obj->a->sqliteCreateFunction('func1', function() use ($obj) {}, 1);
+$obj->a->sqliteCreateAggregate('func2', function() use ($obj) {}, function() use($obj) {});
+$obj->a->sqliteCreateCollation('col', function() use ($obj) {});
+
+?>
+===DONE===
+--EXPECT--
+===DONE===