refs #98 add new flavor Presto

This commit is contained in:
Huan Du
2023-03-27 23:17:33 +08:00
parent 4c1daa8aab
commit 0b1c445a5c
7 changed files with 79 additions and 7 deletions
+1 -1
View File
@@ -114,7 +114,7 @@ To learn how to use builders, check out [examples on GoDoc](https://pkg.go.dev/g
SQL syntax and parameter marks vary in different systems. In this package, we introduce a concept called "flavor" to smooth out these difference.
Right now, MySQL, PostgreSQL, SQLServer, SQLite, CQL and ClickHouse are defined in flavor list. Feel free to open issue or send pull request if anyone asks for a new flavor.
Right now, `MySQL`, `PostgreSQL`, `SQLServer`, `SQLite`, `CQL`, `ClickHouse` and `Presto` are defined in flavor list. Feel free to open issue or send pull request if anyone asks for a new flavor.
By default, all builders uses `DefaultFlavor` to build SQL. The default value is `MySQL`.
+1 -1
View File
@@ -233,7 +233,7 @@ func (args *Args) compileArg(buf *bytes.Buffer, flavor Flavor, values []interfac
}
default:
switch flavor {
case MySQL, SQLite, CQL, ClickHouse:
case MySQL, SQLite, CQL, ClickHouse, Presto:
buf.WriteRune('?')
case PostgreSQL:
fmt.Fprintf(buf, "$%d", len(values)+1)
+12 -3
View File
@@ -18,6 +18,7 @@ const (
SQLServer
CQL
ClickHouse
Presto
)
var (
@@ -55,6 +56,8 @@ func (f Flavor) String() string {
return "CQL"
case ClickHouse:
return "ClickHouse"
case Presto:
return "Presto"
}
return "<invalid>"
@@ -79,6 +82,8 @@ func (f Flavor) Interpolate(sql string, args []interface{}) (string, error) {
return cqlInterpolate(sql, args...)
case ClickHouse:
return clickhouseInterpolate(sql, args...)
case Presto:
return prestoInterpolate(sql, args...)
}
return "", ErrInterpolateNotImplemented
@@ -135,7 +140,7 @@ func (f Flavor) Quote(name string) string {
switch f {
case MySQL, ClickHouse:
return fmt.Sprintf("`%s`", name)
case PostgreSQL, SQLServer, SQLite:
case PostgreSQL, SQLServer, SQLite, Presto:
return fmt.Sprintf(`"%s"`, name)
case CQL:
return fmt.Sprintf("'%s'", name)
@@ -149,18 +154,22 @@ func (f Flavor) PrepareInsertIgnore(table string, ib *InsertBuilder) {
switch ib.args.Flavor {
case MySQL:
ib.verb = "INSERT IGNORE"
case PostgreSQL:
// see https://www.postgresql.org/docs/current/sql-insert.html
ib.verb = "INSERT"
// add sql statement at the end after values, i.e. INSERT INTO ... ON CONFLICT DO NOTHING
ib.marker = insertMarkerAfterValues
ib.SQL("ON CONFLICT DO NOTHING")
case SQLite:
// see https://www.sqlite.org/lang_insert.html
ib.verb = "INSERT OR IGNORE"
case ClickHouse:
// see https://clickhouse.tech/docs/en/sql-reference/statements/insert-into/
case ClickHouse, CQL, SQLServer, Presto:
// All other databases do not support insert ignore
ib.verb = "INSERT"
default:
// panic if the db flavor is not supported
panic(fmt.Errorf("unsupported db flavor: %s", ib.args.Flavor.String()))
+12
View File
@@ -395,6 +395,10 @@ func clickhouseInterpolate(query string, args ...interface{}) (string, error) {
return mysqlLikeInterpolate(ClickHouse, query, args...)
}
func prestoInterpolate(query string, args ...interface{}) (string, error) {
return mysqlLikeInterpolate(Presto, query, args...)
}
func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
switch v := arg.(type) {
case nil:
@@ -436,6 +440,9 @@ func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
case ClickHouse:
buf = append(buf, v.Format("2006-01-02 15:04:05.999999")...)
case Presto:
buf = append(buf, v.Format("2006-01-02 15:04:05.000")...)
}
buf = append(buf, '\'')
@@ -541,6 +548,11 @@ func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
buf = append(buf, "unhex('"...)
buf = appendHex(buf, data)
buf = append(buf, "')"...)
case Presto:
buf = append(buf, "from_hex('"...)
buf = appendHex(buf, data)
buf = append(buf, "')"...)
}
default:
+45
View File
@@ -238,6 +238,51 @@ func TestFlavorInterpolate(t *testing.T) {
"SELECT ?", []interface{}{errorValuer(1)},
"", ErrErrorValuer,
},
{
Presto,
"SELECT * FROM a WHERE name = ? AND state IN (?, ?, ?, ?, ?)", []interface{}{"I'm fine", 42, int8(8), int16(-16), int32(32), int64(64)},
"SELECT * FROM a WHERE name = 'I\\'m fine' AND state IN (42, 8, -16, 32, 64)", nil,
},
{
Presto,
"SELECT * FROM `a?` WHERE name = \"?\" AND state IN (?, '?', ?, ?, ?, ?, ?)", []interface{}{"\r\n\b\t\x1a\x00\\\"'", uint(42), uint8(8), uint16(16), uint32(32), uint64(64), "useless"},
"SELECT * FROM `a?` WHERE name = \"?\" AND state IN ('\\r\\n\\b\\t\\Z\\0\\\\\\\"\\'', '?', 42, 8, 16, 32, 64)", nil,
},
{
Presto,
"SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?", []interface{}{true, false, float32(1.234567), 9.87654321, []byte(nil), []byte("I'm bytes"), dt, time.Time{}, nil},
"SELECT TRUE, FALSE, 1.234567, 9.87654321, NULL, from_hex('49276D206279746573'), '2019-04-24 12:23:34.123', '0000-00-00', NULL", nil,
},
{
Presto,
"SELECT '\\'?', \"\\\"?\", `\\`?`, \\?", []interface{}{MySQL},
"SELECT '\\'?', \"\\\"?\", `\\`?`, \\'MySQL'", nil,
},
{
Presto,
"SELECT ?", []interface{}{byteArr},
"SELECT from_hex('666F6F')", nil,
},
{
Presto,
"SELECT ?", nil,
"", ErrInterpolateMissingArgs,
},
{
Presto,
"SELECT ?", []interface{}{complex(1, 2)},
"", ErrInterpolateUnsupportedArgs,
},
{
Presto,
"SELECT ?", []interface{}{[]complex128{complex(1, 2)}},
"", ErrInterpolateUnsupportedArgs,
},
{
Presto,
"SELECT ?", []interface{}{errorValuer(1)},
"", ErrErrorValuer,
},
}
for idx, c := range cases {
+1 -1
View File
@@ -317,7 +317,7 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
buf.WriteString(" LIMIT ")
buf.WriteString(strconv.Itoa(sb.limit))
}
case PostgreSQL:
case PostgreSQL, Presto:
if sb.limit >= 0 {
buf.WriteString(" LIMIT ")
buf.WriteString(strconv.Itoa(sb.limit))
+7 -1
View File
@@ -112,7 +112,7 @@ func ExampleSelectBuilder_join() {
}
func ExampleSelectBuilder_limit_offset() {
flavors := []Flavor{MySQL, PostgreSQL, SQLite, SQLServer, CQL, ClickHouse}
flavors := []Flavor{MySQL, PostgreSQL, SQLite, SQLServer, CQL, ClickHouse, Presto}
results := make([][]string, len(flavors))
sb := NewSelectBuilder()
saveResults := func() {
@@ -203,6 +203,12 @@ func ExampleSelectBuilder_limit_offset() {
// #2: SELECT * FROM user
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
// #4: SELECT * FROM user LIMIT 1
//
// Presto
// #1: SELECT * FROM user
// #2: SELECT * FROM user OFFSET 0
// #3: SELECT * FROM user LIMIT 1 OFFSET 0
// #4: SELECT * FROM user LIMIT 1
}
func ExampleSelectBuilder_ForUpdate() {