-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Pdo sub classing rough WIP #8707
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
Changes from 30 commits
86f5b53
9d69e0e
c5317fc
357fffa
a3f77cc
b60f678
d95dbfb
6377bb0
479859e
6cbe69e
df94bbf
a1b050e
fd96e22
835c38b
a4b3fcf
a987f0c
5f80549
4454698
cd97c9d
524c893
83bb08c
8803312
08abcf4
9f95d8b
51487c2
4572b8d
4439f57
6aafba0
43acd48
23aab3c
61d8ae2
bb3a634
589c950
48e458b
b51d423
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -218,10 +218,42 @@ static char *dsn_from_uri(char *uri, char *buf, size_t buflen) /* {{{ */ | |
} | ||
/* }}} */ | ||
|
||
/* {{{ */ | ||
PHP_METHOD(PDO, __construct) | ||
|
||
#define MAX_PDO_SUB_CLASSES 64 | ||
static int number_of_pdo_driver_class_entries = 0; | ||
static pdo_driver_class_entry *pdo_driver_class_entries[MAX_PDO_SUB_CLASSES]; | ||
|
||
// It would be possible remove this and roll it into the standard driver class entries | ||
// I chose not to do it at this time, as that would break existing PDO extensions | ||
void pdo_register_driver_specific_class(pdo_driver_class_entry *driver_class_entry) | ||
{ | ||
if (number_of_pdo_driver_class_entries >= MAX_PDO_SUB_CLASSES) { | ||
|
||
} | ||
|
||
pdo_driver_class_entries[number_of_pdo_driver_class_entries] = driver_class_entry; | ||
number_of_pdo_driver_class_entries += 1; | ||
} | ||
|
||
|
||
static | ||
void create_specific_pdo_object(zval *new_object, const char *driver_name) | ||
{ | ||
for (int i=0; i < number_of_pdo_driver_class_entries; i += 1) { | ||
pdo_driver_class_entry *driver_class_entry = pdo_driver_class_entries[i]; | ||
if (strcmp(driver_class_entry->driver_name, driver_name) == 0) { | ||
object_init_ex(new_object, driver_class_entry->driver_ce); | ||
return; | ||
} | ||
} | ||
|
||
// No specific DB implementation found | ||
object_init_ex(new_object, pdo_dbh_ce); | ||
} | ||
|
||
static | ||
void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zval *object, zval *new_zval_object) | ||
{ | ||
zval *object = ZEND_THIS; | ||
pdo_dbh_t *dbh = NULL; | ||
bool is_persistent = 0; | ||
char *data_source; | ||
|
@@ -288,7 +320,25 @@ PHP_METHOD(PDO, __construct) | |
RETURN_THROWS(); | ||
} | ||
|
||
dbh = Z_PDO_DBH_P(object); | ||
if (object == NULL) { | ||
// could this ever happen? | ||
if (driver->driver_name == NULL) { | ||
zend_throw_exception_ex(php_pdo_get_exception(), 0, "Driver name is NULL"); | ||
RETURN_THROWS(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so like:
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that would do the trick! |
||
|
||
create_specific_pdo_object(new_zval_object, driver->driver_name); | ||
|
||
if (new_zval_object == NULL) { | ||
zend_throw_exception_ex(php_pdo_get_exception(), 0, "Failed to create specific PDO class"); | ||
RETURN_THROWS(); | ||
} | ||
|
||
dbh = Z_PDO_DBH_P(new_zval_object); | ||
} | ||
else { | ||
Girgias marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dbh = Z_PDO_DBH_P(object); | ||
} | ||
|
||
/* is this supposed to be a persistent connection ? */ | ||
if (options) { | ||
|
@@ -429,8 +479,24 @@ PHP_METHOD(PDO, __construct) | |
zend_throw_exception(pdo_exception_ce, "Constructor failed", 0); | ||
} | ||
} | ||
|
||
/* {{{ */ | ||
PHP_METHOD(PDO, __construct) | ||
{ | ||
zval *object = ZEND_THIS; | ||
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, object, NULL); | ||
} | ||
/* }}} */ | ||
|
||
|
||
/* {{{ */ | ||
PHP_METHOD(PDO, connect) | ||
{ | ||
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, NULL, return_value); | ||
} | ||
/* }}} */ | ||
|
||
|
||
static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args) /* {{{ */ | ||
{ | ||
if (!Z_ISUNDEF_P(ctor_args)) { | ||
|
@@ -1323,6 +1389,8 @@ static HashTable *dbh_get_gc(zend_object *object, zval **gc_data, int *gc_count) | |
} | ||
|
||
static zend_object_handlers pdo_dbh_object_handlers; | ||
static zend_object_handlers pdosqlite_dbh_object_handlers; | ||
|
||
static void pdo_dbh_free_storage(zend_object *std); | ||
|
||
void pdo_dbh_init(void) | ||
|
@@ -1423,6 +1491,15 @@ void pdo_dbh_init(void) | |
|
||
REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY", (zend_long)PDO_CURSOR_FWDONLY); | ||
REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL", (zend_long)PDO_CURSOR_SCROLL); | ||
|
||
|
||
memcpy(&pdosqlite_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); | ||
pdosqlite_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_object_t, std); | ||
pdosqlite_dbh_object_handlers.free_obj = pdo_dbh_free_storage; | ||
pdosqlite_dbh_object_handlers.clone_obj = NULL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You shouldn't need to specify the clone handler IIRC as it is NULL by default? Same as the compare handler. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed the clone_obj. Not sure what you meant for the compare handler, as that is not set to NULL. |
||
pdosqlite_dbh_object_handlers.get_method = dbh_method_get; | ||
pdosqlite_dbh_object_handlers.compare = zend_objects_not_comparable; | ||
pdosqlite_dbh_object_handlers.get_gc = dbh_get_gc; | ||
} | ||
|
||
static void dbh_free(pdo_dbh_t *dbh, bool free_persistent) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -215,6 +215,16 @@ typedef struct { | |
|
||
} pdo_driver_t; | ||
|
||
// NOTE - This separate struct, could be rolled it into pdo_driver_t | ||
// I chose not to, as that would cause BC break and require a lot of | ||
// downstream work. | ||
typedef struct { | ||
char *driver_name; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if it makes sense to have this be a zend_string that is interned by the driver on startup. But that can be a future improvement. |
||
zend_class_entry *driver_ce; | ||
} pdo_driver_class_entry; | ||
|
||
void pdo_register_driver_specific_class(pdo_driver_class_entry *driver_class_entry); | ||
|
||
/* {{{ methods for a database handle */ | ||
|
||
/* close or otherwise disconnect the database */ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<?php | ||
|
||
/** @generate-class-entries */ | ||
|
||
/** @not-serializable */ | ||
class PdoDblib extends PDO | ||
{ | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* This is a generated file, edit the .stub.php file instead. | ||
* Stub hash: 06c2f52a638c1ca9c56bcbebdc00367bb3eb9b26 */ | ||
|
||
|
||
|
||
|
||
static const zend_function_entry class_PdoDblib_methods[] = { | ||
ZEND_FE_END | ||
}; | ||
|
||
static zend_class_entry *register_class_PdoDblib(zend_class_entry *class_entry_PDO) | ||
{ | ||
zend_class_entry ce, *class_entry; | ||
|
||
INIT_CLASS_ENTRY(ce, "PdoDblib", class_PdoDblib_methods); | ||
class_entry = zend_register_internal_class_ex(&ce, class_entry_PDO); | ||
class_entry->ce_flags |= ZEND_ACC_NOT_SERIALIZABLE; | ||
|
||
return class_entry; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
function getDsnUserAndPassword() | ||
{ | ||
|
||
if (false !== getenv('PDO_DBLIB_TEST_DSN')) { | ||
$dsn = getenv('PDO_DBLIB_TEST_DSN'); | ||
} else { | ||
$dsn = 'dblib:host=localhost;dbname=test'; | ||
} | ||
|
||
if (false !== getenv('PDO_DBLIB_TEST_USER')) { | ||
$user = getenv('PDO_DBLIB_TEST_USER'); | ||
} else { | ||
$user = 'php'; | ||
} | ||
|
||
if (false !== getenv('PDO_DBLIB_TEST_PASS')) { | ||
$pass = getenv('PDO_DBLIB_TEST_PASS'); | ||
} else { | ||
$pass = 'password'; | ||
} | ||
return [$dsn, $user, $pass]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
--TEST-- | ||
PdoDblib basic | ||
--EXTENSIONS-- | ||
pdo | ||
--FILE-- | ||
<?php | ||
|
||
require_once __DIR__ . "/../config_functions.inc"; | ||
|
||
if (class_exists(PdoDblib::class) === false) { | ||
echo "PdoDblib class does not exist.\n"; | ||
exit(-1); | ||
} | ||
echo "PdoDblib class exists.\n"; | ||
|
||
|
||
[$dsn, $user, $pass] = getDsnUserAndPassword(); | ||
|
||
$db = new PdoDblib($dsn, $user, $pass); | ||
|
||
$db->query('drop table if exists #foobar;'); | ||
|
||
$db->query("create table #foobar(name varchar(32)); "); | ||
$db->query("insert into #foobar values('PHP');"); | ||
$db->query("insert into #foobar values('PHP6');"); | ||
|
||
foreach ($db->query('SELECT name FROM #foobar') as $row) { | ||
var_dump($row); | ||
} | ||
|
||
$db->query('drop table #foobar;'); | ||
|
||
echo "Fin."; | ||
?> | ||
--EXPECT-- | ||
PdoDblib class exists. | ||
array(2) { | ||
["name"]=> | ||
string(3) "PHP" | ||
[0]=> | ||
string(3) "PHP" | ||
} | ||
array(2) { | ||
["name"]=> | ||
string(4) "PHP6" | ||
[0]=> | ||
string(4) "PHP6" | ||
} | ||
Fin. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
--TEST-- | ||
PdoDblib create through PDO::connect | ||
--EXTENSIONS-- | ||
pdo | ||
--FILE-- | ||
<?php | ||
|
||
require_once __DIR__ . "/../config_functions.inc"; | ||
|
||
if (class_exists(PdoDblib::class) === false) { | ||
echo "PdoDblib class does not exist.\n"; | ||
exit(-1); | ||
} | ||
|
||
echo "PdoDblib class exists.\n"; | ||
|
||
[$dsn, $user, $pass] = getDsnUserAndPassword(); | ||
|
||
$db = Pdo::connect($dsn, $user, $pass); | ||
|
||
if (!$db instanceof PdoDblib) { | ||
echo "Wrong class type. Should be PdoDblib but is [" . get_class($db) . "\n"; | ||
} | ||
|
||
$db->query('drop table if exists #test;'); | ||
|
||
$db->query("create table #test(name varchar(32)); "); | ||
$db->query("insert into #test values('PHP');"); | ||
$db->query("insert into #test values('PHP6');"); | ||
|
||
foreach ($db->query('SELECT name FROM #test') as $row) { | ||
var_dump($row); | ||
} | ||
|
||
$db->query('drop table #test;'); | ||
|
||
echo "Fin."; | ||
?> | ||
--EXPECT-- | ||
PdoDblib class exists. | ||
array(2) { | ||
["name"]=> | ||
string(3) "PHP" | ||
[0]=> | ||
string(3) "PHP" | ||
} | ||
array(2) { | ||
["name"]=> | ||
string(4) "PHP6" | ||
[0]=> | ||
string(4) "PHP6" | ||
} | ||
Fin. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be unsigned int
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k.