1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Implement PDO driver-specific subclasses

RFC: https://wiki.php.net/rfc/pdo_driver_specific_subclasses
Closes GH-12804

Co-Authored-By: Danack <Danack@basereality.com>
This commit is contained in:
Máté Kocsis
2024-01-11 22:58:28 +01:00
parent b985a31b0a
commit d6a0b3af68
132 changed files with 3181 additions and 201 deletions

11
NEWS
View File

@@ -60,22 +60,33 @@ OpenSSL:
PDO:
. Fixed setAttribute and getAttribute (SakiTakamachi)
. Implement PDO driver-specific subclasses RFC (danack, kocsismate)
PDO_DBLIB:
. Fixed setAttribute and getAttribute (SakiTakamachi)
. Added class PdoDbLib (danack, kocsismate)
PDO_FIREBIRD:
. Fixed setAttribute and getAttribute (SakiTakamachi)
. Feature: Add transaction isolation level and mode settings to pdo_firebird
(SakiTakamachi)
. Added class PdoFirebird. (danack, kocsismate)
PDO_MYSQL:
. Fixed setAttribute and getAttribute (SakiTakamachi)
. Added class PdoMysql. (danack, kocsismate)
PDO_ODBC:
. Added class PdoOdbc. (danack, kocsismate)
PDO_PGSQL:
. Fixed GH-12423, DSN credentials being prioritized over the user/password
PDO constructor arguments. (SakiTakamachi)
. Fixed native float support with pdo_pgsql query results. (Yurunsoft)
. Added class PdoPgsql. (danack, kocsismate)
PDO_SQLITE:
. Added class PdoSqlite. (danack, kocsismate)
PGSQL:
. Added the possibility to have no conditions for pg_select. (OmarEmaraDev)

View File

@@ -152,6 +152,33 @@ PHP 8.4 UPGRADE NOTES
- Phar:
. Added support for the unix timestamp extension for zip archives.
- PDO:
. Added support for driver-specific subclasses.
RFC: https://wiki.php.net/rfc/pdo_driver_specific_subclasses
This RFC adds subclasses for PDO in order to better support
database-specific functionalities. The new classes are
instantiatable either via calling the PDO::connect() method
or by invoking their constructor directly.
PDO_DBLIB:
. Fixed setAttribute and getAttribute (SakiTakamachi)
. Added PdoDbLib class (danack, kocsismate)
PDO_FIREBIRD:
. Added class PdoFirebird.
PDO_MYSQL:
. Added class PdoMysql.
PDO_ODBC:
. Added class PdoOdbc.
PDO_PGSQL:
. Added class PdoPgsql.
PDO_SQLITE:
. Added class PdoSqlite.
- POSIX:
. Added constant POSIX_SC_CHILD_MAX
. Added constant POSIX_SC_CLK_TCK

View File

@@ -41,6 +41,9 @@ zend_class_entry *pdo_exception_ce;
/* the registry of PDO drivers */
HashTable pdo_driver_hash;
/* the registry of PDO driver specific class entries */
HashTable pdo_driver_specific_ce_hash;
/* we use persistent resources for the driver connection stuff */
static int le_ppdo;
@@ -115,7 +118,7 @@ PDO_API zend_result php_pdo_register_driver(const pdo_driver_t *driver) /* {{{ *
return FAILURE;
}
if (!zend_hash_str_exists(&module_registry, "pdo", sizeof("pdo") - 1)) {
zend_error_noreturn(E_ERROR, "You MUST load PDO before loading any PDO drivers");
zend_error_noreturn(E_ERROR, "The PDO extension must be loaded first in order to load PDO drivers");
return FAILURE; /* NOTREACHED */
}
@@ -129,10 +132,22 @@ PDO_API void php_pdo_unregister_driver(const pdo_driver_t *driver) /* {{{ */
return;
}
zend_hash_str_del(&pdo_driver_specific_ce_hash, driver->driver_name, driver->driver_name_len);
zend_hash_str_del(&pdo_driver_hash, driver->driver_name, driver->driver_name_len);
}
/* }}} */
PDO_API zend_result php_pdo_register_driver_specific_ce(const pdo_driver_t *driver, zend_class_entry *ce) /* {{{ */
{
if (!zend_hash_str_exists(&module_registry, "pdo", sizeof("pdo") - 1)) {
zend_error_noreturn(E_ERROR, "The PDO extension must be loaded first in order to load PDO drivers");
return FAILURE; /* NOTREACHED */
}
return zend_hash_str_add_ptr(&pdo_driver_specific_ce_hash, driver->driver_name,
driver->driver_name_len, (void*)ce) != NULL ? SUCCESS : FAILURE;
}
pdo_driver_t *pdo_find_driver(const char *name, int namelen) /* {{{ */
{
return zend_hash_str_find_ptr(&pdo_driver_hash, name, namelen);
@@ -246,6 +261,7 @@ PHP_MINIT_FUNCTION(pdo)
pdo_sqlstate_init_error_table();
zend_hash_init(&pdo_driver_hash, 0, NULL, NULL, 1);
zend_hash_init(&pdo_driver_specific_ce_hash, 0, NULL, NULL, 1);
le_ppdo = zend_register_list_destructors_ex(NULL, php_pdo_pdbh_dtor,
"PDO persistent database", module_number);
@@ -263,6 +279,7 @@ PHP_MINIT_FUNCTION(pdo)
PHP_MSHUTDOWN_FUNCTION(pdo)
{
zend_hash_destroy(&pdo_driver_hash);
zend_hash_destroy(&pdo_driver_specific_ce_hash);
pdo_sqlstate_fini_error_table();
return SUCCESS;
}

View File

@@ -221,10 +221,64 @@ static char *dsn_from_uri(char *uri, char *buf, size_t buflen) /* {{{ */
}
/* }}} */
/* {{{ */
PHP_METHOD(PDO, __construct)
static bool create_driver_specific_pdo_object(pdo_driver_t *driver, zend_class_entry *called_scope, zval *new_object)
{
zend_class_entry *ce;
zend_class_entry *ce_based_on_driver_name = NULL, *ce_based_on_called_object = NULL;
ce_based_on_driver_name = zend_hash_str_find_ptr(&pdo_driver_specific_ce_hash, driver->driver_name, driver->driver_name_len);
ZEND_HASH_MAP_FOREACH_PTR(&pdo_driver_specific_ce_hash, ce) {
if (called_scope != pdo_dbh_ce && instanceof_function(called_scope, ce)) {
ce_based_on_called_object = called_scope;
break;
}
} ZEND_HASH_FOREACH_END();
if (ce_based_on_called_object) {
if (ce_based_on_driver_name) {
if (instanceof_function(ce_based_on_called_object, ce_based_on_driver_name) == false) {
zend_throw_exception_ex(pdo_exception_ce, 0,
"%s::connect() cannot be called when connecting to the \"%s\" driver, "
"either %s::connect() or PDO::connect() must be called instead",
ZSTR_VAL(called_scope->name), driver->driver_name, ZSTR_VAL(ce_based_on_driver_name->name));
return false;
}
/* A driver-specific implementation was instantiated via the connect() method of the appropriate driver class */
object_init_ex(new_object, ce_based_on_called_object);
return true;
} else {
zend_throw_exception_ex(pdo_exception_ce, 0,
"%s::connect() cannot be called when connecting to an unknown driver, "
"PDO::connect() must be called instead",
ZSTR_VAL(called_scope->name));
return false;
}
}
if (ce_based_on_driver_name) {
if (called_scope != pdo_dbh_ce) {
/* A driver-specific implementation was instantiated via the connect method of a wrong driver class */
zend_throw_exception_ex(pdo_exception_ce, 0,
"%s::connect() cannot be called when connecting to the \"%s\" driver, "
"either %s::connect() or PDO::connect() must be called instead",
ZSTR_VAL(called_scope->name), driver->driver_name, ZSTR_VAL(ce_based_on_driver_name->name));
return false;
}
/* A driver-specific implementation was instantiated via PDO::__construct() */
object_init_ex(new_object, ce_based_on_driver_name);
} else {
/* No driver-specific implementation found */
object_init_ex(new_object, called_scope);
}
return true;
}
static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object, zend_class_entry *current_scope, zval *new_zval_object)
{
zval *object = ZEND_THIS;
pdo_dbh_t *dbh = NULL;
bool is_persistent = 0;
char *data_source;
@@ -291,7 +345,16 @@ PHP_METHOD(PDO, __construct)
RETURN_THROWS();
}
dbh = Z_PDO_DBH_P(object);
if (new_zval_object != NULL) {
ZEND_ASSERT((driver->driver_name != NULL) && "PDO driver name is null");
if (!create_driver_specific_pdo_object(driver, current_scope, new_zval_object)) {
RETURN_THROWS();
}
dbh = Z_PDO_DBH_P(new_zval_object);
} else {
dbh = php_pdo_dbh_fetch_inner(object);
}
/* is this supposed to be a persistent connection ? */
if (options) {
@@ -352,7 +415,7 @@ PHP_METHOD(PDO, __construct)
if (pdbh) {
efree(dbh);
/* switch over to the persistent one */
Z_PDO_OBJECT_P(object)->inner = pdbh;
php_pdo_dbh_fetch_object(object)->inner = pdbh;
pdbh->refcount++;
dbh = pdbh;
}
@@ -432,6 +495,19 @@ options:
zend_throw_exception(pdo_exception_ce, "Constructor failed", 0);
}
}
/* {{{ */
PHP_METHOD(PDO, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), EX(This).value.ce, NULL);
}
/* }}} */
/* {{{ */
PHP_METHOD(PDO, connect)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), EX(This).value.ce, return_value);
}
/* }}} */
static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args) /* {{{ */
@@ -1334,6 +1410,7 @@ static HashTable *dbh_get_gc(zend_object *object, zval **gc_data, int *gc_count)
}
static zend_object_handlers pdo_dbh_object_handlers;
static void pdo_dbh_free_storage(zend_object *std);
void pdo_dbh_init(int module_number)

View File

@@ -166,6 +166,13 @@ class PDO
public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
public static function connect(
string $dsn,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?array $options = null
): static {}
/** @tentative-return-type */
public function beginTransaction(): bool {}

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: acd95f74c8b95515d3177f55682f9ee50dd779e9 */
* Stub hash: 006be61b2c519e7d9ca997a7f12135eb3e0f3500 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0)
@@ -8,6 +8,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PDO_connect, 0, 1, IS_STATIC, 0)
ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, username, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, password, IS_STRING, 1, "null")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_PDO_beginTransaction, 0, 0, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
@@ -60,6 +67,7 @@ ZEND_END_ARG_INFO()
ZEND_METHOD(PDO, __construct);
ZEND_METHOD(PDO, connect);
ZEND_METHOD(PDO, beginTransaction);
ZEND_METHOD(PDO, commit);
ZEND_METHOD(PDO, errorCode);
@@ -78,6 +86,7 @@ ZEND_METHOD(PDO, setAttribute);
static const zend_function_entry class_PDO_methods[] = {
ZEND_ME(PDO, __construct, arginfo_class_PDO___construct, ZEND_ACC_PUBLIC)
ZEND_ME(PDO, connect, arginfo_class_PDO_connect, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
ZEND_ME(PDO, beginTransaction, arginfo_class_PDO_beginTransaction, ZEND_ACC_PUBLIC)
ZEND_ME(PDO, commit, arginfo_class_PDO_commit, ZEND_ACC_PUBLIC)
ZEND_ME(PDO, errorCode, arginfo_class_PDO_errorCode, ZEND_ACC_PUBLIC)
@@ -557,5 +566,7 @@ static zend_class_entry *register_class_PDO(void)
zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "__construct", sizeof("__construct") - 1), 2, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
zend_add_parameter_attribute(zend_hash_str_find_ptr(&class_entry->function_table, "connect", sizeof("connect") - 1), 2, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0);
return class_entry;
}

View File

@@ -37,7 +37,7 @@
#define PHP_STMT_GET_OBJ \
pdo_stmt_t *stmt = Z_PDO_STMT_P(ZEND_THIS); \
if (!stmt->dbh) { \
zend_throw_error(NULL, "PDO object is uninitialized"); \
zend_throw_error(NULL, "%s object is uninitialized", ZSTR_VAL(Z_OBJ(EX(This))->ce->name)); \
RETURN_THROWS(); \
} \
@@ -2231,7 +2231,7 @@ zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int
pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
if (!stmt->dbh) {
zend_throw_error(NULL, "PDO object is uninitialized");
zend_throw_error(NULL, "%s object is uninitialized", ZSTR_VAL(ce->name));
return NULL;
}

