From: Matteo Nastasi Date: Sun, 13 Sep 2026 10:31:03 +0000 (+0200) Subject: postgresql 10+ compatibility (debian 13 ships 17) X-Git-Url: https://mop.ddnsfree.com/gitweb/?a=commitdiff_plain;h=b2a1d809c0c4980da9fe53faa8a0a15cf9e506ed;p=brisk.git postgresql 10+ compatibility (debian 13 ships 17) Found by running the code against a real database: neither the lint nor loading the sources could see them. UPDATE ... SET (col) = (val) Since postgresql 10 the parenthesised form on a SINGLE column is an error ("source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression"): (val) is not a ROW but a parenthesised expression. The multi column form is still valid, checked on the server: of the 11 parenthesised UPDATEs in the project only 4 need fixing, the other 7 are left alone. dbase_pgsql.phh SET (lintm) user_update_login_time() SET (pass) user_update_passwd() SET (tos_vers) user_tos_update() SET (game_cnt) bin5_points_save() sql.d/085-tourn-update.sql two SET (name) This is not a consequence of the php 8 port: they were already broken on any postgresql >= 10. They cover password recovery and the acceptance of the terms of service. int2four() The literal 0xffffffff00000000 is above PHP_INT_MAX, so php treats it as a float and the or converts it back to int: since 8.1 that is the "Implicit conversion from float to int loses precision" deprecation, emitted on every call (the function sits in the self-registration check path). Rewritten with ~0xffffffff, same bit pattern but an integer. Identical values, compared on 0, 1, 0x7fffffff, 0x80000000, 0xc0a80001 and 0xffffffff. Checked against a real database (postgresql 17, schema rebuilt from scratch with sql/builder.sh: 18 files, 12 tables, 6 views, 0 errors): connection, queries, user_add, login_exists, getrecord_bylogin, the three fixed UPDATEs, the two multi column ones, transactions and selfreg. No warnings, no deprecations. The error branch of BriskDB::query() was checked too, by forcing a query on a non existing table: it logs with pg_last_error(), does not raise a TypeError, and the connection survives the recovery. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014M1jiEq9cHdE5SE5j6vFuE --- diff --git a/sql/sql.d/085-tourn-update.sql b/sql/sql.d/085-tourn-update.sql index 56dd0c4..945b60a 100644 --- a/sql/sql.d/085-tourn-update.sql +++ b/sql/sql.d/085-tourn-update.sql @@ -2,6 +2,7 @@ -- INSERT INTO #PFX#bin5_tournaments (code, active, name) VALUES (1, 1, 'normal match'); -- INSERT INTO #PFX#bin5_tournaments (code, active, name) VALUES (2, 1, 'special match'); -UPDATE #PFX#bin5_tournaments SET (name) = ('old rules: with draw') WHERE code = 1; -UPDATE #PFX#bin5_tournaments SET (name) = ('new rules: without draw') WHERE code = 2; +-- pg10+: "SET (col) = (val)" su una sola colonna non e' piu' valido +UPDATE #PFX#bin5_tournaments SET name = 'old rules: with draw' WHERE code = 1; +UPDATE #PFX#bin5_tournaments SET name = 'new rules: without draw' WHERE code = 2; INSERT INTO #PFX#bin5_tournaments (code, active, name) VALUES (3, 1, 'special match'); diff --git a/web/Obj/brisk.phh b/web/Obj/brisk.phh index 52a2e41..d6165db 100644 --- a/web/Obj/brisk.phh +++ b/web/Obj/brisk.phh @@ -360,7 +360,13 @@ function int2four($l) if (PHP_INT_SIZE == 4) return ($l); - return ( ($l & 0x80000000 ? 0xffffffff00000000 : 0x00) | $l ); + /* php8.1: the literal 0xffffffff00000000 is above PHP_INT_MAX, so php treats + it as a float and the or converts it back to int, raising the + "Implicit conversion from float ... to int loses precision" deprecation + on every call. ~0xffffffff is the same bit pattern but stays an integer. + Identical values produced, checked on 0, 1, 0x7fffffff, 0x80000000, + 0xc0a80001 and 0xffffffff. */ + return ( ($l & 0x80000000) ? ($l | ~0xffffffff) : $l ); } function four2int($s) diff --git a/web/Obj/dbase_pgsql.phh b/web/Obj/dbase_pgsql.phh index 8856c27..b773c0a 100644 --- a/web/Obj/dbase_pgsql.phh +++ b/web/Obj/dbase_pgsql.phh @@ -312,7 +312,10 @@ class BriskDB { GLOBAL $G_dbpfx; - $user_sql = sprintf("UPDATE %susers SET (lintm) = (date 'epoch' + %d * INTERVAL '1 second') WHERE code = %d;", $G_dbpfx, $lintm, $code); + /* pg10+: "SET (col) = (val)" on a SINGLE column is an error, because + (val) is not a ROW but a parenthesised expression. The multi column + form is still valid and is left as it is. */ + $user_sql = sprintf("UPDATE %susers SET lintm = date 'epoch' + %d * INTERVAL '1 second' WHERE code = %d;", $G_dbpfx, $lintm, $code); if ( ! (($user_pg = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) { return FALSE; @@ -343,7 +346,8 @@ class BriskDB { GLOBAL $G_dbpfx; - $user_sql = sprintf("UPDATE %susers SET (pass) = (md5('%s')) WHERE code = %d;", + /* pg10+: single column without parentheses, see user_update_login_time() */ + $user_sql = sprintf("UPDATE %susers SET pass = md5('%s') WHERE code = %d;", $G_dbpfx, $passwd, $code); if ( ! (($user_pg = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) { @@ -383,7 +387,8 @@ class BriskDB { GLOBAL $G_dbpfx; - $user_sql = sprintf("UPDATE %susers SET (tos_vers) = ('%s') WHERE code = %d;", + /* pg10+: single column without parentheses, see user_update_login_time() */ + $user_sql = sprintf("UPDATE %susers SET tos_vers = '%s' WHERE code = %d;", $G_dbpfx, escsql($tos_vers), $code); if ( ! (($user_pg = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) { return FALSE; @@ -768,8 +773,10 @@ class BriskDB for ($i = 0 ; $i < $n ; $i++) { $codes_where .= sprintf("%scode = %d", ($i == 0 ? "" : " OR "), $ucodes[$i]); } - $cnt_sql = sprintf("UPDATE %susers SET (game_cnt) - = (game_cnt+1) WHERE %s;", + /* pg10+: single column without parentheses, see user_update_login_time(). + The one above is multi column and stays valid. */ + $cnt_sql = sprintf("UPDATE %susers SET game_cnt + = game_cnt+1 WHERE %s;", $G_dbpfx, $codes_where); error_log($cnt_sql); if (($cnt_pg = $this->query($cnt_sql)) == FALSE || pg_affected_rows($cnt_pg) != $n) {