]> granicus.if.org Git - php/commitdiff
Add GC support for PDO driver data
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 2 Oct 2020 08:53:21 +0000 (10:53 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 12 Oct 2020 11:00:41 +0000 (13:00 +0200)
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.

ext/pdo/pdo_dbh.c
ext/pdo/php_pdo_driver.h
ext/pdo_dblib/dblib_driver.c
ext/pdo_firebird/firebird_driver.c
ext/pdo_mysql/mysql_driver.c
ext/pdo_oci/oci_driver.c
ext/pdo_odbc/odbc_driver.c
ext/pdo_pgsql/pgsql_driver.c
ext/pdo_sqlite/sqlite_driver.c
ext/pdo_sqlite/tests/gc.phpt [new file with mode: 0644]

index 2e81db2bbf52d29131f9a042609fed959bd416bb..25ee7afb2e9df15c3db493c9db0e26cc4dc52361 100644 (file)
@@ -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);
 }
 
index 960ddec4efe089b8e22a439e353550448742fa3c..974eb0bad020961ccef263f52e95976d2e998a5a 100644 (file)
@@ -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;
 };
 
 /* }}} */
index 7f160a402f7e23b2fb23b60693cd2bab0a6e480c..e581642037d3ebdd93b6df2acf7cadc862dcd1e9 100644 (file)
@@ -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)
index c27a9e2ed553aeb81fc96f533c1b0c014579b567..c299907f0fea10fc9d70eda8dd863c40fdd0b5e8 100644 (file)
@@ -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 */
 };
 /* }}} */
 
index a666489a503f98ebf329aa237ada68ca92b63fa3..19923464e4c1bee4ac1e100f447809a3b9b17806 100644 (file)
@@ -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 */
 };
 /* }}} */
 
index 096a26575ef0c0a991ef0c87b643774eb18cfe21..2c65fc973ba321fb0553dc189e146a8b3ad9b4dd 100644 (file)
@@ -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) /* {{{ */
index 9a254553d5b31564508bbb53a2ed359da51d11e5..81e4915da56f15773adcd012a060008f5f17a895 100644 (file)
@@ -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) /* {{{ */
index d800d65a2df0e9f38d2d09bb85fd0958da1bffaa..37680b8efacd375353363b02e0942fe8ec38b83a 100644 (file)
@@ -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) /* {{{ */
index 26fa1c00eb82968c51f802722baf2393ee85c89f..a8a96c7a131f647e95c287be1c360ff4e834588f 100644 (file)
@@ -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 (file)
index 0000000..2540769
--- /dev/null
@@ -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===