/** Run commands to alter indexes
* @param string escaped table name
- * @param array{string, string, 'DROP'|list<string>} of ["index type", "name", ["column definition", ...]] or ["index type", "name", "DROP"]
+ * @param list<array{string, string, 'DROP'|list<string>}> of ["index type", "name", ["column definition", ...]] or ["index type", "name", "DROP"]
* @return Result|bool
*/
function alter_indexes($table, $alter) {
- foreach ($alter as $key => $val) {
- $alter[$key] = ($val[2] == "DROP"
+ $changes = array();
+ foreach ($alter as $val) {
+ $changes[] = ($val[2] == "DROP"
? "\nDROP INDEX " . idf_escape($val[1])
: "\nADD $val[0] " . ($val[0] == "PRIMARY" ? "KEY " : "") . ($val[1] != "" ? idf_escape($val[1]) . " " : "") . "(" . implode(", ", $val[2]) . ")"
);
}
- return queries("ALTER TABLE " . table($table) . implode(",", $alter));
+ return queries("ALTER TABLE " . table($table) . implode(",", $changes));
}
/** Run commands to truncate tables
/** Get information about stored routine
* @param string
- * @param string "FUNCTION" or "PROCEDURE"
+ * @param 'FUNCTION'|'PROCEDURE'
* @return Routine
*/
function routine($name, $type) {
foreach ($fields as $field) {
$part = idf_escape($field['field']) . ' ' . $field['full_type']
. default_value($field)
- . ($field['attnotnull'] ? " NOT NULL" : "");
+ . ($field['null'] ? "" : " NOT NULL");
$return_parts[] = $part;
// sequences for fields
}
queries("BEGIN");
}
- foreach ($fields as $key => $field) {
+ $changes = array();
+ foreach ($fields as $field) {
if (preg_match('~GENERATED~', $field[3])) {
unset($originals[array_search($field[0], $originals)]);
}
- $fields[$key] = " " . implode($field);
+ $changes[] = " " . implode($field);
}
- $fields = array_merge($fields, array_filter($foreign));
+ $changes = array_merge($changes, array_filter($foreign));
foreach ($driver->checkConstraints($table) as $check) {
if ($check != $drop_check) {
- $fields[] = " CHECK ($check)";
+ $changes[] = " CHECK ($check)";
}
}
if ($add_check) {
- $fields[] = " CHECK ($add_check)";
+ $changes[] = " CHECK ($add_check)";
}
$temp_name = ($table == $name ? "adminer_$name" : $name);
- if (!queries("CREATE TABLE " . table($temp_name) . " (\n" . implode(",\n", $fields) . "\n)")) {
+ if (!queries("CREATE TABLE " . table($temp_name) . " (\n" . implode(",\n", $changes) . "\n)")) {
// implicit ROLLBACK to not overwrite $connection->error
return false;
}
}
$HTTPS = ($_SERVER["HTTPS"] && strcasecmp($_SERVER["HTTPS"], "off")) || ini_bool("session.cookie_secure"); // session.cookie_secure could be set on HTTP if we are behind a reverse proxy
-@ini_set("session.use_trans_sid", false); // protect links in export, @ - may be disabled
+@ini_set("session.use_trans_sid", '0'); // protect links in export, @ - may be disabled
if (!defined("SID")) {
session_cache_limiter(""); // to allow restarting session
session_name("adminer_sid"); // use specific session name to get own namespace
set_magic_quotes_runtime(false);
}
@set_time_limit(0); // @ - can be disabled
-@ini_set("precision", 15); // @ - can be disabled, 15 - internal PHP precision
+@ini_set("precision", '15'); // @ - can be disabled, 15 - internal PHP precision
include "../adminer/include/lang.inc.php";
include "../adminer/lang/$LANG.inc.php";
/** Get referencable tables with single column primary key except self
* @param string
-* @return Field[] [$table_name => $field]
+* @return array<string, Field> [$table_name => $field]
*/
function referencable_primary($self) {
$return = array(); // table_name => field
* @param string
* @param Field
* @param list<string>
-* @param Field[] returned by referencable_primary()
+* @param string[]
* @param list<string> extra types to prepend
* @return void
*/
}
/** Create SQL string from field type
-* @param Field
+* @param FieldType
* @param string
* @return string
*/
}
/** Print table interior for fields editing
-* @param Field[]
+* @param (Field|RoutineField)[]
* @param list<string>
-* @param string TABLE or PROCEDURE
-* @param Field[] returned by referencable_primary()
+* @param 'TABLE'|'PROCEDURE'
+* @param string[]
* @return void
*/
function edit_fields($fields, $collations, $type = "TABLE", $foreign_keys = array()) {
}
/** Generate SQL query for creating routine
-* @param string "PROCEDURE" or "FUNCTION"
+* @param 'PROCEDURE'|'FUNCTION'
* @param Routine result of routine()
* @return string
*/
}
/** Get select clause for convertible fields
-* @param string[]
+* @param mixed[] only keys are used
* @param Field[]
* @param list<string>
* @return string
$use_cookies = ini_bool("session.use_cookies");
if (!$use_cookies || $force) {
session_write_close(); // improves concurrency if a user opens several pages at once, may be restarted later
- if ($use_cookies && @ini_set("session.use_cookies", false) === false) { // @ - may be disabled
+ if ($use_cookies && @ini_set("session.use_cookies", '0') === false) { // @ - may be disabled
session_start();
}
}
$timeout = $adminer->queryTimeout();
$slow_query = $driver->slowQuery($query, $timeout);
$connection2 = null;
- if (!$slow_query && support("kill") && is_object($connection2 = connect($adminer->credentials())) && ($db == "" || $connection2->select_db($db))) {
- $kill = $connection2->result(connection_id()); // MySQL and MySQLi can use thread_id but it's not in PDO_MySQL
- echo script("const timeout = setTimeout(() => { ajax('" . js_escape(ME) . "script=kill', function () {}, 'kill=$kill&token=$token'); }, 1000 * $timeout);");
+ if (!$slow_query && support("kill")) {
+ $connection2 = connect($adminer->credentials());
+ if (is_object($connection2) && ($db == "" || $connection2->select_db($db))) {
+ $kill = $connection2->result(connection_id()); // MySQL and MySQLi can use thread_id but it's not in PDO_MySQL
+ echo script("const timeout = setTimeout(() => { ajax('" . js_escape(ME) . "script=kill', function () {}, 'kill=$kill&token=$token'); }, 1000 * $timeout);");
+ }
}
ob_flush();
flush();
}
/** Print edit input field
-* @param Field one field from fields()
+* @param Field|RoutineField one field from fields()
* @param mixed
* @param string
* @param bool
}
/** Process edit input field
-* @param Field one field from fields()
+* @param Field|RoutineField one field from fields()
* @return mixed false to leave the original value
*/
function process_input($field) {
}
function next_result() {
- if (!is_object($this->multi)) {
+ /** @var PdoResult|bool */
+ $result = $this->multi;
+ if (!is_object($result)) {
return false;
}
- $this->multi->_offset = 0;
- return @$this->multi->nextRowset(); // @ - PDO_PgSQL doesn't support it
+ $result->_offset = 0;
+ return @$result->nextRowset(); // @ - PDO_PgSQL doesn't support it
}
}
: $driver->update($TABLE, $set, $where_check)
)
);
- $affected = $connection->affected_rows + (is_object($result) ? $result->num_rows : 0); // PostgreSQL with RETURNING fills num_rows
+ $affected = $connection->affected_rows;
+ if (is_object($result)) { // PostgreSQL with RETURNING fills num_rows
+ $affected += $result->num_rows;
+ }
} else {
foreach ((array) $_POST["check"] as $val) {
// where is not unique so OR can't be used
if (is_string($query)) { // get_file() returns error as number, fread() as false
if (function_exists('memory_get_usage') && ($memory_limit = ini_bytes("memory_limit")) != "-1") {
- @ini_set("memory_limit", max($memory_limit, 2 * strlen($query) + memory_get_usage() + 8e6)); // @ - may be disabled, 2 - substr and trim, 8e6 - other variables
+ @ini_set("memory_limit", max($memory_limit, strval(2 * strlen($query) + memory_get_usage() + 8e6))); // @ - may be disabled, 2 - substr and trim, 8e6 - other variables
}
if ($query != "" && strlen($query) < 1e6) { // don't add big queries
stop_session();
}
if (!$_POST["only_errors"]) {
- echo "<p class='message' title='" . h(isset($connection->info) ? $connection->info : "") . "'>" . lang('Query executed OK, %d row(s) affected.', $affected) . "$time\n";
+ echo "<p class='message' title='" . h($connection->info) . "'>" . lang('Query executed OK, %d row(s) affected.', $affected) . "$time\n";
}
}
echo ($warnings ? "<div id='$warnings_id' class='hidden'>\n$warnings</div>\n" : "");
# need to fix
- "~^Function Adminer\\\\fields_from_edit\\(\\) should return~" # Mongo and SimpleDB
- "~Adminer\\\\Result.*mysqli_result~" # mysqli_result
- - "~expects array~" # different shape of array
# not real problems
- - identifier: include.fileNotFound # relative includes
+ - identifier: include.fileNotFound # includes in include/ relative from index.php
- identifier: includeOnce.fileNotFound # ./adminer-plugins.php
- "~^Function (set_magic_quotes_runtime|mysql_)~" # PHP < 7 functions
- "~an unknown class OCI-?Lob~" # this looks like PHPStan bug
- "~^Variable \\$(adminer|connection|driver|drivers|error|HTTPS|LANG|langs|permanent|has_token|token|translations|VERSION) might not be defined~" # declared in bootstrap.inc.php
- "~^Method Adminer\\\\Plugins::\\w+\\(\\) with return type void~" # we use the same pattern for all methods
- - "~Call to function is_object\\(\\) with Adminer\\\\Db\\|string will always evaluate to false~" # is_object(Db) is true
- - "~^Comparison operation \"==\" between \\(array\\|float\\|int\\) and 1~" # it thinks that $affected could be an array
- - "~^Parameter #2 \\$newvalue of function ini_set expects string~" # it expects string|int|float|bool|null since PHP 8.1
- "~expects int, float given~" # this will work
- "~expects bool~" # truthy values
- "~fread expects int<1, max>, 100000~" # 1e6
paths:
- adminer/include/pdo.inc.php
- adminer/drivers/*
+
+ -
+ message: "~ to an undefined ~" # PostgreSQL has this in its version of Db
+ path: adminer/drivers/pgsql.inc.php
# it probably doesn't like $ar[$key] instead of isset($ar[$key]) and thinks that $ar[$key] is always set
- identifier: identical.alwaysFalse
typeAliases:
TableStatus: "array{Name:string, Engine?:?string, Comment?:string, Oid?:numeric-string, Rows?:?numeric-string, Collation?:string, Auto_increment?:?numeric-string, Data_length?:numeric-string, Index_length?:numeric-string, Data_free?:numeric-string, Create_options?:string, nspname?:string}"
- Field: "array{field:?string, full_type:string, type:string, length:numeric-string, unsigned:string, default:?string, null:bool, auto_increment:bool, collation:string, privileges:int[], comment:string, primary:bool, generated:string, orig?:string, on_update:?string, on_delete?:string, inout?:string}"
+ Field: "array{field?:string, full_type:string, type:string, length:numeric-string, unsigned:string, default?:string, null:bool, auto_increment:bool, collation:string, privileges:int[], comment:string, primary:bool, generated:string, orig?:string, on_update?:string, on_delete?:string, default_constraint?: string}"
+ FieldType: "array{type:string, length:numeric-string, unsigned:string, collation:string}" # subset of RoutineField and Field
+ RoutineField: "array{field:string, type:string, length:numeric-string, unsigned:string, null:bool, full_type:string, collation:string, inout?:string}"
Index: "array{type:string, columns:list<string>, lengths:list<numeric-string>, descs:list<?bool>}"
- ForeignKey: "array{db:string, ns?:string, table:string, source:list<string>, target:list<string>, on_delete:string, on_update:string}"
+ ForeignKey: "array{db?:string, ns?:string, table:string, source:list<string>, target:list<?string>, on_delete:string, on_update?:string, definition?:string, deferrable?:string}"
Trigger: "array{Trigger?:string, Timing?:string, Event?:string, Of?:string, Type?:string, Statement?:string}"
- RoutineField: "array{field:string, type:string, length:?string, unsigned:string, null:bool, full_type:string, inout:string, collation:string}"
- Routine: "array{name?:string, fields:list<RoutineField>, comment:string, returns?:array{type:string, length:string, unsigned:string, collation:string}, definition:string, language?:string}"
+ Routine: "array{name?:string, fields:list<RoutineField>, comment:string, returns?:FieldType, definition:string, language?:string}"
BackwardKey: "array{name:string, keys:string[][]}"