]> mop.ddnsfree.com - git repositories - brisk.git/commitdiff
postgresql 10+ compatibility (debian 13 ships 17)
authorMatteo Nastasi <nastasi@alternativeoutput.it>
Sun, 13 Sep 2026 10:31:03 +0000 (12:31 +0200)
committerMatteo Nastasi <nastasi@alternativeoutput.it>
Sun, 13 Sep 2026 10:31:03 +0000 (12:31 +0200)
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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014M1jiEq9cHdE5SE5j6vFuE

sql/sql.d/085-tourn-update.sql
web/Obj/brisk.phh
web/Obj/dbase_pgsql.phh

index 56dd0c4f396afcac8f2a135955eba86a5ff259a4..945b60a5de50af41f4d949561414c558d7e5c883 100644 (file)
@@ -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');
index 52a2e41fdbf74a5f8126a66e739b8c7c5f863b42..d6165db1c065b33417e1275871473d19f869a3b6 100644 (file)
@@ -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)
index 8856c2754b29c3b2c854b12dfac0fd1bf530b2b6..b773c0aa1f9e887359577243bcf123db9559d6dc 100644 (file)
@@ -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) {