You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by er...@apache.org on 2026/08/15 04:32:48 UTC

(opendal) branch main updated: fix(services/d1): repair the upsert statement that breaks every write (#8068)

This is an automated email from the ASF dual-hosted git repository.

erickguan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new daeed4485 fix(services/d1): repair the upsert statement that breaks every write (#8068)
daeed4485 is described below

commit daeed44853296c3f8a20bd0abc171830348d13e0
Author: ZIHAN DAI <99...@users.noreply.github.com>
AuthorDate: Sat Aug 15 14:32:43 2026 +1000

    fix(services/d1): repair the upsert statement that breaks every write (#8068)
    
    * fix(services/d1): repair the upsert statement that breaks every write
    
    The statement built in D1Core::set carries two defects, and either one
    alone is enough to stop a write from landing.
    
    It is a raw string, so the three trailing backslashes are literal
    backslash characters rather than line continuations. SQLite stops at the
    first one:
    
      sqlite> INSERT INTO "data" ("key", "value") \
      Parse error near line 1: unrecognized token: "\"
    
    And the key placeholder is quoted. 'val' is a string literal in SQL, so
    '?' is the one-character string "?" rather than a bind marker. That
    leaves a single placeholder for the two parameters set always sends, and
    every row lands under the literal key "?":
    
      sqlite> INSERT INTO "data" ("key","value") VALUES ('?','hello') ...
      sqlite> SELECT '['||key||'] -> '||value FROM data;
      [?] -> hello
    
    Both arrived together in 311f324cc (#7857), which rewrote the literal as
    a raw string in order to quote the table and column identifiers:
    
      -  "INSERT INTO {table} ({key_field}, {value_field}) \
      -      VALUES (?, ?) \
      +  r#"INSERT INTO "{table}" ("{key_field}", "{value_field}") \
      +      VALUES ('?', ?) \
    
    The identifier quoting that change was after is kept; only the escaping
    and the placeholder are corrected. The statement moves into a
    build_set_query helper so it can be asserted on directly.
    
    The rest of the crate is unaffected: delete and the two SELECTs are
    single-line raw strings with bare `?`, and a sweep for the shape --
    a raw string with a line-ending backslash -- finds no other occurrence
    in the repository.
    
    One observation left out of this change, for a maintainer to judge
    separately: set matches on the HTTP status alone, while get and
    get_length both run D1Response::parse. D1 answers a rejected statement
    with 200 and success:false, so the parse error above was reported to
    callers as a successful write. That is why a service whose every write
    fails has no bug report against it.
    
    Two unit tests. Restoring either defect on its own fails
    set_query_binds_both_parameters; the second test pins the identifier
    quoting and passes against both the old and the new statement, so it
    holds the #7857 intent in place.
    
    * Address review: inline the statement and drop the test module
    
    Review points from @erickguan, both applied:
    
    - build_set_query removed; the format! goes back inline at the call
      site, with the same local bindings the original had
    - test module removed
    
    The diff against main is now three lines: the three literal backslashes
    go, and the key placeholder loses its quotes.
---
 core/services/d1/src/core.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/core/services/d1/src/core.rs b/core/services/d1/src/core.rs
index 9e99f5e59..5b19d8f9f 100644
--- a/core/services/d1/src/core.rs
+++ b/core/services/d1/src/core.rs
@@ -133,9 +133,9 @@ impl D1Core {
         let key_field = &self.key_field;
         let value_field = &self.value_field;
         let query = format!(
-            r#"INSERT INTO "{table}" ("{key_field}", "{value_field}") \
-                VALUES ('?', ?) \
-                ON CONFLICT ("{key_field}") \
+            r#"INSERT INTO "{table}" ("{key_field}", "{value_field}")
+                VALUES (?, ?)
+                ON CONFLICT ("{key_field}")
                     DO UPDATE SET "{value_field}" = EXCLUDED."{value_field}""#,
         );