Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ext/pdo: Turn lazy_object_ref into a zend_object* #17646

Merged
merged 3 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions ext/pdo/pdo_dbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -659,8 +659,6 @@ PHP_METHOD(PDO, prepare)
/* give it a reference to me */
GC_ADDREF(&dbh_obj->std);
stmt->database_object_handle = &dbh_obj->std;
/* we haven't created a lazy object yet */
ZVAL_UNDEF(&stmt->lazy_object_ref);

if (dbh->methods->preparer(dbh, statement, stmt, options)) {
if (Z_TYPE(ctor_args) == IS_ARRAY) {
Expand Down Expand Up @@ -1225,8 +1223,6 @@ PHP_METHOD(PDO, query)
/* give it a reference to me */
GC_ADDREF(&dbh_obj->std);
stmt->database_object_handle = &dbh_obj->std;
/* we haven't created a lazy object yet */
ZVAL_UNDEF(&stmt->lazy_object_ref);

if (dbh->methods->preparer(dbh, statement, stmt, NULL)) {
PDO_STMT_CLEAR_ERR();
Expand Down
16 changes: 8 additions & 8 deletions ext/pdo/pdo_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,17 +206,17 @@ PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count)
stmt->column_count = new_count;
}

static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */
static void pdo_get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */
{
if (Z_ISUNDEF(stmt->lazy_object_ref)) {
if (stmt->lazy_object_ref == NULL) {
pdo_row_t *row = zend_object_alloc(sizeof(pdo_row_t), pdo_row_ce);
row->stmt = stmt;
zend_object_std_init(&row->std, pdo_row_ce);
ZVAL_OBJ(&stmt->lazy_object_ref, &row->std);
stmt->lazy_object_ref = &row->std;
GC_ADDREF(&stmt->std);
GC_DELREF(&row->std);
}
ZVAL_COPY(return_value, &stmt->lazy_object_ref);
ZVAL_OBJ_COPY(return_value, stmt->lazy_object_ref);
}
/* }}} */

Expand Down Expand Up @@ -685,7 +685,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h
}

if (how == PDO_FETCH_LAZY) {
get_lazy_object(stmt, return_value);
pdo_get_lazy_object(stmt, return_value);
return true;
}

Expand Down Expand Up @@ -2369,16 +2369,16 @@ static zval *pdo_row_get_property_ptr_ptr(zend_object *object, zend_string *name
return NULL;
}

void pdo_row_free_storage(zend_object *std)
static void pdo_row_free_storage(zend_object *std)
{
pdo_row_t *row = php_pdo_row_fetch_object(std);
if (row->stmt) {
ZVAL_UNDEF(&row->stmt->lazy_object_ref);
row->stmt->lazy_object_ref = NULL;
OBJ_RELEASE(&row->stmt->std);
}
}

zend_object *pdo_row_new(zend_class_entry *ce)
static zend_object *pdo_row_new(zend_class_entry *ce)
{
pdo_row_t *row = zend_object_alloc(sizeof(pdo_row_t), ce);
zend_object_std_init(&row->std, ce);
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/php_pdo_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ struct _pdo_stmt_t {

/* for lazy fetches, we always return the same lazy object handle.
* Let's keep it here. */
zval lazy_object_ref;
zend_object *lazy_object_ref;

pdo_dbh_t *dbh;
/* we want to keep the dbh alive while we live, so we own a reference */
Expand Down
2 changes: 0 additions & 2 deletions ext/pdo/php_pdo_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@ bool pdo_stmt_describe_columns(pdo_stmt_t *stmt);
bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num,
zval *args, uint32_t variadic_num_args);

extern zend_object *pdo_row_new(zend_class_entry *ce);
extern const zend_function_entry pdo_row_functions[];
extern zend_class_entry *pdo_row_ce;
void pdo_row_free_storage(zend_object *std);
extern zend_object_handlers pdo_row_object_handlers;

zend_object_iterator *php_pdo_dbstmt_iter_get(zend_class_entry *ce, zval *object);
Expand Down
30 changes: 29 additions & 1 deletion ext/pdo/tests/pdo_027.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ $db->exec('create table test027 (id int, name varchar(10))');
$db->exec("INSERT INTO test027 (id,name) VALUES(1,'test1')");
$db->exec("INSERT INTO test027 (id,name) VALUES(2,'test2')");

foreach ($db->query("SELECT * FROM test027", PDO::FETCH_LAZY) as $v) {
$alias = null;
$r = $db->query("SELECT * FROM test027", PDO::FETCH_LAZY);
var_dump($r);
foreach ($r as $v) {
var_dump($alias === $v);
var_dump($v);
$alias = $v;
echo "lazy: " . $v->id.$v->name."\n";
}
echo "End\n";
Expand All @@ -31,6 +37,28 @@ $db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "test027");
?>
--EXPECT--
object(PDOStatement)#2 (1) {
["queryString"]=>
string(21) "SELECT * FROM test027"
}
bool(false)
object(PDORow)#4 (3) {
["queryString"]=>
string(21) "SELECT * FROM test027"
["id"]=>
string(1) "1"
["name"]=>
string(5) "test1"
}
lazy: 1test1
bool(true)
object(PDORow)#4 (3) {
["queryString"]=>
string(21) "SELECT * FROM test027"
["id"]=>
string(1) "2"
["name"]=>
string(5) "test2"
}
lazy: 2test2
End
90 changes: 90 additions & 0 deletions ext/pdo/tests/pdo_fetch_lazy_as_default.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
--TEST--
PDO Common: PDO::FETCH_LAZY set via PDOStatement::setFetchMode()
--DESCRIPTION--
This test uses an EXPECT section because we want to know the object handlers
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('CREATE TABLE pdo_fetch_lazy_as_default_changed(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10), grp VARCHAR(10))');
// Firebird does not allow inserting multiple rows with INSERT INTO
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (1, 'A', 'alpha', 'Group1')");
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (2, 'B', 'beta', 'Group1')");
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (3, 'C', 'gamma', 'Group2')");
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (4, 'D', 'delta', 'Group2')");

