snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
This commit is contained in:
68
internal/goldeneye/clickhouse/queries.go
Normal file
68
internal/goldeneye/clickhouse/queries.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package clickhouse
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sqlc-dev/sqlc/internal/goldeneye/endtoend"
|
||||
)
|
||||
|
||||
// placeholder is one parameter reference in a query, in order of appearance.
|
||||
type placeholder struct {
|
||||
Number int
|
||||
Name string // sqlc.arg / sqlc.narg name, empty for ?
|
||||
}
|
||||
|
||||
// Placeholders are substituted with constant expressions that carry their
|
||||
// ordinal, so they can be told apart from each other and from literal NULLs
|
||||
// once ClickHouse has folded them: the query tree prints the expression a
|
||||
// folded constant came from. NULL coerces to any type, so a comparison
|
||||
// against it analyzes with the other operand's type. LIMIT and OFFSET
|
||||
// reject NULL and only accept unsigned integers, so those get a value no
|
||||
// query would plausibly contain.
|
||||
const limitBase = "4294967295"
|
||||
|
||||
func sentinelFor(lastWord string, ordinal int) string {
|
||||
switch strings.ToLower(lastWord) {
|
||||
case "limit", "offset":
|
||||
return fmt.Sprintf("toUInt64(%s + %d)", limitBase, ordinal)
|
||||
}
|
||||
return fmt.Sprintf("(NULL + %d)", ordinal)
|
||||
}
|
||||
|
||||
// bindPlaceholders rewrites sqlc's parameter syntax (?, sqlc.arg(name),
|
||||
// sqlc.narg(name)) into constants ClickHouse can analyze. ClickHouse binds
|
||||
// every ? positionally, so each placeholder is its own parameter even when
|
||||
// a name repeats, which is how sqlc numbers them too.
|
||||
func bindPlaceholders(sql string) (string, []placeholder) {
|
||||
var phs []placeholder
|
||||
out := endtoend.Rewrite(sql, func(name, lastWord string) string {
|
||||
phs = append(phs, placeholder{Number: len(phs) + 1, Name: name})
|
||||
return sentinelFor(lastWord, len(phs))
|
||||
})
|
||||
return out, phs
|
||||
}
|
||||
|
||||
func isWordByte(c byte) bool {
|
||||
return c == '_' || c == '.' || c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'
|
||||
}
|
||||
|
||||
// skipQuoted returns the index just past the quoted token starting at i,
|
||||
// honouring backslash escapes and doubled quotes.
|
||||
func skipQuoted(s string, i int) int {
|
||||
q := s[i]
|
||||
j := i + 1
|
||||
for j < len(s) {
|
||||
switch {
|
||||
case s[j] == '\\' && j+1 < len(s):
|
||||
j += 2
|
||||
case s[j] == q && j+1 < len(s) && s[j+1] == q:
|
||||
j += 2
|
||||
case s[j] == q:
|
||||
return j + 1
|
||||
default:
|
||||
j++
|
||||
}
|
||||
}
|
||||
return len(s)
|
||||
}
|
||||
Reference in New Issue
Block a user