diff options
26 files changed, 798 insertions, 187 deletions
diff --git a/Zend/tests/grammar/semi_reserved_001.phpt b/Zend/tests/grammar/semi_reserved_001.phpt index 26b3638a47..48937de39e 100644 --- a/Zend/tests/grammar/semi_reserved_001.phpt +++ b/Zend/tests/grammar/semi_reserved_001.phpt @@ -80,7 +80,6 @@ class Obj function __FILE__(){ echo __METHOD__, PHP_EOL; } function __DIR__(){ echo __METHOD__, PHP_EOL; } function __NAMESPACE__(){ echo __METHOD__, PHP_EOL; } - function __halt_compiler(){ echo __METHOD__, PHP_EOL; } } $obj = new Obj; @@ -160,7 +159,6 @@ $obj->__LINE__(); $obj->__FILE__(); $obj->__DIR__(); $obj->__NAMESPACE__(); -$obj->__halt_compiler(); echo "\nDone\n"; @@ -240,6 +238,5 @@ Obj::__LINE__ Obj::__FILE__ Obj::__DIR__ Obj::__NAMESPACE__ -Obj::__halt_compiler Done diff --git a/Zend/tests/grammar/semi_reserved_002.phpt b/Zend/tests/grammar/semi_reserved_002.phpt index 483ac8ce80..a082f9ddbb 100644 --- a/Zend/tests/grammar/semi_reserved_002.phpt +++ b/Zend/tests/grammar/semi_reserved_002.phpt @@ -80,7 +80,6 @@ class Obj static function __FILE__(){ echo __METHOD__, PHP_EOL; } static function __DIR__(){ echo __METHOD__, PHP_EOL; } static function __NAMESPACE__(){ echo __METHOD__, PHP_EOL; } - static function __halt_compiler(){ echo __METHOD__, PHP_EOL; } } Obj::empty(); @@ -158,7 +157,6 @@ Obj::__LINE__(); Obj::__FILE__(); Obj::__DIR__(); Obj::__NAMESPACE__(); -Obj::__halt_compiler(); echo "\nDone\n"; @@ -238,6 +236,5 @@ Obj::__LINE__ Obj::__FILE__ Obj::__DIR__ Obj::__NAMESPACE__ -Obj::__halt_compiler Done diff --git a/Zend/tests/grammar/semi_reserved_005.phpt b/Zend/tests/grammar/semi_reserved_005.phpt index b2b8471bf0..45d20ad0d8 100644 --- a/Zend/tests/grammar/semi_reserved_005.phpt +++ b/Zend/tests/grammar/semi_reserved_005.phpt @@ -79,7 +79,6 @@ class Obj const __FILE__ = '__FILE__'; const __DIR__ = '__DIR__'; const __NAMESPACE__ = '__NAMESPACE__'; - const __HALT_COMPILER = '__halt_compiler'; } echo Obj::EMPTY, PHP_EOL; @@ -156,7 +155,6 @@ echo Obj::__LINE__, PHP_EOL; echo Obj::__FILE__, PHP_EOL; echo Obj::__DIR__, PHP_EOL; echo Obj::__NAMESPACE__, PHP_EOL; -echo Obj::__HALT_COMPILER, PHP_EOL; echo "\nDone\n"; @@ -235,6 +233,5 @@ __LINE__ __FILE__ __DIR__ __NAMESPACE__ -__halt_compiler Done diff --git a/Zend/tests/return_types/bug71978.phpt b/Zend/tests/return_types/bug71978.phpt new file mode 100644 index 0000000000..e3c8440212 --- /dev/null +++ b/Zend/tests/return_types/bug71978.phpt @@ -0,0 +1,21 @@ +--TEST-- +Bug #71978 (Existence of return type hint affects other compatibility rules) +--FILE-- +<?php +class A { + function foo(int $a) {} +} +class B extends A { + function foo(string $a) {} +} +class A1 { + function foo(int $a): int {} +} +class B1 extends A1 { + function foo(string $a): int {} +} +?> +--EXPECTF-- +Warning: Declaration of B::foo(string $a) should be compatible with A::foo(int $a) in %s on line %d + +Warning: Declaration of B1::foo(string $a): int should be compatible with A1::foo(int $a): int in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 55a9fdc909..9042b2f0a2 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -243,11 +243,6 @@ static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_inf return 0; } - if (proto_arg_info->type_hint && proto_arg_info->allow_null && !fe_arg_info->allow_null) { - /* incompatible nullability */ - return 0; - } - return 1; } /* }}} */ @@ -324,6 +319,11 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c return 0; } + if (proto_arg_info->type_hint && proto_arg_info->allow_null && !fe_arg_info->allow_null) { + /* incompatible nullability */ + return 0; + } + /* by-ref constraints on arguments are invariant */ if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) { return 0; @@ -570,17 +570,31 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function * } if (child->common.prototype && ( - child->common.prototype->common.fn_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_HAS_RETURN_TYPE) + child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT )) { - if (UNEXPECTED(!zend_do_perform_implementation_check(child, child->common.prototype))) { - zend_string *method_prototype = zend_get_function_declaration(child->common.prototype); - zend_string *child_prototype = zend_get_function_declaration(child); - zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", ZSTR_VAL(child_prototype), ZSTR_VAL(method_prototype)); - } - } else if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) { + parent = child->common.prototype; + } + if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) { + int error_level; + const char *error_verb; zend_string *method_prototype = zend_get_function_declaration(parent); zend_string *child_prototype = zend_get_function_declaration(child); - zend_error(E_WARNING, "Declaration of %s should be compatible with %s", ZSTR_VAL(child_prototype), ZSTR_VAL(method_prototype)); + + if (child->common.prototype && ( + child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT + )) { + error_level = E_COMPILE_ERROR; + error_verb = "must"; + } else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && + (!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || + !zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1))) { + error_level = E_COMPILE_ERROR; + error_verb = "must"; + } else { + error_level = E_WARNING; + error_verb = "should"; + } + zend_error(error_level, "Declaration of %s %s be compatible with %s", ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype)); zend_string_free(child_prototype); zend_string_free(method_prototype); } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 804ed37473..9f99453cd4 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -272,7 +272,7 @@ reserved_non_modifiers: | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO | T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT | T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS - | T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_HALT_COMPILER + | T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C ; semi_reserved: diff --git a/ext/opcache/README b/ext/opcache/README index c074440130..11c9c2748b 100644 --- a/ext/opcache/README +++ b/ext/opcache/README @@ -213,3 +213,6 @@ opcache.mmap_base processes have to map shared memory into the same address space. This directive allows to manually fix the "Unable to reattach to base address" errors. + +opcache.lockfile_path (default "/tmp") + Absolute path used to store shared lockfiles. diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index 99db6a2564..42a34aa72b 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -217,6 +217,7 @@ typedef struct _zend_accel_directives { zend_long max_file_size; zend_long interned_strings_buffer; char *restrict_api; + char *lockfile_path; #ifdef HAVE_OPCACHE_FILE_CACHE char *file_cache; zend_bool file_cache_only; diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 2fabc8cb3c..e8c274e516 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -298,6 +298,7 @@ ZEND_INI_BEGIN() STD_PHP_INI_BOOLEAN("opcache.enable_cli" , "0" , PHP_INI_SYSTEM, OnUpdateBool, accel_directives.enable_cli, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.error_log" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.error_log, zend_accel_globals, accel_globals) STD_PHP_INI_ENTRY("opcache.restrict_api" , "" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.restrict_api, zend_accel_globals, accel_globals) + STD_PHP_INI_ENTRY("opcache.lockfile_path" , "/tmp" , PHP_INI_SYSTEM, OnUpdateString, accel_directives.lockfile_path, zend_accel_globals, accel_globals) #ifdef ZEND_WIN32 STD_PHP_INI_ENTRY("opcache.mmap_base", NULL, PHP_INI_SYSTEM, OnUpdateString, accel_directives.mmap_base, zend_accel_globals, accel_globals) @@ -710,6 +711,7 @@ static ZEND_FUNCTION(opcache_get_configuration) add_assoc_bool(&directives, "opcache.fast_shutdown", ZCG(accel_directives).fast_shutdown); add_assoc_bool(&directives, "opcache.enable_file_override", ZCG(accel_directives).file_override_enabled); add_assoc_long(&directives, "opcache.optimization_level", ZCG(accel_directives).optimization_level); + add_assoc_string(&directives, "opcache.lockfile_path", STRING_NOT_NULL(ZCG(accel_directives).lockfile_path)); #ifdef HAVE_OPCACHE_FILE_CACHE add_assoc_string(&directives, "opcache.file_cache", ZCG(accel_directives).file_cache ? ZCG(accel_directives).file_cache : ""); diff --git a/ext/opcache/zend_shared_alloc.c b/ext/opcache/zend_shared_alloc.c index 663d905c8d..ff42c4cf0b 100644 --- a/ext/opcache/zend_shared_alloc.c +++ b/ext/opcache/zend_shared_alloc.c @@ -38,7 +38,6 @@ # include "sys/mman.h" #endif -#define TMP_DIR "/tmp" #define SEM_FILENAME_PREFIX ".ZendSem." #define S_H(s) g_shared_alloc_handler->s @@ -55,7 +54,7 @@ zend_smm_shared_globals *smm_shared_globals; static MUTEX_T zts_lock; #endif int lock_file; -static char lockfile_name[sizeof(TMP_DIR) + sizeof(SEM_FILENAME_PREFIX) + 8]; +static char lockfile_name[MAXPATHLEN]; #endif static const zend_shared_memory_handler_entry handler_table[] = { @@ -75,7 +74,7 @@ static const zend_shared_memory_handler_entry handler_table[] = { }; #ifndef ZEND_WIN32 -void zend_shared_alloc_create_lock(void) +void zend_shared_alloc_create_lock(char *lockfile_path) { int val; @@ -83,7 +82,7 @@ void zend_shared_alloc_create_lock(void) zts_lock = tsrm_mutex_alloc(); #endif - sprintf(lockfile_name, "%s/%sXXXXXX", TMP_DIR, SEM_FILENAME_PREFIX); + snprintf(lockfile_name, sizeof(lockfile_name), "%s/%sXXXXXX", lockfile_path, SEM_FILENAME_PREFIX); lock_file = mkstemp(lockfile_name); fchmod(lock_file, 0666); @@ -163,7 +162,11 @@ int zend_shared_alloc_startup(size_t requested_size) smm_shared_globals = &tmp_shared_globals; ZSMMG(shared_free) = requested_size; /* goes to tmp_shared_globals.shared_free */ +#ifndef ZEND_WIN32 + zend_shared_alloc_create_lock(ZCG(accel_directives).lockfile_path); +#else zend_shared_alloc_create_lock(); +#endif if (ZCG(accel_directives).memory_model && ZCG(accel_directives).memory_model[0]) { char *model = ZCG(accel_directives).memory_model; diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c index 9d9424a8b2..ad54ae57b3 100644 --- a/ext/pdo_dblib/dblib_driver.c +++ b/ext/pdo_dblib/dblib_driver.c @@ -101,6 +101,7 @@ static int dblib_handle_preparer(pdo_dbh_t *dbh, const char *sql, size_t sql_len stmt->driver_data = S; stmt->methods = &dblib_stmt_methods; stmt->supports_placeholders = PDO_PLACEHOLDER_NONE; + S->computed_column_name_count = 0; S->err.sqlstate = stmt->error_code; return 1; diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index 49b75ee2bb..a1055434d3 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -218,21 +218,31 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno) return FAILURE; } + if (colno == 0) { + S->computed_column_name_count = 0; + } + col = &stmt->columns[colno]; fname = (char*)dbcolname(H->link, colno+1); if (fname && *fname) { col->name = zend_string_init(fname, strlen(fname), 0); } else { - char buf[16]; - int len; - - len = snprintf(buf, sizeof(buf), "computed%d", colno); - col->name = zend_string_init(buf, len, 0); + if (S->computed_column_name_count > 0) { + char buf[16]; + int len; + + len = snprintf(buf, sizeof(buf), "computed%d", S->computed_column_name_count); + col->name = zend_string_init(buf, len, 0); + } else { + col->name = zend_string_init("computed", strlen("computed"), 0); + } + + S->computed_column_name_count++; } col->maxlen = dbcollen(H->link, colno+1); - col->param_type = PDO_PARAM_STR; + col->param_type = PDO_PARAM_ZVAL; return 1; } @@ -245,78 +255,161 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, pdo_dblib_db_handle *H = S->H; int coltype; - unsigned int tmp_len; - char *tmp_ptr = NULL; + char *data, *tmp_data; + unsigned int data_len, tmp_data_len; + zval *zv = NULL; coltype = dbcoltype(H->link, colno+1); - - *len = dbdatlen(H->link, colno+1); - *ptr = dbdata(H->link, colno+1); - - if (*len == 0 && *ptr == NULL) { - return 1; - } - - switch (coltype) { - case SQLVARBINARY: - case SQLBINARY: - case SQLIMAGE: - case SQLTEXT: - /* FIXME: Above types should be returned as a stream as they can be VERY large */ - case SQLCHAR: - case SQLVARCHAR: - tmp_ptr = emalloc(*len + 1); - memcpy(tmp_ptr, *ptr, *len); - tmp_ptr[*len] = '\0'; - *ptr = tmp_ptr; - break; - case SQLMONEY: - case SQLMONEY4: - case SQLMONEYN: { - DBFLT8 money_value; - dbconvert(NULL, coltype, *ptr, *len, SQLFLT8, (LPBYTE)&money_value, 8); - *len = spprintf(&tmp_ptr, 0, "%.4f", money_value); - *ptr = tmp_ptr; - break; - } - case SQLUNIQUE: { - *len = 37; - tmp_ptr = emalloc(*len + 1); - *len = dbconvert(NULL, SQLUNIQUE, *ptr, *len, SQLCHAR, tmp_ptr, *len); - php_strtoupper(tmp_ptr, *len); - tmp_ptr[36] = '\0'; - *ptr = tmp_ptr; - break; + data = dbdata(H->link, colno+1); + data_len = dbdatlen(H->link, colno+1); + + if (data_len != 0 || data != NULL) { + if (stmt->dbh->stringify) { + switch (coltype) { + case SQLFLT4: + case SQLFLT8: + case SQLINT4: + case SQLINT2: + case SQLINT1: + case SQLBIT: { + if (dbwillconvert(coltype, SQLCHAR)) { + tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */ + tmp_data = emalloc(tmp_data_len); + data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, tmp_data, -1); + + zv = emalloc(sizeof(zval)); + ZVAL_STRING(zv, tmp_data); + + efree(tmp_data); + } + break; + } + } } - case SQLDATETIM4: - case SQLDATETIME: { - DBDATETIME dt; - DBDATEREC di; - - dbconvert(H->link, coltype, (BYTE*) *ptr, -1, SQLDATETIME, (LPBYTE) &dt, -1); - dbdatecrack(H->link, &di, &dt); - *len = spprintf((char**) &tmp_ptr, 20, "%d-%02d-%02d %02d:%02d:%02d", + if (!zv) { + switch (coltype) { + case SQLCHAR: + case SQLVARCHAR: + case SQLTEXT: { +#if ilia_0 + while (data_len>0 && data[data_len-1] == ' ') { /* nuke trailing whitespace */ + data_len--; + } +#endif + } + case SQLVARBINARY: + case SQLBINARY: + case SQLIMAGE: { + zv = emalloc(sizeof(zval)); + ZVAL_STRINGL(zv, data, data_len); + + break; + } + case SQLDATETIME: + case SQLDATETIM4: { + int dl; + DBDATEREC di; + DBDATEREC dt; + + dbconvert(H->link, coltype, data, -1, SQLDATETIME, (LPBYTE) &dt, -1); + dbdatecrack(H->link, &di, (DBDATETIME *) &dt); + + dl = spprintf(&tmp_data, 20, "%d-%02d-%02d %02d:%02d:%02d", #if defined(PHP_DBLIB_IS_MSSQL) || defined(MSDBLIB) - di.year, di.month, di.day, di.hour, di.minute, di.second + di.year, di.month, di.day, di.hour, di.minute, di.second +#else + di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond +#endif + ); + + zv = emalloc(sizeof(zval)); + ZVAL_STRINGL(zv, tmp_data, dl); + + efree(tmp_data); + + break; + } + case SQLFLT4: { + zv = emalloc(sizeof(zval)); + ZVAL_DOUBLE(zv, (double) (*(DBFLT4 *) data)); + + break; + } + case SQLFLT8: { + zv = emalloc(sizeof(zval)); + ZVAL_DOUBLE(zv, (double) (*(DBFLT8 *) data)); + + break; + } + case SQLINT4: { + zv = emalloc(sizeof(zval)); + ZVAL_LONG(zv, (long) ((int) *(DBINT *) data)); + + break; + } + case SQLINT2: { + zv = emalloc(sizeof(zval)); + ZVAL_LONG(zv, (long) ((int) *(DBSMALLINT *) data)); + + break; + } + case SQLINT1: + case SQLBIT: { + zv = emalloc(sizeof(zval)); + ZVAL_LONG(zv, (long) ((int) *(DBTINYINT *) data)); + + break; + } + case SQLMONEY: + case SQLMONEY4: + case SQLMONEYN: { + DBFLT8 money_value; + dbconvert(NULL, coltype, data, 8, SQLFLT8, (LPBYTE)&money_value, -1); + + zv = emalloc(sizeof(zval)); + ZVAL_DOUBLE(zv, money_value); + + if (stmt->dbh->stringify) { + convert_to_string(zv); + } + + break; + } +#ifdef SQLUNIQUE + case SQLUNIQUE: { #else - di.dateyear, di.datemonth+1, di.datedmonth, di.datehour, di.dateminute, di.datesecond + case 36: { /* FreeTDS hack */ #endif - ); + zv = emalloc(sizeof(zval)); + ZVAL_STRINGL(zv, data, 16); /* uniqueidentifier is a 16-byte binary number */ - *ptr = (char*) tmp_ptr; - break; - } - default: - if (dbwillconvert(coltype, SQLCHAR)) { - tmp_len = 32 + (2 * (*len)); /* FIXME: We allocate more than we need here */ - tmp_ptr = emalloc(tmp_len); - *len = dbconvert(NULL, coltype, *ptr, *len, SQLCHAR, tmp_ptr, -1); - *ptr = tmp_ptr; - } else { - *len = 0; /* FIXME: Silently fails and returns null on conversion errors */ - *ptr = NULL; + break; + } + default: { + if (dbwillconvert(coltype, SQLCHAR)) { + tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */ + tmp_data = emalloc(tmp_data_len); + data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, tmp_data, -1); + + zv = emalloc(sizeof(zval)); + ZVAL_STRING(zv, tmp_data); + + efree(tmp_data); + } + + break; + } } + } + } + + if (zv != NULL) { + *ptr = (char*)zv; + *len = sizeof(zval); + } else { + *ptr = NULL; + *len = 0; } *caller_frees = 1; @@ -335,6 +428,7 @@ static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zva pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data; pdo_dblib_db_handle *H = S->H; DBTYPEINFO* dbtypeinfo; + int coltype; if(colno >= stmt->column_count || colno < 0) { return FAILURE; @@ -346,14 +440,28 @@ static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zva if(!dbtypeinfo) return FAILURE; + coltype = dbcoltype(H->link, colno+1); + add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) ); add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision ); add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale ); add_assoc_string(return_value, "column_source", dbcolsource(H->link, colno+1)); - add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(dbcoltype(H->link, colno+1))); - add_assoc_long(return_value, "native_type_id", dbcoltype(H->link, colno+1)); + add_assoc_string(return_value, "native_type", pdo_dblib_get_field_name(coltype)); + add_assoc_long(return_value, "native_type_id", coltype); add_assoc_long(return_value, "native_usertype_id", dbcolutype(H->link, colno+1)); + switch (coltype) { + case SQLBIT: + case SQLINT1: + case SQLINT2: + case SQLINT4: + add_assoc_long(return_value, "pdo_type", PDO_PARAM_INT); + break; + default: + add_assoc_long(return_value, "pdo_type", PDO_PARAM_STR); + break; + } + return 1; } diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h index 5b47922abe..01586881d5 100644 --- a/ext/pdo_dblib/php_pdo_dblib_int.h +++ b/ext/pdo_dblib/php_pdo_dblib_int.h @@ -118,6 +118,7 @@ typedef struct { typedef struct { pdo_dblib_db_handle *H; pdo_dblib_err err; + unsigned int computed_column_name_count; } pdo_dblib_stmt; typedef struct { diff --git a/ext/pdo_dblib/tests/bug_38955.phpt b/ext/pdo_dblib/tests/bug_38955.phpt index 1954ed460b..57adbf6c40 100644 --- a/ext/pdo_dblib/tests/bug_38955.phpt +++ b/ext/pdo_dblib/tests/bug_38955.phpt @@ -37,21 +37,21 @@ array(4) { [0]=> array(1) { ["val"]=> - string(1) "1" + int(1) } [1]=> array(1) { ["val"]=> - string(1) "2" + int(2) } [2]=> array(1) { ["val"]=> - string(1) "3" + int(3) } [3]=> array(1) { ["val"]=> - string(1) "4" + int(4) } } diff --git a/ext/pdo_dblib/tests/bug_45876.phpt b/ext/pdo_dblib/tests/bug_45876.phpt index 920905830a..5f1026e623 100644 --- a/ext/pdo_dblib/tests/bug_45876.phpt +++ b/ext/pdo_dblib/tests/bug_45876.phpt @@ -14,8 +14,8 @@ $stmt->execute(); var_dump($stmt->getColumnMeta(0)); $stmt = null; ?> ---EXPECT-- -array(8) { +--EXPECTF-- +array(10) { ["max_length"]=> int(255) ["precision"]=> @@ -26,10 +26,14 @@ array(8) { string(13) "TABLE_CATALOG" ["native_type"]=> string(4) "char" + ["native_type_id"]=> + int(%d) + ["native_usertype_id"]=> + int(%d) + ["pdo_type"]=> + int(2) ["name"]=> string(13) "TABLE_CATALOG" ["len"]=> int(255) - ["pdo_type"]=> - int(2) } diff --git a/ext/pdo_dblib/tests/bug_47588.phpt b/ext/pdo_dblib/tests/bug_47588.phpt index d8f424e872..262720f632 100644 --- a/ext/pdo_dblib/tests/bug_47588.phpt +++ b/ext/pdo_dblib/tests/bug_47588.phpt @@ -23,21 +23,21 @@ array(3) { [0]=> array(2) { ["My Field"]=> - string(1) "1" + int(1) ["Another Field"]=> string(11) "test_string" } [1]=> array(2) { ["My Field"]=> - string(1) "2" + int(2) ["Another Field"]=> string(11) "test_string" } [2]=> array(2) { ["My Field"]=> - string(1) "3" + int(3) ["Another Field"]=> string(11) "test_string" } diff --git a/ext/pdo_dblib/tests/bug_68957.phpt b/ext/pdo_dblib/tests/bug_68957.phpt index 3d6e2fd13d..47ff461bb3 100644 --- a/ext/pdo_dblib/tests/bug_68957.phpt +++ b/ext/pdo_dblib/tests/bug_68957.phpt @@ -21,7 +21,7 @@ Array ( [0] => Array ( - [computed0] => 1 + [computed] => 1 [0] => 1 ) diff --git a/ext/pdo_dblib/tests/bug_71667.phpt b/ext/pdo_dblib/tests/bug_71667.phpt new file mode 100644 index 0000000000..1c5005fd6a --- /dev/null +++ b/ext/pdo_dblib/tests/bug_71667.phpt @@ -0,0 +1,34 @@ +--TEST-- +PDO_DBLIB: Emulate how mssql extension names "computed" columns +--SKIPIF-- +<?php +if (!extension_loaded('pdo_dblib')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +?> +--FILE-- +<?php +require dirname(__FILE__) . '/config.inc'; + +$stmt = $db->prepare("SELECT 1, 2 AS named, 3"); +$stmt->execute(); +var_dump($stmt->fetchAll()); + +?> +--EXPECT-- +array(1) { + [0]=> + array(6) { + ["computed"]=> + string(1) "1" + [0]=> + string(1) "1" + ["named"]=> + string(1) "2" + [1]=> + string(1) "2" + ["computed1"]=> + string(1) "3" + [2]=> + string(1) "3" + } +} diff --git a/ext/pdo_dblib/tests/timeout.phpt b/ext/pdo_dblib/tests/timeout.phpt index d65046262e..f92a7da72f 100644 --- a/ext/pdo_dblib/tests/timeout.phpt +++ b/ext/pdo_dblib/tests/timeout.phpt @@ -3,6 +3,7 @@ PDO_DBLIB: Set query timeouts --SKIPIF-- <?php if (!extension_loaded('pdo_dblib')) die('skip not loaded'); +if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); require dirname(__FILE__) . '/config.inc'; ?> --FILE-- diff --git a/ext/pdo_dblib/tests/types.phpt b/ext/pdo_dblib/tests/types.phpt new file mode 100644 index 0000000000..dd849adcf8 --- /dev/null +++ b/ext/pdo_dblib/tests/types.phpt @@ -0,0 +1,66 @@ +--TEST-- +PDO_DBLIB: Column data types, with or without stringifying +--SKIPIF-- +<?php +if (!extension_loaded('pdo_dblib')) die('skip not loaded'); +require __DIR__ . '/config.inc'; +?> +--FILE-- +<?php +require __DIR__ . '/config.inc'; + +$sql = " + SELECT + 'foo' AS [char], + CAST('2030-01-01 23:59:59' AS DATETIME) AS [datetime], + CAST(0 AS BIT) AS [false], + 10.5 AS [float], + 1000 AS [int], + CAST(10.5 AS MONEY) AS [money], + CAST('1950-01-18 23:00:00' AS SMALLDATETIME) as [smalldatetime], + CAST(1 AS BIT) AS [true] +"; + +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +var_dump($row['char'] === 'foo'); +var_dump($row['datetime'] === '2030-01-01 23:59:59'); +var_dump($row['false'] === 0); +var_dump($row['float'] === 10.5); +var_dump($row['int'] === 1000); +var_dump($row['money'] === 10.5); +var_dump($row['smalldatetime'] === '1950-01-18 23:00:00'); +var_dump($row['true'] === 1); + +$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true); +$stmt = $db->query($sql); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +var_dump($row['char'] === 'foo'); +var_dump($row['datetime'] === '2030-01-01 23:59:59'); +var_dump($row['false'] === '0'); +var_dump($row['float'] === '10.5'); +var_dump($row['int'] === '1000'); +var_dump($row['money'] === '10.5'); +var_dump($row['smalldatetime'] === '1950-01-18 23:00:00'); +var_dump($row['true'] === '1'); + +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index 6a18d6dfb0..a6a69ac3d0 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -587,12 +587,40 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, zend_ulon return 1; } +static zend_always_inline char * pdo_pgsql_translate_oid_to_table(Oid oid, PGconn *conn) +{ + char *table_name = NULL; + PGresult *tmp_res; + char *querystr = NULL; + + spprintf(&querystr, 0, "SELECT RELNAME FROM PG_CLASS WHERE OID=%d", oid); + + if ((tmp_res = PQexec(conn, querystr)) == NULL || PQresultStatus(tmp_res) != PGRES_TUPLES_OK) { + if (tmp_res) { + PQclear(tmp_res); + } + efree(querystr); + return 0; + } + efree(querystr); + + if ((table_name = PQgetvalue(tmp_res, 0, 0)) == NULL) { + PQclear(tmp_res); + return 0; + } + + PQclear(tmp_res); + return table_name; +} + static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) { pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data; PGresult *res; char *q=NULL; ExecStatusType status; + Oid table_oid; + char *table_name=NULL; if (!S->result) { return FAILURE; @@ -605,46 +633,53 @@ static int pgsql_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *r array_init(return_value); add_assoc_long(return_value, "pgsql:oid", S->cols[colno].pgsql_type); - switch (S->cols[colno].pgsql_type) { - case BOOLOID: - add_assoc_string(return_value, "native_type", BOOLLABEL); - break; - case BYTEAOID: - add_assoc_string(return_value, "native_type", BYTEALABEL); - break; - case INT8OID: - add_assoc_string(return_value, "native_type", INT8LABEL); - break; - case INT2OID: - add_assoc_string(return_value, "native_type", INT2LABEL); - break; - case INT4OID: - add_assoc_string(return_value, "native_type", INT4LABEL); - break; - case TEXTOID: - add_assoc_string(return_value, "native_type", TEXTLABEL); - break; - case VARCHAROID: - add_assoc_string(return_value, "native_type", VARCHARLABEL); - break; - case DATEOID: - add_assoc_string(return_value, "native_type", DATELABEL); - break; - case TIMESTAMPOID: - add_assoc_string(return_value, "native_type", TIMESTAMPLABEL); - break; - default: - /* Fetch metadata from Postgres system catalogue */ - spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type); - res = PQexec(S->H->server, q); - efree(q); - status = PQresultStatus(res); - if (status == PGRES_TUPLES_OK && 1 == PQntuples(res)) { - add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0)); - } - PQclear(res); - } - return 1; + table_oid = PQftable(S->result, colno); + add_assoc_long(return_value, "pgsql:table_oid", table_oid); + table_name = pdo_pgsql_translate_oid_to_table(table_oid, S->H->server); + if (table_name) { + add_assoc_string(return_value, "table", table_name); + } + + switch (S->cols[colno].pgsql_type) { + case BOOLOID: + add_assoc_string(return_value, "native_type", BOOLLABEL); + break; + case BYTEAOID: + add_assoc_string(return_value, "native_type", BYTEALABEL); + break; + case INT8OID: + add_assoc_string(return_value, "native_type", INT8LABEL); + break; + case INT2OID: + add_assoc_string(return_value, "native_type", INT2LABEL); + break; + case INT4OID: + add_assoc_string(return_value, "native_type", INT4LABEL); + break; + case TEXTOID: + add_assoc_string(return_value, "native_type", TEXTLABEL); + break; + case VARCHAROID: + add_assoc_string(return_value, "native_type", VARCHARLABEL); + break; + case DATEOID: + add_assoc_string(return_value, "native_type", DATELABEL); + break; + case TIMESTAMPOID: + add_assoc_string(return_value, "native_type", TIMESTAMPLABEL); + break; + default: + /* Fetch metadata from Postgres system catalogue */ + spprintf(&q, 0, "SELECT TYPNAME FROM PG_TYPE WHERE OID=%u", S->cols[colno].pgsql_type); + res = PQexec(S->H->server, q); + efree(q); + status = PQresultStatus(res); + if (status == PGRES_TUPLES_OK && 1 == PQntuples(res)) { + add_assoc_string(return_value, "native_type", PQgetvalue(res, 0, 0)); + } + PQclear(res); + } + return 1; } static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt) diff --git a/ext/pdo_pgsql/tests/bug62498-32bit.phpt b/ext/pdo_pgsql/tests/bug62498-32bit.phpt new file mode 100644 index 0000000000..edcf52048c --- /dev/null +++ b/ext/pdo_pgsql/tests/bug62498-32bit.phpt @@ -0,0 +1,221 @@ +--TEST-- +PDO PgSQL Bug #62498 (pdo_pgsql inefficient when getColumnMeta() is used), 32-bit +--SKIPIF-- +<?php +if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +PDOTest::skip(); +if (PHP_INT_SIZE > 4) die("skip relevant for 32-bit only"); +?> +--FILE-- +<?php +echo "Begin test...\n"; + +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); +$db->setAttribute (\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + +// create the table +$db->exec("CREATE TEMPORARY TABLE bugtest_62498 (int2col INT2, int4col INT4, int8col INT8, stringcol VARCHAR(255), boolcol BOOLEAN, datecol DATE, textcol TEXT, tscol TIMESTAMP, byteacol BYTEA)"); + +// insert some data +$statement = $db->prepare("INSERT INTO bugtest_62498 (int2col, int4col, int8col, stringcol, boolcol, datecol, textcol, tscol, byteacol) VALUES (:int2val, :int4val, :int8val, :stringval, :boolval, :dateval, :textval, :tsval, :byteaval)"); +$vals = array( + "int2val" => "42", + "int4val" => "42", + "int8val" => "42", + "stringval" => "The Answer", + "boolval" => true, + "dateval" => '2015-12-14', + "textval" => "some text", + "tsval" => 19990108, + "byteaval" => 0, +); +$statement->execute($vals); + +$select = $db->query('SELECT int2col, int4col, int8col, stringcol, boolcol, datecol, textcol, tscol, byteacol FROM bugtest_62498'); +$meta = []; +for ($i=0; $i < count($vals); $i++) { + $meta[] = $select->getColumnMeta($i); +} +var_dump($meta); + +?> +Done +--EXPECTF-- +Begin test... +array(9) { + [0]=> + array(8) { + ["pgsql:oid"]=> + int(21) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(4) "int2" + ["name"]=> + string(7) "int2col" + ["len"]=> + int(2) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(1) + } + [1]=> + array(8) { + ["pgsql:oid"]=> + int(23) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(4) "int4" + ["name"]=> + string(7) "int4col" + ["len"]=> + int(4) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(1) + } + [2]=> + array(8) { + ["pgsql:oid"]=> + int(20) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(4) "int8" + ["name"]=> + string(7) "int8col" + ["len"]=> + int(8) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(2) + } + [3]=> + array(8) { + ["pgsql:oid"]=> + int(1043) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(7) "varchar" + ["name"]=> + string(9) "stringcol" + ["len"]=> + int(-1) + ["precision"]=> + int(259) + ["pdo_type"]=> + int(2) + } + [4]=> + array(8) { + ["pgsql:oid"]=> + int(16) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(4) "bool" + ["name"]=> + string(7) "boolcol" + ["len"]=> + int(1) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(5) + } + [5]=> + array(8) { + ["pgsql:oid"]=> + int(1082) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(4) "date" + ["name"]=> + string(7) "datecol" + ["len"]=> + int(4) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(2) + } + [6]=> + array(8) { + ["pgsql:oid"]=> + int(25) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(4) "text" + ["name"]=> + string(7) "textcol" + ["len"]=> + int(-1) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(2) + } + [7]=> + array(8) { + ["pgsql:oid"]=> + int(1114) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(9) "timestamp" + ["name"]=> + string(5) "tscol" + ["len"]=> + int(8) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(2) + } + [8]=> + array(8) { + ["pgsql:oid"]=> + int(17) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" + ["native_type"]=> + string(5) "bytea" + ["name"]=> + string(8) "byteacol" + ["len"]=> + int(-1) + ["precision"]=> + int(-1) + ["pdo_type"]=> + int(3) + } +} +Done diff --git a/ext/pdo_pgsql/tests/bug62498.phpt b/ext/pdo_pgsql/tests/bug62498.phpt index e4ca3dec4f..53d42fc3fa 100644 --- a/ext/pdo_pgsql/tests/bug62498.phpt +++ b/ext/pdo_pgsql/tests/bug62498.phpt @@ -1,11 +1,12 @@ --TEST-- -PDO PgSQL Bug #62498 (pdo_pgsql inefficient when getColumnMeta() is used) +PDO PgSQL Bug #62498 (pdo_pgsql inefficient when getColumnMeta() is used), 64-bit --SKIPIF-- <?php if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded'); require dirname(__FILE__) . '/config.inc'; require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; PDOTest::skip(); +if (PHP_INT_SIZE < 8) die("skip valid for 64-bit only"); ?> --FILE-- <?php @@ -42,13 +43,17 @@ var_dump($meta); ?> Done ---EXPECT-- +--EXPECTF-- Begin test... array(9) { [0]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(21) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(4) "int2" ["name"]=> @@ -61,9 +66,13 @@ array(9) { int(1) } [1]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(23) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(4) "int4" ["name"]=> @@ -76,9 +85,13 @@ array(9) { int(1) } [2]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(20) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(4) "int8" ["name"]=> @@ -91,9 +104,13 @@ array(9) { int(1) } [3]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(1043) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(7) "varchar" ["name"]=> @@ -106,9 +123,13 @@ array(9) { int(2) } [4]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(16) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(4) "bool" ["name"]=> @@ -121,9 +142,13 @@ array(9) { int(5) } [5]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(1082) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(4) "date" ["name"]=> @@ -136,9 +161,13 @@ array(9) { int(2) } [6]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(25) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(4) "text" ["name"]=> @@ -151,9 +180,13 @@ array(9) { int(2) } [7]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(1114) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(9) "timestamp" ["name"]=> @@ -166,9 +199,13 @@ array(9) { int(2) } [8]=> - array(6) { + array(8) { ["pgsql:oid"]=> int(17) + ["pgsql:table_oid"]=> + int(%d) + ["table"]=> + string(13) "bugtest_62498" ["native_type"]=> string(5) "bytea" ["name"]=> diff --git a/ext/session/session.c b/ext/session/session.c index 238ae877f8..e745b96867 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -1483,7 +1483,7 @@ static void ppid2sid(zval *ppid) { PHPAPI void php_session_reset_id(void) /* {{{ */ { int module_number = PS(module_number); - zval *sid; + zval *sid, *data, *ppid; if (!PS(id)) { php_error_docref(NULL, E_WARNING, "Cannot set session ID - session ID is not initialized"); @@ -1523,13 +1523,20 @@ PHPAPI void php_session_reset_id(void) /* {{{ */ } } - if (APPLY_TRANS_SID) { - /* FIXME: Resetting vars are required when - session is stop/start/regenerated. However, - php_url_scanner_reset_vars() resets all vars - including other URL rewrites set by elsewhere. */ - /* php_url_scanner_reset_vars(); */ - php_url_scanner_add_var(PS(session_name), strlen(PS(session_name)), ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)), 1); + /* Apply trans sid if sid cookie is not set */ + if (APPLY_TRANS_SID + && (data = zend_hash_str_find(&EG(symbol_table), "_COOKIE", sizeof("_COOKIE") - 1))) { + ZVAL_DEREF(data); + if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_str_find(Z_ARRVAL_P(data), PS(session_name), strlen(PS(session_name))))) { + ZVAL_DEREF(ppid); + } else { + /* FIXME: Resetting vars are required when + session is stop/start/regenerated. However, + php_url_scanner_reset_vars() resets all vars + including other URL rewrites set by elsewhere. */ + /* php_url_scanner_reset_vars(); */ + php_url_scanner_add_var(PS(session_name), strlen(PS(session_name)), ZSTR_VAL(PS(id)), ZSTR_LEN(PS(id)), 1); + } } } /* }}} */ diff --git a/ext/session/tests/bug71974.phpt b/ext/session/tests/bug71974.phpt new file mode 100644 index 0000000000..b692bce2c5 --- /dev/null +++ b/ext/session/tests/bug71974.phpt @@ -0,0 +1,23 @@ +--TEST-- +Bug #71974 Trans sid will always be send, even if cookies are available +--SKIPIF-- +<?php include('skipif.inc'); ?> +--INI-- +session.save_handler=files +session.auto_start=0 +session.use_cookies=1 +session.use_only_cookies=0 +session.use_trans_sid=1 +session.use_strict_mode=0 +--COOKIE-- +PHPSESSID=1234567890123456789012345678901234567890 +--FILE-- +<?php +ob_start(); +session_start() +?> +<a href="some.php">abc</a> +--EXPECTF-- +<a href="some.php">abc</a> + + diff --git a/ext/standard/array.c b/ext/standard/array.c index 289870ac1f..a0cdd91d85 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2000,34 +2000,72 @@ PHP_FUNCTION(array_fill) zval *val; zend_long start_key, num; +#ifndef FAST_ZPP if (zend_parse_parameters(ZEND_NUM_ARGS(), "llz", &start_key, &num, &val) == FAILURE) { return; } +#else + ZEND_PARSE_PARAMETERS_START(3, 3) + Z_PARAM_LONG(start_key) + Z_PARAM_LONG(num) + Z_PARAM_ZVAL(val) + ZEND_PARSE_PARAMETERS_END(); +#endif - if (num < 0) { - php_error_docref(NULL, E_WARNING, "Number of elements can't be negative"); - RETURN_FALSE; - } + if (EXPECTED(num > 0)) { + if (sizeof(num) > 4 && UNEXPECTED(EXPECTED(num > 0x7fffffff))) { + php_error_docref(NULL, E_WARNING, "Too many elements"); + RETURN_FALSE; + } else if (UNEXPECTED(start_key > ZEND_LONG_MAX - num + 1)) { + php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied"); + RETURN_FALSE; + } else if (EXPECTED(start_key >= 0) && EXPECTED(start_key < num)) { + /* create packed array */ + Bucket *p; + zend_long n; - /* allocate an array for return */ - array_init_size(return_value, (uint32_t)num); + array_init_size(return_value, (uint32_t)(start_key + num)); + zend_hash_real_init(Z_ARRVAL_P(return_value), 1); + Z_ARRVAL_P(return_value)->nNumUsed = start_key + num; + Z_ARRVAL_P(return_value)->nNumOfElements = num; + Z_ARRVAL_P(return_value)->nInternalPointer = start_key; - if (num == 0) { - return; - } + if (Z_REFCOUNTED_P(val)) { + GC_REFCOUNT(Z_COUNTED_P(val)) += num; + } - num--; - zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, val); - Z_TRY_ADDREF_P(val); + p = Z_ARRVAL_P(return_value)->arData; + n = start_key; - while (num--) { - if (zend_hash_next_index_insert(Z_ARRVAL_P(return_value), val) != NULL) { - Z_TRY_ADDREF_P(val); + while (start_key--) { + ZVAL_UNDEF(&p->val); + p++; + } + while (num--) { + ZVAL_COPY_VALUE(&p->val, val); + p->h = n++; + p->key = NULL; + p++; + } } else { - zval_dtor(return_value); - php_error_docref(NULL, E_WARNING, "Cannot add element to the array as the next element is already occupied"); - RETURN_FALSE; + /* create hash */ + array_init_size(return_value, (uint32_t)num); + zend_hash_real_init(Z_ARRVAL_P(return_value), 0); + if (Z_REFCOUNTED_P(val)) { + GC_REFCOUNT(Z_COUNTED_P(val)) += num; + } + zend_hash_index_add_new(Z_ARRVAL_P(return_value), start_key, val); + while (--num) { + zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), val); + start_key++; + } } + } else if (EXPECTED(num == 0)) { + array_init(return_value); + return; + } else { + php_error_docref(NULL, E_WARNING, "Number of elements can't be negative"); + RETURN_FALSE; } } /* }}} */ |