Skip to content

Commit c35040f

Browse files
authored
Merge pull request #140 from zhangyongding/master
Support Informix SQL, so we can support DBMS using this flavor, e.g. GBase.
2 parents a5eff69 + cd34220 commit c35040f

File tree

10 files changed

+140
-5
lines changed

10 files changed

+140
-5
lines changed

args.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ func (args *Args) compileArg(buf *stringBuilder, flavor Flavor, values []interfa
241241

242242
default:
243243
switch flavor {
244-
case MySQL, SQLite, CQL, ClickHouse, Presto:
244+
case MySQL, SQLite, CQL, ClickHouse, Presto, Informix:
245245
buf.WriteRune('?')
246246
case PostgreSQL:
247247
fmt.Fprintf(buf, "$%d", len(values)+1)

builder_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,19 @@ func ExampleWithFlavor() {
7171
fmt.Println(sql)
7272
fmt.Println(args)
7373

74+
// Explicitly use MySQL as the informix.
75+
sql, args = WithFlavor(Buildf("SELECT * FROM foo WHERE id = %v", 1234), Informix).Build()
76+
77+
fmt.Println(sql)
78+
fmt.Println(args)
79+
7480
// Output:
7581
// SELECT * FROM foo WHERE id = $1
7682
// [1234]
7783
// SELECT * FROM foo WHERE id = ?
7884
// [1234]
85+
// SELECT * FROM foo WHERE id = ?
86+
// [1234]
7987
}
8088

8189
func TestBuildWithPostgreSQL(t *testing.T) {

flavor.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const (
2020
ClickHouse
2121
Presto
2222
Oracle
23+
Informix
2324
)
2425

2526
var (
@@ -61,6 +62,8 @@ func (f Flavor) String() string {
6162
return "Presto"
6263
case Oracle:
6364
return "Oracle"
65+
case Informix:
66+
return "Informix"
6467
}
6568

6669
return "<invalid>"
@@ -89,6 +92,8 @@ func (f Flavor) Interpolate(sql string, args []interface{}) (string, error) {
8992
return prestoInterpolate(sql, args...)
9093
case Oracle:
9194
return oracleInterpolate(sql, args...)
95+
case Informix:
96+
return informixInterpolate(sql, args...)
9297
}
9398

9499
return "", ErrInterpolateNotImplemented
@@ -145,7 +150,7 @@ func (f Flavor) Quote(name string) string {
145150
switch f {
146151
case MySQL, ClickHouse:
147152
return fmt.Sprintf("`%s`", name)
148-
case PostgreSQL, SQLServer, SQLite, Presto, Oracle:
153+
case PostgreSQL, SQLServer, SQLite, Presto, Oracle, Informix:
149154
return fmt.Sprintf(`"%s"`, name)
150155
case CQL:
151156
return fmt.Sprintf("'%s'", name)
@@ -171,7 +176,7 @@ func (f Flavor) PrepareInsertIgnore(table string, ib *InsertBuilder) {
171176
// see https://www.sqlite.org/lang_insert.html
172177
ib.verb = "INSERT OR IGNORE"
173178

174-
case ClickHouse, CQL, SQLServer, Presto:
179+
case ClickHouse, CQL, SQLServer, Presto, Informix:
175180
// All other databases do not support insert ignore
176181
ib.verb = "INSERT"
177182

flavor_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func TestFlavor(t *testing.T) {
2121
CQL: "CQL",
2222
ClickHouse: "ClickHouse",
2323
Oracle: "Oracle",
24+
Informix: "Informix",
2425
}
2526

2627
for f, expected := range cases {
@@ -159,3 +160,21 @@ func ExampleFlavor_Interpolate_oracle() {
159160
// SELECT name FROM user WHERE id = 1234 AND name = 'Charmy Liu' AND enabled = 1
160161
// <nil>
161162
}
163+
164+
func ExampleFlavor_Interpolate_infomix() {
165+
sb := Informix.NewSelectBuilder()
166+
sb.Select("name").From("user").Where(
167+
sb.NE("id", 1234),
168+
sb.E("name", "Charmy Liu"),
169+
sb.E("enabled", true),
170+
)
171+
sql, args := sb.Build()
172+
query, err := Informix.Interpolate(sql, args)
173+
174+
fmt.Println(query)
175+
fmt.Println(err)
176+
177+
// Output:
178+
// SELECT name FROM user WHERE id <> 1234 AND name = 'Charmy Liu' AND enabled = TRUE
179+
// <nil>
180+
}

insert_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,22 @@ func ExampleInsertBuilder_subSelect_oracle() {
212212
// [1]
213213
}
214214

215+
func ExampleInsertBuilder_subSelect_informix() {
216+
ib := Informix.NewInsertBuilder()
217+
ib.InsertInto("demo.user")
218+
ib.Cols("id", "name")
219+
sb := ib.Select("id", "name").From("demo.test")
220+
sb.Where(sb.EQ("id", 1))
221+
222+
sql, args := ib.Build()
223+
fmt.Println(sql)
224+
fmt.Println(args)
225+
226+
// Output:
227+
// INSERT INTO demo.user (id, name) SELECT id, name FROM demo.test WHERE id = ?
228+
// [1]
229+
}
230+
215231
func ExampleInsertBuilder_NumValue() {
216232
ib := NewInsertBuilder()
217233
ib.InsertInto("demo.user")

interpolate.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,10 @@ func prestoInterpolate(query string, args ...interface{}) (string, error) {
399399
return mysqlLikeInterpolate(Presto, query, args...)
400400
}
401401

402+
func informixInterpolate(query string, args ...interface{}) (string, error) {
403+
return mysqlLikeInterpolate(Informix, query, args...)
404+
}
405+
402406
// oraclelInterpolate parses query and replace all ":*" with encoded args.
403407
// If there are more ":*" than len(args), returns ErrMissingArgs.
404408
// Otherwise, if there are less ":*" than len(args), the redundant args are omitted.
@@ -612,6 +616,9 @@ func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
612616
buf = append(buf, v.Format("2006-01-02 15:04:05.999999")...)
613617
buf = append(buf, "', 'YYYY-MM-DD HH24:MI:SS.FF')"...)
614618

619+
case Informix:
620+
buf = append(buf, v.Format("'2006-01-02 15:04:05.999999'")...)
621+
615622
}
616623

617624
case fmt.Stringer:
@@ -734,6 +741,8 @@ func encodeValue(buf []byte, arg interface{}, flavor Flavor) ([]byte, error) {
734741
buf = append(buf, "hextoraw('"...)
735742
buf = appendHex(buf, data)
736743
buf = append(buf, "')"...)
744+
default:
745+
return nil, ErrInterpolateUnsupportedArgs
737746
}
738747

739748
default:

interpolate_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,53 @@ func TestFlavorInterpolate(t *testing.T) {
324324
"SELECT :12345678901234567890", nil,
325325
"", errOutOfRange,
326326
},
327+
{
328+
Informix,
329+
"SELECT * FROM a WHERE name = ? AND state IN (?, ?, ?, ?, ?)", []interface{}{"I'm fine", 42, int8(8), int16(-16), int32(32), int64(64)},
330+
"SELECT * FROM a WHERE name = 'I\\'m fine' AND state IN (42, 8, -16, 32, 64)", nil,
331+
},
332+
{
333+
Informix,
334+
"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"},
335+
"SELECT * FROM `a?` WHERE name = \"?\" AND state IN ('\\r\\n\\b\\t\\Z\\0\\\\\\\"\\'', '?', 42, 8, 16, 32, 64)", nil,
336+
},
337+
{
338+
Informix,
339+
"SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?", []interface{}{true, false, float32(1.234567), float64(9.87654321), []byte(nil), []byte("I'm bytes"), dt, time.Time{}, nil},
340+
// "SELECT TRUE, FALSE, 1.234567, 9.87654321, NULL, _binary'I\\'m bytes', '2019-04-24 12:23:34.123457', '0000-00-00', NULL", nil,
341+
"", ErrInterpolateUnsupportedArgs,
342+
},
343+
{
344+
Informix,
345+
"SELECT '\\'?', \"\\\"?\", `\\`?`, \\?", []interface{}{Informix},
346+
"SELECT '\\'?', \"\\\"?\", `\\`?`, \\'Informix'", nil,
347+
},
348+
{
349+
Informix,
350+
"SELECT ?", []interface{}{byteArr},
351+
// "SELECT _binary'foo'", nil,
352+
"", ErrInterpolateUnsupportedArgs,
353+
},
354+
{
355+
Informix,
356+
"SELECT ?", nil,
357+
"", ErrInterpolateMissingArgs,
358+
},
359+
{
360+
Informix,
361+
"SELECT ?", []interface{}{complex(1, 2)},
362+
"", ErrInterpolateUnsupportedArgs,
363+
},
364+
{
365+
Informix,
366+
"SELECT ?", []interface{}{[]complex128{complex(1, 2)}},
367+
"", ErrInterpolateUnsupportedArgs,
368+
},
369+
{
370+
Informix,
371+
"SELECT ?", []interface{}{errorValuer(1)},
372+
"", ErrErrorValuer,
373+
},
327374
}
328375

329376
for idx, c := range cases {

select.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,24 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
247247
if len(sb.selectCols) > 0 {
248248
buf.WriteLeadingString("SELECT ")
249249

250+
if flavor == Informix {
251+
if sb.offset >= 0 {
252+
buf.WriteString("SKIP ")
253+
buf.WriteString(strconv.Itoa(sb.offset))
254+
buf.WriteString(" ")
255+
}
256+
257+
if sb.limit > 0 {
258+
if sb.offset < 0 {
259+
buf.WriteString("SKIP 0 ")
260+
}
261+
262+
buf.WriteString("FIRST ")
263+
buf.WriteString(strconv.Itoa(sb.limit))
264+
buf.WriteString(" ")
265+
}
266+
}
267+
250268
if sb.distinct {
251269
buf.WriteString("DISTINCT ")
252270
}
@@ -423,6 +441,12 @@ func (sb *SelectBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{
423441
buf.WriteString(strconv.Itoa(min + 1))
424442
}
425443
}
444+
case Informix:
445+
// If ORDER BY is not set, sort column #1 by default.
446+
// It's required to make OFFSET...FETCH work.
447+
if len(sb.orderByCols) == 0 && (sb.limit >= 0 || sb.offset >= 0) {
448+
buf.WriteLeadingString("ORDER BY 1")
449+
}
426450
}
427451

428452
if sb.limit >= 0 {

select_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func ExampleSelectBuilder_join() {
112112
}
113113

114114
func ExampleSelectBuilder_limit_offset() {
115-
flavors := []Flavor{MySQL, PostgreSQL, SQLite, SQLServer, CQL, ClickHouse, Presto, Oracle}
115+
flavors := []Flavor{MySQL, PostgreSQL, SQLite, SQLServer, CQL, ClickHouse, Presto, Oracle, Informix}
116116
results := make([][]string, len(flavors))
117117
sb := NewSelectBuilder()
118118
saveResults := func() {
@@ -233,6 +233,13 @@ func ExampleSelectBuilder_limit_offset() {
233233
// #3: SELECT * FROM ( SELECT ROWNUM r, * FROM ( SELECT * FROM user ) user ) WHERE r BETWEEN 1 AND 1
234234
// #4: SELECT * FROM ( SELECT ROWNUM r, * FROM ( SELECT * FROM user ) user ) WHERE r BETWEEN 1 AND 1
235235
// #5: SELECT * FROM ( SELECT ROWNUM r, * FROM ( SELECT * FROM user ORDER BY id ) user ) WHERE r BETWEEN 2 AND 2
236+
//
237+
// Informix
238+
// #1: SELECT * FROM user
239+
// #2: SELECT SKIP 0 * FROM user ORDER BY 1
240+
// #3: SELECT SKIP 0 FIRST 1 * FROM user ORDER BY 1
241+
// #4: SELECT SKIP 0 FIRST 1 * FROM user ORDER BY 1
242+
// #5: SELECT SKIP 1 FIRST 1 * FROM user ORDER BY id
236243
}
237244

238245
func ExampleSelectBuilder_ForUpdate() {

union.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func (ub *UnionBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}
178178

179179
}
180180

181-
if MySQL == flavor && ub.limit >= 0 || PostgreSQL == flavor {
181+
if ((MySQL == flavor || Informix == flavor) && ub.limit >= 0) || PostgreSQL == flavor {
182182
if ub.offset >= 0 {
183183
buf.WriteLeadingString("OFFSET ")
184184
buf.WriteString(strconv.Itoa(ub.offset))

0 commit comments

Comments
 (0)