From c32c501222693f62f8d553b2a2c6da84aea16123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 19 May 2021 14:21:19 +0200 Subject: [PATCH 01/11] Migrate ext/odbc resources to opaque objects --- Zend/Optimizer/zend_func_infos.h | 25 - ext/odbc/odbc.stub.php | 859 ++++++++++++++----------------- ext/odbc/odbc_arginfo.h | 122 +++-- ext/odbc/php_odbc.c | 815 +++++++++++++++-------------- ext/odbc/php_odbc_includes.h | 16 +- ext/odbc/tests/bug78473.phpt | 6 +- 6 files changed, 912 insertions(+), 931 deletions(-) diff --git a/Zend/Optimizer/zend_func_infos.h b/Zend/Optimizer/zend_func_infos.h index 76628104528fe..6f039f70865ba 100644 --- a/Zend/Optimizer/zend_func_infos.h +++ b/Zend/Optimizer/zend_func_infos.h @@ -308,31 +308,6 @@ static const func_info_t func_infos[] = { F1("mysqli_stat", MAY_BE_STRING|MAY_BE_FALSE), F1("mysqli_store_result", MAY_BE_OBJECT|MAY_BE_FALSE), F1("mysqli_use_result", MAY_BE_OBJECT|MAY_BE_FALSE), - FN("odbc_prepare", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_exec", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_connect", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_pconnect", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_tables", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_columns", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_gettypeinfo", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_primarykeys", MAY_BE_RESOURCE|MAY_BE_FALSE), -#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) - FN("odbc_procedurecolumns", MAY_BE_RESOURCE|MAY_BE_FALSE), -#endif -#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) - FN("odbc_procedures", MAY_BE_RESOURCE|MAY_BE_FALSE), -#endif -#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) - FN("odbc_foreignkeys", MAY_BE_RESOURCE|MAY_BE_FALSE), -#endif - FN("odbc_specialcolumns", MAY_BE_RESOURCE|MAY_BE_FALSE), - FN("odbc_statistics", MAY_BE_RESOURCE|MAY_BE_FALSE), -#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) - FN("odbc_tableprivileges", MAY_BE_RESOURCE|MAY_BE_FALSE), -#endif -#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) - FN("odbc_columnprivileges", MAY_BE_RESOURCE|MAY_BE_FALSE), -#endif F1("opcache_get_status", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_FALSE), F1("opcache_get_configuration", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_FALSE), F1("openssl_x509_parse", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE), diff --git a/ext/odbc/odbc.stub.php b/ext/odbc/odbc.stub.php index 8432260ba6996..b69d91c497264 100644 --- a/ext/odbc/odbc.stub.php +++ b/ext/odbc/odbc.stub.php @@ -2,353 +2,353 @@ /** @generate-class-entries */ -/** - * @var string - * @cvalue PHP_ODBC_TYPE - */ -const ODBC_TYPE = UNKNOWN; -/** - * @var int - * @cvalue PHP_ODBC_BINMODE_PASSTHRU - */ -const ODBC_BINMODE_PASSTHRU = UNKNOWN; -/** - * @var int - * @cvalue PHP_ODBC_BINMODE_RETURN - */ -const ODBC_BINMODE_RETURN = UNKNOWN; -/** - * @var int - * @cvalue PHP_ODBC_BINMODE_CONVERT - */ -const ODBC_BINMODE_CONVERT = UNKNOWN; - -/* Define Constants for options. These Constants are defined in */ - -/** - * @var int - * @cvalue SQL_ODBC_CURSORS - */ -const SQL_ODBC_CURSORS = UNKNOWN; -/** - * @var int - * @cvalue SQL_CUR_USE_DRIVER - */ -const SQL_CUR_USE_DRIVER = UNKNOWN; -/** - * @var int - * @cvalue SQL_CUR_USE_IF_NEEDED - */ -const SQL_CUR_USE_IF_NEEDED = UNKNOWN; -/** - * @var int - * @cvalue SQL_CUR_USE_ODBC - */ -const SQL_CUR_USE_ODBC = UNKNOWN; - -/** - * @var int - * @cvalue SQL_CONCURRENCY - */ -const SQL_CONCURRENCY = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_READ_ONLY - */ -const SQL_CONCUR_READ_ONLY = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_LOCK - */ -const SQL_CONCUR_LOCK = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_ROWVER - */ -const SQL_CONCUR_ROWVER = UNKNOWN; -/** - * @var int - * @cvalue SQL_CONCUR_VALUES - */ -const SQL_CONCUR_VALUES = UNKNOWN; - -/** - * @var int - * @cvalue SQL_CURSOR_TYPE - */ -const SQL_CURSOR_TYPE = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_FORWARD_ONLY - */ -const SQL_CURSOR_FORWARD_ONLY = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_KEYSET_DRIVEN - */ -const SQL_CURSOR_KEYSET_DRIVEN = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_DYNAMIC - */ -const SQL_CURSOR_DYNAMIC = UNKNOWN; -/** - * @var int - * @cvalue SQL_CURSOR_STATIC - */ -const SQL_CURSOR_STATIC = UNKNOWN; - -/** - * @var int - * @cvalue SQL_KEYSET_SIZE - */ -const SQL_KEYSET_SIZE = UNKNOWN; - -/* these are for the Data Source type */ - -/** - * @var int - * @cvalue SQL_FETCH_FIRST - */ -const SQL_FETCH_FIRST = UNKNOWN; -/** - * @var int - * @cvalue SQL_FETCH_NEXT - */ -const SQL_FETCH_NEXT = UNKNOWN; - -/* register the standard data types */ - -/** - * @var int - * @cvalue SQL_CHAR - */ -const SQL_CHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_VARCHAR - */ -const SQL_VARCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_LONGVARCHAR - */ -const SQL_LONGVARCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_DECIMAL - */ -const SQL_DECIMAL = UNKNOWN; -/** - * @var int - * @cvalue SQL_NUMERIC - */ -const SQL_NUMERIC = UNKNOWN; -/** - * @var int - * @cvalue SQL_BIT - */ -const SQL_BIT = UNKNOWN; -/** - * @var int - * @cvalue SQL_TINYINT - */ -const SQL_TINYINT = UNKNOWN; -/** - * @var int - * @cvalue SQL_SMALLINT - */ -const SQL_SMALLINT = UNKNOWN; -/** - * @var int - * @cvalue SQL_INTEGER - */ -const SQL_INTEGER = UNKNOWN; -/** - * @var int - * @cvalue SQL_BIGINT - */ -const SQL_BIGINT = UNKNOWN; -/** - * @var int - * @cvalue SQL_REAL - */ -const SQL_REAL = UNKNOWN; -/** - * @var int - * @cvalue SQL_FLOAT - */ -const SQL_FLOAT = UNKNOWN; -/** - * @var int - * @cvalue SQL_DOUBLE - */ -const SQL_DOUBLE = UNKNOWN; -/** - * @var int - * @cvalue SQL_BINARY - */ -const SQL_BINARY = UNKNOWN; -/** - * @var int - * @cvalue SQL_VARBINARY - */ -const SQL_VARBINARY = UNKNOWN; -/** - * @var int - * @cvalue SQL_LONGVARBINARY - */ -const SQL_LONGVARBINARY = UNKNOWN; -/** - * @var int - * @cvalue SQL_DATE - */ -const SQL_DATE = UNKNOWN; -/** - * @var int - * @cvalue SQL_TIME - */ -const SQL_TIME = UNKNOWN; -/** - * @var int - * @cvalue SQL_TIMESTAMP - */ -const SQL_TIMESTAMP = UNKNOWN; - -#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) -/** - * @var int - * @cvalue SQL_TYPE_DATE - */ -const SQL_TYPE_DATE = UNKNOWN; -/** - * @var int - * @cvalue SQL_TYPE_TIME - */ -const SQL_TYPE_TIME = UNKNOWN; -/** - * @var int - * @cvalue SQL_TYPE_TIMESTAMP - */ -const SQL_TYPE_TIMESTAMP = UNKNOWN; -/** - * @var int - * @cvalue SQL_WCHAR - */ -const SQL_WCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_WVARCHAR - */ -const SQL_WVARCHAR = UNKNOWN; -/** - * @var int - * @cvalue SQL_WLONGVARCHAR - */ -const SQL_WLONGVARCHAR = UNKNOWN; - -/* SQLSpecialColumns values */ - -/** - * @var int - * @cvalue SQL_BEST_ROWID - */ -const SQL_BEST_ROWID = UNKNOWN; -/** - * @var int - * @cvalue SQL_ROWVER - */ -const SQL_ROWVER = UNKNOWN; -/** - * @var int - * @cvalue SQL_SCOPE_CURROW - */ -const SQL_SCOPE_CURROW = UNKNOWN; -/** - * @var int - * @cvalue SQL_SCOPE_TRANSACTION - */ -const SQL_SCOPE_TRANSACTION = UNKNOWN; -/** - * @var int - * @cvalue SQL_SCOPE_SESSION - */ -const SQL_SCOPE_SESSION = UNKNOWN; -/** - * @var int - * @cvalue SQL_NO_NULLS - */ -const SQL_NO_NULLS = UNKNOWN; -/** - * @var int - * @cvalue SQL_NULLABLE - */ -const SQL_NULLABLE = UNKNOWN; - -/* SQLStatistics values */ - -/** - * @var int - * @cvalue SQL_INDEX_UNIQUE - */ -const SQL_INDEX_UNIQUE = UNKNOWN; -/** - * @var int - * @cvalue SQL_INDEX_ALL - */ -const SQL_INDEX_ALL = UNKNOWN; -/** - * @var int - * @cvalue SQL_ENSURE - */ -const SQL_ENSURE = UNKNOWN; -/** - * @var int - * @cvalue SQL_QUICK - */ -const SQL_QUICK = UNKNOWN; - -#endif - - - -function odbc_close_all(): void {} - -/** @param resource $statement */ -function odbc_binmode($statement, int $mode): true {} - -/** @param resource $statement */ -function odbc_longreadlen($statement, int $length): true {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_prepare($odbc, string $query) {} - -/** @param resource $statement */ -function odbc_execute($statement, array $params = []): bool {} - -/** @param resource $statement */ -function odbc_cursor($statement): string|false {} - -#ifdef HAVE_SQLDATASOURCES -/** @param resource $odbc */ -function odbc_data_source($odbc, int $fetch_type): array|null|false {} -#endif - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_exec($odbc, string $query) {} - -/** - * @param resource $odbc - * @return resource|false - * @alias odbc_exec - */ -function odbc_do($odbc, string $query) {} +namespace ODBC { + /** + * @strict-properties + * @not-serializable + */ + class Connection + { + } + + /** + * @strict-properties + * @not-serializable + */ + class Result + { + } +} + +namespace { + /** + * @var string + * @cvalue PHP_ODBC_TYPE + */ + const ODBC_TYPE = UNKNOWN; + /** + * @var int + * @cvalue PHP_ODBC_BINMODE_PASSTHRU + */ + const ODBC_BINMODE_PASSTHRU = UNKNOWN; + /** + * @var int + * @cvalue PHP_ODBC_BINMODE_RETURN + */ + const ODBC_BINMODE_RETURN = UNKNOWN; + /** + * @var int + * @cvalue PHP_ODBC_BINMODE_CONVERT + */ + const ODBC_BINMODE_CONVERT = UNKNOWN; + + /* Define Constants for options. These Constants are defined in */ + + /** + * @var int + * @cvalue SQL_ODBC_CURSORS + */ + const SQL_ODBC_CURSORS = UNKNOWN; + /** + * @var int + * @cvalue SQL_CUR_USE_DRIVER + */ + const SQL_CUR_USE_DRIVER = UNKNOWN; + /** + * @var int + * @cvalue SQL_CUR_USE_IF_NEEDED + */ + const SQL_CUR_USE_IF_NEEDED = UNKNOWN; + /** + * @var int + * @cvalue SQL_CUR_USE_ODBC + */ + const SQL_CUR_USE_ODBC = UNKNOWN; + + /** + * @var int + * @cvalue SQL_CONCURRENCY + */ + const SQL_CONCURRENCY = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_READ_ONLY + */ + const SQL_CONCUR_READ_ONLY = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_LOCK + */ + const SQL_CONCUR_LOCK = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_ROWVER + */ + const SQL_CONCUR_ROWVER = UNKNOWN; + /** + * @var int + * @cvalue SQL_CONCUR_VALUES + */ + const SQL_CONCUR_VALUES = UNKNOWN; + + /** + * @var int + * @cvalue SQL_CURSOR_TYPE + */ + const SQL_CURSOR_TYPE = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_FORWARD_ONLY + */ + const SQL_CURSOR_FORWARD_ONLY = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_KEYSET_DRIVEN + */ + const SQL_CURSOR_KEYSET_DRIVEN = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_DYNAMIC + */ + const SQL_CURSOR_DYNAMIC = UNKNOWN; + /** + * @var int + * @cvalue SQL_CURSOR_STATIC + */ + const SQL_CURSOR_STATIC = UNKNOWN; + + /** + * @var int + * @cvalue SQL_KEYSET_SIZE + */ + const SQL_KEYSET_SIZE = UNKNOWN; + + /* these are for the Data Source type */ + + /** + * @var int + * @cvalue SQL_FETCH_FIRST + */ + const SQL_FETCH_FIRST = UNKNOWN; + /** + * @var int + * @cvalue SQL_FETCH_NEXT + */ + const SQL_FETCH_NEXT = UNKNOWN; + + /* register the standard data types */ + + /** + * @var int + * @cvalue SQL_CHAR + */ + const SQL_CHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_VARCHAR + */ + const SQL_VARCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_LONGVARCHAR + */ + const SQL_LONGVARCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_DECIMAL + */ + const SQL_DECIMAL = UNKNOWN; + /** + * @var int + * @cvalue SQL_NUMERIC + */ + const SQL_NUMERIC = UNKNOWN; + /** + * @var int + * @cvalue SQL_BIT + */ + const SQL_BIT = UNKNOWN; + /** + * @var int + * @cvalue SQL_TINYINT + */ + const SQL_TINYINT = UNKNOWN; + /** + * @var int + * @cvalue SQL_SMALLINT + */ + const SQL_SMALLINT = UNKNOWN; + /** + * @var int + * @cvalue SQL_INTEGER + */ + const SQL_INTEGER = UNKNOWN; + /** + * @var int + * @cvalue SQL_BIGINT + */ + const SQL_BIGINT = UNKNOWN; + /** + * @var int + * @cvalue SQL_REAL + */ + const SQL_REAL = UNKNOWN; + /** + * @var int + * @cvalue SQL_FLOAT + */ + const SQL_FLOAT = UNKNOWN; + /** + * @var int + * @cvalue SQL_DOUBLE + */ + const SQL_DOUBLE = UNKNOWN; + /** + * @var int + * @cvalue SQL_BINARY + */ + const SQL_BINARY = UNKNOWN; + /** + * @var int + * @cvalue SQL_VARBINARY + */ + const SQL_VARBINARY = UNKNOWN; + /** + * @var int + * @cvalue SQL_LONGVARBINARY + */ + const SQL_LONGVARBINARY = UNKNOWN; + /** + * @var int + * @cvalue SQL_DATE + */ + const SQL_DATE = UNKNOWN; + /** + * @var int + * @cvalue SQL_TIME + */ + const SQL_TIME = UNKNOWN; + /** + * @var int + * @cvalue SQL_TIMESTAMP + */ + const SQL_TIMESTAMP = UNKNOWN; + + #if (defined(ODBCVER) && (ODBCVER >= 0x0300)) + /** + * @var int + * @cvalue SQL_TYPE_DATE + */ + const SQL_TYPE_DATE = UNKNOWN; + /** + * @var int + * @cvalue SQL_TYPE_TIME + */ + const SQL_TYPE_TIME = UNKNOWN; + /** + * @var int + * @cvalue SQL_TYPE_TIMESTAMP + */ + const SQL_TYPE_TIMESTAMP = UNKNOWN; + /** + * @var int + * @cvalue SQL_WCHAR + */ + const SQL_WCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_WVARCHAR + */ + const SQL_WVARCHAR = UNKNOWN; + /** + * @var int + * @cvalue SQL_WLONGVARCHAR + */ + const SQL_WLONGVARCHAR = UNKNOWN; + + /* SQLSpecialColumns values */ + + /** + * @var int + * @cvalue SQL_BEST_ROWID + */ + const SQL_BEST_ROWID = UNKNOWN; + /** + * @var int + * @cvalue SQL_ROWVER + */ + const SQL_ROWVER = UNKNOWN; + /** + * @var int + * @cvalue SQL_SCOPE_CURROW + */ + const SQL_SCOPE_CURROW = UNKNOWN; + /** + * @var int + * @cvalue SQL_SCOPE_TRANSACTION + */ + const SQL_SCOPE_TRANSACTION = UNKNOWN; + /** + * @var int + * @cvalue SQL_SCOPE_SESSION + */ + const SQL_SCOPE_SESSION = UNKNOWN; + /** + * @var int + * @cvalue SQL_NO_NULLS + */ + const SQL_NO_NULLS = UNKNOWN; + /** + * @var int + * @cvalue SQL_NULLABLE + */ + const SQL_NULLABLE = UNKNOWN; + + /* SQLStatistics values */ + + /** + * @var int + * @cvalue SQL_INDEX_UNIQUE + */ + const SQL_INDEX_UNIQUE = UNKNOWN; + /** + * @var int + * @cvalue SQL_INDEX_ALL + */ + const SQL_INDEX_ALL = UNKNOWN; + /** + * @var int + * @cvalue SQL_ENSURE + */ + const SQL_ENSURE = UNKNOWN; + /** + * @var int + * @cvalue SQL_QUICK + */ + const SQL_QUICK = UNKNOWN; + + #endif + + function odbc_close_all(): void {} + + function odbc_binmode(ODBC\Result $statement, int $mode): true {} + + function odbc_longreadlen(ODBC\Result $statement, int $length): true {} + + function odbc_prepare(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + + function odbc_execute(ODBC\Result $statement, array $params = []): bool {} + + function odbc_cursor(ODBC\Result $statement): string|false {} + + #ifdef HAVE_SQLDATASOURCES + function odbc_data_source(ODBC\Connection $odbc, int $fetch_type): array|null|false {} + #endif + + function odbc_exec(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + + /** @alias odbc_exec */ + function odbc_do(ODBC\Connection $odbc, string $query): ODBC\Result|false {} #ifdef PHP_ODBC_HAVE_FETCH_HASH /** @param resource $statement */ @@ -364,158 +364,85 @@ function odbc_fetch_array($statement, ?int $row = null): array|false {} */ function odbc_fetch_into($statement, &$array, ?int $row = null): int|false {} -/** @param resource $statement */ -function odbc_fetch_row($statement, ?int $row = null): bool {} + function odbc_fetch_row(ODBC\Result $statement, ?int $row = null): bool {} -/** @param resource $statement */ -function odbc_result($statement, string|int $field): string|bool|null {} + function odbc_result(ODBC\Result $statement, string|int $field): string|bool|null {} -/** - * @param resource $statement - * @deprecated - */ -function odbc_result_all($statement, string $format = ""): int|false {} + /** @deprecated */ + function odbc_result_all(ODBC\Result $statement, string $format = ""): int|false {} -/** @param resource $statement */ -function odbc_free_result($statement): true {} + function odbc_free_result(ODBC\Result $statement): true {} -/** - * @return resource|false - */ -function odbc_connect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER) {} + function odbc_connect(string $dsn, ?string $user = null, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} -/** - * @return resource|false - */ -function odbc_pconnect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER) {} + function odbc_pconnect(string $dsn, ?string $user = null, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} -/** @param resource $odbc */ -function odbc_close($odbc): void {} + function odbc_close(ODBC\Connection $odbc): void {} -/** @param resource $statement */ -function odbc_num_rows($statement): int {} + function odbc_num_rows(ODBC\Result $statement): int {} -#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) -/** @param resource $statement */ -function odbc_next_result($statement): bool {} -#endif + #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) + function odbc_next_result(ODBC\Result $statement): bool {} + #endif -/** @param resource $statement */ -function odbc_num_fields($statement): int {} + function odbc_num_fields(ODBC\Result $statement): int {} -/** @param resource $statement */ -function odbc_field_name($statement, int $field): string|false {} + function odbc_field_name(ODBC\Result $statement, int $field): string|false {} -/** @param resource $statement */ -function odbc_field_type($statement, int $field): string|false {} + function odbc_field_type(ODBC\Result $statement, int $field): string|false {} -/** @param resource $statement */ -function odbc_field_len($statement, int $field): int|false {} + function odbc_field_len(ODBC\Result $statement, int $field): int|false {} -/** - * @param resource $statement - * @alias odbc_field_len - */ -function odbc_field_precision($statement, int $field): int|false {} + /** @alias odbc_field_len */ + function odbc_field_precision(ODBC\Result $statement, int $field): int|false {} -/** @param resource $statement */ -function odbc_field_scale($statement, int $field): int|false {} + function odbc_field_scale(ODBC\Result $statement, int $field): int|false {} -/** @param resource $statement */ -function odbc_field_num($statement, string $field): int|false {} + function odbc_field_num(ODBC\Result $statement, string $field): int|false {} -/** @param resource $odbc */ -function odbc_autocommit($odbc, ?bool $enable = null): int|bool {} + function odbc_autocommit(ODBC\Connection $odbc, ?bool $enable = null): int|bool {} -/** @param resource $odbc */ -function odbc_commit($odbc): bool {} + function odbc_commit(ODBC\Connection $odbc): bool {} -/** @param resource $odbc */ -function odbc_rollback($odbc): bool {} + function odbc_rollback(ODBC\Connection $odbc): bool {} -/** @param resource|null $odbc */ -function odbc_error($odbc = null): string {} + function odbc_error(?ODBC\Connection $odbc = null): string {} -/** @param resource|null $odbc */ -function odbc_errormsg($odbc = null): string {} + function odbc_errormsg(?ODBC\Connection $odbc = null): string {} -/** @param resource $odbc */ -function odbc_setoption($odbc, int $which, int $option, int $value): bool {} + function odbc_setoption(ODBC\Connection|ODBC\Result $odbc, int $which, int $option, int $value): bool {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_tables($odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null) {} + function odbc_tables(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null): ODBC\Result|false {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_columns($odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null) {} + function odbc_columns(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null): ODBC\Result|false {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_gettypeinfo($odbc, int $data_type = 0) {} + function odbc_gettypeinfo(ODBC\Connection $odbc, int $data_type = 0): ODBC\Result|false {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_primarykeys($odbc, ?string $catalog, string $schema, string $table) {} + function odbc_primarykeys(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table): ODBC\Result|false {} -#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_procedurecolumns($odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null) {} + #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) + function odbc_procedurecolumns(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null): ODBC\Result|false {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_procedures($odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null) {} + function odbc_procedures(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null): ODBC\Result|false {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_foreignkeys($odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table) {} -#endif + function odbc_foreignkeys(ODBC\Connection $odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table): ODBC\Result|false {} + #endif -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_specialcolumns($odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable) {} + function odbc_specialcolumns(ODBC\Connection $odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable): ODBC\Result|false {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_statistics($odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy) {} + function odbc_statistics(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy): ODBC\Result|false {} -#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_tableprivileges($odbc, ?string $catalog, string $schema, string $table) {} + #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) + function odbc_tableprivileges(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table): ODBC\Result|false {} -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_columnprivileges($odbc, ?string $catalog, string $schema, string $table, string $column) {} -#endif + function odbc_columnprivileges(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table, string $column): ODBC\Result|false {} + #endif -/* odbc_utils.c */ + /* odbc_utils.c */ -function odbc_connection_string_is_quoted(string $str): bool {} + function odbc_connection_string_is_quoted(string $str): bool {} -function odbc_connection_string_should_quote(string $str): bool {} + function odbc_connection_string_should_quote(string $str): bool {} -function odbc_connection_string_quote(string $str): string {} + function odbc_connection_string_quote(string $str): string {} +} diff --git a/ext/odbc/odbc_arginfo.h b/ext/odbc/odbc_arginfo.h index 7a2916054152f..5f6ddc5a969a1 100644 --- a/ext/odbc/odbc_arginfo.h +++ b/ext/odbc/odbc_arginfo.h @@ -1,36 +1,36 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a64be64f69159d0c8ad2c3b951c6451a040c3c73 */ + * Stub hash: 6483b0aca02dbe2950090e7207832a1426d5d862 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close_all, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_binmode, 0, 2, IS_TRUE, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_longreadlen, 0, 2, IS_TRUE, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_prepare, 0, 0, 2) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_prepare, 0, 2, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_execute, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, params, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_cursor, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() #if defined(HAVE_SQLDATASOURCES) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_data_source, 0, 2, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, fetch_type, IS_LONG, 0) ZEND_END_ARG_INFO() #endif @@ -60,58 +60,58 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_fetch_into, 0, 2, MAY_BE_LO ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_fetch_row, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_result, 0, 2, MAY_BE_STRING|MAY_BE_BOOL|MAY_BE_NULL) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_MASK(0, field, MAY_BE_STRING|MAY_BE_LONG, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_result_all, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, format, IS_STRING, 0, "\"\"") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_free_result, 0, 1, IS_TRUE, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_connect, 0, 0, 1) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_connect, 0, 3, ODBC\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, user, IS_STRING, 1, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, password, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, cursor_option, IS_LONG, 0, "SQL_CUR_USE_DRIVER") ZEND_END_ARG_INFO() #define arginfo_odbc_pconnect arginfo_odbc_connect ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close, 0, 1, IS_VOID, 0) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_num_rows, 0, 1, IS_LONG, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_next_result, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() #endif #define arginfo_odbc_num_fields arginfo_odbc_num_rows ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_name, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_odbc_field_type arginfo_odbc_field_name ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_len, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -120,65 +120,65 @@ ZEND_END_ARG_INFO() #define arginfo_odbc_field_scale arginfo_odbc_field_len ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_num, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_INFO(0, statement) + ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_autocommit, 0, 1, MAY_BE_LONG|MAY_BE_BOOL) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_commit, 0, 1, _IS_BOOL, 0) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_END_ARG_INFO() #define arginfo_odbc_rollback arginfo_odbc_commit ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_error, 0, 0, IS_STRING, 0) - ZEND_ARG_INFO_WITH_DEFAULT_VALUE(0, odbc, "null") + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, odbc, ODBC\\Connection, 1, "null") ZEND_END_ARG_INFO() #define arginfo_odbc_errormsg arginfo_odbc_error ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_setoption, 0, 4, _IS_BOOL, 0) - ZEND_ARG_INFO(0, odbc) + ZEND_ARG_OBJ_TYPE_MASK(0, odbc, ODBC\\Connection|ODBC\\Result, 0, NULL) ZEND_ARG_TYPE_INFO(0, which, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tables, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tables, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, table, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, types, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columns, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columns, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, table, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, column, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_gettypeinfo, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_gettypeinfo, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, data_type, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_primarykeys, 0, 0, 4) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_primarykeys, 0, 4, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) ZEND_END_ARG_INFO() #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedurecolumns, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedurecolumns, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, procedure, IS_STRING, 1, "null") @@ -187,8 +187,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_procedures, 0, 0, 1) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedures, 0, 1, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, procedure, IS_STRING, 1, "null") @@ -196,8 +196,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_foreignkeys, 0, 0, 7) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_foreignkeys, 0, 7, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, pk_catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, pk_schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, pk_table, IS_STRING, 0) @@ -207,8 +207,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_foreignkeys, 0, 0, 7) ZEND_END_ARG_INFO() #endif -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_specialcolumns, 0, 0, 7) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_specialcolumns, 0, 7, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) @@ -217,8 +217,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_specialcolumns, 0, 0, 7) ZEND_ARG_TYPE_INFO(0, nullable, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_statistics, 0, 0, 6) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_statistics, 0, 6, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -227,8 +227,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_statistics, 0, 0, 6) ZEND_END_ARG_INFO() #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_tableprivileges, 0, 0, 4) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tableprivileges, 0, 4, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -236,8 +236,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columnprivileges, 0, 0, 5) - ZEND_ARG_INFO(0, odbc) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columnprivileges, 0, 5, ODBC\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -390,6 +390,14 @@ static const zend_function_entry ext_functions[] = { ZEND_FE_END }; +static const zend_function_entry class_ODBC_Connection_methods[] = { + ZEND_FE_END +}; + +static const zend_function_entry class_ODBC_Result_methods[] = { + ZEND_FE_END +}; + static void register_odbc_symbols(int module_number) { REGISTER_STRING_CONSTANT("ODBC_TYPE", PHP_ODBC_TYPE, CONST_PERSISTENT); @@ -489,3 +497,25 @@ static void register_odbc_symbols(int module_number) zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "odbc_pconnect", sizeof("odbc_pconnect") - 1), 2, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0); } + +static zend_class_entry *register_class_ODBC_Connection(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ODBC", "Connection", class_ODBC_Connection_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; + + return class_entry; +} + +static zend_class_entry *register_class_ODBC_Result(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ODBC", "Result", class_ODBC_Result_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; + + return class_entry; +} diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 5f6f84488030f..7cab3782d6a3f 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -29,6 +29,8 @@ #include "ext/standard/info.h" #include "ext/standard/php_string.h" #include "ext/standard/php_standard.h" +#include "Zend/zend_interfaces.h" +#include "zend_smart_str.h" #include "php_odbc.h" #include "php_odbc_includes.h" @@ -49,18 +51,140 @@ #include "odbc_arginfo.h" -/* - * not defined elsewhere - */ +#define CHECK_ODBC_CONNECTION(conn) \ + if (conn == NULL) { \ + zend_throw_error(NULL, "ODBC connection has already been closed"); \ + RETURN_THROWS(); \ + } -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif +#define CHECK_ODBC_RESULT(result) \ + if (result->conn_ptr == NULL) { \ + zend_throw_error(NULL, "ODBC result has already been closed"); \ + RETURN_THROWS(); \ + } void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent); +static void safe_odbc_disconnect(void *handle); + +static int le_pconn; + +static zend_class_entry *odbc_connection_ce, *odbc_result_ce; +static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_handlers; + +static inline odbc_link *odbc_link_from_obj(zend_object *obj) { + return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); +} + +#define Z_ODBC_LINK_P(zv) odbc_link_from_obj(Z_OBJ_P(zv)) +#define Z_ODBC_CONNECTION_P(zv) Z_ODBC_LINK_P(zv)->connection + +static zend_object *odbc_connection_create_object(zend_class_entry *class_type) { + odbc_link *intern = zend_object_alloc(sizeof(odbc_link), class_type); + + zend_object_std_init(&intern->std, class_type); + object_properties_init(&intern->std, class_type); + intern->std.handlers = &odbc_connection_object_handlers; + + return &intern->std; +} + +static zend_function *odbc_connection_get_constructor(zend_object *object) { + zend_throw_error(NULL, "Cannot directly construct ODBC\\Connection, use odbc_connect() or odbc_pconnect() instead"); + return NULL; +} -static int le_result, le_conn, le_pconn; +static void odbc_link_free(odbc_link *link) +{ + /* If aborted via timer expiration, don't try to call any unixODBC function */ + if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { + safe_odbc_disconnect(link->connection->hdbc); + SQLFreeConnect(link->connection->hdbc); + SQLFreeEnv(link->connection->henv); + } + efree(link->connection); + link->connection = NULL; + ODBCG(num_links)--; + if (!link->persistent) { + zend_hash_del(&ODBCG(connections), link->hash); + } + zend_string_release(link->hash); +} + +static void odbc_connection_free_obj(zend_object *obj) +{ + odbc_link *link = odbc_link_from_obj(obj); + + if (!link->connection) { + zend_object_std_dtor(&link->std); + return; + } + + odbc_link_free(link); + zend_object_std_dtor(&link->std); +} + +static inline odbc_result *odbc_result_from_obj(zend_object *obj) { + return (odbc_result *)((char *)(obj) - XtOffsetOf(odbc_result, std)); +} + +#define Z_ODBC_RESULT_P(zv) odbc_result_from_obj(Z_OBJ_P(zv)) + +static zend_object *odbc_result_create_object(zend_class_entry *class_type) { + odbc_result *intern = zend_object_alloc(sizeof(odbc_result), class_type); + + zend_object_std_init(&intern->std, class_type); + object_properties_init(&intern->std, class_type); + intern->std.handlers = &odbc_result_object_handlers; + + return &intern->std; +} + +static zend_function *odbc_result_get_constructor(zend_object *object) { + zend_throw_error(NULL, "Cannot directly construct ODBC\\Result, use an appropriate odbc_* function instead"); + return NULL; +} + +static void odbc_result_free(odbc_result *res) +{ + int i; + + if (res->values) { + for(i = 0; i < res->numcols; i++) { + if (res->values[i].value) + efree(res->values[i].value); + } + efree(res->values); + res->values = NULL; + } + /* If aborted via timer expiration, don't try to call any unixODBC function */ + if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { +#if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35) + SQLTransact(res->conn_ptr->henv, res->conn_ptr->hdbc, + (SQLUSMALLINT) SQL_COMMIT); +#endif + SQLFreeStmt(res->stmt,SQL_DROP); + /* We don't want the connection to be closed after the last statement has been closed + * Connections will be closed on shutdown + * zend_list_delete(res->conn_ptr->id); + */ + } + if (res->param_info) { + efree(res->param_info); + } + efree(res); +} + +static void odbc_result_free_obj(zend_object *obj) { + odbc_result *result = odbc_result_from_obj(obj); + + if (!result->stmt) { + zend_object_std_dtor(&result->std); + return; + } + + odbc_result_free(result); + zend_object_std_dtor(&result->std); +} #define SAFE_SQL_NTS(n) ((SQLSMALLINT) ((n)?(SQL_NTS):0)) @@ -93,44 +217,18 @@ ZEND_TSRMLS_CACHE_DEFINE() ZEND_GET_MODULE(odbc) #endif -/* {{{ _free_odbc_result */ -static void _free_odbc_result(zend_resource *rsrc) -{ - odbc_result *res = (odbc_result *)rsrc->ptr; - int i; +static void close_results_with_connection(const odbc_connection *conn) { + zval *p; - if (res) { - if (res->values) { - for(i = 0; i < res->numcols; i++) { - if (res->values[i].value) - efree(res->values[i].value); - } - efree(res->values); - res->values = NULL; + ZEND_HASH_FOREACH_VAL(&ODBCG(results), p) { + odbc_result *result = Z_ODBC_RESULT_P(p); + if (result->conn_ptr == conn) { + odbc_result_free((odbc_result*) p); } - /* If aborted via timer expiration, don't try to call any unixODBC function */ - if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { -#if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35) - SQLTransact(res->conn_ptr->henv, res->conn_ptr->hdbc, - (SQLUSMALLINT) SQL_COMMIT); -#endif - SQLFreeStmt(res->stmt,SQL_DROP); - /* We don't want the connection to be closed after the last statement has been closed - * Connections will be closed on shutdown - * zend_list_delete(res->conn_ptr->id); - */ - } - if (res->param_info) { - efree(res->param_info); - } - efree(res); - } + } ZEND_HASH_FOREACH_END(); } -/* }}} */ -/* {{{ safe_odbc_disconnect - * disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) - */ +/* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ static void safe_odbc_disconnect( void *handle ) { int ret; @@ -142,51 +240,13 @@ static void safe_odbc_disconnect( void *handle ) SQLDisconnect( handle ); } } -/* }}} */ - -/* {{{ _close_odbc_conn */ -static void _close_odbc_conn(zend_resource *rsrc) -{ - zend_resource *p; - odbc_result *res; - - odbc_connection *conn = (odbc_connection *)rsrc->ptr; - - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - res = (odbc_result *)p->ptr; - if (res->conn_ptr == conn) { - zend_list_close(p); - } - } - } ZEND_HASH_FOREACH_END(); - - /* If aborted via timer expiration, don't try to call any unixODBC function */ - if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { - safe_odbc_disconnect(conn->hdbc); - SQLFreeConnect(conn->hdbc); - SQLFreeEnv(conn->henv); - } - efree(conn); - ODBCG(num_links)--; -} -/* }}} */ /* {{{ void _close_odbc_pconn */ static void _close_odbc_pconn(zend_resource *rsrc) { - zend_resource *p; - odbc_result *res; odbc_connection *conn = (odbc_connection *)rsrc->ptr; - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - res = (odbc_result *)p->ptr; - if (res->conn_ptr == conn) { - zend_list_close(p); - } - } - } ZEND_HASH_FOREACH_END(); + close_results_with_connection(conn); /* If aborted via timer expiration, don't try to call any unixODBC function */ if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { @@ -198,6 +258,7 @@ static void _close_odbc_pconn(zend_resource *rsrc) ODBCG(num_links)--; ODBCG(num_persistent)--; + rsrc->ptr = NULL; } /* }}} */ @@ -378,6 +439,8 @@ static PHP_GINIT_FUNCTION(odbc) ZEND_TSRMLS_CACHE_UPDATE(); #endif odbc_globals->num_persistent = 0; + zend_hash_init(&odbc_globals->results, 0, NULL, NULL, 1); + zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, 1); } /* {{{ PHP_MINIT_FUNCTION */ @@ -389,19 +452,39 @@ PHP_MINIT_FUNCTION(odbc) #endif REGISTER_INI_ENTRIES(); - le_result = zend_register_list_destructors_ex(_free_odbc_result, NULL, "odbc result", module_number); - le_conn = zend_register_list_destructors_ex(_close_odbc_conn, NULL, "odbc link", module_number); le_pconn = zend_register_list_destructors_ex(NULL, _close_odbc_pconn, "odbc link persistent", module_number); odbc_module_entry.type = type; + register_odbc_symbols(module_number); + + odbc_connection_ce = register_class_ODBC_Connection(); + odbc_connection_ce->create_object = odbc_connection_create_object; + odbc_connection_ce->default_object_handlers = &odbc_connection_object_handlers; + + memcpy(&odbc_connection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + odbc_connection_object_handlers.offset = XtOffsetOf(odbc_link, std); + odbc_connection_object_handlers.free_obj = odbc_connection_free_obj; + odbc_connection_object_handlers.get_constructor = odbc_connection_get_constructor; + odbc_connection_object_handlers.clone_obj = NULL; + odbc_connection_object_handlers.compare = zend_objects_not_comparable; + + odbc_result_ce = register_class_ODBC_Result(); + odbc_result_ce->create_object = odbc_result_create_object; + odbc_result_ce->default_object_handlers = &odbc_result_object_handlers; + + memcpy(&odbc_result_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + odbc_result_object_handlers.offset = XtOffsetOf(odbc_result, std); + odbc_result_object_handlers.free_obj = odbc_result_free_obj; + odbc_result_object_handlers.get_constructor = odbc_result_get_constructor; + odbc_result_object_handlers.clone_obj = NULL; + odbc_result_object_handlers.compare = zend_objects_not_comparable; + #if defined(HAVE_IBMDB2) && defined(_AIX) /* atexit() handler in the DB2/AIX library segfaults in PHP CLI */ /* DB2NOEXITLIST env variable prevents DB2 from invoking atexit() */ putenv("DB2NOEXITLIST=TRUE"); #endif - register_odbc_symbols(module_number); - return SUCCESS; } /* }}} */ @@ -427,6 +510,9 @@ PHP_RSHUTDOWN_FUNCTION(odbc) /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(odbc) { + zend_hash_destroy(&ODBCG(results)); + zend_hash_destroy(&ODBCG(connections)); + UNREGISTER_INI_ENTRIES(); return SUCCESS; } @@ -510,13 +596,12 @@ void php_odbc_fetch_attribs(INTERNAL_FUNCTION_PARAMETERS, int mode) zval *pv_res; zend_long flag; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &flag) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &flag) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (mode) { result->longreadlen = flag; @@ -655,13 +740,12 @@ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) RETCODE rc; zval *pv_conn; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_conn) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); rc = SQLTransact(conn->henv, conn->hdbc, (SQLUSMALLINT)((type)?SQL_COMMIT:SQL_ROLLBACK)); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { @@ -673,19 +757,6 @@ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) } /* }}} */ -/* {{{ _close_pconn_with_res */ -static int _close_pconn_with_res(zval *zv, void *p) -{ - zend_resource *le = Z_RES_P(zv); - zend_resource *res = (zend_resource*)p; - if (le->type == le_pconn && (((odbc_connection *)(le->ptr))->res == res)) { - return ZEND_HASH_APPLY_REMOVE; - } else { - return ZEND_HASH_APPLY_KEEP; - } -} -/* }}} */ - /* {{{ odbc_column_lengths */ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) { @@ -704,13 +775,12 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) zval *pv_res; zend_long pv_num; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &pv_num) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &pv_num) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (pv_num < 1) { zend_argument_value_error(2, "must be greater than 0"); @@ -738,30 +808,26 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ Close all ODBC connections */ PHP_FUNCTION(odbc_close_all) { - zend_resource *p; + zval *p; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } /* Loop through list and close all statements */ - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - zend_list_close(p); - } + ZEND_HASH_FOREACH_VAL(&ODBCG(results), p) { + odbc_result_free((odbc_result*) p); } ZEND_HASH_FOREACH_END(); - /* Second loop through list, now close all connections */ - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr) { - if (p->type == le_conn){ - zend_list_close(p); - } else if (p->type == le_pconn){ - zend_list_close(p); - /* Delete the persistent connection */ - zend_hash_apply_with_argument(&EG(persistent_list), - _close_pconn_with_res, (void *)p); - } + /* Second loop through list, now close all non-persistent connections */ + ZEND_HASH_FOREACH_VAL(&ODBCG(connections), p) { + odbc_link_free((odbc_link*) p); + } ZEND_HASH_FOREACH_END(); + + /* Third loop through persistent list, now close all persistent connections */ + ZEND_HASH_FOREACH_VAL(&EG(persistent_list), p) { + if (Z_RES_P(p)->type == le_pconn) { + zend_list_close(Z_RES_P(p)); } } ZEND_HASH_FOREACH_END(); } @@ -795,29 +861,29 @@ PHP_FUNCTION(odbc_prepare) SQLUINTEGER scrollopts; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pv_conn, &query, &query_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pv_conn, odbc_connection_ce, &query, &query_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); result->numparams = 0; result->param_info = NULL; rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -870,12 +936,10 @@ PHP_FUNCTION(odbc_prepare) odbc_sql_error(result->conn_ptr, result->stmt, "SQLDescribeParameter"); SQLFreeStmt(result->stmt, SQL_RESET_PARAMS); efree(result->param_info); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } } - - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -914,13 +978,12 @@ PHP_FUNCTION(odbc_execute) int i, ne; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|h", &pv_res, &pv_param_ht) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|h", &pv_res, odbc_result_ce, &pv_param_ht) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numparams > 0) { if ((ne = zend_hash_num_elements(pv_param_ht)) < result->numparams) { @@ -1071,13 +1134,12 @@ PHP_FUNCTION(odbc_cursor) odbc_result *result; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); rc = SQLGetInfo(result->conn_ptr->hdbc,SQL_MAX_CURSOR_NAME_LEN, (void *)&max_len,sizeof(max_len),&len); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { @@ -1129,7 +1191,7 @@ PHP_FUNCTION(odbc_data_source) UCHAR server_name[100], desc[200]; SQLSMALLINT len1=0, len2=0, fetch_type; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &zv_conn, &zv_fetch_type) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &zv_conn, odbc_connection_ce, &zv_fetch_type) == FAILURE) { RETURN_THROWS(); } @@ -1140,9 +1202,8 @@ PHP_FUNCTION(odbc_data_source) RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(zv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(zv_conn); + CHECK_ODBC_CONNECTION(conn); /* now we have the "connection" lets call the DataSource object */ rc = SQLDataSources(conn->henv, @@ -1192,26 +1253,26 @@ PHP_FUNCTION(odbc_exec) SQLUINTEGER scrollopts; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pv_conn, &query, &query_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pv_conn, odbc_connection_ce, &query, &query_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -1238,7 +1299,7 @@ PHP_FUNCTION(odbc_exec) */ odbc_sql_error(conn, result->stmt, "SQLExecDirect"); SQLFreeStmt(result->stmt, SQL_DROP); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -1253,7 +1314,6 @@ PHP_FUNCTION(odbc_exec) Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -1277,13 +1337,12 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) SQLUSMALLINT RowStatus[1]; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l!", &pv_res, &pv_row, &pv_row_is_null) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!", &pv_res, odbc_result_ce, &pv_row, &pv_row_is_null) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); /* TODO deprecate $row argument values less than 1 after PHP 8.4 */ @@ -1321,6 +1380,7 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) else #endif result->fetched++; + } for(i = 0; i < result->numcols; i++) { sql_c_type = SQL_C_CHAR; @@ -1437,13 +1497,12 @@ PHP_FUNCTION(odbc_fetch_into) SQLUSMALLINT RowStatus[1]; #endif /* HAVE_SQL_EXTENDED_FETCH */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz|l!", &pv_res, &pv_res_arr, &pv_row, &pv_row_is_null) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Oz|l!", &pv_res, odbc_result_ce, &pv_res_arr, &pv_row, &pv_row_is_null) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); /* TODO deprecate $row argument values less than 1 after PHP 8.4 */ @@ -1484,6 +1543,7 @@ PHP_FUNCTION(odbc_fetch_into) else #endif result->fetched++; + } for(i = 0; i < result->numcols; i++) { sql_c_type = SQL_C_CHAR; @@ -1567,13 +1627,12 @@ PHP_FUNCTION(odbc_fetch_row) SQLUSMALLINT RowStatus[1]; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l!", &pv_res, &pv_row, &pv_row_is_null) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l!", &pv_res, odbc_result_ce, &pv_row, &pv_row_is_null) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); #ifndef HAVE_SQL_EXTENDED_FETCH if (!pv_row_is_null) { @@ -1635,7 +1694,7 @@ PHP_FUNCTION(odbc_result) #endif ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_RESOURCE(pv_res) + Z_PARAM_OBJECT_OF_CLASS(pv_res, odbc_result_ce) Z_PARAM_STR_OR_LONG(pv_field_str, pv_field_long) ZEND_PARSE_PARAMETERS_END(); @@ -1647,9 +1706,8 @@ PHP_FUNCTION(odbc_result) field_ind = (int) pv_field_long - 1; } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -1843,13 +1901,12 @@ PHP_FUNCTION(odbc_result_all) SQLUSMALLINT RowStatus[1]; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s", &pv_res, &pv_format, &pv_format_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s", &pv_res, odbc_result_ce, &pv_format, &pv_format_len) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -1977,13 +2034,12 @@ PHP_FUNCTION(odbc_free_result) odbc_result *result; int i; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->values) { for (i = 0; i < result->numcols; i++) { @@ -2016,18 +2072,23 @@ PHP_FUNCTION(odbc_pconnect) /* }}} */ /* {{{ odbc_sqlconnect */ -int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int cur_opt, int persistent) +bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, int persistent, zend_string *hash) { RETCODE rc; + odbc_link *link; + + object_init_ex(zv, odbc_connection_ce); + link = Z_ODBC_LINK_P(zv); + link->connection = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent); + memset(link->connection, 0, sizeof(odbc_connection)); - *conn = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent); - memset(*conn, 0, sizeof(odbc_connection)); - (*conn)->persistent = persistent; - SQLAllocEnv(&((*conn)->henv)); - SQLAllocConnect((*conn)->henv, &((*conn)->hdbc)); + link->persistent = persistent; + link->hash = hash; + SQLAllocEnv(link->connection->henv); + SQLAllocConnect(link->connection->henv, link->connection->hdbc); #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) - SQLSetConnectOption((*conn)->hdbc, SQL_TRANSLATE_OPTION, + SQLSetConnectOption((link->connection->hdbc, SQL_TRANSLATE_OPTION, SQL_SOLID_XLATOPT_NOCNV); #endif #ifdef HAVE_OPENLINK @@ -2035,16 +2096,15 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int char dsnbuf[1024]; short dsnbuflen; - rc = SQLDriverConnect((*conn)->hdbc, NULL, db, SQL_NTS, dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); + rc = SQLDriverConnect(link->connection->hdbc, NULL, db, SQL_NTS, dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); } #else if (cur_opt != SQL_CUR_DEFAULT) { - rc = SQLSetConnectOption((*conn)->hdbc, SQL_ODBC_CURSORS, cur_opt); + rc = SQLSetConnectOption(link->connection->hdbc, SQL_ODBC_CURSORS, cur_opt); if (rc != SQL_SUCCESS) { /* && rc != SQL_SUCCESS_WITH_INFO ? */ - odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLSetConnectOption"); - SQLFreeConnect((*conn)->hdbc); - pefree(*conn, persistent); - return FALSE; + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLSetConnectOption"); + SQLFreeConnect(link->connection->hdbc); + return false; } } /* Possible fix for bug #10250 @@ -2126,9 +2186,9 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int } if (direct) { - rc = SQLDriverConnect((*conn)->hdbc, NULL, (SQLCHAR *) ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); + rc = SQLDriverConnect(link->connection->hdbc, NULL, (SQLCHAR *) ldb, strlen(ldb), dsnbuf, sizeof(dsnbuf) - 1, &dsnbuflen, SQL_DRIVER_NOPROMPT); } else { - rc = SQLConnect((*conn)->hdbc, (SQLCHAR *) db, SQL_NTS, (SQLCHAR *) uid, SQL_NTS, (SQLCHAR *) pwd, SQL_NTS); + rc = SQLConnect(link->connection->hdbc, (SQLCHAR *) db, SQL_NTS, (SQLCHAR *) uid, SQL_NTS, (SQLCHAR *) pwd, SQL_NTS); } if (ldb) { @@ -2136,17 +2196,15 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int } } #else - rc = SQLConnect((*conn)->hdbc, (SQLCHAR *) db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS); + rc = SQLConnect(link->connection->hdbc, (SQLCHAR *) db, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS); #endif #endif if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - odbc_sql_error(*conn, SQL_NULL_HSTMT, "SQLConnect"); - SQLFreeConnect((*conn)->hdbc); - pefree((*conn), persistent); - return FALSE; + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLConnect"); + SQLFreeConnect(link->connection->hdbc); + return false; } -/* (*conn)->open = 1;*/ - return TRUE; + return true; } /* }}} */ @@ -2190,42 +2248,43 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) persistent = 0; } + smart_str hashed_details = {0}; + smart_str_append_printf(&hashed_details, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt); + try_and_get_another_connection: if (persistent) { - char *hashed_details; - int hashed_len; zend_resource *le; - hashed_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt); - /* the link is not in the persistent list */ - if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_len)) == NULL) { + if ((le = zend_hash_find_ptr(&EG(persistent_list), hashed_details.s)) == NULL) { if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { php_error_docref(NULL, E_WARNING, "Too many open links (" ZEND_LONG_FMT ")", ODBCG(num_links)); - efree(hashed_details); + smart_str_free(&hashed_details); RETURN_FALSE; } if (ODBCG(max_persistent) != -1 && ODBCG(num_persistent) >= ODBCG(max_persistent)) { php_error_docref(NULL, E_WARNING,"Too many open persistent links (" ZEND_LONG_FMT ")", ODBCG(num_persistent)); - efree(hashed_details); + smart_str_free(&hashed_details); RETURN_FALSE; } - if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 1)) { - efree(hashed_details); + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, 1, hashed_details.s)) { + smart_str_free(&hashed_details); + zval_ptr_dtor(return_value); RETURN_FALSE; } - if (zend_register_persistent_resource(hashed_details, hashed_len, db_conn, le_pconn) == NULL) { - free(db_conn); - efree(hashed_details); + db_conn = Z_ODBC_CONNECTION_P(return_value); + + if (zend_register_persistent_resource(ZSTR_VAL(hashed_details.s), ZSTR_LEN(hashed_details.s), db_conn, le_pconn) == NULL) { + smart_str_free(&hashed_details); + zval_ptr_dtor(return_value); RETURN_FALSE; } + ODBCG(num_persistent)++; ODBCG(num_links)++; - db_conn->res = zend_register_resource(db_conn, le_pconn); - RETVAL_RES(db_conn->res); } else { /* found connection */ ZEND_ASSERT(le->type == le_pconn); @@ -2248,7 +2307,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) &dead, 0, NULL); if (ret == SQL_SUCCESS && dead == SQL_CD_TRUE) { /* Bail early here, since we know it's gone */ - zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_len); + zend_hash_del(&EG(persistent_list), hashed_details.s); goto try_and_get_another_connection; } /* If the driver doesn't support it, or returns @@ -2260,7 +2319,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) d_name, sizeof(d_name), &len); if(ret != SQL_SUCCESS || len == 0) { - zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_len); + zend_hash_del(&EG(persistent_list), hashed_details.s); /* Commented out to fix a possible double closure error * when working with persistent connections as submitted by * bug #15758 @@ -2271,23 +2330,29 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) goto try_and_get_another_connection; } } + + object_init_ex(return_value, odbc_connection_ce); + odbc_link *link = Z_ODBC_LINK_P(return_value); + link->connection = db_conn; + link->hash = zend_string_copy(hashed_details.s); + link->persistent = 1; } - efree(hashed_details); - db_conn->res = zend_register_resource(db_conn, le_pconn); - RETVAL_RES(db_conn->res); } else { /* non persistent */ if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { - php_error_docref(NULL, E_WARNING,"Too many open connections (" ZEND_LONG_FMT ")",ODBCG(num_links)); + php_error_docref(NULL, E_WARNING,"Too many open connections (" ZEND_LONG_FMT ")", ODBCG(num_links)); + smart_str_free(&hashed_details); RETURN_FALSE; } - if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 0)) { + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, 0, hashed_details.s)) { + smart_str_free(&hashed_details); RETURN_FALSE; } - db_conn->res = zend_register_resource(db_conn, le_conn); - RETVAL_RES(db_conn->res); ODBCG(num_links)++; } + + zend_hash_update(&ODBCG(connections), hashed_details.s, return_value); + smart_str_free(&hashed_details); } /* }}} */ @@ -2295,37 +2360,22 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) PHP_FUNCTION(odbc_close) { zval *pv_conn; - zend_resource *p; - odbc_connection *conn; - odbc_result *res; - int is_pconn = 0; + odbc_link *link; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_conn) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + link = Z_ODBC_LINK_P(pv_conn); + CHECK_ODBC_CONNECTION(link->connection); - if (Z_RES_P(pv_conn)->type == le_pconn) { - is_pconn = 1; + if (link->persistent) { + zend_hash_del(&EG(persistent_list), link->hash); } - ZEND_HASH_FOREACH_PTR(&EG(regular_list), p) { - if (p->ptr && (p->type == le_result)) { - res = (odbc_result *)p->ptr; - if (res->conn_ptr == conn) { - zend_list_close(p); - } - } - } ZEND_HASH_FOREACH_END(); - - zend_list_close(Z_RES_P(pv_conn)); + close_results_with_connection(link->connection); - if(is_pconn){ - zend_hash_apply_with_argument(&EG(persistent_list), _close_pconn_with_res, (void *) Z_RES_P(pv_conn)); - } + odbc_link_free(link); } /* }}} */ @@ -2336,13 +2386,12 @@ PHP_FUNCTION(odbc_num_rows) SQLLEN rows; zval *pv_res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); SQLRowCount(result->stmt, &rows); RETURN_LONG(rows); @@ -2357,13 +2406,12 @@ PHP_FUNCTION(odbc_next_result) zval *pv_res; int rc, i; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->values) { for(i = 0; i < result->numcols; i++) { @@ -2405,13 +2453,12 @@ PHP_FUNCTION(odbc_num_fields) odbc_result *result; zval *pv_res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &pv_res) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); RETURN_LONG(result->numcols); } @@ -2424,13 +2471,12 @@ PHP_FUNCTION(odbc_field_name) zval *pv_res; zend_long pv_num; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &pv_num) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &pv_num) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (pv_num < 1) { zend_argument_value_error(2, "must be greater than 0"); @@ -2460,13 +2506,12 @@ PHP_FUNCTION(odbc_field_type) zval *pv_res; zend_long pv_num; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &pv_res, &pv_num) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &pv_res, odbc_result_ce, &pv_num) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (pv_num < 1) { zend_argument_value_error(2, "must be greater than 0"); @@ -2510,13 +2555,12 @@ PHP_FUNCTION(odbc_field_num) odbc_result *result; zval *pv_res; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &pv_res, &fname, &fname_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os", &pv_res, odbc_result_ce, &fname, &fname_len) == FAILURE) { RETURN_THROWS(); } - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_res), "ODBC result", le_result)) == NULL) { - RETURN_THROWS(); - } + result = Z_ODBC_RESULT_P(pv_res); + CHECK_ODBC_RESULT(result); if (result->numcols == 0) { php_error_docref(NULL, E_WARNING, "No tuples available at this result index"); @@ -2547,13 +2591,12 @@ PHP_FUNCTION(odbc_autocommit) bool pv_onoff = 0; bool pv_onoff_is_null = true; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|b!", &pv_conn, &pv_onoff, &pv_onoff_is_null) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b!", &pv_conn, odbc_connection_ce, &pv_onoff, &pv_onoff_is_null) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); if (!pv_onoff_is_null) { rc = SQLSetConnectOption(conn->hdbc, SQL_AUTOCOMMIT, pv_onoff ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF); @@ -2596,14 +2639,14 @@ static void php_odbc_lasterror(INTERNAL_FUNCTION_PARAMETERS, int mode) zval *pv_handle = NULL; char *ret; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &pv_handle) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|O!", &pv_handle, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } if (pv_handle) { - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_handle), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_handle); + CHECK_ODBC_CONNECTION(conn); + if (mode == 0) { ret = conn->laststate; } else { @@ -2644,36 +2687,42 @@ PHP_FUNCTION(odbc_errormsg) */ PHP_FUNCTION(odbc_setoption) { - odbc_connection *conn; + odbc_link *link; odbc_result *result; RETCODE rc; zval *pv_handle; zend_long pv_which, pv_opt, pv_val; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "olll", &pv_handle, &pv_which, &pv_opt, &pv_val) == FAILURE) { RETURN_THROWS(); } switch (pv_which) { case 1: /* SQLSetConnectOption */ - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_handle), "ODBC-Link", le_conn, le_pconn))) { + if (!instanceof_function(Z_OBJCE_P(pv_handle), odbc_connection_ce)) { + zend_argument_type_error(1, "must be of type ODBC\\Connection for SQLSetConnectOption()"); RETURN_THROWS(); } + link = Z_ODBC_LINK_P(pv_handle); + CHECK_ODBC_CONNECTION(link->connection); - if (conn->persistent) { + if (link->persistent) { php_error_docref(NULL, E_WARNING, "Unable to set option for persistent connection"); RETURN_FALSE; } - rc = SQLSetConnectOption(conn->hdbc, (unsigned short) pv_opt, pv_val); + rc = SQLSetConnectOption(link->connection->hdbc, (unsigned short) pv_opt, pv_val); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { - odbc_sql_error(conn, SQL_NULL_HSTMT, "SetConnectOption"); + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SetConnectOption"); RETURN_FALSE; } break; case 2: /* SQLSetStmtOption */ - if ((result = (odbc_result *)zend_fetch_resource(Z_RES_P(pv_handle), "ODBC result", le_result)) == NULL) { + if (!instanceof_function(Z_OBJCE_P(pv_handle), odbc_result_ce)) { + zend_argument_type_error(1, "must be of type ODBC\\Result for SQLSetStmtOption()"); RETURN_THROWS(); } + result = Z_ODBC_RESULT_P(pv_handle); + CHECK_ODBC_RESULT(result); rc = SQLSetStmtOption(result->stmt, (unsigned short) pv_opt, pv_val); @@ -2705,27 +2754,27 @@ PHP_FUNCTION(odbc_tables) size_t cat_len = 0, schema_len = 0, table_len = 0, type_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len, &type, &type_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2742,7 +2791,7 @@ PHP_FUNCTION(odbc_tables) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLTables"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2756,7 +2805,6 @@ PHP_FUNCTION(odbc_tables) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -2770,27 +2818,27 @@ PHP_FUNCTION(odbc_columns) size_t cat_len = 0, schema_len = 0, table_len = 0, column_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len, &column, &column_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2809,7 +2857,7 @@ PHP_FUNCTION(odbc_columns) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLColumns"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2823,7 +2871,6 @@ PHP_FUNCTION(odbc_columns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -2838,27 +2885,27 @@ PHP_FUNCTION(odbc_columnprivileges) size_t cat_len = 0, schema_len, table_len, column_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!sss", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!sss", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len, &column, &column_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2870,7 +2917,7 @@ PHP_FUNCTION(odbc_columnprivileges) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLColumnPrivileges"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2884,7 +2931,6 @@ PHP_FUNCTION(odbc_columnprivileges) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_DBMAKER || HAVE_SOLID*/ @@ -2900,7 +2946,7 @@ PHP_FUNCTION(odbc_foreignkeys) size_t pcat_len = 0, pschema_len, ptable_len, fcat_len, fschema_len, ftable_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!sssss", &pv_conn, &pcat, &pcat_len, &pschema, &pschema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!sssss", &pv_conn, odbc_connection_ce, &pcat, &pcat_len, &pschema, &pschema_len, &ptable, &ptable_len, &fcat, &fcat_len, &fschema, &fschema_len, &ftable, &ftable_len) == FAILURE) { RETURN_THROWS(); } @@ -2917,22 +2963,22 @@ PHP_FUNCTION(odbc_foreignkeys) EMPTY_TO_NULL(ftable); #endif - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2960,7 +3006,6 @@ PHP_FUNCTION(odbc_foreignkeys) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_SOLID */ @@ -2968,6 +3013,9 @@ PHP_FUNCTION(odbc_foreignkeys) /* {{{ Returns a result identifier containing information about data types supported by the data source */ PHP_FUNCTION(odbc_gettypeinfo) { + zend_value_error("Nope"); + RETURN_THROWS(); + zval *pv_conn; zend_long pv_data_type = SQL_ALL_TYPES; odbc_result *result = NULL; @@ -2975,28 +3023,30 @@ PHP_FUNCTION(odbc_gettypeinfo) RETCODE rc; SQLSMALLINT data_type; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &pv_conn, &pv_data_type) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &pv_conn, odbc_connection_ce, &pv_data_type) == FAILURE) { RETURN_THROWS(); } + printf("Hell noo"); + data_type = (SQLSMALLINT) pv_data_type; - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3004,7 +3054,7 @@ PHP_FUNCTION(odbc_gettypeinfo) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLGetTypeInfo"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3018,7 +3068,6 @@ PHP_FUNCTION(odbc_gettypeinfo) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3032,26 +3081,26 @@ PHP_FUNCTION(odbc_primarykeys) size_t cat_len = 0, schema_len, table_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!ss", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3062,7 +3111,7 @@ PHP_FUNCTION(odbc_primarykeys) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLPrimaryKeys"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3076,7 +3125,6 @@ PHP_FUNCTION(odbc_primarykeys) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3091,27 +3139,27 @@ PHP_FUNCTION(odbc_procedurecolumns) size_t cat_len = 0, schema_len = 0, proc_len = 0, col_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len, &col, &col_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3123,7 +3171,7 @@ PHP_FUNCTION(odbc_procedurecolumns) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLProcedureColumns"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3137,7 +3185,6 @@ PHP_FUNCTION(odbc_procedurecolumns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3153,26 +3200,26 @@ PHP_FUNCTION(odbc_procedures) size_t cat_len = 0, schema_len = 0, proc_len = 0; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|s!s!s!", &pv_conn, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!s!s!", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &proc, &proc_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3183,7 +3230,7 @@ PHP_FUNCTION(odbc_procedures) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLProcedures"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3197,7 +3244,6 @@ PHP_FUNCTION(odbc_procedures) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3214,7 +3260,7 @@ PHP_FUNCTION(odbc_specialcolumns) SQLUSMALLINT type, scope, nullable; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rls!ssll", &pv_conn, &vtype, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ols!ssll", &pv_conn, odbc_connection_ce, &vtype, &cat, &cat_len, &schema, &schema_len, &name, &name_len, &vscope, &vnullable) == FAILURE) { RETURN_THROWS(); } @@ -3223,22 +3269,22 @@ PHP_FUNCTION(odbc_specialcolumns) scope = (SQLUSMALLINT) vscope; nullable = (SQLUSMALLINT) vnullable; - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3251,7 +3297,7 @@ PHP_FUNCTION(odbc_specialcolumns) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLSpecialColumns"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3265,7 +3311,6 @@ PHP_FUNCTION(odbc_specialcolumns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3281,7 +3326,7 @@ PHP_FUNCTION(odbc_statistics) SQLUSMALLINT unique, reserved; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!ssll", &pv_conn, &cat, &cat_len, &schema, &schema_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!ssll", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &name, &name_len, &vunique, &vreserved) == FAILURE) { RETURN_THROWS(); } @@ -3289,22 +3334,22 @@ PHP_FUNCTION(odbc_statistics) unique = (SQLUSMALLINT) vunique; reserved = (SQLUSMALLINT) vreserved; - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3317,7 +3362,7 @@ PHP_FUNCTION(odbc_statistics) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLStatistics"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3331,7 +3376,6 @@ PHP_FUNCTION(odbc_statistics) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ @@ -3346,26 +3390,26 @@ PHP_FUNCTION(odbc_tableprivileges) size_t cat_len = 0, schema_len, table_len; RETCODE rc; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs!ss", &pv_conn, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "Os!ss", &pv_conn, odbc_connection_ce, &cat, &cat_len, &schema, &schema_len, &table, &table_len) == FAILURE) { RETURN_THROWS(); } - if (!(conn = (odbc_connection *)zend_fetch_resource2(Z_RES_P(pv_conn), "ODBC-Link", le_conn, le_pconn))) { - RETURN_THROWS(); - } + conn = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(conn); - result = (odbc_result *)ecalloc(1, sizeof(odbc_result)); + object_init_ex(return_value, odbc_result_ce); + result = Z_ODBC_RESULT_P(return_value); rc = PHP_ODBC_SQLALLOCSTMT(conn->hdbc, &(result->stmt)); if (rc == SQL_INVALID_HANDLE) { - efree(result); php_error_docref(NULL, E_WARNING, "SQLAllocStmt error 'Invalid Handle'"); + zval_ptr_dtor(return_value); RETURN_FALSE; } if (rc == SQL_ERROR) { odbc_sql_error(conn, SQL_NULL_HSTMT, "SQLAllocStmt"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3376,7 +3420,7 @@ PHP_FUNCTION(odbc_tableprivileges) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLTablePrivileges"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3390,7 +3434,6 @@ PHP_FUNCTION(odbc_tableprivileges) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); } /* }}} */ #endif /* HAVE_DBMAKER */ diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h index 07ee99e2f0075..b10951c3b4b52 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -191,10 +191,15 @@ typedef struct odbc_connection { ODBC_SQL_CONN_T hdbc; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - zend_resource *res; - int persistent; } odbc_connection; +typedef struct odbc_link { + odbc_connection *connection; + zend_string *hash; + bool persistent; + zend_object std; +} odbc_link; + typedef struct odbc_result_value { char name[256]; char *value; @@ -220,8 +225,9 @@ typedef struct odbc_result { zend_long longreadlen; int binmode; int fetched; - odbc_param_info * param_info; + odbc_param_info *param_info; odbc_connection *conn_ptr; + zend_object std; } odbc_result; ZEND_BEGIN_MODULE_GLOBALS(odbc) @@ -240,8 +246,8 @@ ZEND_BEGIN_MODULE_GLOBALS(odbc) zend_long default_cursortype; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - HashTable *resource_list; - HashTable *resource_plist; + HashTable results; + HashTable connections; ZEND_END_MODULE_GLOBALS(odbc) int odbc_add_result(HashTable *list, odbc_result *result); diff --git a/ext/odbc/tests/bug78473.phpt b/ext/odbc/tests/bug78473.phpt index 3903187a36219..bed712e37bd8d 100644 --- a/ext/odbc/tests/bug78473.phpt +++ b/ext/odbc/tests/bug78473.phpt @@ -11,6 +11,6 @@ try { } var_dump(STDIN); ?> ---EXPECTF-- -odbc_close(): supplied resource is not a valid ODBC-Link resource -resource(%d) of type (stream) +--EXPECT-- +odbc_close(): Argument #1 ($odbc) must be of type ODBC\Connection, resource given +resource(1) of type (stream) From cceabac75423d7cf54a75434bbd4eb4c99931dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Thu, 28 Sep 2023 21:48:50 +0200 Subject: [PATCH 02/11] Address code review comments --- ext/odbc/php_odbc.c | 58 ++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 7cab3782d6a3f..9313b6445ed65 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -146,12 +146,11 @@ static zend_function *odbc_result_get_constructor(zend_object *object) { static void odbc_result_free(odbc_result *res) { - int i; - if (res->values) { - for(i = 0; i < res->numcols; i++) { - if (res->values[i].value) + for (int i = 0; i < res->numcols; i++) { + if (res->values[i].value) { efree(res->values[i].value); + } } efree(res->values); res->values = NULL; @@ -165,7 +164,6 @@ static void odbc_result_free(odbc_result *res) SQLFreeStmt(res->stmt,SQL_DROP); /* We don't want the connection to be closed after the last statement has been closed * Connections will be closed on shutdown - * zend_list_delete(res->conn_ptr->id); */ } if (res->param_info) { @@ -190,6 +188,7 @@ static void odbc_result_free_obj(zend_object *obj) { PHP_ODBC_API ZEND_DECLARE_MODULE_GLOBALS(odbc) static PHP_GINIT_FUNCTION(odbc); +static PHP_GSHUTDOWN_FUNCTION(odbc); /* {{{ odbc_module_entry */ zend_module_entry odbc_module_entry = { @@ -204,7 +203,7 @@ zend_module_entry odbc_module_entry = { PHP_ODBC_VERSION, PHP_MODULE_GLOBALS(odbc), PHP_GINIT(odbc), - NULL, + PHP_GSHUTDOWN(odbc), NULL, STANDARD_MODULE_PROPERTIES_EX }; @@ -218,12 +217,14 @@ ZEND_GET_MODULE(odbc) #endif static void close_results_with_connection(const odbc_connection *conn) { + zend_ulong num_index; zval *p; - ZEND_HASH_FOREACH_VAL(&ODBCG(results), p) { + ZEND_HASH_FOREACH_NUM_KEY_VAL(&ODBCG(results), num_index, p) { odbc_result *result = Z_ODBC_RESULT_P(p); if (result->conn_ptr == conn) { odbc_result_free((odbc_result*) p); + zend_hash_index_del(&ODBCG(results), num_index); } } ZEND_HASH_FOREACH_END(); } @@ -443,6 +444,12 @@ static PHP_GINIT_FUNCTION(odbc) zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, 1); } +static PHP_GSHUTDOWN_FUNCTION(odbc) +{ + zend_hash_destroy(&odbc_globals->results); + zend_hash_destroy(&odbc_globals->connections); +} + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(odbc) { @@ -510,9 +517,6 @@ PHP_RSHUTDOWN_FUNCTION(odbc) /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(odbc) { - zend_hash_destroy(&ODBCG(results)); - zend_hash_destroy(&ODBCG(connections)); - UNREGISTER_INI_ENTRIES(); return SUCCESS; } @@ -819,6 +823,8 @@ PHP_FUNCTION(odbc_close_all) odbc_result_free((odbc_result*) p); } ZEND_HASH_FOREACH_END(); + zend_hash_clean(&ODBCG(results)); + /* Second loop through list, now close all non-persistent connections */ ZEND_HASH_FOREACH_VAL(&ODBCG(connections), p) { odbc_link_free((odbc_link*) p); @@ -912,7 +918,7 @@ PHP_FUNCTION(odbc_prepare) break; default: odbc_sql_error(conn, result->stmt, "SQLPrepare"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -940,6 +946,8 @@ PHP_FUNCTION(odbc_prepare) RETURN_FALSE; } } + + zend_hash_next_index_insert_new(&ODBCG(results), return_value); } /* }}} */ @@ -1314,6 +1322,8 @@ PHP_FUNCTION(odbc_exec) Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; + + zend_hash_next_index_insert_new(&ODBCG(results), return_value); } /* }}} */ @@ -2072,7 +2082,7 @@ PHP_FUNCTION(odbc_pconnect) /* }}} */ /* {{{ odbc_sqlconnect */ -bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, int persistent, zend_string *hash) +bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool persistent, zend_string *hash) { RETCODE rc; odbc_link *link; @@ -2103,7 +2113,6 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, int rc = SQLSetConnectOption(link->connection->hdbc, SQL_ODBC_CURSORS, cur_opt); if (rc != SQL_SUCCESS) { /* && rc != SQL_SUCCESS_WITH_INFO ? */ odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLSetConnectOption"); - SQLFreeConnect(link->connection->hdbc); return false; } } @@ -2201,7 +2210,6 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, int #endif if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLConnect"); - SQLFreeConnect(link->connection->hdbc); return false; } return true; @@ -2269,7 +2277,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) RETURN_FALSE; } - if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, 1, hashed_details.s)) { + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, true, hashed_details.s)) { smart_str_free(&hashed_details); zval_ptr_dtor(return_value); RETURN_FALSE; @@ -2344,8 +2352,9 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) RETURN_FALSE; } - if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, 0, hashed_details.s)) { + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, false, hashed_details.s)) { smart_str_free(&hashed_details); + zval_ptr_dtor(return_value); RETURN_FALSE; } ODBCG(num_links)++; @@ -2805,6 +2814,8 @@ PHP_FUNCTION(odbc_tables) } result->conn_ptr = conn; result->fetched = 0; + + zend_hash_next_index_insert_new(&ODBCG(results), return_value); } /* }}} */ @@ -2871,6 +2882,8 @@ PHP_FUNCTION(odbc_columns) } result->conn_ptr = conn; result->fetched = 0; + + zend_hash_next_index_insert_new(&ODBCG(results), return_value); } /* }}} */ @@ -2931,6 +2944,8 @@ PHP_FUNCTION(odbc_columnprivileges) } result->conn_ptr = conn; result->fetched = 0; + + zend_hash_next_index_insert_new(&ODBCG(results), return_value); } /* }}} */ #endif /* HAVE_DBMAKER || HAVE_SOLID*/ @@ -2992,7 +3007,7 @@ PHP_FUNCTION(odbc_foreignkeys) if (rc == SQL_ERROR) { odbc_sql_error(conn, result->stmt, "SQLForeignKeys"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -3006,6 +3021,8 @@ PHP_FUNCTION(odbc_foreignkeys) } result->conn_ptr = conn; result->fetched = 0; + + zend_hash_next_index_insert_new(&ODBCG(results), return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3013,9 +3030,6 @@ PHP_FUNCTION(odbc_foreignkeys) /* {{{ Returns a result identifier containing information about data types supported by the data source */ PHP_FUNCTION(odbc_gettypeinfo) { - zend_value_error("Nope"); - RETURN_THROWS(); - zval *pv_conn; zend_long pv_data_type = SQL_ALL_TYPES; odbc_result *result = NULL; @@ -3027,8 +3041,6 @@ PHP_FUNCTION(odbc_gettypeinfo) RETURN_THROWS(); } - printf("Hell noo"); - data_type = (SQLSMALLINT) pv_data_type; conn = Z_ODBC_CONNECTION_P(pv_conn); @@ -3068,6 +3080,8 @@ PHP_FUNCTION(odbc_gettypeinfo) } result->conn_ptr = conn; result->fetched = 0; + + zend_hash_next_index_insert_new(&ODBCG(results), return_value); } /* }}} */ From 16c8b5868189104a2e56d31e3e8ef2c041dbcd53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sat, 6 Apr 2024 10:56:51 +0200 Subject: [PATCH 03/11] Fixes --- ext/odbc/php_odbc.c | 148 +++++++++++------- ext/odbc/tests/bug78470.phpt | 3 +- ext/odbc/tests/odbc_close_all_001.phpt | 24 ++- ext/odbc/tests/odbc_columnprivileges_001.phpt | 9 +- ext/odbc/tests/odbc_free_result_001.phpt | 30 ++-- ext/odbc/tests/odbc_tables_001.phpt | 12 +- 6 files changed, 144 insertions(+), 82 deletions(-) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 9313b6445ed65..1c5589f734b22 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -65,12 +65,18 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent); static void safe_odbc_disconnect(void *handle); +static void close_results_with_connection(const odbc_connection *conn); static int le_pconn; static zend_class_entry *odbc_connection_ce, *odbc_result_ce; static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_handlers; +static void odbc_insert_new_result(zval *result) { + Z_TRY_ADDREF_P(result); + zend_hash_next_index_insert_new(&ODBCG(results), result); +} + static inline odbc_link *odbc_link_from_obj(zend_object *obj) { return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); } @@ -95,19 +101,29 @@ static zend_function *odbc_connection_get_constructor(zend_object *object) { static void odbc_link_free(odbc_link *link) { - /* If aborted via timer expiration, don't try to call any unixODBC function */ - if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { - safe_odbc_disconnect(link->connection->hdbc); - SQLFreeConnect(link->connection->hdbc); - SQLFreeEnv(link->connection->henv); - } - efree(link->connection); - link->connection = NULL; - ODBCG(num_links)--; - if (!link->persistent) { + ZEND_ASSERT(link->connection && "link has already been closed"); + + if (link->persistent) { + zend_hash_del(&EG(persistent_list), link->hash); + } else { + close_results_with_connection(link->connection); + zend_hash_del(&ODBCG(connections), link->hash); + + /* If aborted via timer expiration, don't try to call any unixODBC function */ + if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { + safe_odbc_disconnect(link->connection->hdbc); + SQLFreeConnect(link->connection->hdbc); + SQLFreeEnv(link->connection->henv); + } + efree(link->connection); + ODBCG(num_links)--; } + + link->connection = NULL; + zend_string_release(link->hash); + link->hash = NULL; } static void odbc_connection_free_obj(zend_object *obj) @@ -146,6 +162,8 @@ static zend_function *odbc_result_get_constructor(zend_object *object) { static void odbc_result_free(odbc_result *res) { + ZEND_ASSERT(res->conn_ptr && "result has already been closed"); + if (res->values) { for (int i = 0; i < res->numcols; i++) { if (res->values[i].value) { @@ -154,6 +172,7 @@ static void odbc_result_free(odbc_result *res) } efree(res->values); res->values = NULL; + res->numcols = 0; } /* If aborted via timer expiration, don't try to call any unixODBC function */ if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { @@ -165,21 +184,33 @@ static void odbc_result_free(odbc_result *res) /* We don't want the connection to be closed after the last statement has been closed * Connections will be closed on shutdown */ + res->stmt = NULL; } if (res->param_info) { efree(res->param_info); + res->param_info = NULL; } - efree(res); + res->conn_ptr = NULL; } static void odbc_result_free_obj(zend_object *obj) { + zend_ulong num_index; + zval *p; + odbc_result *result = odbc_result_from_obj(obj); - if (!result->stmt) { + if (!result->conn_ptr) { zend_object_std_dtor(&result->std); return; } + ZEND_HASH_FOREACH_NUM_KEY_VAL(&ODBCG(results), num_index, p) { + odbc_result *res = Z_ODBC_RESULT_P(p); + if (res->stmt == result->stmt) { + zend_hash_index_del(&ODBCG(results), num_index); + } + } ZEND_HASH_FOREACH_END(); + odbc_result_free(result); zend_object_std_dtor(&result->std); } @@ -223,7 +254,7 @@ static void close_results_with_connection(const odbc_connection *conn) { ZEND_HASH_FOREACH_NUM_KEY_VAL(&ODBCG(results), num_index, p) { odbc_result *result = Z_ODBC_RESULT_P(p); if (result->conn_ptr == conn) { - odbc_result_free((odbc_result*) p); + odbc_result_free(result); zend_hash_index_del(&ODBCG(results), num_index); } } ZEND_HASH_FOREACH_END(); @@ -256,6 +287,7 @@ static void _close_odbc_pconn(zend_resource *rsrc) SQLFreeEnv(conn->henv); } free(conn); + conn = NULL; ODBCG(num_links)--; ODBCG(num_persistent)--; @@ -812,30 +844,38 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ Close all ODBC connections */ PHP_FUNCTION(odbc_close_all) { - zval *p; + odbc_link *p; + zval *zv; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } - /* Loop through list and close all statements */ - ZEND_HASH_FOREACH_VAL(&ODBCG(results), p) { - odbc_result_free((odbc_result*) p); + /* Loop through the connection list, now close all non-persistent connections and their results */ + ZEND_HASH_FOREACH_PTR(&ODBCG(connections), p) { + if (p->connection) { + odbc_link_free(p); + } } ZEND_HASH_FOREACH_END(); - zend_hash_clean(&ODBCG(results)); + zend_hash_clean(&ODBCG(connections)); - /* Second loop through list, now close all non-persistent connections */ - ZEND_HASH_FOREACH_VAL(&ODBCG(connections), p) { - odbc_link_free((odbc_link*) p); + /* Loop through the persistent list, now close all persistent connections and their results */ + ZEND_HASH_FOREACH_VAL(&EG(persistent_list), zv) { + if (Z_RES_P(zv)->type == le_pconn) { + zend_list_close(Z_RES_P(zv)); + } } ZEND_HASH_FOREACH_END(); - /* Third loop through persistent list, now close all persistent connections */ - ZEND_HASH_FOREACH_VAL(&EG(persistent_list), p) { - if (Z_RES_P(p)->type == le_pconn) { - zend_list_close(Z_RES_P(p)); + /* Loop through the results list searching for any dangling results and close all statements */ + ZEND_HASH_FOREACH_VAL(&ODBCG(results), zv) { + odbc_result *result = Z_ODBC_RESULT_P(zv); + if (result->conn_ptr) { + odbc_result_free(result); } } ZEND_HASH_FOREACH_END(); + + zend_hash_clean(&ODBCG(results)); } /* }}} */ @@ -947,7 +987,7 @@ PHP_FUNCTION(odbc_prepare) } } - zend_hash_next_index_insert_new(&ODBCG(results), return_value); + odbc_insert_new_result(return_value); } /* }}} */ @@ -1323,7 +1363,7 @@ PHP_FUNCTION(odbc_exec) result->conn_ptr = conn; result->fetched = 0; - zend_hash_next_index_insert_new(&ODBCG(results), return_value); + odbc_insert_new_result(return_value); } /* }}} */ @@ -1390,7 +1430,6 @@ static void php_odbc_fetch_hash(INTERNAL_FUNCTION_PARAMETERS, int result_type) else #endif result->fetched++; - } for(i = 0; i < result->numcols; i++) { sql_c_type = SQL_C_CHAR; @@ -1500,7 +1539,7 @@ PHP_FUNCTION(odbc_fetch_into) SQLSMALLINT sql_c_type; char *buf = NULL; zval *pv_res, *pv_res_arr, tmp; - zend_long pv_row = 0; + zend_long pv_row = -1; bool pv_row_is_null = true; #ifdef HAVE_SQL_EXTENDED_FETCH SQLULEN crow; @@ -1553,7 +1592,6 @@ PHP_FUNCTION(odbc_fetch_into) else #endif result->fetched++; - } for(i = 0; i < result->numcols; i++) { sql_c_type = SQL_C_CHAR; @@ -1630,7 +1668,7 @@ PHP_FUNCTION(odbc_fetch_row) odbc_result *result; RETCODE rc; zval *pv_res; - zend_long pv_row = 0; + zend_long pv_row = -1; bool pv_row_is_null = true; #ifdef HAVE_SQL_EXTENDED_FETCH SQLULEN crow; @@ -1674,6 +1712,7 @@ PHP_FUNCTION(odbc_fetch_row) if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { RETURN_FALSE; } + #ifdef HAVE_SQL_EXTENDED_FETCH if (!pv_row_is_null) { result->fetched = (SQLLEN)pv_row; @@ -2042,7 +2081,6 @@ PHP_FUNCTION(odbc_free_result) { zval *pv_res; odbc_result *result; - int i; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_res, odbc_result_ce) == FAILURE) { RETURN_THROWS(); @@ -2051,18 +2089,10 @@ PHP_FUNCTION(odbc_free_result) result = Z_ODBC_RESULT_P(pv_res); CHECK_ODBC_RESULT(result); - if (result->values) { - for (i = 0; i < result->numcols; i++) { - if (result->values[i].value) { - efree(result->values[i].value); - } - } - efree(result->values); - result->values = NULL; + if (result->conn_ptr) { + odbc_result_free(result); } - zend_list_close(Z_RES_P(pv_res)); - RETURN_TRUE; } /* }}} */ @@ -2085,6 +2115,7 @@ PHP_FUNCTION(odbc_pconnect) bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool persistent, zend_string *hash) { RETCODE rc; + SQLRETURN ret; odbc_link *link; object_init_ex(zv, odbc_connection_ce); @@ -2093,9 +2124,18 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool memset(link->connection, 0, sizeof(odbc_connection)); link->persistent = persistent; - link->hash = hash; - SQLAllocEnv(link->connection->henv); - SQLAllocConnect(link->connection->henv, link->connection->hdbc); + link->hash = zend_string_copy(hash); + ret = SQLAllocEnv(&((*link->connection).henv)); + if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLAllocEnv"); + return false; + } + + ret = SQLAllocConnect((*link->connection).henv, &((*link->connection).hdbc)); + if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { + odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLAllocConnect"); + return false; + } #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) SQLSetConnectOption((link->connection->hdbc, SQL_TRANSLATE_OPTION, @@ -2358,9 +2398,9 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) RETURN_FALSE; } ODBCG(num_links)++; + zend_hash_update_ptr(&ODBCG(connections), hashed_details.s, Z_ODBC_LINK_P(return_value)); } - zend_hash_update(&ODBCG(connections), hashed_details.s, return_value); smart_str_free(&hashed_details); } /* }}} */ @@ -2378,12 +2418,6 @@ PHP_FUNCTION(odbc_close) link = Z_ODBC_LINK_P(pv_conn); CHECK_ODBC_CONNECTION(link->connection); - if (link->persistent) { - zend_hash_del(&EG(persistent_list), link->hash); - } - - close_results_with_connection(link->connection); - odbc_link_free(link); } /* }}} */ @@ -2815,7 +2849,7 @@ PHP_FUNCTION(odbc_tables) result->conn_ptr = conn; result->fetched = 0; - zend_hash_next_index_insert_new(&ODBCG(results), return_value); + odbc_insert_new_result(return_value); } /* }}} */ @@ -2883,7 +2917,7 @@ PHP_FUNCTION(odbc_columns) result->conn_ptr = conn; result->fetched = 0; - zend_hash_next_index_insert_new(&ODBCG(results), return_value); + odbc_insert_new_result(return_value); } /* }}} */ @@ -2945,7 +2979,7 @@ PHP_FUNCTION(odbc_columnprivileges) result->conn_ptr = conn; result->fetched = 0; - zend_hash_next_index_insert_new(&ODBCG(results), return_value); + odbc_insert_new_result(return_value); } /* }}} */ #endif /* HAVE_DBMAKER || HAVE_SOLID*/ @@ -3022,7 +3056,7 @@ PHP_FUNCTION(odbc_foreignkeys) result->conn_ptr = conn; result->fetched = 0; - zend_hash_next_index_insert_new(&ODBCG(results), return_value); + odbc_insert_new_result(return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3081,7 +3115,7 @@ PHP_FUNCTION(odbc_gettypeinfo) result->conn_ptr = conn; result->fetched = 0; - zend_hash_next_index_insert_new(&ODBCG(results), return_value); + odbc_insert_new_result(return_value); } /* }}} */ diff --git a/ext/odbc/tests/bug78470.phpt b/ext/odbc/tests/bug78470.phpt index ea601a1fdfcac..f14865a90e363 100644 --- a/ext/odbc/tests/bug78470.phpt +++ b/ext/odbc/tests/bug78470.phpt @@ -12,4 +12,5 @@ $conn = odbc_connect($dsn, $user, $pass); var_dump(odbc_specialcolumns($conn, SQL_BEST_ROWID, '', '', '', SQL_SCOPE_CURROW, SQL_NO_NULLS)); ?> --EXPECTF-- -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} diff --git a/ext/odbc/tests/odbc_close_all_001.phpt b/ext/odbc/tests/odbc_close_all_001.phpt index f5334ce7500a2..8e3b134e91059 100644 --- a/ext/odbc/tests/odbc_close_all_001.phpt +++ b/ext/odbc/tests/odbc_close_all_001.phpt @@ -28,11 +28,19 @@ var_dump($result2); ?> --EXPECTF-- -resource(%d) of type (odbc link) -resource(%d) of type (odbc link persistent) -resource(%d) of type (odbc result) -resource(%d) of type (odbc result) -resource(%d) of type (Unknown) -resource(%d) of type (Unknown) -resource(%d) of type (Unknown) -resource(%d) of type (Unknown) +object(ODBC\Connection)#%d (%d) { +} +object(ODBC\Connection)#%d (%d) { +} +object(ODBC\Result)#%d (%d) { +} +object(ODBC\Result)#%d (%d) { +} +object(ODBC\Connection)#%d (%d) { +} +object(ODBC\Connection)#%d (%d) { +} +object(ODBC\Result)#%d (%d) { +} +object(ODBC\Result)#%d (%d) { +} diff --git a/ext/odbc/tests/odbc_columnprivileges_001.phpt b/ext/odbc/tests/odbc_columnprivileges_001.phpt index 5aba25895551f..552c88f23731a 100644 --- a/ext/odbc/tests/odbc_columnprivileges_001.phpt +++ b/ext/odbc/tests/odbc_columnprivileges_001.phpt @@ -22,7 +22,8 @@ var_dump(odbc_fetch_row($result)); ?> --EXPECTF-- -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} bool(false) Deprecated: odbc_columnprivileges(): Passing null to parameter #3 ($schema) of type string is deprecated in %s on line %d @@ -30,7 +31,9 @@ Deprecated: odbc_columnprivileges(): Passing null to parameter #3 ($schema) of t Deprecated: odbc_columnprivileges(): Passing null to parameter #4 ($table) of type string is deprecated in %s on line %d Deprecated: odbc_columnprivileges(): Passing null to parameter #5 ($column) of type string is deprecated in %s on line %d -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} bool(false) -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} bool(false) diff --git a/ext/odbc/tests/odbc_free_result_001.phpt b/ext/odbc/tests/odbc_free_result_001.phpt index 8fc4075581a2f..2490c05e4c740 100644 --- a/ext/odbc/tests/odbc_free_result_001.phpt +++ b/ext/odbc/tests/odbc_free_result_001.phpt @@ -17,22 +17,34 @@ odbc_exec($conn, 'INSERT INTO free_result VALUES (1), (2)'); $res = odbc_exec($conn, 'SELECT * FROM free_result'); -var_dump(odbc_fetch_row($res)); -var_dump(odbc_result($res, 'test')); -var_dump(odbc_free_result($res)); try { - var_dump(odbc_free_result($conn)); + var_dump(odbc_fetch_row($res)); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(odbc_result($res, 'test')); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(odbc_free_result($res)); } catch (TypeError $e) { echo $e->getMessage(), "\n"; } +try { + var_dump(odbc_free_result($conn)); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} try { var_dump(odbc_fetch_row($res)); -} catch (TypeError $e) { +} catch (Error $e) { echo $e->getMessage(), "\n"; } try { var_dump(odbc_result($res, 'test')); -} catch (TypeError $e) { +} catch (Error $e) { echo $e->getMessage(), "\n"; } ?> @@ -46,6 +58,6 @@ odbc_exec($conn, 'DROP TABLE free_result'); bool(true) string(1) "1" bool(true) -odbc_free_result(): supplied resource is not a valid ODBC result resource -odbc_fetch_row(): supplied resource is not a valid ODBC result resource -odbc_result(): supplied resource is not a valid ODBC result resource +odbc_free_result(): Argument #1 ($statement) must be of type ODBC\Result, ODBC\Connection given +ODBC result has already been closed +ODBC result has already been closed diff --git a/ext/odbc/tests/odbc_tables_001.phpt b/ext/odbc/tests/odbc_tables_001.phpt index 7d4d816c7de06..f013be7f06ba8 100644 --- a/ext/odbc/tests/odbc_tables_001.phpt +++ b/ext/odbc/tests/odbc_tables_001.phpt @@ -27,13 +27,17 @@ var_dump(odbc_fetch_row($result)); ?> --EXPECTF-- -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} bool(false) -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} bool(true) bool(true) -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} bool(true) bool(true) -resource(%d) of type (odbc result) +object(ODBC\Result)#%d (%d) { +} bool(false) From 4a7b5f61d17accc2e054463e9ab32cf97eab634f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 17 Apr 2024 23:13:14 +0200 Subject: [PATCH 04/11] Fix some of the code review comments --- ext/odbc/php_odbc.c | 207 ++++++++++++++++++----------------- ext/odbc/php_odbc_includes.h | 5 +- 2 files changed, 109 insertions(+), 103 deletions(-) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 1c5589f734b22..374c7ac97345a 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -65,59 +65,49 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent); static void safe_odbc_disconnect(void *handle); -static void close_results_with_connection(const odbc_connection *conn); +static void close_results_with_connection(odbc_connection *conn); +static inline odbc_result *odbc_result_from_obj(zend_object *obj); static int le_pconn; static zend_class_entry *odbc_connection_ce, *odbc_result_ce; static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_handlers; -static void odbc_insert_new_result(zval *result) { - Z_TRY_ADDREF_P(result); - zend_hash_next_index_insert_new(&ODBCG(results), result); -} - -static inline odbc_link *odbc_link_from_obj(zend_object *obj) { - return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); -} - #define Z_ODBC_LINK_P(zv) odbc_link_from_obj(Z_OBJ_P(zv)) #define Z_ODBC_CONNECTION_P(zv) Z_ODBC_LINK_P(zv)->connection +#define Z_ODBC_RESULT_P(zv) odbc_result_from_obj(Z_OBJ_P(zv)) -static zend_object *odbc_connection_create_object(zend_class_entry *class_type) { - odbc_link *intern = zend_object_alloc(sizeof(odbc_link), class_type); - - zend_object_std_init(&intern->std, class_type); - object_properties_init(&intern->std, class_type); - intern->std.handlers = &odbc_connection_object_handlers; - - return &intern->std; -} +static void odbc_insert_new_result(odbc_connection *connection, zval *result) { + ZEND_ASSERT(Z_TYPE_P(result) == IS_OBJECT && instanceof_function(Z_OBJCE_P(result), odbc_result_ce)); + if (!connection->results) { + connection->results = zend_new_array(1); + } -static zend_function *odbc_connection_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct ODBC\\Connection, use odbc_connect() or odbc_pconnect() instead"); - return NULL; + zend_hash_next_index_insert_new(connection->results, result); + odbc_result *res = Z_ODBC_RESULT_P(result); + res->index = zend_hash_num_elements(connection->results) - 1; + Z_ADDREF_P(result); } static void odbc_link_free(odbc_link *link) { ZEND_ASSERT(link->connection && "link has already been closed"); - if (link->persistent) { - zend_hash_del(&EG(persistent_list), link->hash); - } else { - close_results_with_connection(link->connection); - - zend_hash_del(&ODBCG(connections), link->hash); + close_results_with_connection(link->connection); + if (!link->persistent) { /* If aborted via timer expiration, don't try to call any unixODBC function */ if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { safe_odbc_disconnect(link->connection->hdbc); SQLFreeConnect(link->connection->hdbc); SQLFreeEnv(link->connection->henv); } + link->connection->hdbc = NULL; + link->connection->henv = NULL; efree(link->connection); ODBCG(num_links)--; + + zend_hash_del(&ODBCG(non_persistent_connections), link->hash); } link->connection = NULL; @@ -126,16 +116,33 @@ static void odbc_link_free(odbc_link *link) link->hash = NULL; } +static inline odbc_link *odbc_link_from_obj(zend_object *obj) { + return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); +} + +static zend_object *odbc_connection_create_object(zend_class_entry *class_type) { + odbc_link *intern = zend_object_alloc(sizeof(odbc_link), class_type); + + zend_object_std_init(&intern->std, class_type); + object_properties_init(&intern->std, class_type); + intern->std.handlers = &odbc_connection_object_handlers; + + return &intern->std; +} + +static zend_function *odbc_connection_get_constructor(zend_object *object) { + zend_throw_error(NULL, "Cannot directly construct ODBC\\Connection, use odbc_connect() or odbc_pconnect() instead"); + return NULL; +} + static void odbc_connection_free_obj(zend_object *obj) { odbc_link *link = odbc_link_from_obj(obj); - if (!link->connection) { - zend_object_std_dtor(&link->std); - return; + if (link->connection) { + odbc_link_free(link); } - odbc_link_free(link); zend_object_std_dtor(&link->std); } @@ -143,8 +150,6 @@ static inline odbc_result *odbc_result_from_obj(zend_object *obj) { return (odbc_result *)((char *)(obj) - XtOffsetOf(odbc_result, std)); } -#define Z_ODBC_RESULT_P(zv) odbc_result_from_obj(Z_OBJ_P(zv)) - static zend_object *odbc_result_create_object(zend_class_entry *class_type) { odbc_result *intern = zend_object_alloc(sizeof(odbc_result), class_type); @@ -174,6 +179,7 @@ static void odbc_result_free(odbc_result *res) res->values = NULL; res->numcols = 0; } + /* If aborted via timer expiration, don't try to call any unixODBC function */ if (res->stmt && !(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { #if defined(HAVE_SOLID) || defined(HAVE_SOLID_30) || defined(HAVE_SOLID_35) @@ -190,28 +196,21 @@ static void odbc_result_free(odbc_result *res) efree(res->param_info); res->param_info = NULL; } + + HashTable *tmp = res->conn_ptr->results; res->conn_ptr = NULL; + if (tmp) { + zend_hash_index_del(tmp, res->index); + } } static void odbc_result_free_obj(zend_object *obj) { - zend_ulong num_index; - zval *p; - odbc_result *result = odbc_result_from_obj(obj); - if (!result->conn_ptr) { - zend_object_std_dtor(&result->std); - return; + if (result->conn_ptr) { + odbc_result_free(result); } - ZEND_HASH_FOREACH_NUM_KEY_VAL(&ODBCG(results), num_index, p) { - odbc_result *res = Z_ODBC_RESULT_P(p); - if (res->stmt == result->stmt) { - zend_hash_index_del(&ODBCG(results), num_index); - } - } ZEND_HASH_FOREACH_END(); - - odbc_result_free(result); zend_object_std_dtor(&result->std); } @@ -247,17 +246,23 @@ ZEND_TSRMLS_CACHE_DEFINE() ZEND_GET_MODULE(odbc) #endif -static void close_results_with_connection(const odbc_connection *conn) { - zend_ulong num_index; +static void close_results_with_connection(odbc_connection *conn) { zval *p; - ZEND_HASH_FOREACH_NUM_KEY_VAL(&ODBCG(results), num_index, p) { + if (conn->results == NULL) { + return; + } + + ZEND_HASH_FOREACH_VAL(conn->results, p) { odbc_result *result = Z_ODBC_RESULT_P(p); - if (result->conn_ptr == conn) { + if (result->conn_ptr) { odbc_result_free(result); - zend_hash_index_del(&ODBCG(results), num_index); } } ZEND_HASH_FOREACH_END(); + + zend_hash_destroy(conn->results); + FREE_HASHTABLE(conn->results); + conn->results = NULL; } /* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ @@ -287,7 +292,6 @@ static void _close_odbc_pconn(zend_resource *rsrc) SQLFreeEnv(conn->henv); } free(conn); - conn = NULL; ODBCG(num_links)--; ODBCG(num_persistent)--; @@ -472,14 +476,12 @@ static PHP_GINIT_FUNCTION(odbc) ZEND_TSRMLS_CACHE_UPDATE(); #endif odbc_globals->num_persistent = 0; - zend_hash_init(&odbc_globals->results, 0, NULL, NULL, 1); - zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, 1); + zend_hash_init(&odbc_globals->non_persistent_connections, 0, NULL, NULL, 1); } static PHP_GSHUTDOWN_FUNCTION(odbc) { - zend_hash_destroy(&odbc_globals->results); - zend_hash_destroy(&odbc_globals->connections); + zend_hash_destroy(&odbc_globals->non_persistent_connections); } /* {{{ PHP_MINIT_FUNCTION */ @@ -844,38 +846,28 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ Close all ODBC connections */ PHP_FUNCTION(odbc_close_all) { - odbc_link *p; zval *zv; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); } - /* Loop through the connection list, now close all non-persistent connections and their results */ - ZEND_HASH_FOREACH_PTR(&ODBCG(connections), p) { - if (p->connection) { - odbc_link_free(p); + ZEND_HASH_FOREACH_VAL(&ODBCG(non_persistent_connections), zv) { + odbc_link *link = Z_ODBC_LINK_P(zv); + if (link->connection) { + odbc_link_free(link); } } ZEND_HASH_FOREACH_END(); - zend_hash_clean(&ODBCG(connections)); + /* Loop through the non-persistent connection list, now close all non-persistent connections and their results */ + zend_hash_clean(&ODBCG(non_persistent_connections)); - /* Loop through the persistent list, now close all persistent connections and their results */ + /* Loop through the persistent connection list, now close all persistent connections and their results */ ZEND_HASH_FOREACH_VAL(&EG(persistent_list), zv) { if (Z_RES_P(zv)->type == le_pconn) { zend_list_close(Z_RES_P(zv)); } } ZEND_HASH_FOREACH_END(); - - /* Loop through the results list searching for any dangling results and close all statements */ - ZEND_HASH_FOREACH_VAL(&ODBCG(results), zv) { - odbc_result *result = Z_ODBC_RESULT_P(zv); - if (result->conn_ptr) { - odbc_result_free(result); - } - } ZEND_HASH_FOREACH_END(); - - zend_hash_clean(&ODBCG(results)); } /* }}} */ @@ -970,7 +962,6 @@ PHP_FUNCTION(odbc_prepare) } else { result->values = NULL; } - Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; @@ -987,7 +978,7 @@ PHP_FUNCTION(odbc_prepare) } } - odbc_insert_new_result(return_value); + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -1359,11 +1350,10 @@ PHP_FUNCTION(odbc_exec) } else { result->values = NULL; } - Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; - odbc_insert_new_result(return_value); + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -2089,9 +2079,7 @@ PHP_FUNCTION(odbc_free_result) result = Z_ODBC_RESULT_P(pv_res); CHECK_ODBC_RESULT(result); - if (result->conn_ptr) { - odbc_result_free(result); - } + odbc_result_free(result); RETURN_TRUE; } @@ -2383,24 +2371,29 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) odbc_link *link = Z_ODBC_LINK_P(return_value); link->connection = db_conn; link->hash = zend_string_copy(hashed_details.s); - link->persistent = 1; - } - } else { /* non persistent */ - if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { - php_error_docref(NULL, E_WARNING,"Too many open connections (" ZEND_LONG_FMT ")", ODBCG(num_links)); - smart_str_free(&hashed_details); - RETURN_FALSE; + link->persistent = true; } + } else { + zval *tmp; + if ((tmp = zend_hash_find(&ODBCG(non_persistent_connections), hashed_details.s)) == NULL) { /* non-persistent, new */ + if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { + php_error_docref(NULL, E_WARNING, "Too many open connections (" ZEND_LONG_FMT ")", ODBCG(num_links)); + smart_str_free(&hashed_details); + RETURN_FALSE; + } - if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, false, hashed_details.s)) { - smart_str_free(&hashed_details); - zval_ptr_dtor(return_value); - RETURN_FALSE; + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, false, hashed_details.s)) { + smart_str_free(&hashed_details); + zval_ptr_dtor(return_value); + RETURN_FALSE; + } + ODBCG(num_links)++; + + zend_hash_add_new(&ODBCG(non_persistent_connections), hashed_details.s, return_value); + } else { /* non-persistent, pre-existing */ + ZVAL_COPY(return_value, tmp); } - ODBCG(num_links)++; - zend_hash_update_ptr(&ODBCG(connections), hashed_details.s, Z_ODBC_LINK_P(return_value)); } - smart_str_free(&hashed_details); } /* }}} */ @@ -2849,7 +2842,7 @@ PHP_FUNCTION(odbc_tables) result->conn_ptr = conn; result->fetched = 0; - odbc_insert_new_result(return_value); + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -2917,7 +2910,7 @@ PHP_FUNCTION(odbc_columns) result->conn_ptr = conn; result->fetched = 0; - odbc_insert_new_result(return_value); + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -2979,7 +2972,7 @@ PHP_FUNCTION(odbc_columnprivileges) result->conn_ptr = conn; result->fetched = 0; - odbc_insert_new_result(return_value); + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_DBMAKER || HAVE_SOLID*/ @@ -3056,7 +3049,7 @@ PHP_FUNCTION(odbc_foreignkeys) result->conn_ptr = conn; result->fetched = 0; - odbc_insert_new_result(return_value); + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3115,7 +3108,7 @@ PHP_FUNCTION(odbc_gettypeinfo) result->conn_ptr = conn; result->fetched = 0; - odbc_insert_new_result(return_value); + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3173,6 +3166,8 @@ PHP_FUNCTION(odbc_primarykeys) } result->conn_ptr = conn; result->fetched = 0; + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3233,6 +3228,8 @@ PHP_FUNCTION(odbc_procedurecolumns) } result->conn_ptr = conn; result->fetched = 0; + + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3292,6 +3289,8 @@ PHP_FUNCTION(odbc_procedures) } result->conn_ptr = conn; result->fetched = 0; + + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3359,6 +3358,8 @@ PHP_FUNCTION(odbc_specialcolumns) } result->conn_ptr = conn; result->fetched = 0; + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3424,6 +3425,8 @@ PHP_FUNCTION(odbc_statistics) } result->conn_ptr = conn; result->fetched = 0; + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3482,6 +3485,8 @@ PHP_FUNCTION(odbc_tableprivileges) } result->conn_ptr = conn; result->fetched = 0; + + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_DBMAKER */ diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h index b10951c3b4b52..55935f1a1dc2c 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -191,6 +191,7 @@ typedef struct odbc_connection { ODBC_SQL_CONN_T hdbc; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; + HashTable *results; } odbc_connection; typedef struct odbc_link { @@ -227,6 +228,7 @@ typedef struct odbc_result { int fetched; odbc_param_info *param_info; odbc_connection *conn_ptr; + uint32_t index; zend_object std; } odbc_result; @@ -246,8 +248,7 @@ ZEND_BEGIN_MODULE_GLOBALS(odbc) zend_long default_cursortype; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - HashTable results; - HashTable connections; + HashTable non_persistent_connections; ZEND_END_MODULE_GLOBALS(odbc) int odbc_add_result(HashTable *list, odbc_result *result); From 24696c0ac61aee31122195ea6c0eecdb22d9cdbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sun, 21 Apr 2024 22:37:27 +0200 Subject: [PATCH 05/11] New reviww round --- ext/odbc/odbc.stub.php | 4 +- ext/odbc/odbc_arginfo.h | 6 +-- ext/odbc/php_odbc.c | 101 ++++++++++++++++------------------- ext/odbc/php_odbc_includes.h | 2 +- 4 files changed, 53 insertions(+), 60 deletions(-) diff --git a/ext/odbc/odbc.stub.php b/ext/odbc/odbc.stub.php index b69d91c497264..f5ccb1c63d3f7 100644 --- a/ext/odbc/odbc.stub.php +++ b/ext/odbc/odbc.stub.php @@ -373,9 +373,9 @@ function odbc_result_all(ODBC\Result $statement, string $format = ""): int|false function odbc_free_result(ODBC\Result $statement): true {} - function odbc_connect(string $dsn, ?string $user = null, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} + function odbc_connect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} - function odbc_pconnect(string $dsn, ?string $user = null, #[\SensitiveParameter] string $password, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} + function odbc_pconnect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} function odbc_close(ODBC\Connection $odbc): void {} diff --git a/ext/odbc/odbc_arginfo.h b/ext/odbc/odbc_arginfo.h index 5f6ddc5a969a1..451db23d7a0ab 100644 --- a/ext/odbc/odbc_arginfo.h +++ b/ext/odbc/odbc_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 6483b0aca02dbe2950090e7207832a1426d5d862 */ + * Stub hash: c0d3607a59dba96e10fe27c061cf7d7da11dda2c */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close_all, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -78,10 +78,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_free_result, 0, 1, IS_TRUE, ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_connect, 0, 3, ODBC\\Connection, MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_connect, 0, 1, ODBC\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, user, IS_STRING, 1, "null") - ZEND_ARG_TYPE_INFO(0, password, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, password, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, cursor_option, IS_LONG, 0, "SQL_CUR_USE_DRIVER") ZEND_END_ARG_INFO() diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 374c7ac97345a..bc5e2ff155b2f 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -79,13 +79,10 @@ static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_ static void odbc_insert_new_result(odbc_connection *connection, zval *result) { ZEND_ASSERT(Z_TYPE_P(result) == IS_OBJECT && instanceof_function(Z_OBJCE_P(result), odbc_result_ce)); - if (!connection->results) { - connection->results = zend_new_array(1); - } - zend_hash_next_index_insert_new(connection->results, result); odbc_result *res = Z_ODBC_RESULT_P(result); - res->index = zend_hash_num_elements(connection->results) - 1; + res->index = connection->results.nNextFreeElement; + zend_hash_next_index_insert_new(&connection->results, result); Z_ADDREF_P(result); } @@ -107,13 +104,17 @@ static void odbc_link_free(odbc_link *link) efree(link->connection); ODBCG(num_links)--; - zend_hash_del(&ODBCG(non_persistent_connections), link->hash); + if (link->hash) { + zend_hash_del(&ODBCG(non_persistent_connections), link->hash); + } } link->connection = NULL; - zend_string_release(link->hash); - link->hash = NULL; + if (link->hash) { + zend_string_release_ex(link->hash, link->persistent); + link->hash = NULL; + } } static inline odbc_link *odbc_link_from_obj(zend_object *obj) { @@ -197,11 +198,9 @@ static void odbc_result_free(odbc_result *res) res->param_info = NULL; } - HashTable *tmp = res->conn_ptr->results; + HashTable *tmp = &res->conn_ptr->results; res->conn_ptr = NULL; - if (tmp) { - zend_hash_index_del(tmp, res->index); - } + zend_hash_index_del(tmp, res->index); } static void odbc_result_free_obj(zend_object *obj) { @@ -249,20 +248,14 @@ ZEND_GET_MODULE(odbc) static void close_results_with_connection(odbc_connection *conn) { zval *p; - if (conn->results == NULL) { - return; - } - - ZEND_HASH_FOREACH_VAL(conn->results, p) { + ZEND_HASH_FOREACH_VAL(&conn->results, p) { odbc_result *result = Z_ODBC_RESULT_P(p); if (result->conn_ptr) { odbc_result_free(result); } } ZEND_HASH_FOREACH_END(); - zend_hash_destroy(conn->results); - FREE_HASHTABLE(conn->results); - conn->results = NULL; + zend_hash_destroy(&conn->results); } /* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ @@ -852,6 +845,7 @@ PHP_FUNCTION(odbc_close_all) RETURN_THROWS(); } + /* Loop through the non-persistent connection list, now close all non-persistent connections and their results */ ZEND_HASH_FOREACH_VAL(&ODBCG(non_persistent_connections), zv) { odbc_link *link = Z_ODBC_LINK_P(zv); if (link->connection) { @@ -859,7 +853,6 @@ PHP_FUNCTION(odbc_close_all) } } ZEND_HASH_FOREACH_END(); - /* Loop through the non-persistent connection list, now close all non-persistent connections and their results */ zend_hash_clean(&ODBCG(non_persistent_connections)); /* Loop through the persistent connection list, now close all persistent connections and their results */ @@ -1529,7 +1522,7 @@ PHP_FUNCTION(odbc_fetch_into) SQLSMALLINT sql_c_type; char *buf = NULL; zval *pv_res, *pv_res_arr, tmp; - zend_long pv_row = -1; + zend_long pv_row = 0; bool pv_row_is_null = true; #ifdef HAVE_SQL_EXTENDED_FETCH SQLULEN crow; @@ -1658,7 +1651,7 @@ PHP_FUNCTION(odbc_fetch_row) odbc_result *result; RETCODE rc; zval *pv_res; - zend_long pv_row = -1; + zend_long pv_row = 0; bool pv_row_is_null = true; #ifdef HAVE_SQL_EXTENDED_FETCH SQLULEN crow; @@ -2100,7 +2093,7 @@ PHP_FUNCTION(odbc_pconnect) /* }}} */ /* {{{ odbc_sqlconnect */ -bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool persistent, zend_string *hash) +bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool persistent, char *hash, int hash_len) { RETCODE rc; SQLRETURN ret; @@ -2108,18 +2101,17 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool object_init_ex(zv, odbc_connection_ce); link = Z_ODBC_LINK_P(zv); - link->connection = (odbc_connection *)pemalloc(sizeof(odbc_connection), persistent); - memset(link->connection, 0, sizeof(odbc_connection)); - + link->connection = pecalloc(1, sizeof(odbc_connection), persistent); + zend_hash_init(&link->connection->results, 0, NULL, NULL, 1); link->persistent = persistent; - link->hash = zend_string_copy(hash); - ret = SQLAllocEnv(&((*link->connection).henv)); + link->hash = zend_string_init(hash, hash_len, persistent); + ret = SQLAllocEnv(&link->connection->henv); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLAllocEnv"); return false; } - ret = SQLAllocConnect((*link->connection).henv, &((*link->connection).hdbc)); + ret = SQLAllocConnect(link->connection->henv, &link->connection->hdbc); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { odbc_sql_error(link->connection, SQL_NULL_HSTMT, "SQLAllocConnect"); return false; @@ -2244,11 +2236,6 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool } /* }}} */ -/* Persistent connections: two list-types le_pconn, le_conn and a plist - * where hashed connection info is stored together with index pointer to - * the actual link of type le_pconn in the list. Only persistent - * connections get hashed up. - */ /* {{{ odbc_do_connect */ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) { @@ -2284,8 +2271,8 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) persistent = 0; } - smart_str hashed_details = {0}; - smart_str_append_printf(&hashed_details, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt); + char *hashed_details; + int hashed_details_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt); try_and_get_another_connection: @@ -2293,28 +2280,28 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) zend_resource *le; /* the link is not in the persistent list */ - if ((le = zend_hash_find_ptr(&EG(persistent_list), hashed_details.s)) == NULL) { + if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashed_details, hashed_details_len)) == NULL) { if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { php_error_docref(NULL, E_WARNING, "Too many open links (" ZEND_LONG_FMT ")", ODBCG(num_links)); - smart_str_free(&hashed_details); + efree(hashed_details); RETURN_FALSE; } if (ODBCG(max_persistent) != -1 && ODBCG(num_persistent) >= ODBCG(max_persistent)) { php_error_docref(NULL, E_WARNING,"Too many open persistent links (" ZEND_LONG_FMT ")", ODBCG(num_persistent)); - smart_str_free(&hashed_details); + efree(hashed_details); RETURN_FALSE; } - if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, true, hashed_details.s)) { - smart_str_free(&hashed_details); + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, true, hashed_details, hashed_details_len)) { + efree(hashed_details); zval_ptr_dtor(return_value); RETURN_FALSE; } db_conn = Z_ODBC_CONNECTION_P(return_value); - if (zend_register_persistent_resource(ZSTR_VAL(hashed_details.s), ZSTR_LEN(hashed_details.s), db_conn, le_pconn) == NULL) { - smart_str_free(&hashed_details); + if (zend_register_persistent_resource(hashed_details, hashed_details_len, db_conn, le_pconn) == NULL) { + efree(hashed_details); zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2343,7 +2330,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) &dead, 0, NULL); if (ret == SQL_SUCCESS && dead == SQL_CD_TRUE) { /* Bail early here, since we know it's gone */ - zend_hash_del(&EG(persistent_list), hashed_details.s); + zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_details_len); goto try_and_get_another_connection; } /* If the driver doesn't support it, or returns @@ -2355,7 +2342,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) d_name, sizeof(d_name), &len); if(ret != SQL_SUCCESS || len == 0) { - zend_hash_del(&EG(persistent_list), hashed_details.s); + zend_hash_str_del(&EG(persistent_list), hashed_details, hashed_details_len); /* Commented out to fix a possible double closure error * when working with persistent connections as submitted by * bug #15758 @@ -2370,38 +2357,38 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) object_init_ex(return_value, odbc_connection_ce); odbc_link *link = Z_ODBC_LINK_P(return_value); link->connection = db_conn; - link->hash = zend_string_copy(hashed_details.s); + link->hash = zend_string_init(hashed_details, hashed_details_len, persistent); link->persistent = true; } } else { zval *tmp; - if ((tmp = zend_hash_find(&ODBCG(non_persistent_connections), hashed_details.s)) == NULL) { /* non-persistent, new */ + if ((tmp = zend_hash_str_find(&ODBCG(non_persistent_connections), hashed_details, hashed_details_len)) == NULL) { /* non-persistent, new */ if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { php_error_docref(NULL, E_WARNING, "Too many open connections (" ZEND_LONG_FMT ")", ODBCG(num_links)); - smart_str_free(&hashed_details); + efree(hashed_details); RETURN_FALSE; } - if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, false, hashed_details.s)) { - smart_str_free(&hashed_details); + if (!odbc_sqlconnect(return_value, db, uid, pwd, cur_opt, false, hashed_details, hashed_details_len)) { + efree(hashed_details); zval_ptr_dtor(return_value); RETURN_FALSE; } ODBCG(num_links)++; - zend_hash_add_new(&ODBCG(non_persistent_connections), hashed_details.s, return_value); + zend_hash_str_add_new(&ODBCG(non_persistent_connections), hashed_details, hashed_details_len, return_value); } else { /* non-persistent, pre-existing */ ZVAL_COPY(return_value, tmp); } } - smart_str_free(&hashed_details); + efree(hashed_details); } /* }}} */ /* {{{ Close an ODBC connection */ PHP_FUNCTION(odbc_close) { - zval *pv_conn; + zval *pv_conn, *zv; odbc_link *link; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { @@ -2412,6 +2399,12 @@ PHP_FUNCTION(odbc_close) CHECK_ODBC_CONNECTION(link->connection); odbc_link_free(link); + + ZEND_HASH_FOREACH_VAL(&EG(persistent_list), zv) { + if (Z_RES_P(zv)->type == le_pconn && link->connection == Z_RES_P(zv)->ptr) { + zend_list_close(Z_RES_P(zv)); + } + } ZEND_HASH_FOREACH_END(); } /* }}} */ diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h index 55935f1a1dc2c..ef885b065102b 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -191,7 +191,7 @@ typedef struct odbc_connection { ODBC_SQL_CONN_T hdbc; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - HashTable *results; + HashTable results; } odbc_connection; typedef struct odbc_link { From 54ef55fc04f6b46576cfabcde42ed278dad225a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 24 Apr 2024 23:33:53 +0200 Subject: [PATCH 06/11] New fixes --- ext/odbc/php_odbc.c | 62 +++++++++++------ .../odbc_non_persistent_connection_reuse.phpt | 69 +++++++++++++++++++ ext/odbc/tests/odbc_persistent_close_all.phpt | 69 +++++++++++++++++++ 3 files changed, 180 insertions(+), 20 deletions(-) create mode 100644 ext/odbc/tests/odbc_non_persistent_connection_reuse.phpt create mode 100644 ext/odbc/tests/odbc_persistent_close_all.phpt diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index bc5e2ff155b2f..b28718feb5104 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -81,11 +81,42 @@ static void odbc_insert_new_result(odbc_connection *connection, zval *result) { ZEND_ASSERT(Z_TYPE_P(result) == IS_OBJECT && instanceof_function(Z_OBJCE_P(result), odbc_result_ce)); odbc_result *res = Z_ODBC_RESULT_P(result); + res->index = connection->results.nNextFreeElement; - zend_hash_next_index_insert_new(&connection->results, result); + zend_hash_index_add_new(&connection->results, res->index, result); Z_ADDREF_P(result); } +static inline odbc_link *odbc_link_from_obj(zend_object *obj) { + return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); +} + +static int _close_pconn_with_res(zval *zv, void *p) +{ + zend_resource *le = Z_RES_P(zv); + if (le->type != le_pconn) { + return ZEND_HASH_APPLY_KEEP; + } + + odbc_connection *list_conn = ((odbc_connection *)(le->ptr)); + odbc_connection *obj_conn = odbc_link_from_obj((zend_object*)p)->connection; + if (list_conn == obj_conn) { + return ZEND_HASH_APPLY_REMOVE; + } + + return ZEND_HASH_APPLY_KEEP; +} + +static int _close_pconn(zval *zv) +{ + zend_resource *le = Z_RES_P(zv); + if (le->type == le_pconn) { + return ZEND_HASH_APPLY_REMOVE; + } else { + return ZEND_HASH_APPLY_KEEP; + } +} + static void odbc_link_free(odbc_link *link) { ZEND_ASSERT(link->connection && "link has already been closed"); @@ -101,6 +132,7 @@ static void odbc_link_free(odbc_link *link) } link->connection->hdbc = NULL; link->connection->henv = NULL; + zend_hash_destroy(&link->connection->results); efree(link->connection); ODBCG(num_links)--; @@ -117,10 +149,6 @@ static void odbc_link_free(odbc_link *link) } } -static inline odbc_link *odbc_link_from_obj(zend_object *obj) { - return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); -} - static zend_object *odbc_connection_create_object(zend_class_entry *class_type) { odbc_link *intern = zend_object_alloc(sizeof(odbc_link), class_type); @@ -253,9 +281,10 @@ static void close_results_with_connection(odbc_connection *conn) { if (result->conn_ptr) { odbc_result_free(result); } + GC_DELREF(&result->std); } ZEND_HASH_FOREACH_END(); - zend_hash_destroy(&conn->results); + zend_hash_clean(&conn->results); } /* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ @@ -277,6 +306,7 @@ static void _close_odbc_pconn(zend_resource *rsrc) odbc_connection *conn = (odbc_connection *)rsrc->ptr; close_results_with_connection(conn); + zend_hash_destroy(&conn->results); /* If aborted via timer expiration, don't try to call any unixODBC function */ if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { @@ -284,7 +314,6 @@ static void _close_odbc_pconn(zend_resource *rsrc) SQLFreeConnect(conn->hdbc); SQLFreeEnv(conn->henv); } - free(conn); ODBCG(num_links)--; ODBCG(num_persistent)--; @@ -855,12 +884,7 @@ PHP_FUNCTION(odbc_close_all) zend_hash_clean(&ODBCG(non_persistent_connections)); - /* Loop through the persistent connection list, now close all persistent connections and their results */ - ZEND_HASH_FOREACH_VAL(&EG(persistent_list), zv) { - if (Z_RES_P(zv)->type == le_pconn) { - zend_list_close(Z_RES_P(zv)); - } - } ZEND_HASH_FOREACH_END(); + zend_hash_apply(&EG(persistent_list), _close_pconn); } /* }}} */ @@ -2388,7 +2412,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) /* {{{ Close an ODBC connection */ PHP_FUNCTION(odbc_close) { - zval *pv_conn, *zv; + zval *pv_conn; odbc_link *link; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { @@ -2398,13 +2422,11 @@ PHP_FUNCTION(odbc_close) link = Z_ODBC_LINK_P(pv_conn); CHECK_ODBC_CONNECTION(link->connection); - odbc_link_free(link); + if (link->persistent) { + zend_hash_apply_with_argument(&EG(persistent_list), _close_pconn_with_res, (void *) Z_OBJ_P(pv_conn)); + } - ZEND_HASH_FOREACH_VAL(&EG(persistent_list), zv) { - if (Z_RES_P(zv)->type == le_pconn && link->connection == Z_RES_P(zv)->ptr) { - zend_list_close(Z_RES_P(zv)); - } - } ZEND_HASH_FOREACH_END(); + odbc_link_free(link); } /* }}} */ diff --git a/ext/odbc/tests/odbc_non_persistent_connection_reuse.phpt b/ext/odbc/tests/odbc_non_persistent_connection_reuse.phpt new file mode 100644 index 0000000000000..12bbc9fc6faea --- /dev/null +++ b/ext/odbc/tests/odbc_non_persistent_connection_reuse.phpt @@ -0,0 +1,69 @@ +--TEST-- +odbc_pconnect(): Make sure non-persistent connections are reused +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(21) "PHP odbc_connect test" +string(21) "PHP odbc_connect test" +NULL diff --git a/ext/odbc/tests/odbc_persistent_close_all.phpt b/ext/odbc/tests/odbc_persistent_close_all.phpt new file mode 100644 index 0000000000000..6bc5a4563978f --- /dev/null +++ b/ext/odbc/tests/odbc_persistent_close_all.phpt @@ -0,0 +1,69 @@ +--TEST-- +odbc_pconnect(): Make sure closing a persistent connection works in case of odbc_close_all() +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(22) "PHP odbc_pconnect test" +string(22) "PHP odbc_pconnect test" +NULL From 048379869f62225f9e1cee1b6f13b2d9f0d62e8e Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 25 Apr 2024 21:18:52 +0200 Subject: [PATCH 07/11] Fix one leak 1. GC_DELREF isn't enough because the hash table may hold the last reference 2. The reference should be deleted inside the odbc_result_free function to avoid forgetting to call it in other places. --- ext/odbc/php_odbc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index b28718feb5104..32063daebf0b3 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -228,7 +228,8 @@ static void odbc_result_free(odbc_result *res) HashTable *tmp = &res->conn_ptr->results; res->conn_ptr = NULL; - zend_hash_index_del(tmp, res->index); + zend_result status = zend_hash_index_del(tmp, res->index); + ZEND_ASSERT(status == SUCCESS); } static void odbc_result_free_obj(zend_object *obj) { @@ -281,7 +282,6 @@ static void close_results_with_connection(odbc_connection *conn) { if (result->conn_ptr) { odbc_result_free(result); } - GC_DELREF(&result->std); } ZEND_HASH_FOREACH_END(); zend_hash_clean(&conn->results); @@ -2126,7 +2126,7 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool object_init_ex(zv, odbc_connection_ce); link = Z_ODBC_LINK_P(zv); link->connection = pecalloc(1, sizeof(odbc_connection), persistent); - zend_hash_init(&link->connection->results, 0, NULL, NULL, 1); + zend_hash_init(&link->connection->results, 0, NULL, ZVAL_PTR_DTOR, 1); link->persistent = persistent; link->hash = zend_string_init(hash, hash_len, persistent); ret = SQLAllocEnv(&link->connection->henv); From 4282362d65e7c0f251ad8023ded73d50a64aed76 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Thu, 25 Apr 2024 21:19:57 +0200 Subject: [PATCH 08/11] Move instanceof check inside ZEND_DEBUG guard This makes sure we don't get a performance penalty in release mode because the release mode build will still perform the call as the compiler doesn't know instanceof is side-effect-free. --- ext/odbc/php_odbc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 32063daebf0b3..5f9aad6bf2f46 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -78,7 +78,10 @@ static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_ #define Z_ODBC_RESULT_P(zv) odbc_result_from_obj(Z_OBJ_P(zv)) static void odbc_insert_new_result(odbc_connection *connection, zval *result) { - ZEND_ASSERT(Z_TYPE_P(result) == IS_OBJECT && instanceof_function(Z_OBJCE_P(result), odbc_result_ce)); + ZEND_ASSERT(Z_TYPE_P(result) == IS_OBJECT); +#if ZEND_DEBUG + ZEND_ASSERT(instanceof_function(Z_OBJCE_P(result), odbc_result_ce)); +#endif odbc_result *res = Z_ODBC_RESULT_P(result); From 887b79369ec07c8d8c2af3bb569b98b46748c6c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Fri, 26 Apr 2024 09:46:11 +0200 Subject: [PATCH 09/11] Hopefully fix all memleaks --- ext/odbc/php_odbc.c | 54 +++++++++++++--------- ext/odbc/php_odbc_includes.h | 8 +++- ext/odbc/tests/odbc_close_001.phpt | 62 ++++++++++++++++++++++++++ ext/odbc/tests/odbc_close_all_001.phpt | 37 ++++++++++----- 4 files changed, 128 insertions(+), 33 deletions(-) create mode 100644 ext/odbc/tests/odbc_close_001.phpt diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 5f9aad6bf2f46..bd32f4bcad04d 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -102,7 +102,7 @@ static int _close_pconn_with_res(zval *zv, void *p) } odbc_connection *list_conn = ((odbc_connection *)(le->ptr)); - odbc_connection *obj_conn = odbc_link_from_obj((zend_object*)p)->connection; + odbc_connection *obj_conn = (odbc_connection *) p; if (list_conn == obj_conn) { return ZEND_HASH_APPLY_REMOVE; } @@ -138,10 +138,10 @@ static void odbc_link_free(odbc_link *link) zend_hash_destroy(&link->connection->results); efree(link->connection); ODBCG(num_links)--; + } - if (link->hash) { - zend_hash_del(&ODBCG(non_persistent_connections), link->hash); - } + if (link->hash) { + zend_hash_del(&ODBCG(connections), link->hash); } link->connection = NULL; @@ -317,6 +317,7 @@ static void _close_odbc_pconn(zend_resource *rsrc) SQLFreeConnect(conn->hdbc); SQLFreeEnv(conn->henv); } + free(conn); ODBCG(num_links)--; ODBCG(num_persistent)--; @@ -501,12 +502,12 @@ static PHP_GINIT_FUNCTION(odbc) ZEND_TSRMLS_CACHE_UPDATE(); #endif odbc_globals->num_persistent = 0; - zend_hash_init(&odbc_globals->non_persistent_connections, 0, NULL, NULL, 1); + zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, 1); } static PHP_GSHUTDOWN_FUNCTION(odbc) { - zend_hash_destroy(&odbc_globals->non_persistent_connections); + zend_hash_destroy(&odbc_globals->connections); } /* {{{ PHP_MINIT_FUNCTION */ @@ -878,14 +879,14 @@ PHP_FUNCTION(odbc_close_all) } /* Loop through the non-persistent connection list, now close all non-persistent connections and their results */ - ZEND_HASH_FOREACH_VAL(&ODBCG(non_persistent_connections), zv) { + ZEND_HASH_FOREACH_VAL(&ODBCG(connections), zv) { odbc_link *link = Z_ODBC_LINK_P(zv); if (link->connection) { odbc_link_free(link); } } ZEND_HASH_FOREACH_END(); - zend_hash_clean(&ODBCG(non_persistent_connections)); + zend_hash_clean(&ODBCG(connections)); zend_hash_apply(&EG(persistent_list), _close_pconn); } @@ -2299,7 +2300,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) } char *hashed_details; - int hashed_details_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt); + int hashed_details_len = spprintf(&hashed_details, 0, "%d_%s_%s_%s_%s_%d", persistent, ODBC_TYPE, db, uid, pwd, cur_opt); try_and_get_another_connection: @@ -2333,6 +2334,8 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) RETURN_FALSE; } + zend_hash_str_add_new(&ODBCG(connections), hashed_details, hashed_details_len, return_value); + ODBCG(num_persistent)++; ODBCG(num_links)++; } else { /* found connection */ @@ -2381,15 +2384,22 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) } } - object_init_ex(return_value, odbc_connection_ce); - odbc_link *link = Z_ODBC_LINK_P(return_value); - link->connection = db_conn; - link->hash = zend_string_init(hashed_details, hashed_details_len, persistent); - link->persistent = true; + zval *tmp; + if ((tmp = zend_hash_str_find(&ODBCG(connections), hashed_details, hashed_details_len)) == NULL) { + object_init_ex(return_value, odbc_connection_ce); + odbc_link *link = Z_ODBC_LINK_P(return_value); + link->connection = db_conn; + link->hash = zend_string_init(hashed_details, hashed_details_len, persistent); + link->persistent = true; + } else { + ZVAL_COPY(return_value, tmp); + + ZEND_ASSERT(Z_ODBC_CONNECTION_P(return_value) == db_conn && "Persistent connection has changed"); + } } - } else { + } else { /* non-persistent */ zval *tmp; - if ((tmp = zend_hash_str_find(&ODBCG(non_persistent_connections), hashed_details, hashed_details_len)) == NULL) { /* non-persistent, new */ + if ((tmp = zend_hash_str_find(&ODBCG(connections), hashed_details, hashed_details_len)) == NULL) { /* non-persistent, new */ if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { php_error_docref(NULL, E_WARNING, "Too many open connections (" ZEND_LONG_FMT ")", ODBCG(num_links)); efree(hashed_details); @@ -2403,7 +2413,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) } ODBCG(num_links)++; - zend_hash_str_add_new(&ODBCG(non_persistent_connections), hashed_details, hashed_details_len, return_value); + zend_hash_str_add_new(&ODBCG(connections), hashed_details, hashed_details_len, return_value); } else { /* non-persistent, pre-existing */ ZVAL_COPY(return_value, tmp); } @@ -2417,19 +2427,21 @@ PHP_FUNCTION(odbc_close) { zval *pv_conn; odbc_link *link; + odbc_connection *connection; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } link = Z_ODBC_LINK_P(pv_conn); - CHECK_ODBC_CONNECTION(link->connection); + connection = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(connection); + + odbc_link_free(link); if (link->persistent) { - zend_hash_apply_with_argument(&EG(persistent_list), _close_pconn_with_res, (void *) Z_OBJ_P(pv_conn)); + zend_hash_apply_with_argument(&EG(persistent_list), _close_pconn_with_res, (void *) connection); } - - odbc_link_free(link); } /* }}} */ diff --git a/ext/odbc/php_odbc_includes.h b/ext/odbc/php_odbc_includes.h index ef885b065102b..71daf2f2d5194 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -248,7 +248,13 @@ ZEND_BEGIN_MODULE_GLOBALS(odbc) zend_long default_cursortype; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - HashTable non_persistent_connections; + /* Stores ODBC links throughout the duration of a request. The connection member may be either persistent or + * non-persistent. In the former case, it is a pointer to an item in EG(persistent_list). This solution makes it + * possible to properly free links during RSHUTDOWN (or when they are explicitly closed), while persistent + * connections themselves are going to be freed later during the shutdown process (or when they are explicitly + * closed). + */ + HashTable connections; ZEND_END_MODULE_GLOBALS(odbc) int odbc_add_result(HashTable *list, odbc_result *result); diff --git a/ext/odbc/tests/odbc_close_001.phpt b/ext/odbc/tests/odbc_close_001.phpt new file mode 100644 index 0000000000000..2bcc0ba1b7c4f --- /dev/null +++ b/ext/odbc/tests/odbc_close_001.phpt @@ -0,0 +1,62 @@ +--TEST-- +odbc_close(): Basic test +--EXTENSIONS-- +odbc +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} + +try { + odbc_columns($conn2, '', '', '', ''); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + odbc_num_rows($result1); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +try { + odbc_num_rows($result2); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +?> +--EXPECTF-- +object(ODBC\Connection)#%d (%d) { +} +object(ODBC\Connection)#%d (%d) { +} +object(ODBC\Result)#%d (%d) { +} +object(ODBC\Result)#%d (%d) { +} +ODBC connection has already been closed +ODBC connection has already been closed +ODBC result has already been closed +ODBC result has already been closed diff --git a/ext/odbc/tests/odbc_close_all_001.phpt b/ext/odbc/tests/odbc_close_all_001.phpt index 8e3b134e91059..47da881accf70 100644 --- a/ext/odbc/tests/odbc_close_all_001.phpt +++ b/ext/odbc/tests/odbc_close_all_001.phpt @@ -21,21 +21,32 @@ var_dump($result2); odbc_close_all(); -var_dump($conn1); -var_dump($conn2); -var_dump($result1); -var_dump($result2); - -?> ---EXPECTF-- -object(ODBC\Connection)#%d (%d) { +try { + odbc_columns($conn1, '', '', '', ''); +} catch (Error $e) { + echo $e->getMessage() . "\n"; } -object(ODBC\Connection)#%d (%d) { + +try { + odbc_columns($conn2, '', '', '', ''); +} catch (Error $e) { + echo $e->getMessage() . "\n"; } -object(ODBC\Result)#%d (%d) { + +try { + odbc_num_rows($result1); +} catch (Error $e) { + echo $e->getMessage() . "\n"; } -object(ODBC\Result)#%d (%d) { + +try { + odbc_num_rows($result2); +} catch (Error $e) { + echo $e->getMessage() . "\n"; } + +?> +--EXPECTF-- object(ODBC\Connection)#%d (%d) { } object(ODBC\Connection)#%d (%d) { @@ -44,3 +55,7 @@ object(ODBC\Result)#%d (%d) { } object(ODBC\Result)#%d (%d) { } +ODBC connection has already been closed +ODBC connection has already been closed +ODBC result has already been closed +ODBC result has already been closed From f75d4b32003979abc7dfda69ca73e91a3ab1705c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sat, 27 Apr 2024 22:20:16 +0200 Subject: [PATCH 10/11] Fix one more address round and rename namespace to Odbc --- UPGRADING | 6 + ext/odbc/odbc.stub.php | 122 +++++------ ext/odbc/odbc_arginfo.h | 102 +++++----- ext/odbc/php_odbc.c | 190 ++++++++---------- ext/odbc/tests/bug78470.phpt | 2 +- ext/odbc/tests/bug78473.phpt | 2 +- ext/odbc/tests/odbc_close_001.phpt | 8 +- ext/odbc/tests/odbc_close_all_001.phpt | 8 +- ext/odbc/tests/odbc_columnprivileges_001.phpt | 6 +- ext/odbc/tests/odbc_free_result_001.phpt | 2 +- ext/odbc/tests/odbc_tables_001.phpt | 8 +- 11 files changed, 224 insertions(+), 232 deletions(-) diff --git a/UPGRADING b/UPGRADING index ad6e5b839a8a0..ab71c4d7db576 100644 --- a/UPGRADING +++ b/UPGRADING @@ -67,6 +67,12 @@ PHP 8.4 UPGRADE NOTES - ODBC: . odbc_fetch_row() returns false when a value less than or equal to 0 is passed for parameter $row. Now, a warning is emitted in this case. + . odbc_connect() and odbc_pconnect() will now return an Odbc\Connection + object rather than a resource. Return value checks using is_resource() + should be replaced with checks for `false`. + . odbc_prepare(), odbc_exec(), and various other functions will now return + an Odbc\Result object rather than a resource. Return value checks using + is_resource() should be replaced with checks for `false`. - Opcache: . The JIT config defaults changed from opcache.jit=tracing and diff --git a/ext/odbc/odbc.stub.php b/ext/odbc/odbc.stub.php index f5ccb1c63d3f7..8e7a43d059dfc 100644 --- a/ext/odbc/odbc.stub.php +++ b/ext/odbc/odbc.stub.php @@ -2,7 +2,7 @@ /** @generate-class-entries */ -namespace ODBC { +namespace Odbc { /** * @strict-properties * @not-serializable @@ -234,7 +234,7 @@ class Result */ const SQL_TIMESTAMP = UNKNOWN; - #if (defined(ODBCVER) && (ODBCVER >= 0x0300)) +#if (defined(ODBCVER) && (ODBCVER >= 0x0300)) /** * @var int * @cvalue SQL_TYPE_DATE @@ -327,116 +327,116 @@ class Result */ const SQL_QUICK = UNKNOWN; - #endif +#endif function odbc_close_all(): void {} - function odbc_binmode(ODBC\Result $statement, int $mode): true {} + function odbc_binmode(Odbc\Result $statement, int $mode): true {} - function odbc_longreadlen(ODBC\Result $statement, int $length): true {} + function odbc_longreadlen(Odbc\Result $statement, int $length): true {} - function odbc_prepare(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + function odbc_prepare(Odbc\Connection $odbc, string $query): Odbc\Result|false {} - function odbc_execute(ODBC\Result $statement, array $params = []): bool {} + function odbc_execute(Odbc\Result $statement, array $params = []): bool {} - function odbc_cursor(ODBC\Result $statement): string|false {} + function odbc_cursor(Odbc\Result $statement): string|false {} - #ifdef HAVE_SQLDATASOURCES - function odbc_data_source(ODBC\Connection $odbc, int $fetch_type): array|null|false {} - #endif +#ifdef HAVE_SQLDATASOURCES + function odbc_data_source(Odbc\Connection $odbc, int $fetch_type): array|null|false {} +#endif - function odbc_exec(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + function odbc_exec(Odbc\Connection $odbc, string $query): Odbc\Result|false {} /** @alias odbc_exec */ - function odbc_do(ODBC\Connection $odbc, string $query): ODBC\Result|false {} + function odbc_do(Odbc\Connection $odbc, string $query): Odbc\Result|false {} #ifdef PHP_ODBC_HAVE_FETCH_HASH -/** @param resource $statement */ -function odbc_fetch_object($statement, ?int $row = null): stdClass|false {} + /** @param resource $statement */ + function odbc_fetch_object($statement, ?int $row = null): stdClass|false {} -/** @param resource $statement */ -function odbc_fetch_array($statement, ?int $row = null): array|false {} + /** @param resource $statement */ + function odbc_fetch_array($statement, ?int $row = null): array|false {} #endif -/** - * @param resource $statement - * @param array $array - */ -function odbc_fetch_into($statement, &$array, ?int $row = null): int|false {} + /** + * @param resource $statement + * @param array $array + */ + function odbc_fetch_into($statement, &$array, ?int $row = null): int|false {} - function odbc_fetch_row(ODBC\Result $statement, ?int $row = null): bool {} + function odbc_fetch_row(Odbc\Result $statement, ?int $row = null): bool {} - function odbc_result(ODBC\Result $statement, string|int $field): string|bool|null {} + function odbc_result(Odbc\Result $statement, string|int $field): string|bool|null {} /** @deprecated */ - function odbc_result_all(ODBC\Result $statement, string $format = ""): int|false {} + function odbc_result_all(Odbc\Result $statement, string $format = ""): int|false {} - function odbc_free_result(ODBC\Result $statement): true {} + function odbc_free_result(Odbc\Result $statement): true {} - function odbc_connect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} + function odbc_connect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER): Odbc\Connection|false {} - function odbc_pconnect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER): ODBC\Connection|false {} + function odbc_pconnect(string $dsn, ?string $user = null, #[\SensitiveParameter] ?string $password = null, int $cursor_option = SQL_CUR_USE_DRIVER): Odbc\Connection|false {} - function odbc_close(ODBC\Connection $odbc): void {} + function odbc_close(Odbc\Connection $odbc): void {} - function odbc_num_rows(ODBC\Result $statement): int {} + function odbc_num_rows(Odbc\Result $statement): int {} - #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) - function odbc_next_result(ODBC\Result $statement): bool {} - #endif +#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) + function odbc_next_result(Odbc\Result $statement): bool {} +#endif - function odbc_num_fields(ODBC\Result $statement): int {} + function odbc_num_fields(Odbc\Result $statement): int {} - function odbc_field_name(ODBC\Result $statement, int $field): string|false {} + function odbc_field_name(Odbc\Result $statement, int $field): string|false {} - function odbc_field_type(ODBC\Result $statement, int $field): string|false {} + function odbc_field_type(Odbc\Result $statement, int $field): string|false {} - function odbc_field_len(ODBC\Result $statement, int $field): int|false {} + function odbc_field_len(Odbc\Result $statement, int $field): int|false {} /** @alias odbc_field_len */ - function odbc_field_precision(ODBC\Result $statement, int $field): int|false {} + function odbc_field_precision(Odbc\Result $statement, int $field): int|false {} - function odbc_field_scale(ODBC\Result $statement, int $field): int|false {} + function odbc_field_scale(Odbc\Result $statement, int $field): int|false {} - function odbc_field_num(ODBC\Result $statement, string $field): int|false {} + function odbc_field_num(Odbc\Result $statement, string $field): int|false {} - function odbc_autocommit(ODBC\Connection $odbc, ?bool $enable = null): int|bool {} + function odbc_autocommit(Odbc\Connection $odbc, ?bool $enable = null): int|bool {} - function odbc_commit(ODBC\Connection $odbc): bool {} + function odbc_commit(Odbc\Connection $odbc): bool {} - function odbc_rollback(ODBC\Connection $odbc): bool {} + function odbc_rollback(Odbc\Connection $odbc): bool {} - function odbc_error(?ODBC\Connection $odbc = null): string {} + function odbc_error(?Odbc\Connection $odbc = null): string {} - function odbc_errormsg(?ODBC\Connection $odbc = null): string {} + function odbc_errormsg(?Odbc\Connection $odbc = null): string {} - function odbc_setoption(ODBC\Connection|ODBC\Result $odbc, int $which, int $option, int $value): bool {} + function odbc_setoption(Odbc\Connection|Odbc\Result $odbc, int $which, int $option, int $value): bool {} - function odbc_tables(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null): ODBC\Result|false {} + function odbc_tables(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $types = null): Odbc\Result|false {} - function odbc_columns(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null): ODBC\Result|false {} + function odbc_columns(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $table = null, ?string $column = null): Odbc\Result|false {} - function odbc_gettypeinfo(ODBC\Connection $odbc, int $data_type = 0): ODBC\Result|false {} + function odbc_gettypeinfo(Odbc\Connection $odbc, int $data_type = 0): Odbc\Result|false {} - function odbc_primarykeys(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table): ODBC\Result|false {} + function odbc_primarykeys(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table): Odbc\Result|false {} - #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) - function odbc_procedurecolumns(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null): ODBC\Result|false {} +#if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) + function odbc_procedurecolumns(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null, ?string $column = null): Odbc\Result|false {} - function odbc_procedures(ODBC\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null): ODBC\Result|false {} + function odbc_procedures(Odbc\Connection $odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null): Odbc\Result|false {} - function odbc_foreignkeys(ODBC\Connection $odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table): ODBC\Result|false {} - #endif + function odbc_foreignkeys(Odbc\Connection $odbc, ?string $pk_catalog, string $pk_schema, string $pk_table, string $fk_catalog, string $fk_schema, string $fk_table): Odbc\Result|false {} +#endif - function odbc_specialcolumns(ODBC\Connection $odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable): ODBC\Result|false {} + function odbc_specialcolumns(Odbc\Connection $odbc, int $type, ?string $catalog, string $schema, string $table, int $scope, int $nullable): Odbc\Result|false {} - function odbc_statistics(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy): ODBC\Result|false {} + function odbc_statistics(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table, int $unique, int $accuracy): Odbc\Result|false {} - #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) - function odbc_tableprivileges(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table): ODBC\Result|false {} +#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) + function odbc_tableprivileges(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table): Odbc\Result|false {} - function odbc_columnprivileges(ODBC\Connection $odbc, ?string $catalog, string $schema, string $table, string $column): ODBC\Result|false {} - #endif + function odbc_columnprivileges(Odbc\Connection $odbc, ?string $catalog, string $schema, string $table, string $column): Odbc\Result|false {} +#endif /* odbc_utils.c */ diff --git a/ext/odbc/odbc_arginfo.h b/ext/odbc/odbc_arginfo.h index 451db23d7a0ab..681625f3eb997 100644 --- a/ext/odbc/odbc_arginfo.h +++ b/ext/odbc/odbc_arginfo.h @@ -1,36 +1,36 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c0d3607a59dba96e10fe27c061cf7d7da11dda2c */ + * Stub hash: 34cebf41d91e4dacb8655a935c629ac62f0bb5ab */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close_all, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_binmode, 0, 2, IS_TRUE, 0) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO(0, mode, IS_LONG, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_longreadlen, 0, 2, IS_TRUE, 0) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO(0, length, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_prepare, 0, 2, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_prepare, 0, 2, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, query, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_execute, 0, 1, _IS_BOOL, 0) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, params, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_cursor, 0, 1, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_END_ARG_INFO() #if defined(HAVE_SQLDATASOURCES) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_data_source, 0, 2, MAY_BE_ARRAY|MAY_BE_NULL|MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, fetch_type, IS_LONG, 0) ZEND_END_ARG_INFO() #endif @@ -60,25 +60,25 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_fetch_into, 0, 2, MAY_BE_LO ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_fetch_row, 0, 1, _IS_BOOL, 0) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, row, IS_LONG, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_result, 0, 2, MAY_BE_STRING|MAY_BE_BOOL|MAY_BE_NULL) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_MASK(0, field, MAY_BE_STRING|MAY_BE_LONG, NULL) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_result_all, 0, 1, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, format, IS_STRING, 0, "\"\"") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_free_result, 0, 1, IS_TRUE, 0) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_connect, 0, 1, ODBC\\Connection, MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_connect, 0, 1, Odbc\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, dsn, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, user, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, password, IS_STRING, 1, "null") @@ -88,30 +88,30 @@ ZEND_END_ARG_INFO() #define arginfo_odbc_pconnect arginfo_odbc_connect ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close, 0, 1, IS_VOID, 0) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_num_rows, 0, 1, IS_LONG, 0) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_END_ARG_INFO() #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_next_result, 0, 1, _IS_BOOL, 0) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_END_ARG_INFO() #endif #define arginfo_odbc_num_fields arginfo_odbc_num_rows ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_name, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_odbc_field_type arginfo_odbc_field_name ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_len, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -120,65 +120,65 @@ ZEND_END_ARG_INFO() #define arginfo_odbc_field_scale arginfo_odbc_field_len ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_field_num, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, statement, ODBC\\Result, 0) + ZEND_ARG_OBJ_INFO(0, statement, Odbc\\Result, 0) ZEND_ARG_TYPE_INFO(0, field, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_odbc_autocommit, 0, 1, MAY_BE_LONG|MAY_BE_BOOL) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_commit, 0, 1, _IS_BOOL, 0) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_END_ARG_INFO() #define arginfo_odbc_rollback arginfo_odbc_commit ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_error, 0, 0, IS_STRING, 0) - ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, odbc, ODBC\\Connection, 1, "null") + ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, odbc, Odbc\\Connection, 1, "null") ZEND_END_ARG_INFO() #define arginfo_odbc_errormsg arginfo_odbc_error ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_setoption, 0, 4, _IS_BOOL, 0) - ZEND_ARG_OBJ_TYPE_MASK(0, odbc, ODBC\\Connection|ODBC\\Result, 0, NULL) + ZEND_ARG_OBJ_TYPE_MASK(0, odbc, Odbc\\Connection|Odbc\\Result, 0, NULL) ZEND_ARG_TYPE_INFO(0, which, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, option, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, value, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tables, 0, 1, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tables, 0, 1, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, table, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, types, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columns, 0, 1, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columns, 0, 1, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, table, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, column, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_gettypeinfo, 0, 1, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_gettypeinfo, 0, 1, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, data_type, IS_LONG, 0, "0") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_primarykeys, 0, 4, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_primarykeys, 0, 4, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) ZEND_END_ARG_INFO() #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedurecolumns, 0, 1, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedurecolumns, 0, 1, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, procedure, IS_STRING, 1, "null") @@ -187,8 +187,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedures, 0, 1, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_procedures, 0, 1, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, catalog, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, schema, IS_STRING, 1, "null") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, procedure, IS_STRING, 1, "null") @@ -196,8 +196,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) && !defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_foreignkeys, 0, 7, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_foreignkeys, 0, 7, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, pk_catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, pk_schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, pk_table, IS_STRING, 0) @@ -207,8 +207,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_foreignkeys, 0, 7, ODBC ZEND_END_ARG_INFO() #endif -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_specialcolumns, 0, 7, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_specialcolumns, 0, 7, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, type, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) @@ -217,8 +217,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_specialcolumns, 0, 7, O ZEND_ARG_TYPE_INFO(0, nullable, IS_LONG, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_statistics, 0, 6, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_statistics, 0, 6, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -227,8 +227,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_statistics, 0, 6, ODBC\ ZEND_END_ARG_INFO() #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tableprivileges, 0, 4, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_tableprivileges, 0, 4, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -236,8 +236,8 @@ ZEND_END_ARG_INFO() #endif #if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35) -ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columnprivileges, 0, 5, ODBC\\Result, MAY_BE_FALSE) - ZEND_ARG_OBJ_INFO(0, odbc, ODBC\\Connection, 0) +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_odbc_columnprivileges, 0, 5, Odbc\\Result, MAY_BE_FALSE) + ZEND_ARG_OBJ_INFO(0, odbc, Odbc\\Connection, 0) ZEND_ARG_TYPE_INFO(0, catalog, IS_STRING, 1) ZEND_ARG_TYPE_INFO(0, schema, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, table, IS_STRING, 0) @@ -390,11 +390,11 @@ static const zend_function_entry ext_functions[] = { ZEND_FE_END }; -static const zend_function_entry class_ODBC_Connection_methods[] = { +static const zend_function_entry class_Odbc_Connection_methods[] = { ZEND_FE_END }; -static const zend_function_entry class_ODBC_Result_methods[] = { +static const zend_function_entry class_Odbc_Result_methods[] = { ZEND_FE_END }; @@ -498,22 +498,22 @@ static void register_odbc_symbols(int module_number) zend_add_parameter_attribute(zend_hash_str_find_ptr(CG(function_table), "odbc_pconnect", sizeof("odbc_pconnect") - 1), 2, ZSTR_KNOWN(ZEND_STR_SENSITIVEPARAMETER), 0); } -static zend_class_entry *register_class_ODBC_Connection(void) +static zend_class_entry *register_class_Odbc_Connection(void) { zend_class_entry ce, *class_entry; - INIT_NS_CLASS_ENTRY(ce, "ODBC", "Connection", class_ODBC_Connection_methods); + INIT_NS_CLASS_ENTRY(ce, "Odbc", "Connection", class_Odbc_Connection_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; return class_entry; } -static zend_class_entry *register_class_ODBC_Result(void) +static zend_class_entry *register_class_Odbc_Result(void) { zend_class_entry ce, *class_entry; - INIT_NS_CLASS_ENTRY(ce, "ODBC", "Result", class_ODBC_Result_methods); + INIT_NS_CLASS_ENTRY(ce, "Odbc", "Result", class_Odbc_Result_methods); class_entry = zend_register_internal_class_ex(&ce, NULL); class_entry->ce_flags |= ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE; diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index bd32f4bcad04d..dd9c8a2dcc93c 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -77,7 +77,8 @@ static zend_object_handlers odbc_connection_object_handlers, odbc_result_object_ #define Z_ODBC_CONNECTION_P(zv) Z_ODBC_LINK_P(zv)->connection #define Z_ODBC_RESULT_P(zv) odbc_result_from_obj(Z_OBJ_P(zv)) -static void odbc_insert_new_result(odbc_connection *connection, zval *result) { +static void odbc_insert_new_result(odbc_connection *connection, zval *result) +{ ZEND_ASSERT(Z_TYPE_P(result) == IS_OBJECT); #if ZEND_DEBUG ZEND_ASSERT(instanceof_function(Z_OBJCE_P(result), odbc_result_ce)); @@ -90,20 +91,16 @@ static void odbc_insert_new_result(odbc_connection *connection, zval *result) { Z_ADDREF_P(result); } -static inline odbc_link *odbc_link_from_obj(zend_object *obj) { +static inline odbc_link *odbc_link_from_obj(zend_object *obj) +{ return (odbc_link *)((char *)(obj) - XtOffsetOf(odbc_link, std)); } static int _close_pconn_with_res(zval *zv, void *p) { zend_resource *le = Z_RES_P(zv); - if (le->type != le_pconn) { - return ZEND_HASH_APPLY_KEEP; - } - odbc_connection *list_conn = ((odbc_connection *)(le->ptr)); - odbc_connection *obj_conn = (odbc_connection *) p; - if (list_conn == obj_conn) { + if (le->ptr == p) { return ZEND_HASH_APPLY_REMOVE; } @@ -120,6 +117,41 @@ static int _close_pconn(zval *zv) } } +/* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ +static void safe_odbc_disconnect( void *handle ) +{ + int ret; + + ret = SQLDisconnect( handle ); + if ( ret == SQL_ERROR ) + { + SQLTransact( NULL, handle, SQL_ROLLBACK ); + SQLDisconnect( handle ); + } +} + +static void free_connection(odbc_connection *conn, bool persistent) +{ + /* If aborted via timer expiration, don't try to call any unixODBC function */ + if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { + safe_odbc_disconnect(conn->hdbc); + SQLFreeConnect(conn->hdbc); + SQLFreeEnv(conn->henv); + } + + conn->hdbc = NULL; + conn->henv = NULL; + + zend_hash_destroy(&conn->results); + + pefree(conn, persistent); + + ODBCG(num_links)--; + if (persistent) { + ODBCG(num_persistent)--; + } +} + static void odbc_link_free(odbc_link *link) { ZEND_ASSERT(link->connection && "link has already been closed"); @@ -127,32 +159,20 @@ static void odbc_link_free(odbc_link *link) close_results_with_connection(link->connection); if (!link->persistent) { - /* If aborted via timer expiration, don't try to call any unixODBC function */ - if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { - safe_odbc_disconnect(link->connection->hdbc); - SQLFreeConnect(link->connection->hdbc); - SQLFreeEnv(link->connection->henv); - } - link->connection->hdbc = NULL; - link->connection->henv = NULL; - zend_hash_destroy(&link->connection->results); - efree(link->connection); - ODBCG(num_links)--; - } - - if (link->hash) { - zend_hash_del(&ODBCG(connections), link->hash); + free_connection(link->connection, link->persistent); } link->connection = NULL; if (link->hash) { + zend_hash_del(&ODBCG(connections), link->hash); zend_string_release_ex(link->hash, link->persistent); link->hash = NULL; } } -static zend_object *odbc_connection_create_object(zend_class_entry *class_type) { +static zend_object *odbc_connection_create_object(zend_class_entry *class_type) +{ odbc_link *intern = zend_object_alloc(sizeof(odbc_link), class_type); zend_object_std_init(&intern->std, class_type); @@ -162,7 +182,8 @@ static zend_object *odbc_connection_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *odbc_connection_get_constructor(zend_object *object) { +static zend_function *odbc_connection_get_constructor(zend_object *object) +{ zend_throw_error(NULL, "Cannot directly construct ODBC\\Connection, use odbc_connect() or odbc_pconnect() instead"); return NULL; } @@ -178,11 +199,13 @@ static void odbc_connection_free_obj(zend_object *obj) zend_object_std_dtor(&link->std); } -static inline odbc_result *odbc_result_from_obj(zend_object *obj) { +static inline odbc_result *odbc_result_from_obj(zend_object *obj) +{ return (odbc_result *)((char *)(obj) - XtOffsetOf(odbc_result, std)); } -static zend_object *odbc_result_create_object(zend_class_entry *class_type) { +static zend_object *odbc_result_create_object(zend_class_entry *class_type) +{ odbc_result *intern = zend_object_alloc(sizeof(odbc_result), class_type); zend_object_std_init(&intern->std, class_type); @@ -192,7 +215,8 @@ static zend_object *odbc_result_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *odbc_result_get_constructor(zend_object *object) { +static zend_function *odbc_result_get_constructor(zend_object *object) +{ zend_throw_error(NULL, "Cannot directly construct ODBC\\Result, use an appropriate odbc_* function instead"); return NULL; } @@ -229,13 +253,14 @@ static void odbc_result_free(odbc_result *res) res->param_info = NULL; } - HashTable *tmp = &res->conn_ptr->results; + HashTable *results = &res->conn_ptr->results; res->conn_ptr = NULL; - zend_result status = zend_hash_index_del(tmp, res->index); + zend_result status = zend_hash_index_del(results, res->index); ZEND_ASSERT(status == SUCCESS); } -static void odbc_result_free_obj(zend_object *obj) { +static void odbc_result_free_obj(zend_object *obj) +{ odbc_result *result = odbc_result_from_obj(obj); if (result->conn_ptr) { @@ -277,7 +302,8 @@ ZEND_TSRMLS_CACHE_DEFINE() ZEND_GET_MODULE(odbc) #endif -static void close_results_with_connection(odbc_connection *conn) { +static void close_results_with_connection(odbc_connection *conn) +{ zval *p; ZEND_HASH_FOREACH_VAL(&conn->results, p) { @@ -290,37 +316,14 @@ static void close_results_with_connection(odbc_connection *conn) { zend_hash_clean(&conn->results); } -/* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ -static void safe_odbc_disconnect( void *handle ) -{ - int ret; - - ret = SQLDisconnect( handle ); - if ( ret == SQL_ERROR ) - { - SQLTransact( NULL, handle, SQL_ROLLBACK ); - SQLDisconnect( handle ); - } -} - /* {{{ void _close_odbc_pconn */ static void _close_odbc_pconn(zend_resource *rsrc) { odbc_connection *conn = (odbc_connection *)rsrc->ptr; close_results_with_connection(conn); - zend_hash_destroy(&conn->results); - - /* If aborted via timer expiration, don't try to call any unixODBC function */ - if (!(PG(connection_status) & PHP_CONNECTION_TIMEOUT)) { - safe_odbc_disconnect(conn->hdbc); - SQLFreeConnect(conn->hdbc); - SQLFreeEnv(conn->henv); - } - free(conn); + free_connection(conn, true); - ODBCG(num_links)--; - ODBCG(num_persistent)--; rsrc->ptr = NULL; } /* }}} */ @@ -502,7 +505,7 @@ static PHP_GINIT_FUNCTION(odbc) ZEND_TSRMLS_CACHE_UPDATE(); #endif odbc_globals->num_persistent = 0; - zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, 1); + zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, true); } static PHP_GSHUTDOWN_FUNCTION(odbc) @@ -524,7 +527,7 @@ PHP_MINIT_FUNCTION(odbc) register_odbc_symbols(module_number); - odbc_connection_ce = register_class_ODBC_Connection(); + odbc_connection_ce = register_class_Odbc_Connection(); odbc_connection_ce->create_object = odbc_connection_create_object; odbc_connection_ce->default_object_handlers = &odbc_connection_object_handlers; @@ -535,7 +538,7 @@ PHP_MINIT_FUNCTION(odbc) odbc_connection_object_handlers.clone_obj = NULL; odbc_connection_object_handlers.compare = zend_objects_not_comparable; - odbc_result_ce = register_class_ODBC_Result(); + odbc_result_ce = register_class_Odbc_Result(); odbc_result_ce->create_object = odbc_result_create_object; odbc_result_ce->default_object_handlers = &odbc_result_object_handlers; @@ -800,7 +803,6 @@ void odbc_bindcols(odbc_result *result) /* {{{ odbc_transact */ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) { - odbc_connection *conn; RETCODE rc; zval *pv_conn; @@ -808,7 +810,7 @@ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); rc = SQLTransact(conn->henv, conn->hdbc, (SQLUSMALLINT)((type)?SQL_COMMIT:SQL_ROLLBACK)); @@ -878,7 +880,7 @@ PHP_FUNCTION(odbc_close_all) RETURN_THROWS(); } - /* Loop through the non-persistent connection list, now close all non-persistent connections and their results */ + /* Loop through the link list, now close all links and their results */ ZEND_HASH_FOREACH_VAL(&ODBCG(connections), zv) { odbc_link *link = Z_ODBC_LINK_P(zv); if (link->connection) { @@ -913,7 +915,6 @@ PHP_FUNCTION(odbc_prepare) char *query; size_t query_len; odbc_result *result = NULL; - odbc_connection *conn; RETCODE rc; int i; #ifdef HAVE_SQL_EXTENDED_FETCH @@ -924,7 +925,7 @@ PHP_FUNCTION(odbc_prepare) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -1247,7 +1248,6 @@ PHP_FUNCTION(odbc_data_source) zval *zv_conn; zend_long zv_fetch_type; RETCODE rc = 0; /* assume all is good */ - odbc_connection *conn; UCHAR server_name[100], desc[200]; SQLSMALLINT len1=0, len2=0, fetch_type; @@ -1262,7 +1262,7 @@ PHP_FUNCTION(odbc_data_source) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(zv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(zv_conn); CHECK_ODBC_CONNECTION(conn); /* now we have the "connection" lets call the DataSource object */ @@ -1307,7 +1307,6 @@ PHP_FUNCTION(odbc_exec) char *query; size_t query_len; odbc_result *result = NULL; - odbc_connection *conn; RETCODE rc; #ifdef HAVE_SQL_EXTENDED_FETCH SQLUINTEGER scrollopts; @@ -1317,7 +1316,7 @@ PHP_FUNCTION(odbc_exec) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -2130,7 +2129,7 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool object_init_ex(zv, odbc_connection_ce); link = Z_ODBC_LINK_P(zv); link->connection = pecalloc(1, sizeof(odbc_connection), persistent); - zend_hash_init(&link->connection->results, 0, NULL, ZVAL_PTR_DTOR, 1); + zend_hash_init(&link->connection->results, 0, NULL, ZVAL_PTR_DTOR, true); link->persistent = persistent; link->hash = zend_string_init(hash, hash_len, persistent); ret = SQLAllocEnv(&link->connection->henv); @@ -2300,7 +2299,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) } char *hashed_details; - int hashed_details_len = spprintf(&hashed_details, 0, "%d_%s_%s_%s_%s_%d", persistent, ODBC_TYPE, db, uid, pwd, cur_opt); + size_t hashed_details_len = spprintf(&hashed_details, 0, "%d_%s_%s_%s_%s_%d", persistent, ODBC_TYPE, db, uid, pwd, cur_opt); try_and_get_another_connection: @@ -2384,22 +2383,22 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) } } - zval *tmp; - if ((tmp = zend_hash_str_find(&ODBCG(connections), hashed_details, hashed_details_len)) == NULL) { + zval *link_zval; + if ((link_zval = zend_hash_str_find(&ODBCG(connections), hashed_details, hashed_details_len)) == NULL) { object_init_ex(return_value, odbc_connection_ce); odbc_link *link = Z_ODBC_LINK_P(return_value); link->connection = db_conn; link->hash = zend_string_init(hashed_details, hashed_details_len, persistent); link->persistent = true; } else { - ZVAL_COPY(return_value, tmp); + ZVAL_COPY(return_value, link_zval); ZEND_ASSERT(Z_ODBC_CONNECTION_P(return_value) == db_conn && "Persistent connection has changed"); } } } else { /* non-persistent */ - zval *tmp; - if ((tmp = zend_hash_str_find(&ODBCG(connections), hashed_details, hashed_details_len)) == NULL) { /* non-persistent, new */ + zval *link_zval; + if ((link_zval = zend_hash_str_find(&ODBCG(connections), hashed_details, hashed_details_len)) == NULL) { /* non-persistent, new */ if (ODBCG(max_links) != -1 && ODBCG(num_links) >= ODBCG(max_links)) { php_error_docref(NULL, E_WARNING, "Too many open connections (" ZEND_LONG_FMT ")", ODBCG(num_links)); efree(hashed_details); @@ -2415,7 +2414,7 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) zend_hash_str_add_new(&ODBCG(connections), hashed_details, hashed_details_len, return_value); } else { /* non-persistent, pre-existing */ - ZVAL_COPY(return_value, tmp); + ZVAL_COPY(return_value, link_zval); } } efree(hashed_details); @@ -2427,14 +2426,13 @@ PHP_FUNCTION(odbc_close) { zval *pv_conn; odbc_link *link; - odbc_connection *connection; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &pv_conn, odbc_connection_ce) == FAILURE) { RETURN_THROWS(); } link = Z_ODBC_LINK_P(pv_conn); - connection = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *connection = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(connection); odbc_link_free(link); @@ -2651,7 +2649,6 @@ PHP_FUNCTION(odbc_field_num) /* There can be problems with pconnections!*/ PHP_FUNCTION(odbc_autocommit) { - odbc_connection *conn; RETCODE rc; zval *pv_conn; bool pv_onoff = 0; @@ -2661,7 +2658,7 @@ PHP_FUNCTION(odbc_autocommit) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); if (!pv_onoff_is_null) { @@ -2815,7 +2812,6 @@ PHP_FUNCTION(odbc_tables) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema = NULL, *table = NULL, *type = NULL; size_t cat_len = 0, schema_len = 0, table_len = 0, type_len = 0; RETCODE rc; @@ -2825,7 +2821,7 @@ PHP_FUNCTION(odbc_tables) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -2881,7 +2877,6 @@ PHP_FUNCTION(odbc_columns) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema = NULL, *table = NULL, *column = NULL; size_t cat_len = 0, schema_len = 0, table_len = 0, column_len = 0; RETCODE rc; @@ -2891,7 +2886,7 @@ PHP_FUNCTION(odbc_columns) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -2950,7 +2945,6 @@ PHP_FUNCTION(odbc_columnprivileges) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema, *table, *column; size_t cat_len = 0, schema_len, table_len, column_len; RETCODE rc; @@ -2960,7 +2954,7 @@ PHP_FUNCTION(odbc_columnprivileges) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3013,7 +3007,6 @@ PHP_FUNCTION(odbc_foreignkeys) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *pcat = NULL, *pschema, *ptable, *fcat, *fschema, *ftable; size_t pcat_len = 0, pschema_len, ptable_len, fcat_len, fschema_len, ftable_len; RETCODE rc; @@ -3035,7 +3028,7 @@ PHP_FUNCTION(odbc_foreignkeys) EMPTY_TO_NULL(ftable); #endif - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3090,7 +3083,6 @@ PHP_FUNCTION(odbc_gettypeinfo) zval *pv_conn; zend_long pv_data_type = SQL_ALL_TYPES; odbc_result *result = NULL; - odbc_connection *conn; RETCODE rc; SQLSMALLINT data_type; @@ -3100,7 +3092,7 @@ PHP_FUNCTION(odbc_gettypeinfo) data_type = (SQLSMALLINT) pv_data_type; - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3147,7 +3139,6 @@ PHP_FUNCTION(odbc_primarykeys) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema = NULL, *table = NULL; size_t cat_len = 0, schema_len, table_len; RETCODE rc; @@ -3156,7 +3147,7 @@ PHP_FUNCTION(odbc_primarykeys) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3207,7 +3198,6 @@ PHP_FUNCTION(odbc_procedurecolumns) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema = NULL, *proc = NULL, *col = NULL; size_t cat_len = 0, schema_len = 0, proc_len = 0, col_len = 0; RETCODE rc; @@ -3217,7 +3207,7 @@ PHP_FUNCTION(odbc_procedurecolumns) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3270,7 +3260,6 @@ PHP_FUNCTION(odbc_procedures) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema = NULL, *proc = NULL; size_t cat_len = 0, schema_len = 0, proc_len = 0; RETCODE rc; @@ -3279,7 +3268,7 @@ PHP_FUNCTION(odbc_procedures) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3331,7 +3320,6 @@ PHP_FUNCTION(odbc_specialcolumns) zval *pv_conn; zend_long vtype, vscope, vnullable; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema = NULL, *name = NULL; size_t cat_len = 0, schema_len, name_len; SQLUSMALLINT type, scope, nullable; @@ -3346,7 +3334,7 @@ PHP_FUNCTION(odbc_specialcolumns) scope = (SQLUSMALLINT) vscope; nullable = (SQLUSMALLINT) vnullable; - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3399,7 +3387,6 @@ PHP_FUNCTION(odbc_statistics) zval *pv_conn; zend_long vunique, vreserved; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema, *name; size_t cat_len = 0, schema_len, name_len; SQLUSMALLINT unique, reserved; @@ -3413,7 +3400,7 @@ PHP_FUNCTION(odbc_statistics) unique = (SQLUSMALLINT) vunique; reserved = (SQLUSMALLINT) vreserved; - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); @@ -3466,7 +3453,6 @@ PHP_FUNCTION(odbc_tableprivileges) { zval *pv_conn; odbc_result *result = NULL; - odbc_connection *conn; char *cat = NULL, *schema = NULL, *table = NULL; size_t cat_len = 0, schema_len, table_len; RETCODE rc; @@ -3475,7 +3461,7 @@ PHP_FUNCTION(odbc_tableprivileges) RETURN_THROWS(); } - conn = Z_ODBC_CONNECTION_P(pv_conn); + odbc_connection *conn = Z_ODBC_CONNECTION_P(pv_conn); CHECK_ODBC_CONNECTION(conn); object_init_ex(return_value, odbc_result_ce); diff --git a/ext/odbc/tests/bug78470.phpt b/ext/odbc/tests/bug78470.phpt index f14865a90e363..92bd5c067f7b0 100644 --- a/ext/odbc/tests/bug78470.phpt +++ b/ext/odbc/tests/bug78470.phpt @@ -12,5 +12,5 @@ $conn = odbc_connect($dsn, $user, $pass); var_dump(odbc_specialcolumns($conn, SQL_BEST_ROWID, '', '', '', SQL_SCOPE_CURROW, SQL_NO_NULLS)); ?> --EXPECTF-- -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } diff --git a/ext/odbc/tests/bug78473.phpt b/ext/odbc/tests/bug78473.phpt index bed712e37bd8d..9313237efde2b 100644 --- a/ext/odbc/tests/bug78473.phpt +++ b/ext/odbc/tests/bug78473.phpt @@ -12,5 +12,5 @@ try { var_dump(STDIN); ?> --EXPECT-- -odbc_close(): Argument #1 ($odbc) must be of type ODBC\Connection, resource given +odbc_close(): Argument #1 ($odbc) must be of type Odbc\Connection, resource given resource(1) of type (stream) diff --git a/ext/odbc/tests/odbc_close_001.phpt b/ext/odbc/tests/odbc_close_001.phpt index 2bcc0ba1b7c4f..1c970b58959d9 100644 --- a/ext/odbc/tests/odbc_close_001.phpt +++ b/ext/odbc/tests/odbc_close_001.phpt @@ -48,13 +48,13 @@ try { ?> --EXPECTF-- -object(ODBC\Connection)#%d (%d) { +object(Odbc\Connection)#%d (%d) { } -object(ODBC\Connection)#%d (%d) { +object(Odbc\Connection)#%d (%d) { } -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } ODBC connection has already been closed ODBC connection has already been closed diff --git a/ext/odbc/tests/odbc_close_all_001.phpt b/ext/odbc/tests/odbc_close_all_001.phpt index 47da881accf70..3dc24b5679d56 100644 --- a/ext/odbc/tests/odbc_close_all_001.phpt +++ b/ext/odbc/tests/odbc_close_all_001.phpt @@ -47,13 +47,13 @@ try { ?> --EXPECTF-- -object(ODBC\Connection)#%d (%d) { +object(Odbc\Connection)#%d (%d) { } -object(ODBC\Connection)#%d (%d) { +object(Odbc\Connection)#%d (%d) { } -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } ODBC connection has already been closed ODBC connection has already been closed diff --git a/ext/odbc/tests/odbc_columnprivileges_001.phpt b/ext/odbc/tests/odbc_columnprivileges_001.phpt index 552c88f23731a..be8fa20699009 100644 --- a/ext/odbc/tests/odbc_columnprivileges_001.phpt +++ b/ext/odbc/tests/odbc_columnprivileges_001.phpt @@ -22,7 +22,7 @@ var_dump(odbc_fetch_row($result)); ?> --EXPECTF-- -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } bool(false) @@ -31,9 +31,9 @@ Deprecated: odbc_columnprivileges(): Passing null to parameter #3 ($schema) of t Deprecated: odbc_columnprivileges(): Passing null to parameter #4 ($table) of type string is deprecated in %s on line %d Deprecated: odbc_columnprivileges(): Passing null to parameter #5 ($column) of type string is deprecated in %s on line %d -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } bool(false) -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } bool(false) diff --git a/ext/odbc/tests/odbc_free_result_001.phpt b/ext/odbc/tests/odbc_free_result_001.phpt index 2490c05e4c740..28808f64208cf 100644 --- a/ext/odbc/tests/odbc_free_result_001.phpt +++ b/ext/odbc/tests/odbc_free_result_001.phpt @@ -58,6 +58,6 @@ odbc_exec($conn, 'DROP TABLE free_result'); bool(true) string(1) "1" bool(true) -odbc_free_result(): Argument #1 ($statement) must be of type ODBC\Result, ODBC\Connection given +odbc_free_result(): Argument #1 ($statement) must be of type Odbc\Result, Odbc\Connection given ODBC result has already been closed ODBC result has already been closed diff --git a/ext/odbc/tests/odbc_tables_001.phpt b/ext/odbc/tests/odbc_tables_001.phpt index f013be7f06ba8..4708bcd801d6f 100644 --- a/ext/odbc/tests/odbc_tables_001.phpt +++ b/ext/odbc/tests/odbc_tables_001.phpt @@ -27,17 +27,17 @@ var_dump(odbc_fetch_row($result)); ?> --EXPECTF-- -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } bool(false) -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } bool(true) bool(true) -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } bool(true) bool(true) -object(ODBC\Result)#%d (%d) { +object(Odbc\Result)#%d (%d) { } bool(false) From 46d653d01a4103171aff276ac7834b4910ae00c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sun, 28 Apr 2024 15:26:26 +0200 Subject: [PATCH 11/11] Fix last code review comments --- ext/odbc/php_odbc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index dd9c8a2dcc93c..7d6fea2966924 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -120,9 +120,8 @@ static int _close_pconn(zval *zv) /* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ static void safe_odbc_disconnect( void *handle ) { - int ret; + int ret = SQLDisconnect( handle ); - ret = SQLDisconnect( handle ); if ( ret == SQL_ERROR ) { SQLTransact( NULL, handle, SQL_ROLLBACK ); @@ -177,7 +176,6 @@ static zend_object *odbc_connection_create_object(zend_class_entry *class_type) zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); - intern->std.handlers = &odbc_connection_object_handlers; return &intern->std; } @@ -210,7 +208,6 @@ static zend_object *odbc_result_create_object(zend_class_entry *class_type) zend_object_std_init(&intern->std, class_type); object_properties_init(&intern->std, class_type); - intern->std.handlers = &odbc_result_object_handlers; return &intern->std; }