View File

@@ -19,9 +19,12 @@
#include "zend.h"
extern zend_module_entry pdo_module_entry;
PHPAPI extern zend_module_entry pdo_module_entry;
#define phpext_pdo_ptr &pdo_module_entry
PHPAPI extern zend_class_entry *pdo_dbh_ce;
PHPAPI extern zend_object *pdo_dbh_new(zend_class_entry *ce);
#include "php_version.h"
#define PHP_PDO_VERSION PHP_VERSION
@@ -50,14 +53,11 @@ PHP_MINFO_FUNCTION(pdo);
#define REGISTER_PDO_CLASS_CONST_LONG(const_name, value) \
zend_declare_class_constant_long(php_pdo_get_dbh_ce(), const_name, sizeof(const_name)-1, (zend_long)value);
#define REGISTER_PDO_CLASS_CONST_STRING(const_name, value) \
zend_declare_class_constant_stringl(php_pdo_get_dbh_ce(), const_name, sizeof(const_name)-1, value, sizeof(value)-1);
#define LONG_CONST(c) (zend_long) c
#define PDO_CONSTRUCT_CHECK \
if (!dbh->driver) { \
zend_throw_error(NULL, "PDO object is not initialized, constructor was not called"); \
zend_throw_error(NULL, "%s object is uninitialized", ZSTR_VAL(Z_OBJ(EX(This))->ce->name)); \
RETURN_THROWS(); \
} \

View File

@@ -653,6 +653,11 @@ PDO_API zend_result php_pdo_register_driver(const pdo_driver_t *driver);
/* call this in MSHUTDOWN to unregister your PDO driver */
PDO_API void php_pdo_unregister_driver(const pdo_driver_t *driver);
/* Call this in MINIT to register the PDO driver specific class entry.
* Registering the driver specific class entry might fail and should be reported accordingly in MINIT.
* Unregistering the class entry is not necessary, since php_pdo_unregister_driver() takes care of it. */
PDO_API zend_result php_pdo_register_driver_specific_ce(const pdo_driver_t *driver, zend_class_entry *ce);
/* For the convenience of drivers, this function will parse a data source
* string, of the form "name=value; name2=value2" and populate variables
* according to the data you pass in and array of pdo_data_src_parser structures */

View File

@@ -22,15 +22,14 @@
#include "php_pdo_error.h"
extern HashTable pdo_driver_hash;
extern HashTable pdo_driver_specific_ce_hash;
extern zend_class_entry *pdo_exception_ce;
int php_pdo_list_entry(void);
void pdo_dbh_init(int module_number);
void pdo_stmt_init(void);
extern zend_object *pdo_dbh_new(zend_class_entry *ce);
extern const zend_function_entry pdo_dbh_functions[];
extern zend_class_entry *pdo_dbh_ce;
extern ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor);
extern zend_object *pdo_dbstmt_new(zend_class_entry *ce);

View File

