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/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..8e7a43d059dfc 100644 --- a/ext/odbc/odbc.stub.php +++ b/ext/odbc/odbc.stub.php @@ -2,520 +2,447 @@ /** @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; +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; + /** + * @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_close_all(): void {} + function odbc_longreadlen(Odbc\Result $statement, int $length): true {} -/** @param resource $statement */ -function odbc_binmode($statement, int $mode): true {} + function odbc_prepare(Odbc\Connection $odbc, string $query): Odbc\Result|false {} -/** @param resource $statement */ -function odbc_longreadlen($statement, int $length): true {} + function odbc_execute(Odbc\Result $statement, array $params = []): bool {} -/** - * @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 {} + function odbc_cursor(Odbc\Result $statement): string|false {} #ifdef HAVE_SQLDATASOURCES -/** @param resource $odbc */ -function odbc_data_source($odbc, int $fetch_type): array|null|false {} + function odbc_data_source(Odbc\Connection $odbc, int $fetch_type): array|null|false {} #endif -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_exec($odbc, string $query) {} + function odbc_exec(Odbc\Connection $odbc, string $query): Odbc\Result|false {} -/** - * @param resource $odbc - * @return resource|false - * @alias odbc_exec - */ -function odbc_do($odbc, string $query) {} + /** @alias odbc_exec */ + 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 {} -/** @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 = null, 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 = null, 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 {} + 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) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_procedures($odbc, ?string $catalog = null, ?string $schema = null, ?string $procedure = null) {} - -/** - * @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) {} + 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_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) {} - -/** - * @param resource $odbc - * @return resource|false - */ -function odbc_columnprivileges($odbc, ?string $catalog, string $schema, string $table, string $column) {} + 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 -/* 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..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: a64be64f69159d0c8ad2c3b951c6451a040c3c73 */ + * 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_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,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_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, 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_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..7d6fea2966924 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,23 +51,227 @@ #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 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; + +#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 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)); +#endif + + odbc_result *res = Z_ODBC_RESULT_P(result); + + res->index = connection->results.nNextFreeElement; + 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); -static int le_result, le_conn, le_pconn; + if (le->ptr == p) { + 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; + } +} + +/* disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) */ +static void safe_odbc_disconnect( void *handle ) +{ + int 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"); + + close_results_with_connection(link->connection); + + if (!link->persistent) { + 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) +{ + 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); + + 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) { + 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)); +} + +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); + + 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) +{ + 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) { + efree(res->values[i].value); + } + } + 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)) { +#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 + */ + res->stmt = NULL; + } + if (res->param_info) { + efree(res->param_info); + res->param_info = NULL; + } + + HashTable *results = &res->conn_ptr->results; + res->conn_ptr = NULL; + zend_result status = zend_hash_index_del(results, res->index); + ZEND_ASSERT(status == SUCCESS); +} + +static void odbc_result_free_obj(zend_object *obj) +{ + odbc_result *result = odbc_result_from_obj(obj); + + if (result->conn_ptr) { + odbc_result_free(result); + } + + zend_object_std_dtor(&result->std); +} #define SAFE_SQL_NTS(n) ((SQLSMALLINT) ((n)?(SQL_NTS):0)) 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 = { @@ -80,7 +286,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 }; @@ -93,111 +299,29 @@ 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; - - 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; - } - /* 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); - } -} -/* }}} */ - -/* {{{ safe_odbc_disconnect - * disconnect, and if it fails, then issue a rollback for any pending transaction (lurcher) - */ -static void safe_odbc_disconnect( void *handle ) +static void close_results_with_connection(odbc_connection *conn) { - int ret; + zval *p; - ret = SQLDisconnect( handle ); - if ( ret == SQL_ERROR ) - { - SQLTransact( NULL, handle, SQL_ROLLBACK ); - 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_VAL(&conn->results, p) { + odbc_result *result = Z_ODBC_RESULT_P(p); + if (result->conn_ptr) { + odbc_result_free(result); } } 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)--; + zend_hash_clean(&conn->results); } -/* }}} */ /* {{{ 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(); - - /* 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); + close_results_with_connection(conn); + free_connection(conn, true); - ODBCG(num_links)--; - ODBCG(num_persistent)--; + rsrc->ptr = NULL; } /* }}} */ @@ -378,6 +502,12 @@ static PHP_GINIT_FUNCTION(odbc) ZEND_TSRMLS_CACHE_UPDATE(); #endif odbc_globals->num_persistent = 0; + zend_hash_init(&odbc_globals->connections, 0, NULL, NULL, true); +} + +static PHP_GSHUTDOWN_FUNCTION(odbc) +{ + zend_hash_destroy(&odbc_globals->connections); } /* {{{ PHP_MINIT_FUNCTION */ @@ -389,19 +519,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; } /* }}} */ @@ -510,13 +660,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; @@ -651,17 +800,15 @@ void odbc_bindcols(odbc_result *result) /* {{{ odbc_transact */ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type) { - odbc_connection *conn; 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(); - } + 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)); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { @@ -673,19 +820,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 +838,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,32 +871,23 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ Close all ODBC connections */ PHP_FUNCTION(odbc_close_all) { - zend_resource *p; + zval *zv; 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); + /* 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) { + odbc_link_free(link); } } 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); - } - } - } ZEND_HASH_FOREACH_END(); + zend_hash_clean(&ODBCG(connections)); + + zend_hash_apply(&EG(persistent_list), _close_pconn); } /* }}} */ @@ -788,36 +912,35 @@ 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 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(); - } + odbc_connection *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; } @@ -846,7 +969,7 @@ PHP_FUNCTION(odbc_prepare) break; default: odbc_sql_error(conn, result->stmt, "SQLPrepare"); - efree(result); + zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -858,7 +981,6 @@ PHP_FUNCTION(odbc_prepare) } else { result->values = NULL; } - Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; @@ -870,12 +992,12 @@ 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)); + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -914,13 +1036,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 +1192,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) { @@ -1125,11 +1245,10 @@ 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; - 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 +1259,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(); - } + odbc_connection *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, @@ -1186,32 +1304,31 @@ 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; #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(); - } + odbc_connection *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 +1355,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; } @@ -1250,10 +1367,10 @@ PHP_FUNCTION(odbc_exec) } else { result->values = NULL; } - Z_ADDREF_P(pv_conn); result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -1277,13 +1394,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 */ @@ -1437,13 +1553,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 */ @@ -1567,13 +1682,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) { @@ -1605,6 +1719,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; @@ -1635,7 +1750,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 +1762,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 +1957,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"); @@ -1975,27 +2088,15 @@ PHP_FUNCTION(odbc_free_result) { zval *pv_res; 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++) { - if (result->values[i].value) { - efree(result->values[i].value); - } - } - efree(result->values); - result->values = NULL; - } - - zend_list_close(Z_RES_P(pv_res)); + odbc_result_free(result); RETURN_TRUE; } @@ -2016,18 +2117,32 @@ 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, bool persistent, char *hash, int hash_len) { RETCODE rc; + SQLRETURN ret; + odbc_link *link; - *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)); + 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, true); + link->persistent = persistent; + 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); + 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((*conn)->hdbc, SQL_TRANSLATE_OPTION, + SQLSetConnectOption((link->connection->hdbc, SQL_TRANSLATE_OPTION, SQL_SOLID_XLATOPT_NOCNV); #endif #ifdef HAVE_OPENLINK @@ -2035,16 +2150,14 @@ 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"); + return false; } } /* Possible fix for bug #10250 @@ -2126,9 +2239,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,25 +2249,17 @@ 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"); + return false; } -/* (*conn)->open = 1;*/ - return TRUE; + return true; } /* }}} */ -/* 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) { @@ -2190,17 +2295,16 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) persistent = 0; } + char *hashed_details; + 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: 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_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)); efree(hashed_details); @@ -2212,20 +2316,24 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) RETURN_FALSE; } - if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 1)) { + 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; } - if (zend_register_persistent_resource(hashed_details, hashed_len, db_conn, le_pconn) == NULL) { - free(db_conn); + db_conn = Z_ODBC_CONNECTION_P(return_value); + + 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; } + + zend_hash_str_add_new(&ODBCG(connections), hashed_details, hashed_details_len, return_value); + 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 +2356,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_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 @@ -2260,7 +2368,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_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 @@ -2271,23 +2379,42 @@ void odbc_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) goto try_and_get_another_connection; } } + + 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, link_zval); + + ZEND_ASSERT(Z_ODBC_CONNECTION_P(return_value) == db_conn && "Persistent connection has changed"); + } } - 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)); - RETURN_FALSE; - } + } else { /* non-persistent */ + 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); + RETURN_FALSE; + } - if (!odbc_sqlconnect(&db_conn, db, uid, pwd, cur_opt, 0)) { - RETURN_FALSE; + 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_str_add_new(&ODBCG(connections), hashed_details, hashed_details_len, return_value); + } else { /* non-persistent, pre-existing */ + ZVAL_COPY(return_value, link_zval); } - db_conn->res = zend_register_resource(db_conn, le_conn); - RETVAL_RES(db_conn->res); - ODBCG(num_links)++; } + efree(hashed_details); } /* }}} */ @@ -2295,36 +2422,20 @@ 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(); - } - - if (Z_RES_P(pv_conn)->type == le_pconn) { - is_pconn = 1; - } - - 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(); + link = Z_ODBC_LINK_P(pv_conn); + odbc_connection *connection = Z_ODBC_CONNECTION_P(pv_conn); + CHECK_ODBC_CONNECTION(connection); - zend_list_close(Z_RES_P(pv_conn)); + odbc_link_free(link); - if(is_pconn){ - zend_hash_apply_with_argument(&EG(persistent_list), _close_pconn_with_res, (void *) Z_RES_P(pv_conn)); + if (link->persistent) { + zend_hash_apply_with_argument(&EG(persistent_list), _close_pconn_with_res, (void *) connection); } } /* }}} */ @@ -2336,13 +2447,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 +2467,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 +2514,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 +2532,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 +2567,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 +2616,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"); @@ -2541,19 +2646,17 @@ 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; 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(); - } + odbc_connection *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 +2699,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 +2747,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); @@ -2700,32 +2809,31 @@ 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; - 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(); - } + odbc_connection *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 +2850,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 +2864,8 @@ PHP_FUNCTION(odbc_tables) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -2765,32 +2874,31 @@ 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; - 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(); - } + odbc_connection *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 +2917,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 +2931,8 @@ PHP_FUNCTION(odbc_columns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -2833,32 +2942,31 @@ 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; - 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(); - } + odbc_connection *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 +2978,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 +2992,8 @@ PHP_FUNCTION(odbc_columnprivileges) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_DBMAKER || HAVE_SOLID*/ @@ -2895,12 +3004,11 @@ 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; - 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 +3025,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(); - } + odbc_connection *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; } @@ -2946,7 +3054,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; } @@ -2960,7 +3068,8 @@ PHP_FUNCTION(odbc_foreignkeys) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -2971,32 +3080,31 @@ 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; - 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(); } 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(); - } + odbc_connection *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 +3112,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 +3126,8 @@ PHP_FUNCTION(odbc_gettypeinfo) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3027,31 +3136,30 @@ 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; - 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(); - } + odbc_connection *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 +3170,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 +3184,8 @@ PHP_FUNCTION(odbc_primarykeys) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3086,32 +3195,31 @@ 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; - 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(); - } + odbc_connection *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 +3231,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 +3245,8 @@ PHP_FUNCTION(odbc_procedurecolumns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3148,31 +3257,30 @@ 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; - 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(); - } + odbc_connection *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 +3291,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 +3305,8 @@ PHP_FUNCTION(odbc_procedures) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ #endif /* HAVE_SOLID */ @@ -3208,13 +3317,12 @@ 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; 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 +3331,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(); - } + odbc_connection *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 +3359,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 +3373,8 @@ PHP_FUNCTION(odbc_specialcolumns) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3275,13 +3384,12 @@ 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; 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 +3397,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(); - } + odbc_connection *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 +3425,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 +3439,8 @@ PHP_FUNCTION(odbc_statistics) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + odbc_insert_new_result(conn, return_value); } /* }}} */ @@ -3341,31 +3450,30 @@ 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; - 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(); - } + odbc_connection *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 +3484,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 +3498,8 @@ PHP_FUNCTION(odbc_tableprivileges) } result->conn_ptr = conn; result->fetched = 0; - RETURN_RES(zend_register_resource(result, le_result)); + + 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 07ee99e2f0075..71daf2f2d5194 100644 --- a/ext/odbc/php_odbc_includes.h +++ b/ext/odbc/php_odbc_includes.h @@ -191,10 +191,16 @@ typedef struct odbc_connection { ODBC_SQL_CONN_T hdbc; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - zend_resource *res; - int persistent; + HashTable results; } 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 +226,10 @@ 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; + uint32_t index; + zend_object std; } odbc_result; ZEND_BEGIN_MODULE_GLOBALS(odbc) @@ -240,8 +248,13 @@ ZEND_BEGIN_MODULE_GLOBALS(odbc) zend_long default_cursortype; char laststate[6]; char lasterrormsg[SQL_MAX_MESSAGE_LENGTH]; - HashTable *resource_list; - HashTable *resource_plist; + /* 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/bug78470.phpt b/ext/odbc/tests/bug78470.phpt index ea601a1fdfcac..92bd5c067f7b0 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/bug78473.phpt b/ext/odbc/tests/bug78473.phpt index 3903187a36219..9313237efde2b 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) diff --git a/ext/odbc/tests/odbc_close_001.phpt b/ext/odbc/tests/odbc_close_001.phpt new file mode 100644 index 0000000000000..1c970b58959d9 --- /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 f5334ce7500a2..3dc24b5679d56 100644 --- a/ext/odbc/tests/odbc_close_all_001.phpt +++ b/ext/odbc/tests/odbc_close_all_001.phpt @@ -21,18 +21,41 @@ var_dump($result2); odbc_close_all(); -var_dump($conn1); -var_dump($conn2); -var_dump($result1); -var_dump($result2); +try { + odbc_columns($conn1, '', '', '', ''); +} catch (Error $e) { + echo $e->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-- -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) { +} +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_columnprivileges_001.phpt b/ext/odbc/tests/odbc_columnprivileges_001.phpt index 5aba25895551f..be8fa20699009 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..28808f64208cf 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_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 diff --git a/ext/odbc/tests/odbc_tables_001.phpt b/ext/odbc/tests/odbc_tables_001.phpt index 7d4d816c7de06..4708bcd801d6f 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)