Fix upsert ON CONFLICT: missing :identifier expr + numbered parameters#95
Fix upsert ON CONFLICT: missing :identifier expr + numbered parameters#95AlanMcCann wants to merge 1 commit intoocean:mainfrom
Conversation
Two bugs in SQL generation that cause "near ?: syntax error" on any
INSERT ... ON CONFLICT DO UPDATE query:
1. Missing :identifier expression handler. Ecto generates ON CONFLICT
UPDATE clauses using fragment expressions containing {:identifier, _,
["column_name"]} tuples. Without a matching expr/3 clause, these fall
through to the catch-all which returns bare "?", producing invalid SQL
like: SET "col" = EXCLUDED.?
2. Bare ? parameter placeholders. SQLite requires numbered positional
parameters (?1, ?2, ...) when a statement contains multiple parameter
groups (INSERT values + ON CONFLICT UPDATE). The ecto_sqlite3 adapter
already uses this pattern.
Fixes all upsert operations including Ash Framework's upsert? actions.
WalkthroughThe LibSQL adapter's INSERT SQL generation has been refactored to use numbered positional bind parameters ( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/ecto/adapters/libsql/connection.ex`:
- Around line 1184-1189: The IN with a bound list branch still emits bare "?"
placeholders; update the clause handling the pattern {:in, _, [left, {:^, _, [_,
length]}]} inside expr/3 to emit numbered placeholders like the generic {:^, [],
[ix]} clause does: generate a sequence of "?" + Integer.to_string(start_index)
through "?" + Integer.to_string(start_index + length - 1) (matching the same
numbering scheme used by expr({:^,[],[ix]},...)), join them with ", " and return
the full parenthesized placeholder list so SQLite gets ?1, ?2, ... for IN ^list.
Ensure you reference and reuse the same index base/offset logic used by
expr({:^,...}) so numbering remains consistent across other parameter groups.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7f519f1b-e1b3-479f-8e81-0e161b5058ae
📒 Files selected for processing (1)
lib/ecto/adapters/libsql/connection.ex
| # Parameter placeholder - use numbered parameters (?1, ?2, ...). | ||
| # SQLite requires numbered parameters when a statement has multiple | ||
| # parameter groups (e.g., INSERT values + ON CONFLICT UPDATE). | ||
| defp expr({:^, [], [ix]}, _sources, _query) do | ||
| [?? | Integer.to_string(ix + 1)] | ||
| end |
There was a problem hiding this comment.
Finish the numbered-placeholder pass for IN ^list.
This change only renumbers the generic {:^, ...} case. The dedicated {:in, _, [left, {:^, _, [_, length]}]} branch below still expands to bare ? placeholders, so queries that use IN ^list can still hit SQLite's numbered-parameter requirement.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/ecto/adapters/libsql/connection.ex` around lines 1184 - 1189, The IN with
a bound list branch still emits bare "?" placeholders; update the clause
handling the pattern {:in, _, [left, {:^, _, [_, length]}]} inside expr/3 to
emit numbered placeholders like the generic {:^, [], [ix]} clause does: generate
a sequence of "?" + Integer.to_string(start_index) through "?" +
Integer.to_string(start_index + length - 1) (matching the same numbering scheme
used by expr({:^,[],[ix]},...)), join them with ", " and return the full
parenthesized placeholder list so SQLite gets ?1, ?2, ... for IN ^list. Ensure
you reference and reuse the same index base/offset logic used by expr({:^,...})
so numbering remains consistent across other parameter groups.
Two bugs in SQL generation that cause "near ?: syntax error" on any INSERT ... ON CONFLICT DO UPDATE query:
Missing :identifier expression handler. Ecto generates ON CONFLICT UPDATE clauses using fragment expressions containing {:identifier, _, ["column_name"]} tuples. Without a matching expr/3 clause, these fall through to the catch-all which returns bare "?", producing invalid SQL like: SET "col" = EXCLUDED.?
Bare ? parameter placeholders. SQLite requires numbered positional parameters (?1, ?2, ...) when a statement contains multiple parameter groups (INSERT values + ON CONFLICT UPDATE). The ecto_sqlite3 adapter already uses this pattern.
Fixes all upsert operations including Ash Framework's upsert? actions.
Summary by CodeRabbit
Bug Fixes