@@ -18,7 +18,7 @@ if (getenv('PDOTEST_DSN') === false) {
class PDOTest {
// create an instance of the PDO driver, based on
// the current environment
static function factory($classname = 'PDO') {
static function factory($classname = PDO::class) {
$dsn = getenv('PDOTEST_DSN');
$user = getenv('PDOTEST_USER');
$pass = getenv('PDOTEST_PASS');
@@ -54,12 +54,12 @@ class PDOTest {
}
}
static function test_factory($file) {
static function test_factory($file, $classname = PDO::class) {
$config = self::get_config($file);
foreach ($config['ENV'] as $k => $v) {
putenv("$k=$v");
}
return self::factory();
return self::factory($classname);
}
static function get_config($file) {

View File

@@ -34,6 +34,6 @@ try {
?>
--EXPECT--
PDO object is not initialized, constructor was not called
PDO object is uninitialized
PDO object is uninitialized
MyPDO object is uninitialized
MyPDOStatement object is uninitialized
MyPDOStatement object is uninitialized

View File

@@ -27,10 +27,13 @@
#include "php_pdo_dblib.h"
#include "php_pdo_dblib_int.h"
#include "zend_exceptions.h"
#include "pdo_dblib_arginfo.h"
ZEND_DECLARE_MODULE_GLOBALS(dblib)
static PHP_GINIT_FUNCTION(dblib);
static zend_class_entry *PdoDblib_ce;
static const zend_module_dep pdo_dblib_deps[] = {
ZEND_MOD_REQUIRED("pdo")
ZEND_MOD_END
@@ -201,6 +204,9 @@ PHP_MINIT_FUNCTION(pdo_dblib)
return FAILURE;
}
PdoDblib_ce = register_class_PdoDblib(pdo_dbh_ce);
PdoDblib_ce->create_object = pdo_dbh_new;
if (FAILURE == php_pdo_register_driver(&pdo_dblib_driver)) {
return FAILURE;
}
@@ -210,7 +216,7 @@ PHP_MINIT_FUNCTION(pdo_dblib)
dbmsghandle((MHANDLEFUNC) pdo_dblib_msg_handler);
#endif
return SUCCESS;
return php_pdo_register_driver_specific_ce(&pdo_dblib_driver, PdoDblib_ce);
}
PHP_MSHUTDOWN_FUNCTION(pdo_dblib)

View File

@@ -0,0 +1,31 @@
<?php
/** @generate-class-entries */
/**
* @strict-properties
* @not-serializable
*/
class PdoDblib extends PDO
{
/** @cvalue PDO_DBLIB_ATTR_CONNECTION_TIMEOUT */
public const int ATTR_CONNECTION_TIMEOUT = UNKNOWN;
/** @cvalue PDO_DBLIB_ATTR_QUERY_TIMEOUT */
public const int ATTR_QUERY_TIMEOUT = UNKNOWN;
/** @cvalue PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER */
public const int ATTR_STRINGIFY_UNIQUEIDENTIFIER = UNKNOWN;
/** @cvalue PDO_DBLIB_ATTR_VERSION */
public const int ATTR_VERSION = UNKNOWN;
/** @cvalue PDO_DBLIB_ATTR_TDS_VERSION */
public const int ATTR_TDS_VERSION = UNKNOWN;
/** @cvalue PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS */
public const int ATTR_SKIP_EMPTY_ROWSETS = UNKNOWN;
/** @cvalue PDO_DBLIB_ATTR_DATETIME_CONVERT */
public const int ATTR_DATETIME_CONVERT = UNKNOWN;
}

62
ext/pdo_dblib/pdo_dblib_arginfo.h generated Normal file
View File

@@ -0,0 +1,62 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: d2a7022c8e6e259b452786e00867b4a167d58277 */
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_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE;
zval const_ATTR_CONNECTION_TIMEOUT_value;
ZVAL_LONG(&const_ATTR_CONNECTION_TIMEOUT_value, PDO_DBLIB_ATTR_CONNECTION_TIMEOUT);
zend_string *const_ATTR_CONNECTION_TIMEOUT_name = zend_string_init_interned("ATTR_CONNECTION_TIMEOUT", sizeof("ATTR_CONNECTION_TIMEOUT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_CONNECTION_TIMEOUT_name, &const_ATTR_CONNECTION_TIMEOUT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_CONNECTION_TIMEOUT_name);
zval const_ATTR_QUERY_TIMEOUT_value;
ZVAL_LONG(&const_ATTR_QUERY_TIMEOUT_value, PDO_DBLIB_ATTR_QUERY_TIMEOUT);
zend_string *const_ATTR_QUERY_TIMEOUT_name = zend_string_init_interned("ATTR_QUERY_TIMEOUT", sizeof("ATTR_QUERY_TIMEOUT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_QUERY_TIMEOUT_name, &const_ATTR_QUERY_TIMEOUT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_QUERY_TIMEOUT_name);
zval const_ATTR_STRINGIFY_UNIQUEIDENTIFIER_value;
ZVAL_LONG(&const_ATTR_STRINGIFY_UNIQUEIDENTIFIER_value, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER);
zend_string *const_ATTR_STRINGIFY_UNIQUEIDENTIFIER_name = zend_string_init_interned("ATTR_STRINGIFY_UNIQUEIDENTIFIER", sizeof("ATTR_STRINGIFY_UNIQUEIDENTIFIER") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_STRINGIFY_UNIQUEIDENTIFIER_name, &const_ATTR_STRINGIFY_UNIQUEIDENTIFIER_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_STRINGIFY_UNIQUEIDENTIFIER_name);
zval const_ATTR_VERSION_value;
ZVAL_LONG(&const_ATTR_VERSION_value, PDO_DBLIB_ATTR_VERSION);
zend_string *const_ATTR_VERSION_name = zend_string_init_interned("ATTR_VERSION", sizeof("ATTR_VERSION") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_VERSION_name, &const_ATTR_VERSION_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_VERSION_name);
zval const_ATTR_TDS_VERSION_value;
ZVAL_LONG(&const_ATTR_TDS_VERSION_value, PDO_DBLIB_ATTR_TDS_VERSION);
zend_string *const_ATTR_TDS_VERSION_name = zend_string_init_interned("ATTR_TDS_VERSION", sizeof("ATTR_TDS_VERSION") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_TDS_VERSION_name, &const_ATTR_TDS_VERSION_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_TDS_VERSION_name);
zval const_ATTR_SKIP_EMPTY_ROWSETS_value;
ZVAL_LONG(&const_ATTR_SKIP_EMPTY_ROWSETS_value, PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS);
zend_string *const_ATTR_SKIP_EMPTY_ROWSETS_name = zend_string_init_interned("ATTR_SKIP_EMPTY_ROWSETS", sizeof("ATTR_SKIP_EMPTY_ROWSETS") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SKIP_EMPTY_ROWSETS_name, &const_ATTR_SKIP_EMPTY_ROWSETS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SKIP_EMPTY_ROWSETS_name);
zval const_ATTR_DATETIME_CONVERT_value;
ZVAL_LONG(&const_ATTR_DATETIME_CONVERT_value, PDO_DBLIB_ATTR_DATETIME_CONVERT);
zend_string *const_ATTR_DATETIME_CONVERT_name = zend_string_init_interned("ATTR_DATETIME_CONVERT", sizeof("ATTR_DATETIME_CONVERT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_DATETIME_CONVERT_name, &const_ATTR_DATETIME_CONVERT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_DATETIME_CONVERT_name);
return class_entry;
}

View File

@@ -5,13 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
// creating a proc need to be a statement in it's own batch, so we need to do a little setup first
$db->query("create table #test_batch_stmt_ins_exec(id int); ");
$db->query(

View File

@@ -5,13 +5,15 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->query(
"create table #test_batch_stmt_ins_sel_up_del(id int);" .
"insert into #test_batch_stmt_ins_sel_up_del values(1), (2), (3);" .

View File

@@ -5,13 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->query(
"create table #test_batch_stmt_ins_up(id int);" .
"insert into #test_batch_stmt_ins_up values(1), (2), (3);" .

View File

@@ -5,13 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->query(
"create table #test_batch_stmt_rowcount(id int); " .
"set rowcount 2; " .

View File

@@ -5,13 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->query(
"create table #test_batch_stmt_transaction(id int);" .
"insert into #test_batch_stmt_transaction values(1), (2), (3);" .

View File

@@ -5,13 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->query(
"create table #test_batch_stmt_try(id int);" .
"insert into #test_batch_stmt_try values(1), (2), (3);" .

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
/*We see these rows */
$db->query("CREATE table test38955(val int)");
$db->beginTransaction();
@@ -34,6 +37,7 @@ var_dump($rows);
--CLEAN--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db->exec("DROP TABLE IF EXISTS test38955");
?>
--EXPECT--

View File

@@ -5,6 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--CONFLICTS--
all
@@ -12,6 +13,7 @@ all
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->prepare("select top 1 ic1.* from information_schema.columns ic1");
$stmt->execute();
var_dump($stmt->getColumnMeta(0));

View File

@@ -5,11 +5,13 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db->query('CREATE TABLE "Test Table47588" ("My Field" int, "Another Field" varchar(32) not null default \'test_string\')');
$db->query('INSERT INTO "Test Table47588" ("My Field") values(1), (2), (3)');
$rs = $db->query('SELECT * FROM "Test Table47588"');
@@ -19,6 +21,7 @@ echo "Done.\n";
--CLEAN--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db->exec('DROP TABLE IF EXISTS "Test Table47588"');
?>
--EXPECT--

View File

@@ -6,6 +6,7 @@ pdo_dblib
<?php
if (getenv('SKIP_REPEAT')) die('skip May fail on repeat');
require __DIR__ . '/config.inc';
getDbConnection();
?>
--CONFLICTS--
all
@@ -13,6 +14,8 @@ all
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
/* This should be sufficient to overflow any buffers */
$stmt = $db->prepare("select *
from information_schema.columns ic1

View File

@@ -5,10 +5,12 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db->query('set dateformat ymd');
$rs = $db->query("select cast('1950-01-18 23:00:00' as smalldatetime) as sdt, cast('2030-01-01 23:59:59' as datetime) as dt");
var_dump($rs->fetchAll(PDO::FETCH_ASSOC));

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->query('SELECT 1; SELECT 2; SELECT 3;');
var_dump($stmt->fetch());
var_dump($stmt->fetch());

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$query = "declare @myInt int = 1; select @myInt;";
$stmt = $db->query($query);
$stmt->nextRowset(); // Added line

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$sql = '
SET NOCOUNT ON
SELECT 0 AS [result]

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$sql = "
exec dbo.sp_executesql N'
SELECT TOP 1 * FROM sysobjects

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->prepare("SELECT 1, 2 AS named, 3");
$stmt->execute();
var_dump($stmt->fetchAll());

View File

@@ -5,12 +5,15 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (in_array($db->getAttribute(PDO::DBLIB_ATTR_TDS_VERSION), ['4.2', '4.6', '5.0', '6.0', '7.0'])) die('skip bigint type is unsupported by active TDS version');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
// on 64-bit machines, these columns should come back as ints
// on 32-bit machines, they will come back as strings because zend_long isn't big enough
$expected = PHP_INT_SIZE == 8 ? 1 : '1';

View File

@@ -13,30 +13,59 @@ function strstartswith($haystack, $needle) {
return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== false;
}
if (false !== getenv('PDO_DBLIB_TEST_DSN')) {
$dsn = getenv('PDO_DBLIB_TEST_DSN');
} else {
$dsn = 'dblib:host=localhost;dbname=test';
function getCredentials() {
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];
}
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';
}
try {
$db = new PDO($dsn, $user, $pass);
function setAttributes(PDO $db) {
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
} catch (PDOException $e) {
die('skip ' . $e->getMessage());
}
function getDbConnection(string $class = PDO::class, ?array $attributes = null) {
[$dsn, $user, $pass] = getCredentials();
try {
$db = new $class($dsn, $user, $pass, $attributes);
if ($attributes === null) {
setAttributes($db);
}
} catch (PDOException $e) {
die('skip ' . $e->getMessage());
}
return $db;
}
function connectToDb() {
[$dsn, $user, $pass] = getCredentials();
try {
$db = PDO::connect($dsn, $user, $pass);
setAttributes($db);
} catch (PDOException $e) {
die('skip ' . $e->getMessage());
}
return $db;
}
?>

View File

@@ -5,12 +5,15 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (in_array($db->getAttribute(PDO::DBLIB_ATTR_TDS_VERSION), ['4.2', '4.6', '5.0', '6.0', '7.0', '7.1', '7.2'])) die('skip feature unsupported by this TDS version');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$sql = "SELECT convert(datetime2, '10231017 10:22:44.1355318') AS [d]";
var_dump($db->getAttribute(PDO::DBLIB_ATTR_DATETIME_CONVERT));

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$sql = "SELECT convert(datetime, '20171027 10:22:44.135') AS [d]";
var_dump($db->getAttribute(PDO::DBLIB_ATTR_DATETIME_CONVERT));

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$version = $db->getAttribute(PDO::DBLIB_ATTR_TDS_VERSION);
var_dump((is_string($version) && strlen($version)) || $version === false);

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$version = $db->getAttribute(PDO::DBLIB_ATTR_VERSION);
var_dump(is_string($version) && strlen($version));

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$stmt = $db->prepare('SELECT :value');
$stmt->bindValue(':value', 'foo', PDO::PARAM_STR | PDO::PARAM_STR_NATL);
$stmt->execute();

View File

@@ -5,10 +5,12 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
var_dump($db->quote(true, PDO::PARAM_BOOL));
var_dump($db->quote(false, PDO::PARAM_BOOL));
var_dump($db->quote(42, PDO::PARAM_INT));
@@ -26,7 +28,7 @@ var_dump($db->quote('foo', PDO::PARAM_STR | PDO::PARAM_STR_CHAR));
var_dump($db->quote('über', PDO::PARAM_STR));
var_dump($db->quote('über', PDO::PARAM_STR | PDO::PARAM_STR_NATL));
$db = new PDO($dsn, $user, $pass, [PDO::ATTR_DEFAULT_STR_PARAM => PDO::PARAM_STR_NATL]);
$db = getDbConnection(PDO::class, [PDO::ATTR_DEFAULT_STR_PARAM => PDO::PARAM_STR_NATL]);
var_dump($db->getAttribute(PDO::ATTR_DEFAULT_STR_PARAM) === PDO::PARAM_STR_NATL);
?>

View File

@@ -0,0 +1,44 @@
--TEST--
PdoDblib basic
--EXTENSIONS--
pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection(PdoDblib::class);
$db->query("CREATE TABLE #pdo_dblib_001(name VARCHAR(32)); ");
$db->query("INSERT INTO #pdo_dblib_001 VALUES('PHP'), ('PHP6');");
foreach ($db->query('SELECT name FROM #pdo_dblib_001') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db->query('DROP TABLE IF EXISTS #pdo_dblib_001');
?>
--EXPECT--
array(2) {
["name"]=>
string(3) "PHP"
[0]=>
string(3) "PHP"
}
array(2) {
["name"]=>
string(4) "PHP6"
[0]=>
string(4) "PHP6"
}
Fin.

View File

@@ -0,0 +1,48 @@
--TEST--
PdoDblib create through PDO::connect
--EXTENSIONS--
pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = connectToDb();
if (!$db instanceof PdoDblib) {
echo "Wrong class type. Should be PdoDblib but is " . get_class($db) . "\n";
}
$db->query("CREATE TABLE #pdo_dblib_002(name VARCHAR(32))");
$db->query("INSERT INTO #pdo_dblib_002 VALUES('PHP'), ('PHP6')");
foreach ($db->query('SELECT name FROM #pdo_dblib_002') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db->query('DROP TABLE IF EXISTS #pdo_dblib_002');
?>
--EXPECT--
array(2) {
["name"]=>
string(3) "PHP"
[0]=>
string(3) "PHP"
}
array(2) {
["name"]=>
string(4) "PHP6"
[0]=>
string(4) "PHP6"
}
Fin.

View File

@@ -5,12 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
if (in_array($db->getAttribute(PDO::DBLIB_ATTR_TDS_VERSION), ['4.2', '4.6'])) die('skip feature unsupported by this TDS version');
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$testGUID = '82A88958-672B-4C22-842F-216E2B88E72A';
$testGUIDBinary = base64_decode('WImogitnIkyELyFuK4jnKg==');

View File

@@ -6,15 +6,18 @@ pdo_dblib
<?php
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$sql = 'WAITFOR DELAY \'00:00:02\'';
// regular timeout attribute, set after instance created, will affect query timeout, causing this query to fail
$db = new PDO($dsn, $user, $pass);
$db = getDbConnection();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->setAttribute(PDO::ATTR_TIMEOUT, 1);
$stmt = $db->prepare($sql);
@@ -28,7 +31,7 @@ if (!$stmt->execute()) {
}
// pdo_dblib-specific timeout attribute, set after instance created, will control query timeout, causing this query to fail
$db = new PDO($dsn, $user, $pass);
$db = getDbConnection();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$db->setAttribute(PDO::DBLIB_ATTR_QUERY_TIMEOUT, 1);
$stmt = $db->prepare($sql);
@@ -42,7 +45,7 @@ if (!$stmt->execute()) {
}
// regular timeout attribute will affect query timeout, causing this query to fail
$db = new PDO($dsn, $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::ATTR_TIMEOUT => 1]);
$db = getDbConnection(PDO::class, [PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::ATTR_TIMEOUT => 1]);
$stmt = $db->prepare($sql);
if (!$stmt->execute()) {
echo "OK\n";
@@ -54,7 +57,7 @@ if (!$stmt->execute()) {
}
// pdo_dblib-specific timeout attribute will control query timeout, causing this query to fail
$db = new PDO($dsn, $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::DBLIB_ATTR_QUERY_TIMEOUT => 1]);
$db = getDbConnection(PDO::class, [PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT, PDO::DBLIB_ATTR_QUERY_TIMEOUT => 1]);
$stmt = $db->prepare($sql);
if (!$stmt->execute()) {
echo "OK\n";

View File

@@ -5,11 +5,14 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
function get_expected_float_string() {
global $db;

View File

@@ -25,6 +25,9 @@
#include "pdo/php_pdo_driver.h"
#include "php_pdo_firebird.h"
#include "php_pdo_firebird_int.h"
#include "pdo_firebird_arginfo.h"
static zend_class_entry *PdoFirebird_ce;
/* {{{ pdo_firebird_deps */
static const zend_module_dep pdo_firebird_deps[] = {
@@ -67,12 +70,15 @@ PHP_MINIT_FUNCTION(pdo_firebird) /* {{{ */
return FAILURE;
}
PdoFirebird_ce = register_class_PdoFirebird(pdo_dbh_ce);
PdoFirebird_ce->create_object = pdo_dbh_new;
#ifdef ZEND_SIGNALS
/* firebird replaces some signals at runtime, suppress warnings. */
SIGG(check) = 0;
#endif
return SUCCESS;
return php_pdo_register_driver_specific_ce(&pdo_firebird_driver, PdoFirebird_ce);
}
/* }}} */

View File

@@ -0,0 +1,34 @@
<?php
/** @generate-class-entries */
/**
* @strict-properties
* @not-serializable
*/
class PdoFirebird extends PDO
{
/** @cvalue PDO_FB_ATTR_DATE_FORMAT */
public const int ATTR_DATE_FORMAT = UNKNOWN;
/** @cvalue PDO_FB_ATTR_TIME_FORMAT */
public const int ATTR_TIME_FORMAT = UNKNOWN;
/** @cvalue PDO_FB_ATTR_TIMESTAMP_FORMAT */
public const int ATTR_TIMESTAMP_FORMAT = UNKNOWN;
/** @cvalue PDO_FB_TRANSACTION_ISOLATION_LEVEL */
public const int TRANSACTION_ISOLATION_LEVEL = UNKNOWN;
/** @cvalue PDO_FB_READ_COMMITTED */
public const int READ_COMMITTED = UNKNOWN;
/** @cvalue PDO_FB_REPEATABLE_READ */
public const int REPEATABLE_READ = UNKNOWN;
/** @cvalue PDO_FB_SERIALIZABLE */
public const int SERIALIZABLE = UNKNOWN;
/** @cvalue PDO_FB_WRITABLE_TRANSACTION */
public const int WRITABLE_TRANSACTION = UNKNOWN;
}

68
ext/pdo_firebird/pdo_firebird_arginfo.h generated Normal file
View File

@@ -0,0 +1,68 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 037c073de9e3e3593c62cb7da8ee7202c38c2723 */
static const zend_function_entry class_PdoFirebird_methods[] = {
ZEND_FE_END
};
static zend_class_entry *register_class_PdoFirebird(zend_class_entry *class_entry_PDO)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "PdoFirebird", class_PdoFirebird_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_PDO);
class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE;
zval const_ATTR_DATE_FORMAT_value;
ZVAL_LONG(&const_ATTR_DATE_FORMAT_value, PDO_FB_ATTR_DATE_FORMAT);
zend_string *const_ATTR_DATE_FORMAT_name = zend_string_init_interned("ATTR_DATE_FORMAT", sizeof("ATTR_DATE_FORMAT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_DATE_FORMAT_name, &const_ATTR_DATE_FORMAT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_DATE_FORMAT_name);
zval const_ATTR_TIME_FORMAT_value;
ZVAL_LONG(&const_ATTR_TIME_FORMAT_value, PDO_FB_ATTR_TIME_FORMAT);
zend_string *const_ATTR_TIME_FORMAT_name = zend_string_init_interned("ATTR_TIME_FORMAT", sizeof("ATTR_TIME_FORMAT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_TIME_FORMAT_name, &const_ATTR_TIME_FORMAT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_TIME_FORMAT_name);
zval const_ATTR_TIMESTAMP_FORMAT_value;
ZVAL_LONG(&const_ATTR_TIMESTAMP_FORMAT_value, PDO_FB_ATTR_TIMESTAMP_FORMAT);
zend_string *const_ATTR_TIMESTAMP_FORMAT_name = zend_string_init_interned("ATTR_TIMESTAMP_FORMAT", sizeof("ATTR_TIMESTAMP_FORMAT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_TIMESTAMP_FORMAT_name, &const_ATTR_TIMESTAMP_FORMAT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_TIMESTAMP_FORMAT_name);
zval const_TRANSACTION_ISOLATION_LEVEL_value;
ZVAL_LONG(&const_TRANSACTION_ISOLATION_LEVEL_value, PDO_FB_TRANSACTION_ISOLATION_LEVEL);
zend_string *const_TRANSACTION_ISOLATION_LEVEL_name = zend_string_init_interned("TRANSACTION_ISOLATION_LEVEL", sizeof("TRANSACTION_ISOLATION_LEVEL") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_TRANSACTION_ISOLATION_LEVEL_name, &const_TRANSACTION_ISOLATION_LEVEL_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_TRANSACTION_ISOLATION_LEVEL_name);
zval const_READ_COMMITTED_value;
ZVAL_LONG(&const_READ_COMMITTED_value, PDO_FB_READ_COMMITTED);
zend_string *const_READ_COMMITTED_name = zend_string_init_interned("READ_COMMITTED", sizeof("READ_COMMITTED") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_READ_COMMITTED_name, &const_READ_COMMITTED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_READ_COMMITTED_name);
zval const_REPEATABLE_READ_value;
ZVAL_LONG(&const_REPEATABLE_READ_value, PDO_FB_REPEATABLE_READ);
zend_string *const_REPEATABLE_READ_name = zend_string_init_interned("REPEATABLE_READ", sizeof("REPEATABLE_READ") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_REPEATABLE_READ_name, &const_REPEATABLE_READ_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_REPEATABLE_READ_name);
zval const_SERIALIZABLE_value;
ZVAL_LONG(&const_SERIALIZABLE_value, PDO_FB_SERIALIZABLE);
zend_string *const_SERIALIZABLE_name = zend_string_init_interned("SERIALIZABLE", sizeof("SERIALIZABLE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_SERIALIZABLE_name, &const_SERIALIZABLE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_SERIALIZABLE_name);
zval const_WRITABLE_TRANSACTION_value;
ZVAL_LONG(&const_WRITABLE_TRANSACTION_value, PDO_FB_WRITABLE_TRANSACTION);
zend_string *const_WRITABLE_TRANSACTION_name = zend_string_init_interned("WRITABLE_TRANSACTION", sizeof("WRITABLE_TRANSACTION") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_WRITABLE_TRANSACTION_name, &const_WRITABLE_TRANSACTION_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_WRITABLE_TRANSACTION_name);
return class_entry;
}

View File

@@ -17,6 +17,7 @@ $table = "autocommit_pdo_firebird";
echo "========== in auto commit mode ==========\n";
echo "auto commit mode ON\n";
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
echo "create table and insert\n";
@@ -53,6 +54,7 @@ echo "done!";
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE autocommit_pdo_firebird");
?>
--EXPECTF--

View File

@@ -10,6 +10,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
--FILE--
<?php
require("testdb.inc");
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
echo "========== not in manually transaction ==========\n";

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$dbh->exec('CREATE TABLE test47415 (idx int NOT NULL PRIMARY KEY, txt VARCHAR(20))');
@@ -36,6 +37,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test47415");
unset($dbh);
?>

View File

@@ -14,6 +14,7 @@ require("testdb.inc");
$value = '2';
$dbh = getDbConnection();
$dbh->exec('CREATE TABLE test48877 (A integer)');
$dbh->exec("INSERT INTO test48877 VALUES ('1')");
$dbh->exec("INSERT INTO test48877 VALUES ('2')");
@@ -39,6 +40,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test48877");
unset($dbh);
?>

View File

@@ -12,6 +12,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
require("testdb.inc");
$dbh = getDbConnection();
$dbh->exec('CREATE TABLE test53280(A VARCHAR(30), B VARCHAR(30), C VARCHAR(30))');
$dbh->exec("INSERT INTO test53280 VALUES ('A', 'B', 'C')");
@@ -37,6 +38,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test53280");
unset($dbh);
?>

View File

@@ -12,6 +12,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
require("testdb.inc");
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$dbh->exec("CREATE TABLE test62024 (ID INTEGER NOT NULL, TEXT VARCHAR(10))");
@@ -41,6 +42,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test62024");
unset($dbh);
?>

View File

@@ -12,6 +12,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
require("testdb.inc");
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$dbh->exec("CREATE TABLE test64037 (ID INTEGER NOT NULL, TEXT VARCHAR(10), COST NUMERIC(15, 2))");
$dbh->exec("INSERT INTO test64037 (ID, TEXT, COST) VALUES (1, 'test', -1.0)");
@@ -37,6 +38,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test64037");
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->exec('recreate table test72583 (aint integer, asmi smallint)');
$dbh->exec('insert into test72583 values (1, -1)');
$S = $dbh->prepare('select aint, asmi from test72583');
@@ -23,6 +24,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test72583");
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->exec('recreate table test72931 (id integer)');
$S = $dbh->prepare('insert into test72931 (id) values (1) returning id');
$S->execute();
@@ -22,6 +23,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test72931");
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->exec('recreate table test73087 (id integer not null, content blob sub_type 1 segment size 80)');
$S = $dbh->prepare('insert into test73087 (id, content) values (:id, :content)');
for ($I = 1; $I < 10; $I++) {
@@ -29,6 +30,7 @@ echo 'OK';
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test73087");
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->exec('recreate table test74462 (id integer not null, abool boolean)');
$dbh->exec('insert into test74462 (id, abool) values (1, true)');
$dbh->exec('insert into test74462 (id, abool) values (2, false)');
@@ -24,6 +25,7 @@ var_dump($D);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test74462");
unset($dbh);
?>

View File

@@ -22,15 +22,17 @@ select n,
from r
';
for ($i = 0; $i < 10; $i++) {
$sth = $dbh->prepare($sql);
$sth->execute();
$rows = $sth->fetchAll();
unset($rows);
unset($sth);
}
unset($dbh);
echo "OK";
$dbh = getDbConnection();
for ($i = 0; $i < 10; $i++) {
$sth = $dbh->prepare($sql);
$sth->execute();
$rows = $sth->fetchAll();
unset($rows);
unset($sth);
}
unset($dbh);
echo "OK";
?>
--EXPECT--
OK

View File

@@ -24,6 +24,7 @@ select trim(s) as s from t where b is not distinct from :p
SQL;
try {
$dbh = getDbConnection();
$query = $dbh->prepare($sql);
// PDO::PARAM_BOOL

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->exec("CREATE TABLE bug80521 (foo INTEGER)");
var_dump($dbh->prepare("SELECT foo FROM bug80521 WHERE foo = :foo_bar"));
?>
@@ -22,6 +23,7 @@ object(PDOStatement)#%d (1) {
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE bug80521");
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$dbh->exec('create table test_aaa (id integer)');
$S = $dbh->prepare('insert into test_aaa (id) values (:id) returning id');
@@ -23,6 +24,7 @@ echo 'OK';
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE test_aaa");
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
unset($dbh);
echo "done\n";

View File

@@ -12,6 +12,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
require("testdb.inc");
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
@$dbh->exec('DROP TABLE test_ddl');
@$dbh->exec('DROP GENERATOR gen_test_ddl_id');

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
$dbh->exec("CREATE TABLE test_ddl2 (val int)");
$dbh->beginTransaction();
@@ -27,6 +28,7 @@ echo "done\n";
--CLEAN--
<?php
require("testdb.inc");
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
@$dbh->exec('DROP TABLE test_ddl2');
@$dbh->exec('DROP TABLE test_ddl2_2');

View File

@@ -15,6 +15,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$dbh->setAttribute(PDO::FB_ATTR_TIMESTAMP_FORMAT, '%Y-%m-%d %H:%M:%S');
@@ -56,6 +57,7 @@ echo "done\n";
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec('DROP TABLE test_dialect_1');
unset($dbh);
--EXPECT--

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$table = 'error_handle';
@@ -30,12 +31,13 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec('DROP TABLE error_handle');
unset($dbh);
?>
--EXPECTF--
dbh error
Warning: PDO::query(): SQLSTATE[22018]: Invalid character value for cast specification: -413 conversion error from string "str" in %s on line 10
Warning: PDO::query(): SQLSTATE[22018]: Invalid character value for cast specification: -413 conversion error from string "str" in %s on line %d
stmt error
Warning: PDOStatement::execute(): SQLSTATE[22018]: Invalid character value for cast specification: -413 conversion error from string "str" in %s on line 16
Warning: PDOStatement::execute(): SQLSTATE[22018]: Invalid character value for cast specification: -413 conversion error from string "str" in %s on line %d

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
var_dump($dbh->getAttribute(PDO::ATTR_CONNECTION_STATUS));
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
@@ -47,6 +48,7 @@ echo "done\n";
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec('DROP TABLE test_execute');
unset($dbh);
--EXPECT--

View File

@@ -10,9 +10,10 @@ A bug in firebird causes a memory leak when calling `isc_attach_database()`.
See https://github.com/FirebirdSQL/firebird/issues/7849
--FILE--
<?php
require("testdb.inc");
require("testdb.inc");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$sql = '
execute block (a int = :e, b int = :d)
@@ -29,16 +30,16 @@ begin
suspend;
end
';
$query = $dbh->prepare($sql);
$query->execute(['d' => 1, 'e' => 2]);
$row = $query->fetch(\PDO::FETCH_OBJ);
var_dump($row->N);
var_dump($row->M);
unset($query);
unset($dbh);
echo "done\n";
$query = $dbh->prepare($sql);
$query->execute(['d' => 1, 'e' => 2]);
$row = $query->fetch(\PDO::FETCH_OBJ);
var_dump($row->N);
var_dump($row->M);
unset($query);
unset($dbh);
echo "done\n";
?>
--EXPECT--
int(13)

View File

@@ -29,6 +29,7 @@ CREATE TABLE gh10908(
MYBOOL BOOLEAN
);
EOT;
$dbh = getDbConnection();
$dbh->exec($sql);
$dbh->exec("INSERT INTO gh10908 VALUES(1, 'ABC', 12.34, 1.0, 2.0, '2023-03-24 17:39', '2023-03-24', '17:39', 'abcdefg', 32767, 200000, 'azertyuiop', false);");
@@ -57,6 +58,7 @@ echo "Did not crash\n";
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE gh10908");
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require 'testdb.inc';
$dbh = getDbConnection();
$dbh->exec("CREATE TABLE gh8576 (name CHAR(1) CHARACTER SET UTF8)");
$dbh->exec("INSERT INTO gh8576 VALUES ('A')");
$stmt = $dbh->query("SELECT * FROM gh8576");
@@ -29,6 +30,7 @@ array(1) {
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE gh8576");
unset($dbh);
?>

View File

@@ -10,11 +10,12 @@ A bug in firebird causes a memory leak when calling `isc_attach_database()`.
See https://github.com/FirebirdSQL/firebird/issues/7849
--FILE--
<?php
require("testdb.inc");
require("testdb.inc");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$dbh = getDbConnection();
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$sql = '
$sql = '
select 1 as n
-- :f
from rdb$database
@@ -31,15 +32,14 @@ select 1 as n
from rdb$database
where 1=:d /* and :f = 5 */ and 2=:e
';
$query = $dbh->prepare($sql);
$query->execute(['d' => 1, 'e' => 2]);
$row = $query->fetch(\PDO::FETCH_OBJ);
var_dump($row->N);
unset($query);
unset($dbh);
echo "done\n";
$query = $dbh->prepare($sql);
$query->execute(['d' => 1, 'e' => 2]);
$row = $query->fetch(\PDO::FETCH_OBJ);
var_dump($row->N);
unset($query);
unset($dbh);
echo "done\n";
?>
--EXPECT--
int(1)

View File

@@ -0,0 +1,44 @@
--TEST--
PDO_firebird subclass basic
--EXTENSIONS--
pdo_firebird
--SKIPIF--
<?php require(__DIR__ . '/skipif.inc'); ?>
--FILE--
<?php
require_once __DIR__ . "/testdb.inc";
$db = getDbConnection();
$db->query('CREATE TABLE pdofirebird_001 (idx INT NOT NULL PRIMARY KEY, name VARCHAR(20))');
$db->query("INSERT INTO pdofirebird_001 VALUES (1, 'PHP')");
$db->query("INSERT INTO pdofirebird_001 VALUES (2, 'PHP6')");
foreach ($db->query('SELECT name FROM pdofirebird_001') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require_once __DIR__ . '/testdb.inc';
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE pdofirebird_001");
unset($dbh);
?>
--EXPECT--
array(2) {
["NAME"]=>
string(3) "PHP"
[0]=>
string(3) "PHP"
}
array(2) {
["NAME"]=>
string(4) "PHP6"
[0]=>
string(4) "PHP6"
}
Fin.

View File

@@ -0,0 +1,55 @@
--TEST--
PDO_firebird connect through PDO::connect
--EXTENSIONS--
pdo_firebird
--SKIPIF--
<?php require(__DIR__ . '/skipif.inc'); ?>
--FILE--
<?php
require_once __DIR__ . "/testdb.inc";
$db = connectToDb();
if (!$db instanceof PdoFirebird) {
echo "Wrong class type. Should be PdoFirebird but is " . get_class($db) . "\n";
}
$db->query('CREATE TABLE pdofirebird_002 (idx INT NOT NULL PRIMARY KEY, name VARCHAR(20))');
$db->exec("INSERT INTO pdofirebird_002 VALUES(1, 'A')");
$db->exec("INSERT INTO pdofirebird_002 VALUES(2, 'B')");
$db->exec("INSERT INTO pdofirebird_002 VALUES(3, 'C')");
foreach ($db->query('SELECT name FROM pdofirebird_002') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require_once __DIR__ . "/testdb.inc";
$dbh = getDbConnection();
@$dbh->exec("DROP TABLE pdofirebird_002");
unset($dbh);
?>
--EXPECT--
array(2) {
["NAME"]=>
string(1) "A"
[0]=>
string(1) "A"
}
array(2) {
["NAME"]=>
string(1) "B"
[0]=>
string(1) "B"
}
array(2) {
["NAME"]=>
string(1) "C"
[0]=>
string(1) "C"
}
Fin.

View File

@@ -12,6 +12,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
require("testdb.inc");
$dbh = getDbConnection();
$dbh->exec('CREATE TABLE test_rowcount (A VARCHAR(10))');
$dbh->exec("INSERT INTO test_rowcount VALUES ('A')");
$dbh->exec("INSERT INTO test_rowcount VALUES ('A')");
@@ -41,6 +42,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec('DROP TABLE test_rowcount');
unset($dbh);
--EXPECT--

View File

@@ -17,5 +17,12 @@ if(!PDO_FIREBIRD_TEST_DSN)
die('Error: PDO_FIREBIRD_TEST_DSN must be set');
}
$dbh = new PDO(PDO_FIREBIRD_TEST_DSN, PDO_FIREBIRD_TEST_USER, PDO_FIREBIRD_TEST_PASS) or die;
function getDbConnection($class = PDO::class): PDO {
return new $class(PDO_FIREBIRD_TEST_DSN, PDO_FIREBIRD_TEST_USER, PDO_FIREBIRD_TEST_PASS);
}
function connectToDb(): PdoFirebird {
return PdoFirebird::connect(PDO_FIREBIRD_TEST_DSN, PDO_FIREBIRD_TEST_USER, PDO_FIREBIRD_TEST_PASS);
}
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
unset($dbh);
$table = 'transaction_access_mode';
@@ -130,6 +131,7 @@ unset($dbh);
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec('DROP TABLE transaction_access_mode');
unset($dbh);
?>

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
unset($dbh);
$levelStrs = [

View File

@@ -11,6 +11,7 @@ See https://github.com/FirebirdSQL/firebird/issues/7849
<?php
require("testdb.inc");
$dbh = getDbConnection();
unset($dbh);
$table = 'txn_isolation_level_behavior';
@@ -127,6 +128,7 @@ echo "done!";
--CLEAN--
<?php
require 'testdb.inc';
$dbh = getDbConnection();
@$dbh->exec('DROP TABLE txn_isolation_level_behavior');
unset($dbh);
?>

View File

@@ -26,6 +26,9 @@
#include "pdo/php_pdo_driver.h"
#include "php_pdo_mysql.h"
#include "php_pdo_mysql_int.h"
#include "pdo_mysql_arginfo.h"
static zend_class_entry *pdo_mysql_ce;
#ifdef COMPILE_DL_PDO_MYSQL
#ifdef ZTS
@@ -81,6 +84,22 @@ static const MYSQLND_REVERSE_API pdo_mysql_reverse_api = {
};
#endif
/* proto string PDO::mysqlGetWarningCount()
* Returns the number of SQL warnings during the execution of the last statement
*/
PHP_METHOD(PdoMysql, getWarningCount)
{
pdo_dbh_t *dbh;
pdo_mysql_db_handle *H;
ZEND_PARSE_PARAMETERS_NONE();
dbh = Z_PDO_DBH_P(ZEND_THIS);
PDO_CONSTRUCT_CHECK;
H = (pdo_mysql_db_handle *)dbh->driver_data;
RETURN_LONG(mysql_warning_count(H->server));
}
/* {{{ PHP_INI_BEGIN */
PHP_INI_BEGIN()
@@ -118,7 +137,7 @@ static PHP_MINIT_FUNCTION(pdo_mysql)
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CAPATH", (zend_long)PDO_MYSQL_ATTR_SSL_CAPATH);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CIPHER", (zend_long)PDO_MYSQL_ATTR_SSL_CIPHER);
#if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SERVER_PUBLIC_KEY", (zend_long)PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SERVER_PUBLIC_KEY", (zend_long)PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY);
#endif
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_MULTI_STATEMENTS", (zend_long)PDO_MYSQL_ATTR_MULTI_STATEMENTS);
#ifdef PDO_USE_MYSQLND
@@ -132,7 +151,14 @@ static PHP_MINIT_FUNCTION(pdo_mysql)
mysqlnd_reverse_api_register_api(&pdo_mysql_reverse_api);
#endif
return php_pdo_register_driver(&pdo_mysql_driver);
pdo_mysql_ce = register_class_PdoMysql(pdo_dbh_ce);
pdo_mysql_ce->create_object = pdo_dbh_new;
if (php_pdo_register_driver(&pdo_mysql_driver) == FAILURE) {
return FAILURE;
}
return php_pdo_register_driver_specific_ce(&pdo_mysql_driver, pdo_mysql_ce);
}
/* }}} */

View File

@@ -0,0 +1,75 @@
<?php
/** @generate-class-entries */
/**
* @strict-properties
* @not-serializable
*/
class PdoMysql extends PDO
{
/** @cvalue PDO_MYSQL_ATTR_USE_BUFFERED_QUERY */
public const int ATTR_USE_BUFFERED_QUERY = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_LOCAL_INFILE */
public const int ATTR_LOCAL_INFILE = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_INIT_COMMAND */
public const int ATTR_INIT_COMMAND = UNKNOWN;
#ifndef PDO_USE_MYSQLND
/** @cvalue PDO_MYSQL_ATTR_MAX_BUFFER_SIZE */
public const int ATTR_MAX_BUFFER_SIZE = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_READ_DEFAULT_FILE */
public const int ATTR_READ_DEFAULT_FILE = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_READ_DEFAULT_GROUP */
public const int ATTR_READ_DEFAULT_GROUP = UNKNOWN;
#endif
/** @cvalue PDO_MYSQL_ATTR_COMPRESS */
public const int ATTR_COMPRESS = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_DIRECT_QUERY */
public const int ATTR_DIRECT_QUERY = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_FOUND_ROWS */
public const int ATTR_FOUND_ROWS = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_IGNORE_SPACE */
public const int ATTR_IGNORE_SPACE = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_SSL_KEY */
public const int ATTR_SSL_KEY = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_SSL_CERT */
public const int ATTR_SSL_CERT = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_SSL_CA */
public const int ATTR_SSL_CA = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_SSL_CAPATH */
public const int ATTR_SSL_CAPATH = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_SSL_CIPHER */
public const int ATTR_SSL_CIPHER = UNKNOWN;
#if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
/** @cvalue PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY */
public const int ATTR_SERVER_PUBLIC_KEY = UNKNOWN;
#endif
/** @cvalue PDO_MYSQL_ATTR_MULTI_STATEMENTS */
public const int ATTR_MULTI_STATEMENTS = UNKNOWN;
/** @cvalue PDO_MYSQL_ATTR_SSL_VERIFY_SERVER_CERT */
public const int ATTR_SSL_VERIFY_SERVER_CERT = UNKNOWN;
#if MYSQL_VERSION_ID >= 80021 || defined(PDO_USE_MYSQLND)
/** @cvalue PDO_MYSQL_ATTR_LOCAL_INFILE_DIRECTORY */
public const int ATTR_LOCAL_INFILE_DIRECTORY = UNKNOWN;
#endif
public function getWarningCount(): int {}
}

149
ext/pdo_mysql/pdo_mysql_arginfo.h generated Normal file
View File

@@ -0,0 +1,149 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 3e797a44fc026ab43bf4bec26cf6fe492116cb25 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PdoMysql_getWarningCount, 0, 0, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_METHOD(PdoMysql, getWarningCount);
static const zend_function_entry class_PdoMysql_methods[] = {
ZEND_ME(PdoMysql, getWarningCount, arginfo_class_PdoMysql_getWarningCount, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static zend_class_entry *register_class_PdoMysql(zend_class_entry *class_entry_PDO)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "PdoMysql", class_PdoMysql_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_PDO);
class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE;
zval const_ATTR_USE_BUFFERED_QUERY_value;
ZVAL_LONG(&const_ATTR_USE_BUFFERED_QUERY_value, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY);
zend_string *const_ATTR_USE_BUFFERED_QUERY_name = zend_string_init_interned("ATTR_USE_BUFFERED_QUERY", sizeof("ATTR_USE_BUFFERED_QUERY") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_USE_BUFFERED_QUERY_name, &const_ATTR_USE_BUFFERED_QUERY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_USE_BUFFERED_QUERY_name);
zval const_ATTR_LOCAL_INFILE_value;
ZVAL_LONG(&const_ATTR_LOCAL_INFILE_value, PDO_MYSQL_ATTR_LOCAL_INFILE);
zend_string *const_ATTR_LOCAL_INFILE_name = zend_string_init_interned("ATTR_LOCAL_INFILE", sizeof("ATTR_LOCAL_INFILE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_LOCAL_INFILE_name, &const_ATTR_LOCAL_INFILE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_LOCAL_INFILE_name);
zval const_ATTR_INIT_COMMAND_value;
ZVAL_LONG(&const_ATTR_INIT_COMMAND_value, PDO_MYSQL_ATTR_INIT_COMMAND);
zend_string *const_ATTR_INIT_COMMAND_name = zend_string_init_interned("ATTR_INIT_COMMAND", sizeof("ATTR_INIT_COMMAND") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_INIT_COMMAND_name, &const_ATTR_INIT_COMMAND_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_INIT_COMMAND_name);
#if !defined(PDO_USE_MYSQLND)
zval const_ATTR_MAX_BUFFER_SIZE_value;
ZVAL_LONG(&const_ATTR_MAX_BUFFER_SIZE_value, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE);
zend_string *const_ATTR_MAX_BUFFER_SIZE_name = zend_string_init_interned("ATTR_MAX_BUFFER_SIZE", sizeof("ATTR_MAX_BUFFER_SIZE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_MAX_BUFFER_SIZE_name, &const_ATTR_MAX_BUFFER_SIZE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_MAX_BUFFER_SIZE_name);
#endif
#if !defined(PDO_USE_MYSQLND)
zval const_ATTR_READ_DEFAULT_FILE_value;
ZVAL_LONG(&const_ATTR_READ_DEFAULT_FILE_value, PDO_MYSQL_ATTR_READ_DEFAULT_FILE);
zend_string *const_ATTR_READ_DEFAULT_FILE_name = zend_string_init_interned("ATTR_READ_DEFAULT_FILE", sizeof("ATTR_READ_DEFAULT_FILE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_READ_DEFAULT_FILE_name, &const_ATTR_READ_DEFAULT_FILE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_READ_DEFAULT_FILE_name);
#endif
#if !defined(PDO_USE_MYSQLND)
zval const_ATTR_READ_DEFAULT_GROUP_value;
ZVAL_LONG(&const_ATTR_READ_DEFAULT_GROUP_value, PDO_MYSQL_ATTR_READ_DEFAULT_GROUP);
zend_string *const_ATTR_READ_DEFAULT_GROUP_name = zend_string_init_interned("ATTR_READ_DEFAULT_GROUP", sizeof("ATTR_READ_DEFAULT_GROUP") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_READ_DEFAULT_GROUP_name, &const_ATTR_READ_DEFAULT_GROUP_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_READ_DEFAULT_GROUP_name);
#endif
zval const_ATTR_COMPRESS_value;
ZVAL_LONG(&const_ATTR_COMPRESS_value, PDO_MYSQL_ATTR_COMPRESS);
zend_string *const_ATTR_COMPRESS_name = zend_string_init_interned("ATTR_COMPRESS", sizeof("ATTR_COMPRESS") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_COMPRESS_name, &const_ATTR_COMPRESS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_COMPRESS_name);
zval const_ATTR_DIRECT_QUERY_value;
ZVAL_LONG(&const_ATTR_DIRECT_QUERY_value, PDO_MYSQL_ATTR_DIRECT_QUERY);
zend_string *const_ATTR_DIRECT_QUERY_name = zend_string_init_interned("ATTR_DIRECT_QUERY", sizeof("ATTR_DIRECT_QUERY") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_DIRECT_QUERY_name, &const_ATTR_DIRECT_QUERY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_DIRECT_QUERY_name);
zval const_ATTR_FOUND_ROWS_value;
ZVAL_LONG(&const_ATTR_FOUND_ROWS_value, PDO_MYSQL_ATTR_FOUND_ROWS);
zend_string *const_ATTR_FOUND_ROWS_name = zend_string_init_interned("ATTR_FOUND_ROWS", sizeof("ATTR_FOUND_ROWS") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_FOUND_ROWS_name, &const_ATTR_FOUND_ROWS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_FOUND_ROWS_name);
zval const_ATTR_IGNORE_SPACE_value;
ZVAL_LONG(&const_ATTR_IGNORE_SPACE_value, PDO_MYSQL_ATTR_IGNORE_SPACE);
zend_string *const_ATTR_IGNORE_SPACE_name = zend_string_init_interned("ATTR_IGNORE_SPACE", sizeof("ATTR_IGNORE_SPACE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_IGNORE_SPACE_name, &const_ATTR_IGNORE_SPACE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_IGNORE_SPACE_name);
zval const_ATTR_SSL_KEY_value;
ZVAL_LONG(&const_ATTR_SSL_KEY_value, PDO_MYSQL_ATTR_SSL_KEY);
zend_string *const_ATTR_SSL_KEY_name = zend_string_init_interned("ATTR_SSL_KEY", sizeof("ATTR_SSL_KEY") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SSL_KEY_name, &const_ATTR_SSL_KEY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SSL_KEY_name);
zval const_ATTR_SSL_CERT_value;
ZVAL_LONG(&const_ATTR_SSL_CERT_value, PDO_MYSQL_ATTR_SSL_CERT);
zend_string *const_ATTR_SSL_CERT_name = zend_string_init_interned("ATTR_SSL_CERT", sizeof("ATTR_SSL_CERT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SSL_CERT_name, &const_ATTR_SSL_CERT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SSL_CERT_name);
zval const_ATTR_SSL_CA_value;
ZVAL_LONG(&const_ATTR_SSL_CA_value, PDO_MYSQL_ATTR_SSL_CA);
zend_string *const_ATTR_SSL_CA_name = zend_string_init_interned("ATTR_SSL_CA", sizeof("ATTR_SSL_CA") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SSL_CA_name, &const_ATTR_SSL_CA_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SSL_CA_name);
zval const_ATTR_SSL_CAPATH_value;
ZVAL_LONG(&const_ATTR_SSL_CAPATH_value, PDO_MYSQL_ATTR_SSL_CAPATH);
zend_string *const_ATTR_SSL_CAPATH_name = zend_string_init_interned("ATTR_SSL_CAPATH", sizeof("ATTR_SSL_CAPATH") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SSL_CAPATH_name, &const_ATTR_SSL_CAPATH_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SSL_CAPATH_name);
zval const_ATTR_SSL_CIPHER_value;
ZVAL_LONG(&const_ATTR_SSL_CIPHER_value, PDO_MYSQL_ATTR_SSL_CIPHER);
zend_string *const_ATTR_SSL_CIPHER_name = zend_string_init_interned("ATTR_SSL_CIPHER", sizeof("ATTR_SSL_CIPHER") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SSL_CIPHER_name, &const_ATTR_SSL_CIPHER_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SSL_CIPHER_name);
#if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
zval const_ATTR_SERVER_PUBLIC_KEY_value;
ZVAL_LONG(&const_ATTR_SERVER_PUBLIC_KEY_value, PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY);
zend_string *const_ATTR_SERVER_PUBLIC_KEY_name = zend_string_init_interned("ATTR_SERVER_PUBLIC_KEY", sizeof("ATTR_SERVER_PUBLIC_KEY") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SERVER_PUBLIC_KEY_name, &const_ATTR_SERVER_PUBLIC_KEY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SERVER_PUBLIC_KEY_name);
#endif
zval const_ATTR_MULTI_STATEMENTS_value;
ZVAL_LONG(&const_ATTR_MULTI_STATEMENTS_value, PDO_MYSQL_ATTR_MULTI_STATEMENTS);
zend_string *const_ATTR_MULTI_STATEMENTS_name = zend_string_init_interned("ATTR_MULTI_STATEMENTS", sizeof("ATTR_MULTI_STATEMENTS") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_MULTI_STATEMENTS_name, &const_ATTR_MULTI_STATEMENTS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_MULTI_STATEMENTS_name);
zval const_ATTR_SSL_VERIFY_SERVER_CERT_value;
ZVAL_LONG(&const_ATTR_SSL_VERIFY_SERVER_CERT_value, PDO_MYSQL_ATTR_SSL_VERIFY_SERVER_CERT);
zend_string *const_ATTR_SSL_VERIFY_SERVER_CERT_name = zend_string_init_interned("ATTR_SSL_VERIFY_SERVER_CERT", sizeof("ATTR_SSL_VERIFY_SERVER_CERT") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_SSL_VERIFY_SERVER_CERT_name, &const_ATTR_SSL_VERIFY_SERVER_CERT_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_SSL_VERIFY_SERVER_CERT_name);
#if MYSQL_VERSION_ID >= 80021 || defined(PDO_USE_MYSQLND)
zval const_ATTR_LOCAL_INFILE_DIRECTORY_value;
ZVAL_LONG(&const_ATTR_LOCAL_INFILE_DIRECTORY_value, PDO_MYSQL_ATTR_LOCAL_INFILE_DIRECTORY);
zend_string *const_ATTR_LOCAL_INFILE_DIRECTORY_name = zend_string_init_interned("ATTR_LOCAL_INFILE_DIRECTORY", sizeof("ATTR_LOCAL_INFILE_DIRECTORY") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_LOCAL_INFILE_DIRECTORY_name, &const_ATTR_LOCAL_INFILE_DIRECTORY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_LOCAL_INFILE_DIRECTORY_name);
#endif
return class_entry;
}

View File

@@ -8,7 +8,7 @@ foreach ($env as $k => $v) {
class MySQLPDOTest extends PDOTest {
static function factory($classname = 'PDO', $mydsn = null, $myAttr = null) {
static function factory($classname = PDO::class, $mydsn = null, $myAttr = null) {
$dsn = self::getDSN($mydsn);
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;

View File

@@ -14,6 +14,7 @@ MySQLPDOTest::skipNotTransactionalEngine();
$expected = [
'__construct' => true,
'connect' => true,
'prepare' => true,
'beginTransaction' => true,
'commit' => true,

View File

@@ -0,0 +1,47 @@
--TEST--
PDO_mysql subclass basic
--EXTENSIONS--
pdo_mysql
--SKIPIF--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
MySQLPDOTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
$db = MySQLPDOTest::factory(PdoMysql::class);
$db->query('CREATE TABLE pdomysql_001 (id INT, name TEXT)');
$db->query('INSERT INTO pdomysql_001 VALUES (NULL, "PHP")');
$db->query('INSERT INTO pdomysql_001 VALUES (NULL, "PHP6")');
foreach ($db->query('SELECT name FROM pdomysql_001') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
$db = MySQLPDOTest::factory();
$db->exec('DROP TABLE IF EXISTS pdomysql_001');
?>
--EXPECT--
array(2) {
["name"]=>
string(3) "PHP"
[0]=>
string(3) "PHP"
}
array(2) {
["name"]=>
string(4) "PHP6"
[0]=>
string(4) "PHP6"
}
Fin.

View File

@@ -0,0 +1,54 @@
--TEST--
PDO_mysql connect through PDO::connect
--EXTENSIONS--
pdo_mysql
--SKIPIF--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
MySQLPDOTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
$db = Pdo::connect(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS);
if (!$db instanceof PdoMysql) {
echo "Wrong class type. Should be PdoMysql but is " . get_class($db) . "\n";
}
$db->exec('CREATE TABLE pdomysql_002(id INT NOT NULL PRIMARY KEY, name VARCHAR(10))');
$db->exec("INSERT INTO pdomysql_002 VALUES(1, 'A'), (2, 'B'), (3, 'C')");
foreach ($db->query('SELECT name FROM pdomysql_002') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
$db = MySQLPDOTest::factory();
$db->query('DROP TABLE pdomysql_002');
?>
--EXPECT--
array(2) {
["name"]=>
string(1) "A"
[0]=>
string(1) "A"
}
array(2) {
["name"]=>
string(1) "B"
[0]=>
string(1) "B"
}
array(2) {
["name"]=>
string(1) "C"
[0]=>
string(1) "C"
}
Fin.

View File

@@ -0,0 +1,29 @@
--TEST--
PDO_mysql getWarningCount
--EXTENSIONS--
pdo_mysql
--SKIPIF--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
MySQLPDOTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/mysql_pdo_test.inc';
$db = Pdo::connect(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS);
if (!$db instanceof PdoMysql) {
echo "Wrong class type. Should be PdoMysql but is " . get_class($db) . "\n";
}
$assertWarnings = function ($db, $q, $count) {
$db->query($q);
printf("Query %s produced %d warnings\n", $q, $db->getWarningCount());
};
$assertWarnings($db, 'SELECT 1 = 1', 0);
$assertWarnings($db, 'SELECT 1 = "A"', 1);
--EXPECT--
Query SELECT 1 = 1 produced 0 warnings
Query SELECT 1 = "A" produced 1 warnings

View File

@@ -27,6 +27,8 @@
#include "php_pdo_odbc_int.h"
#include "pdo_odbc_arginfo.h"
static zend_class_entry *pdo_odbc_ce;
/* {{{ pdo_odbc_deps[] */
static const zend_module_dep pdo_odbc_deps[] = {
ZEND_MOD_REQUIRED("pdo")
@@ -105,7 +107,10 @@ PHP_MINIT_FUNCTION(pdo_odbc)
REGISTER_PDO_CLASS_CONST_LONG("ODBC_SQL_USE_DRIVER", SQL_CUR_USE_DRIVER);
REGISTER_PDO_CLASS_CONST_LONG("ODBC_SQL_USE_ODBC", SQL_CUR_USE_ODBC);
return SUCCESS;
pdo_odbc_ce = register_class_PdoOdbc(pdo_dbh_ce);
pdo_odbc_ce->create_object = pdo_dbh_new;
return php_pdo_register_driver_specific_ce(&pdo_odbc_driver, pdo_odbc_ce);
}
/* }}} */

View File

@@ -7,3 +7,25 @@
* @cvalue PDO_ODBC_TYPE
*/
const PDO_ODBC_TYPE = UNKNOWN;
/**
* @strict-properties
* @not-serializable
*/
class PdoOdbc extends PDO
{
/** @cvalue PDO_ODBC_ATTR_USE_CURSOR_LIBRARY */
public const int ATTR_USE_CURSOR_LIBRARY = UNKNOWN;
/** @cvalue PDO_ODBC_ATTR_ASSUME_UTF8 */
public const int ATTR_ASSUME_UTF8 = UNKNOWN;
/** @cvalue SQL_CUR_USE_IF_NEEDED */
public const int SQL_USE_IF_NEEDED = UNKNOWN;
/** @cvalue SQL_CUR_USE_DRIVER */
public const int SQL_USE_DRIVER = UNKNOWN;
/** @cvalue SQL_CUR_USE_ODBC */
public const int SQL_USE_ODBC = UNKNOWN;
}

View File

@@ -1,9 +1,55 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 7927099133bf60cab0464aae8c9de8f7ef2732bd */
* Stub hash: 3cc19acf5943c09a011f15d9ef6d0f443d4b8a71 */
static const zend_function_entry class_PdoOdbc_methods[] = {
ZEND_FE_END
};
static void register_pdo_odbc_symbols(int module_number)
{
REGISTER_STRING_CONSTANT("PDO_ODBC_TYPE", PDO_ODBC_TYPE, CONST_PERSISTENT);
}
static zend_class_entry *register_class_PdoOdbc(zend_class_entry *class_entry_PDO)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "PdoOdbc", class_PdoOdbc_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_PDO);
class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE;
zval const_ATTR_USE_CURSOR_LIBRARY_value;
ZVAL_LONG(&const_ATTR_USE_CURSOR_LIBRARY_value, PDO_ODBC_ATTR_USE_CURSOR_LIBRARY);
zend_string *const_ATTR_USE_CURSOR_LIBRARY_name = zend_string_init_interned("ATTR_USE_CURSOR_LIBRARY", sizeof("ATTR_USE_CURSOR_LIBRARY") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_USE_CURSOR_LIBRARY_name, &const_ATTR_USE_CURSOR_LIBRARY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_USE_CURSOR_LIBRARY_name);
zval const_ATTR_ASSUME_UTF8_value;
ZVAL_LONG(&const_ATTR_ASSUME_UTF8_value, PDO_ODBC_ATTR_ASSUME_UTF8);
zend_string *const_ATTR_ASSUME_UTF8_name = zend_string_init_interned("ATTR_ASSUME_UTF8", sizeof("ATTR_ASSUME_UTF8") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_ASSUME_UTF8_name, &const_ATTR_ASSUME_UTF8_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_ASSUME_UTF8_name);
zval const_SQL_USE_IF_NEEDED_value;
ZVAL_LONG(&const_SQL_USE_IF_NEEDED_value, SQL_CUR_USE_IF_NEEDED);
zend_string *const_SQL_USE_IF_NEEDED_name = zend_string_init_interned("SQL_USE_IF_NEEDED", sizeof("SQL_USE_IF_NEEDED") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_SQL_USE_IF_NEEDED_name, &const_SQL_USE_IF_NEEDED_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_SQL_USE_IF_NEEDED_name);
zval const_SQL_USE_DRIVER_value;
ZVAL_LONG(&const_SQL_USE_DRIVER_value, SQL_CUR_USE_DRIVER);
zend_string *const_SQL_USE_DRIVER_name = zend_string_init_interned("SQL_USE_DRIVER", sizeof("SQL_USE_DRIVER") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_SQL_USE_DRIVER_name, &const_SQL_USE_DRIVER_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_SQL_USE_DRIVER_name);
zval const_SQL_USE_ODBC_value;
ZVAL_LONG(&const_SQL_USE_ODBC_value, SQL_CUR_USE_ODBC);
zend_string *const_SQL_USE_ODBC_name = zend_string_init_interned("SQL_USE_ODBC", sizeof("SQL_USE_ODBC") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_SQL_USE_ODBC_name, &const_SQL_USE_ODBC_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_SQL_USE_ODBC_name);
return class_entry;
}

View File

@@ -0,0 +1,45 @@
--TEST--
PDO_odbc subclass basic
--EXTENSIONS--
pdo_odbc
--SKIPIF--
<?php
require 'ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$config = PDOTest::get_config(__DIR__ . "/common.phpt");
$db = new PdoOdbc($config['ENV']['PDOTEST_DSN'], $config['ENV']['PDOTEST_USER'], $config['ENV']['PDOTEST_PASS']);
$db->query("CREATE TABLE pdoodbc_001 (id INT, name TEXT)");
$db->query("INSERT INTO pdoodbc_001 VALUES (NULL, 'PHP'), (NULL, 'PHP6')");
foreach ($db->query('SELECT name FROM pdoodbc_001') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("DROP TABLE IF EXISTS pdoodbc_001");
?>
--EXPECT--
array(2) {
["name"]=>
string(3) "PHP"
[0]=>
string(3) "PHP"
}
array(2) {
["name"]=>
string(4) "PHP6"
[0]=>
string(4) "PHP6"
}
Fin.

View File

@@ -0,0 +1,54 @@
--TEST--
PDO_mysql connect through PDO::connect
--EXTENSIONS--
PDO_odbc
--SKIPIF--
<?php
require 'ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$config = PDOTest::get_config(__DIR__ . "/common.phpt");
$db = PdoOdbc::connect($config['ENV']['PDOTEST_DSN'], $config['ENV']['PDOTEST_USER'], $config['ENV']['PDOTEST_PASS']);
if (!$db instanceof PdoOdbc) {
echo "Wrong class type. Should be PdoOdbc but is " . get_class($db) . "\n";
}
$db->exec('CREATE TABLE pdoodbc_002(id INT NOT NULL PRIMARY KEY, name VARCHAR(10))');
$db->exec("INSERT INTO pdoodbc_002 VALUES(1, 'A'), (2, 'B'), (3, 'C')");
foreach ($db->query('SELECT name FROM pdoodbc_002') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec("DROP TABLE IF EXISTS pdoodbc_002");
?>
--EXPECT--
array(2) {
["name"]=>
string(1) "A"
[0]=>
string(1) "A"
}
array(2) {
["name"]=>
string(1) "B"
[0]=>
string(1) "B"
}
array(2) {
["name"]=>
string(1) "C"
[0]=>
string(1) "C"
}
Fin.

View File

@@ -22,9 +22,13 @@
#include "php_ini.h"
#include "ext/standard/info.h"
#include "pdo/php_pdo.h"
#include "pdo/php_pdo_int.h"
#include "pdo/php_pdo_driver.h"
#include "php_pdo_pgsql.h"
#include "php_pdo_pgsql_int.h"
#include "pdo_pgsql_arginfo.h"
static zend_class_entry *PdoPgsql_ce;
/* {{{ pdo_sqlite_deps */
static const zend_module_dep pdo_pgsql_deps[] = {
@@ -53,6 +57,94 @@ zend_module_entry pdo_pgsql_module_entry = {
ZEND_GET_MODULE(pdo_pgsql)
#endif
/* Escape an identifier for insertion into a text field */
PHP_METHOD(PdoPgsql, escapeIdentifier)
{
zend_string *from = NULL;
char *tmp;
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
RETURN_THROWS();
}
dbh = Z_PDO_DBH_P(ZEND_THIS);
PDO_CONSTRUCT_CHECK;
PDO_DBH_CLEAR_ERR();
/* Obtain db Handle */
H = (pdo_pgsql_db_handle *)dbh->driver_data;
if (H->server == NULL) {
zend_throw_error(NULL, "PostgreSQL connection has already been closed");
RETURN_THROWS();
}
tmp = PQescapeIdentifier(H->server, ZSTR_VAL(from), ZSTR_LEN(from));
if (!tmp) {
pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
PDO_HANDLE_DBH_ERR();
RETURN_THROWS();
}
RETVAL_STRING(tmp);
PQfreemem(tmp);
}
/* Returns true if the copy worked fine or false if error */
PHP_METHOD(PdoPgsql, copyFromArray)
{
pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Returns true if the copy worked fine or false if error */
PHP_METHOD(PdoPgsql, copyFromFile)
{
pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Returns true if the copy worked fine or false if error */
PHP_METHOD(PdoPgsql, copyToFile)
{
pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Returns true if the copy worked fine or false if error */
PHP_METHOD(PdoPgsql, copyToArray)
{
pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Creates a new large object, returning its identifier. Must be called inside a transaction. */
PHP_METHOD(PdoPgsql, lobCreate)
{
pgsqlLOBCreate_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Opens an existing large object stream. Must be called inside a transaction. */
PHP_METHOD(PdoPgsql, lobOpen)
{
pgsqlLOBOpen_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Deletes the large object identified by oid. Must be called inside a transaction. */
PHP_METHOD(PdoPgsql, lobUnlink)
{
pgsqlLOBUnlink_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Get asynchronous notification */
PHP_METHOD(PdoPgsql, getNotify)
{
pgsqlGetNotify_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* Get backend(server) pid */
PHP_METHOD(PdoPgsql, getPid)
{
pgsqlGetPid_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* true global environment */
/* {{{ PHP_MINIT_FUNCTION */
@@ -65,7 +157,14 @@ PHP_MINIT_FUNCTION(pdo_pgsql)
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_INERROR", (zend_long)PGSQL_TRANSACTION_INERROR);
REGISTER_PDO_CLASS_CONST_LONG("PGSQL_TRANSACTION_UNKNOWN", (zend_long)PGSQL_TRANSACTION_UNKNOWN);
return php_pdo_register_driver(&pdo_pgsql_driver);
PdoPgsql_ce = register_class_PdoPgsql(pdo_dbh_ce);
PdoPgsql_ce->create_object = pdo_dbh_new;
if (php_pdo_register_driver(&pdo_pgsql_driver) == FAILURE) {
return FAILURE;
}
return php_pdo_register_driver_specific_ce(&pdo_pgsql_driver, PdoPgsql_ce);
}
/* }}} */

View File

@@ -0,0 +1,50 @@
<?php
/** @generate-class-entries */
/**
* @strict-properties
* @not-serializable
*/
class PdoPgsql extends PDO
{
/** @cvalue PDO_PGSQL_ATTR_DISABLE_PREPARES */
public const int ATTR_DISABLE_PREPARES = UNKNOWN;
/** @cvalue PGSQL_TRANSACTION_IDLE */
public const int TRANSACTION_IDLE = UNKNOWN;
/** @cvalue PGSQL_TRANSACTION_ACTIVE */
public const int TRANSACTION_ACTIVE = UNKNOWN;
/** @cvalue PGSQL_TRANSACTION_INTRANS */
public const int TRANSACTION_INTRANS = UNKNOWN;
/** @cvalue PGSQL_TRANSACTION_INERROR */
public const int TRANSACTION_INERROR = UNKNOWN;
/** @cvalue PGSQL_TRANSACTION_UNKNOWN */
public const int TRANSACTION_UNKNOWN = UNKNOWN;
public function escapeIdentifier(string $input): string {}
public function copyFromArray(string $tableName, array $rows, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null): bool {}
public function copyFromFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null): bool {}
public function copyToArray(string $tableName, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null): array|false {}
public function copyToFile(string $tableName, string $filename, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null): bool {}
public function lobCreate(): string|false {}
// Opens an existing large object stream. Must be called inside a transaction.
/** @return resource|false */
public function lobOpen(string $oid, string $mode = "rb"){}
public function lobUnlink(string $oid): bool {}
public function getNotify(int $fetchMode = PDO::FETCH_DEFAULT, int $timeoutMilliseconds = 0): array|false {}
public function getPid(): int {}
}

125
ext/pdo_pgsql/pdo_pgsql_arginfo.h generated Normal file
View File

@@ -0,0 +1,125 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 2be4e9679d29fcbc3330b78f9e63c4c6e1284f19 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PdoPgsql_escapeIdentifier, 0, 1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, input, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PdoPgsql_copyFromArray, 0, 2, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, tableName, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, rows, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, separator, IS_STRING, 0, "\"\\t\"")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nullAs, IS_STRING, 0, "\"\\\\\\\\N\"")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fields, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PdoPgsql_copyFromFile, 0, 2, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, tableName, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, separator, IS_STRING, 0, "\"\\t\"")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nullAs, IS_STRING, 0, "\"\\\\\\\\N\"")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fields, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_PdoPgsql_copyToArray, 0, 1, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, tableName, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, separator, IS_STRING, 0, "\"\\t\"")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, nullAs, IS_STRING, 0, "\"\\\\\\\\N\"")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fields, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_PdoPgsql_copyToFile arginfo_class_PdoPgsql_copyFromFile
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_PdoPgsql_lobCreate, 0, 0, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PdoPgsql_lobOpen, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, oid, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, mode, IS_STRING, 0, "\"rb\"")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PdoPgsql_lobUnlink, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, oid, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_PdoPgsql_getNotify, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, fetchMode, IS_LONG, 0, "PDO::FETCH_DEFAULT")
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, timeoutMilliseconds, IS_LONG, 0, "0")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_PdoPgsql_getPid, 0, 0, IS_LONG, 0)
ZEND_END_ARG_INFO()
ZEND_METHOD(PdoPgsql, escapeIdentifier);
ZEND_METHOD(PdoPgsql, copyFromArray);
ZEND_METHOD(PdoPgsql, copyFromFile);
ZEND_METHOD(PdoPgsql, copyToArray);
ZEND_METHOD(PdoPgsql, copyToFile);
ZEND_METHOD(PdoPgsql, lobCreate);
ZEND_METHOD(PdoPgsql, lobOpen);
ZEND_METHOD(PdoPgsql, lobUnlink);
ZEND_METHOD(PdoPgsql, getNotify);
ZEND_METHOD(PdoPgsql, getPid);
static const zend_function_entry class_PdoPgsql_methods[] = {
ZEND_ME(PdoPgsql, escapeIdentifier, arginfo_class_PdoPgsql_escapeIdentifier, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, copyFromArray, arginfo_class_PdoPgsql_copyFromArray, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, copyFromFile, arginfo_class_PdoPgsql_copyFromFile, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, copyToArray, arginfo_class_PdoPgsql_copyToArray, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, copyToFile, arginfo_class_PdoPgsql_copyToFile, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, lobCreate, arginfo_class_PdoPgsql_lobCreate, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, lobOpen, arginfo_class_PdoPgsql_lobOpen, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, lobUnlink, arginfo_class_PdoPgsql_lobUnlink, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, getNotify, arginfo_class_PdoPgsql_getNotify, ZEND_ACC_PUBLIC)
ZEND_ME(PdoPgsql, getPid, arginfo_class_PdoPgsql_getPid, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static zend_class_entry *register_class_PdoPgsql(zend_class_entry *class_entry_PDO)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "PdoPgsql", class_PdoPgsql_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_PDO);
class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE;
zval const_ATTR_DISABLE_PREPARES_value;
ZVAL_LONG(&const_ATTR_DISABLE_PREPARES_value, PDO_PGSQL_ATTR_DISABLE_PREPARES);
zend_string *const_ATTR_DISABLE_PREPARES_name = zend_string_init_interned("ATTR_DISABLE_PREPARES", sizeof("ATTR_DISABLE_PREPARES") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_ATTR_DISABLE_PREPARES_name, &const_ATTR_DISABLE_PREPARES_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_ATTR_DISABLE_PREPARES_name);
zval const_TRANSACTION_IDLE_value;
ZVAL_LONG(&const_TRANSACTION_IDLE_value, PGSQL_TRANSACTION_IDLE);
zend_string *const_TRANSACTION_IDLE_name = zend_string_init_interned("TRANSACTION_IDLE", sizeof("TRANSACTION_IDLE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_TRANSACTION_IDLE_name, &const_TRANSACTION_IDLE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_TRANSACTION_IDLE_name);
zval const_TRANSACTION_ACTIVE_value;
ZVAL_LONG(&const_TRANSACTION_ACTIVE_value, PGSQL_TRANSACTION_ACTIVE);
zend_string *const_TRANSACTION_ACTIVE_name = zend_string_init_interned("TRANSACTION_ACTIVE", sizeof("TRANSACTION_ACTIVE") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_TRANSACTION_ACTIVE_name, &const_TRANSACTION_ACTIVE_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_TRANSACTION_ACTIVE_name);
zval const_TRANSACTION_INTRANS_value;
ZVAL_LONG(&const_TRANSACTION_INTRANS_value, PGSQL_TRANSACTION_INTRANS);
zend_string *const_TRANSACTION_INTRANS_name = zend_string_init_interned("TRANSACTION_INTRANS", sizeof("TRANSACTION_INTRANS") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_TRANSACTION_INTRANS_name, &const_TRANSACTION_INTRANS_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_TRANSACTION_INTRANS_name);
zval const_TRANSACTION_INERROR_value;
ZVAL_LONG(&const_TRANSACTION_INERROR_value, PGSQL_TRANSACTION_INERROR);
zend_string *const_TRANSACTION_INERROR_name = zend_string_init_interned("TRANSACTION_INERROR", sizeof("TRANSACTION_INERROR") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_TRANSACTION_INERROR_name, &const_TRANSACTION_INERROR_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_TRANSACTION_INERROR_name);
zval const_TRANSACTION_UNKNOWN_value;
ZVAL_LONG(&const_TRANSACTION_UNKNOWN_value, PGSQL_TRANSACTION_UNKNOWN);
zend_string *const_TRANSACTION_UNKNOWN_name = zend_string_init_interned("TRANSACTION_UNKNOWN", sizeof("TRANSACTION_UNKNOWN") - 1, 1);
zend_declare_typed_class_constant(class_entry, const_TRANSACTION_UNKNOWN_name, &const_TRANSACTION_UNKNOWN_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG));
zend_string_release(const_TRANSACTION_UNKNOWN_name);
return class_entry;
}

View File

@@ -588,8 +588,7 @@ static bool pgsql_handle_rollback(pdo_dbh_t *dbh)
return ret;
}
/* {{{ Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromArray)
void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -604,8 +603,8 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromArray)
ExecStatusType status;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|sss!",
&table_name, &table_name_len, &pg_rows,
&pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
&table_name, &table_name_len, &pg_rows,
&pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
RETURN_THROWS();
}
@@ -699,10 +698,15 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromArray)
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromFile)
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromArray)
{
pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
void pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -715,8 +719,8 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromFile)
php_stream *stream;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sp|sss!",
&table_name, &table_name_len, &filename, &filename_len,
&pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
&table_name, &table_name_len, &filename, &filename_len,
&pg_delim, &pg_delim_len, &pg_null_as, &pg_null_as_len, &pg_fields, &pg_fields_len) == FAILURE) {
RETURN_THROWS();
}
@@ -796,11 +800,15 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromFile)
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyToFile)
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyFromFile)
{
pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
void pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -891,10 +899,16 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyToFile)
RETURN_FALSE;
}
}
/* }}} */
/* {{{ Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyToArray)
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyToFile)
{
pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
void pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -966,11 +980,15 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyToArray)
RETURN_FALSE;
}
}
/* {{{ Returns true if the copy worked fine or false if error */
PHP_METHOD(PDO_PGSql_Ext, pgsqlCopyToArray)
{
pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ Creates a new large object, returning its identifier. Must be called inside a transaction. */
PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBCreate)
void pgsqlLOBCreate_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -995,10 +1013,15 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBCreate)
PDO_HANDLE_DBH_ERR();
RETURN_FALSE;
}
/* {{{ Creates a new large object, returning its identifier. Must be called inside a transaction. */
PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBCreate)
{
pgsqlLOBCreate_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ Opens an existing large object stream. Must be called inside a transaction. */
PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBOpen)
void pgsqlLOBOpen_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -1046,10 +1069,15 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBOpen)
PDO_HANDLE_DBH_ERR();
RETURN_FALSE;
}
/* {{{ Opens an existing large object stream. Must be called inside a transaction. */
PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBOpen)
{
pgsqlLOBOpen_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ Deletes the large object identified by oid. Must be called inside a transaction. */
PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBUnlink)
void pgsqlLOBUnlink_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -1081,10 +1109,15 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBUnlink)
PDO_HANDLE_DBH_ERR();
RETURN_FALSE;
}
/* {{{ Deletes the large object identified by oid. Must be called inside a transaction. */
PHP_METHOD(PDO_PGSql_Ext, pgsqlLOBUnlink)
{
pgsqlLOBUnlink_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ Get asynchronous notification */
PHP_METHOD(PDO_PGSql_Ext, pgsqlGetNotify)
void pgsqlGetNotify_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -1161,10 +1194,15 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlGetNotify)
PQfreemem(pgsql_notify);
}
/* {{{ Get asynchronous notification */
PHP_METHOD(PDO_PGSql_Ext, pgsqlGetNotify)
{
pgsqlGetNotify_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
/* {{{ Get backend(server) pid */
PHP_METHOD(PDO_PGSql_Ext, pgsqlGetPid)
void pgsqlGetPid_internal(INTERNAL_FUNCTION_PARAMETERS)
{
pdo_dbh_t *dbh;
pdo_pgsql_db_handle *H;
@@ -1178,6 +1216,12 @@ PHP_METHOD(PDO_PGSql_Ext, pgsqlGetPid)
RETURN_LONG(PQbackendPID(H->server));
}
/* {{{ Get backend(server) pid */
PHP_METHOD(PDO_PGSql_Ext, pgsqlGetPid)
{
pgsqlGetPid_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}
/* }}} */
static const zend_function_entry *pdo_pgsql_get_driver_methods(pdo_dbh_t *dbh, int kind)

View File

@@ -109,4 +109,14 @@ extern const php_stream_ops pdo_pgsql_lob_stream_ops;
void pdo_libpq_version(char *buf, size_t len);
void pdo_pgsql_close_lob_streams(pdo_dbh_t *dbh);
void pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlLOBCreate_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlLOBOpen_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlLOBUnlink_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlGetNotify_internal(INTERNAL_FUNCTION_PARAMETERS);
void pgsqlGetPid_internal(INTERNAL_FUNCTION_PARAMETERS);
#endif /* PHP_PDO_PGSQL_INT_H */

View File

@@ -0,0 +1,47 @@
--TEST--
PdoPgsql subclass basic
--EXTENSIONS--
pdo
pdo_pgsql
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
require dirname(__DIR__, 2) . '/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . "/config.inc";
$db = new PdoPgsql($config['ENV']['PDOTEST_DSN']);
$db->query('CREATE TABLE pdopgsql_001 (id INT, name TEXT)');
$db->query("INSERT INTO pdopgsql_001 VALUES (NULL, 'PHP'), (NULL, 'PHP6')");
foreach ($db->query('SELECT name FROM pdopgsql_001') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require __DIR__ . '/../../pdo/tests/pdo_test.inc';
$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt');
$pdo->query("DROP TABLE IF EXISTS pdopgsql_001");
?>
--EXPECT--
array(2) {
["name"]=>
string(3) "PHP"
[0]=>
string(3) "PHP"
}
array(2) {
["name"]=>
string(4) "PHP6"
[0]=>
string(4) "PHP6"
}
Fin.

View File

@@ -0,0 +1,56 @@
--TEST--
PdoPgsql connect through PDO::connect
--EXTENSIONS--
pdo
pdo_pgsql
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
require dirname(__DIR__, 2) . '/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . "/config.inc";
$db = Pdo::connect($config['ENV']['PDOTEST_DSN']);
if (!$db instanceof PdoPgsql) {
echo "Wrong class type. Should be PdoPgsql but is " . get_class($db) . "\n";
}
$db->exec('CREATE TABLE pdopgsql_002(id INT NOT NULL PRIMARY KEY, name VARCHAR(10))');
$db->exec("INSERT INTO pdopgsql_002 VALUES(1, 'A'), (2, 'B'), (3, 'C')");
foreach ($db->query('SELECT name FROM pdopgsql_002') as $row) {
var_dump($row);
}
echo "Fin.";
?>
--CLEAN--
<?php
require __DIR__ . '/../../pdo/tests/pdo_test.inc';
$pdo = PDOTest::test_factory(__DIR__ . '/common.phpt');
$pdo->query("DROP TABLE IF EXISTS pdopgsql_002");
?>
--EXPECT--
array(2) {
["name"]=>
string(1) "A"
[0]=>
string(1) "A"
}
array(2) {
["name"]=>
string(1) "B"
[0]=>
string(1) "B"
}
array(2) {
["name"]=>
string(1) "C"
[0]=>
string(1) "C"
}
Fin.

View File

@@ -0,0 +1,32 @@
--TEST--
PdoPgsql getWarningCount
--EXTENSIONS--
pdo
pdo_pgsql
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
require dirname(__DIR__, 2) . '/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . "/config.inc";
$db = Pdo::connect($config['ENV']['PDOTEST_DSN']);
if (!$db instanceof PdoPgsql) {
echo "Wrong class type. Should be PdoPgsql but is " . get_class($db) . "\n";
}
echo $db->escapeIdentifier("This is a quote\"") . "\n";
try {
$db->escapeIdentifier("aa\xC3\xC3\xC3");
} catch (PDOException $e) {
echo $e->getMessage() . "\n";
}
--EXPECT--
"This is a quote"""
SQLSTATE[HY000]: General error: 7 incomplete multibyte character

Some files were not shown because too many files have changed in this diff Show More