diff --git a/batch/updatecontactdb.php b/batch/updatecontactdb.php index 640666a68..c78921172 100644 --- a/batch/updatecontactdb.php +++ b/batch/updatecontactdb.php @@ -85,7 +85,7 @@ // perform role updates if (!empty($qv)) { - Dbl::ql($cdb, "insert into Roles (contactDbId,confid,roles,activity_at) values ?v on duplicate key update roles=values(roles), activity_at=values(activity_at)", $qv); + Dbl::ql($cdb, "insert into Roles (contactDbId,confid,roles,activity_at) values ?v ?U on duplicate key update roles=?U(roles), activity_at=?U(activity_at)", $qv); } // remove old roles @@ -105,7 +105,7 @@ Dbl::free($result); if (!empty($qv)) { - Dbl::ql($cdb, "insert into ConferencePapers (confid,paperId,title) values ?v on duplicate key update title=values(title)", $qv); + Dbl::ql($cdb, "insert into ConferencePapers (confid,paperId,title) values ?v ?U on duplicate key update title=?U(title)", $qv); } Dbl::ql($cdb, "delete from ConferencePapers where confid=? and paperId?A", $confid, $pids); if ($confrow->last_submission_at != $max_submitted) { diff --git a/lib/dbl.php b/lib/dbl.php index ef3b39d62..922630c9f 100644 --- a/lib/dbl.php +++ b/lib/dbl.php @@ -268,16 +268,45 @@ static private function format_query_args($dblink, $qstr, $argv) { $strpos = $argpos = 0; $usedargs = []; $simpleargs = true; + $U_mysql8 = null; while (($strpos = strpos($qstr, "?", $strpos)) !== false) { - // argument name + $prefix = substr($qstr, 0, $strpos); $nextpos = $strpos + 1; $nextch = substr($qstr, $nextpos, 1); + + // non-argument expansions if ($nextch === "?") { - $qstr = substr($qstr, 0, $strpos + 1) . substr($qstr, $strpos + 2); - $strpos = $strpos + 1; + $qstr = $prefix . substr($qstr, $nextpos); + $strpos = $nextpos; continue; - } else if ($nextch === "{" - && ($rbracepos = strpos($qstr, "}", $nextpos + 1)) !== false) { + } else if ($nextch === "U") { + $U_mysql8 = $U_mysql8 ?? (strpos($dblink->server_info, "Maria") === false + && $dblink->server_version >= 80020); + $ql = substr($qstr, 0, $strpos); + if (substr($qstr, $nextpos + 1, 1) === "(") { + $rparen = strpos($qstr, ")", $nextpos + 2); + $name = substr($qstr, $nextpos + 2, $rparen - $nextpos - 2); + $suffix = substr($qstr, $rparen + 1); + if ($U_mysql8) { + $qstr = "{$prefix}__values.{$name}{$suffix}"; + } else { + $qstr = "{$prefix}values({$name}){$suffix}"; + } + } else { + $suffix = substr($qstr, $nextpos + 1); + if ($U_mysql8) { + $qstr = "{$prefix} as __values {$suffix}"; + } else { + $qstr = "{$prefix}{$suffix}"; + } + } + $nextpos = strlen($qstr) - strlen($suffix); + continue; + } + + // find argument + if ($nextch === "{" + && ($rbracepos = strpos($qstr, "}", $nextpos + 1)) !== false) { $thisarg = substr($qstr, $nextpos + 1, $rbracepos - $nextpos - 1); if ($thisarg === (string) (int) $thisarg) --$thisarg; @@ -294,6 +323,7 @@ static private function format_query_args($dblink, $qstr, $argv) { trigger_error(self::landmark() . ": query '$original_qstr' argument " . (is_int($thisarg) ? $thisarg + 1 : $thisarg) . " not set"); } $usedargs[$thisarg] = true; + // argument format $arg = $argv[$thisarg] ?? null; if ($nextch === "e" || $nextch === "E") { @@ -387,7 +417,7 @@ static private function format_query_args($dblink, $qstr, $argv) { } // combine $suffix = substr($qstr, $nextpos); - $qstr = substr($qstr, 0, $strpos) . $arg . $suffix; + $qstr = "$prefix$arg$suffix"; $strpos = strlen($qstr) - strlen($suffix); } if ($simpleargs && $argpos !== count($argv)) { diff --git a/src/api/api_searchconfig.php b/src/api/api_searchconfig.php index 02fe09123..a71a75152 100644 --- a/src/api/api_searchconfig.php +++ b/src/api/api_searchconfig.php @@ -305,7 +305,7 @@ static function save_namedsearch(Contact $user, Qrequest $qreq) { $qv[] = ["ss:" . $search_names[$lname], Conf::$now, json_encode_db($q)]; } if (!empty($qv)) { - $user->conf->qe("insert into Settings (name, value, data) values ?v on duplicate key update value=values(value), data=values(data)", $qv); + $user->conf->qe("insert into Settings (name, value, data) values ?v ?U on duplicate key update value=?U(value), data=?U(data)", $qv); } $user->conf->replace_named_searches(); return self::namedsearch($user, $qreq); diff --git a/src/conference.php b/src/conference.php index 5a87e9bad..6fc60ede6 100644 --- a/src/conference.php +++ b/src/conference.php @@ -804,7 +804,7 @@ function save_setting($name, $value, $data = null) { if (is_array($dval) || is_object($dval)) { $dval = json_encode_db($dval); } - $result = $this->qe("insert into Settings (name, value, data) values (?, ?, ?) on duplicate key update value=values(value), data=values(data)", $name, $value, $dval); + $result = $this->qe("insert into Settings (name, value, data) values (?, ?, ?) ?U on duplicate key update value=?U(value), data=?U(data)", $name, $value, $dval); if (!Dbl::is_error($result)) { $this->settings[$name] = $value; $this->settingTexts[$name] = $dval; diff --git a/src/mergecontacts.php b/src/mergecontacts.php index 0a891bddb..2c5232b8a 100644 --- a/src/mergecontacts.php +++ b/src/mergecontacts.php @@ -99,7 +99,7 @@ private function merge() { } } if (!empty($qv)) { - $this->q("insert into PaperConflict (paperId,contactId,conflictType) values ?v on duplicate key update conflictType=values(conflictType)", $qv); + $this->q("insert into PaperConflict (paperId,contactId,conflictType) values ?v ?U on duplicate key update conflictType=?U(conflictType)", $qv); } $this->q("delete from PaperConflict where contactId=?", $this->oldu->contactId); $this->conf->q_raw("unlock tables"); diff --git a/src/settingvalues.php b/src/settingvalues.php index df608bfb0..d0a636c46 100644 --- a/src/settingvalues.php +++ b/src/settingvalues.php @@ -1749,8 +1749,8 @@ function execute() { //Conf::msg_info(Ht::pre_text_wrap(Dbl::format_query("delete from Settings where name?a", $dv))); } if (!empty($av)) { - $this->conf->qe("insert into Settings (name, value, data) values ?v on duplicate key update value=values(value), data=values(data)", $av); - //Conf::msg_info(Ht::pre_text_wrap(Dbl::format_query("insert into Settings (name, value, data) values ?v on duplicate key update value=values(value), data=values(data)", $av))); + $this->conf->qe("insert into Settings (name, value, data) values ?v ?U on duplicate key update value=?U(value), data=?U(data)", $av); + //Conf::msg_info(Ht::pre_text_wrap(Dbl::format_query("insert into Settings (name, value, data) values ?v ?U on duplicate key update value=?U(value), data=?U(data)", $av))); } $this->conf->qe_raw("unlock tables"); diff --git a/src/updateschema.php b/src/updateschema.php index abd0b6043..f2ffc4fb8 100644 --- a/src/updateschema.php +++ b/src/updateschema.php @@ -264,7 +264,7 @@ private function v154_mimetype_extensions() { $qv[] = [$row->mimetypeid, $row->mimetype, $extension]; } Dbl::free($result); - return empty($qv) || $this->conf->ql_ok("insert into Mimetype (mimetypeid, mimetype, extension) values ?v on duplicate key update extension=values(extension)", $qv); + return empty($qv) || $this->conf->ql_ok("insert into Mimetype (mimetypeid, mimetype, extension) values ?v ?U on duplicate key update extension=?U(extension)", $qv); } private function v174_paper_review_tfields() { @@ -630,8 +630,8 @@ function run() { && $conf->ql_ok("alter table OptionType add `optionValues` text NOT NULL default ''")) { $conf->update_schema_version(14); } - if ($conf->sversion === 14 - && $conf->ql_ok("insert into Settings (name, value) select 'rev_tokens', count(reviewId) from PaperReview where reviewToken!=0 on duplicate key update value=values(value)")) { + if ($conf->sversion === 14) { + $conf->update_rev_tokens_setting(0); $conf->update_schema_version(15); } if ($conf->sversion === 15) { @@ -688,10 +688,11 @@ function run() { $conf->update_schema_version(25); } if ($conf->sversion === 25) { - if ($conf->settings["final_done"] > 0 + if (($fd = $conf->settings["final_done"]) > 0 && !isset($conf->settings["final_soft"]) - && $conf->ql_ok("insert into Settings (name, value) values ('final_soft', " . $conf->settings["final_done"] . ") on duplicate key update value=values(value)")) - $conf->settings["final_soft"] = $conf->settings["final_done"]; + && $conf->ql_ok("insert into Settings (name, value) values ('final_soft', ?) on duplicate key update value=?", $fd, $fd)) { + $conf->settings["final_soft"] = $fd; + } $conf->update_schema_version(26); } if ($conf->sversion === 26 diff --git a/test/setup.php b/test/setup.php index 0a5bd89f9..7ccf1948b 100644 --- a/test/setup.php +++ b/test/setup.php @@ -306,6 +306,23 @@ function xassert_neqq($a, $b) { return $ok; } +/** @param list $b + * @return bool */ +function xassert_in_eqq($a, $b) { + ++Xassert::$n; + $ok = false; + foreach ($b as $bx) { + $ok = $ok || $a === $bx; + } + if ($ok) { + ++Xassert::$nsuccess; + } else { + trigger_error("Assertion " . var_export($a, true) . " \in " . var_export($b, true) + . " failed at " . assert_location() . "\n", E_USER_WARNING); + } + return $ok; +} + /** @return bool */ function xassert_eq($a, $b) { ++Xassert::$n; diff --git a/test/test02.php b/test/test02.php index 034272809..b9df7f702 100644 --- a/test/test02.php +++ b/test/test02.php @@ -35,6 +35,8 @@ xassert_eqq(Dbl::format_query("Hello"), "Hello"); xassert_eqq(Dbl::format_query("Hello??"), "Hello?"); xassert_eqq(Dbl::format_query("Hello????"), "Hello??"); +xassert_eqq(Dbl::format_query("Hello????? What the heck", 1), "Hello??1 What the heck"); +xassert_in_eqq(Dbl::format_query("Hello ?U? ?U(a)?", 1, 2), ["Hello 1 values(a)2", "Hello as __values 1 __values.a2"]); xassert_eqq(Dbl::format_query("select ?, ?, ?, ?s, ?s, ?s, ?", 1, "a", null, 2, "b", null, 3), "select 1, 'a', NULL, 2, b, , 3");