Skip to content

Commit

Permalink
refs #98 add new flavor Presto
Browse files Browse the repository at this point in the history
  • Loading branch information
huandu committed Mar 27, 2023
1 parent 71a8512 commit cf15575
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

Expand Down
2 changes: 1 addition & 1 deletion args.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 12 additions & 3 deletions flavor.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
SQLServer
CQL
ClickHouse
Presto
)

var (
Expand Down Expand Up @@ -55,6 +56,8 @@ func (f Flavor) String() string {
return "CQL"
case ClickHouse:
return "ClickHouse"
case Presto:
return "Presto"
}

return "<invalid>"
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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()))
Expand Down
12 changes: 12 additions & 0 deletions interpolate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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, '\'')
Expand Down Expand Up @@ -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:
Expand Down
45 changes: 45 additions & 0 deletions interpolate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion select.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
8 changes: 7 additions & 1 deletion select_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down

0 comments on commit cf15575

Please sign in to comment.