function to_upper_with_log(string $str): string {
echo __FUNCTION__, '(', var_export($str, true), ')', PHP_EOL;
return strtoupper($str);
}

$pdoQuery = $db->prepare('SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed');
$pdoQuery->execute();
$pdoQuery->setFetchMode(PDO::FETCH_LAZY);

class Test {
public $val1;
public $val2;
}
$o = new Test();

var_dump($pdoQuery->fetch());
var_dump($pdoQuery->fetchObject(Test::class));
var_dump($pdoQuery->fetch());
$pdoQuery->setFetchMode(PDO::FETCH_INTO, $o);
var_dump($pdoQuery->fetch());
var_dump($o);

?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_fetch_lazy_as_default_changed");
?>
--EXPECT--
object(PDORow)#4 (3) {
["queryString"]=>
string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed"
["val2"]=>
string(5) "alpha"
["val1"]=>
string(1) "A"
}
object(Test)#4 (2) {
["val1"]=>
string(1) "B"
["val2"]=>
string(4) "beta"
}
object(PDORow)#4 (3) {
["queryString"]=>
string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed"
["val2"]=>
string(5) "gamma"
["val1"]=>
string(1) "C"
}
object(Test)#3 (2) {
["val1"]=>
string(1) "D"
["val2"]=>
string(5) "delta"
}
object(Test)#3 (2) {
["val1"]=>
string(1) "D"
["val2"]=>
string(5) "delta"
}
89 changes: 89 additions & 0 deletions ext/pdo/tests/pdo_fetch_lazy_as_not_default.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
--TEST--
PDO Common: PDO::FETCH_LAZY when FETCH_INTO set via PDOStatement::setFetchMode()
--DESCRIPTION--
This test uses an EXPECT section because we want to know the object handlers
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('CREATE TABLE pdo_fetch_lazy_as_default_changed(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10), grp VARCHAR(10))');
// Firebird does not allow inserting multiple rows with INSERT INTO
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (1, 'A', 'alpha', 'Group1')");
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (2, 'B', 'beta', 'Group1')");
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (3, 'C', 'gamma', 'Group2')");
$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (4, 'D', 'delta', 'Group2')");

function to_upper_with_log(string $str): string {
echo __FUNCTION__, '(', var_export($str, true), ')', PHP_EOL;
return strtoupper($str);
}

$pdoQuery = $db->prepare('SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed');
$pdoQuery->execute();

class Test {
public $val1;
public $val2;
}
$o = new Test();

$pdoQuery->setFetchMode(PDO::FETCH_INTO, $o);

var_dump($pdoQuery->fetch());
var_dump($pdoQuery->fetch(PDO::FETCH_LAZY));
var_dump($pdoQuery->fetch());

$another_obj = new stdClass();
var_dump($another_obj);

var_dump($pdoQuery->fetch(PDO::FETCH_LAZY));

?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_fetch_lazy_as_default_changed");
?>
--EXPECT--
object(Test)#3 (2) {
["val1"]=>
string(1) "A"
["val2"]=>
string(5) "alpha"
}
object(PDORow)#4 (3) {
["queryString"]=>
string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed"
["val2"]=>
string(4) "beta"
["val1"]=>
string(1) "B"
}
object(Test)#3 (2) {
["val1"]=>
string(1) "C"
["val2"]=>
string(5) "gamma"
}
object(stdClass)#4 (0) {
}
object(PDORow)#5 (3) {
["queryString"]=>
string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed"
["val2"]=>
string(5) "delta"
["val1"]=>
string(1) "D"
}
37 changes: 37 additions & 0 deletions ext/pdo/tests/pdo_query_fetch_lazy001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
PDO Common: PDO::query() with PDO::FETCH_LAZY unused result
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('create table pdo_query_fetch_lazy_001 (id int, name varchar(10))');
$db->exec("INSERT INTO pdo_query_fetch_lazy_001 (id,name) VALUES(1,'test1')");
$db->exec("INSERT INTO pdo_query_fetch_lazy_001 (id,name) VALUES(2,'test2')");

$r = $db->query("SELECT * FROM pdo_query_fetch_lazy_001", PDO::FETCH_LAZY);
var_dump($r);
echo "End\n";
?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_query_fetch_lazy_001");
?>
--EXPECT--
object(PDOStatement)#2 (1) {
["queryString"]=>
string(38) "SELECT * FROM pdo_query_fetch_lazy_001"
}
End
Loading