Skip to content

Commit 6c8da00

Browse files
committed
Fixes 2462, 2574, 2579
1 parent abe3be2 commit 6c8da00

12 files changed

Lines changed: 176 additions & 117 deletions

File tree

postgres/parser/parser/sql/sql_parser.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (p PostgresFormatter) GenerateCreateTablePrimaryKeyDefinition(pkCols []stri
137137

138138
func (p PostgresFormatter) GenerateCreateTableIndexDefinition(isUnique, isSpatial, isFullText, isVector bool, indexID string, indexCols []string, comment string) (string, bool) {
139139
if isUnique {
140-
return fmt.Sprintf(" UNIQUE %s (%s)", p.QuoteIdentifier(indexID), strings.Join(indexCols, ",")), true
140+
return fmt.Sprintf(" CONSTRAINT %s UNIQUE (%s)", p.QuoteIdentifier(indexID), strings.Join(indexCols, ",")), true
141141
}
142142

143143
// TODO: this interface is not sufficient for SHOW CREATE TABLE output, where we will need to return multiple

server/config/parameters_list.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3540,6 +3540,8 @@ var postgresConfigParameters = map[string]sql.SystemVariable{
35403540
ValidateFunc: func(_, new any) (any, bool) {
35413541
switch v := new.(type) {
35423542
case string:
3543+
v = strings.TrimSpace(v)
3544+
vplus := "+" + v // This allows for 10:00:00 to match since we'd expect +10:00:00 for a time zone
35433545
if strings.ToLower(v) == "local" {
35443546
// TODO: this should be the IANA name, not whatever Go decides to use
35453547
// https://pkg.go.dev/github.com/thlib/go-timezone-local/tzlocal seems useful in this case.
@@ -3573,6 +3575,10 @@ var postgresConfigParameters = map[string]sql.SystemVariable{
35733575
if err == nil {
35743576
return parsed.Format("-07:00:00"), true
35753577
}
3578+
parsed, err = time.Parse(layout, vplus)
3579+
if err == nil {
3580+
return parsed.Format("-07:00:00"), true
3581+
}
35763582
}
35773583
return nil, false
35783584
}

server/functions/array_append.go

Lines changed: 0 additions & 44 deletions
This file was deleted.

server/functions/array_cat.go

Lines changed: 0 additions & 54 deletions
This file was deleted.

server/functions/binary/concatenate.go

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ import (
2929
// initBinaryConcatenate registers the functions to the catalog.
3030
func initBinaryConcatenate() {
3131
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, anytextcat)
32+
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, array_append)
33+
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, array_cat)
34+
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, array_prepend)
3235
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, byteacat)
3336
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, jsonb_concat)
3437
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, textanycat)
3538
framework.RegisterBinaryFunction(framework.Operator_BinaryConcatenate, textcat)
36-
// TODO: array_append, array_cat, array_prepend, bitcat, tsquery_or, tsvector_concat
39+
// TODO: bitcat, tsquery_or, tsvector_concat
3740
}
3841

3942
// anytextcat_callable is the callable logic for the anytextcat function.
@@ -55,6 +58,65 @@ var anytextcat = framework.Function2{
5558
Callable: anytextcat_callable,
5659
}
5760

61+
// array_append represents the PostgreSQL function of the same name, taking the same parameters.
62+
var array_append = framework.Function2{
63+
Name: "array_append",
64+
Return: pgtypes.AnyArray, // TODO: should be anycompatiblearray
65+
Parameters: [2]*pgtypes.DoltgresType{pgtypes.AnyArray, pgtypes.AnyElement}, // TODO: should be anycompatiblearray, anycompatible
66+
Strict: false,
67+
Callable: func(ctx *sql.Context, paramsAndReturn [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
68+
if val1 == nil {
69+
return []any{val2}, nil
70+
}
71+
array := val1.([]any)
72+
returnArray := make([]any, len(array)+1)
73+
copy(returnArray, array)
74+
returnArray[len(returnArray)-1] = val2
75+
return returnArray, nil
76+
},
77+
}
78+
79+
// array_cat represents the PostgreSQL function of the same name, taking the same parameters.
80+
var array_cat = framework.Function2{
81+
Name: "array_cat",
82+
Return: pgtypes.AnyArray, // TODO: should be anycompatiblearray
83+
Parameters: [2]*pgtypes.DoltgresType{pgtypes.AnyArray, pgtypes.AnyArray}, // TODO: should be anycompatiblearray, anycompatiblearray
84+
Strict: false,
85+
Callable: func(ctx *sql.Context, paramsAndReturn [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
86+
if val1 == nil && val2 == nil {
87+
return nil, nil
88+
} else if val1 == nil {
89+
return val2, nil
90+
} else if val2 == nil {
91+
return val1, nil
92+
}
93+
94+
array1 := val1.([]any)
95+
array2 := val2.([]any)
96+
97+
// Concatenate the arrays
98+
result := make([]any, len(array1)+len(array2))
99+
copy(result, array1)
100+
copy(result[len(array1):], array2)
101+
102+
return result, nil
103+
},
104+
}
105+
106+
// array_prepend represents the PostgreSQL function of the same name, taking the same parameters.
107+
var array_prepend = framework.Function2{
108+
Name: "array_prepend",
109+
Return: pgtypes.AnyArray, // TODO: should be anycompatiblearray
110+
Parameters: [2]*pgtypes.DoltgresType{pgtypes.AnyElement, pgtypes.AnyArray}, // TODO: should be anycompatible, anycompatiblearray
111+
Strict: false,
112+
Callable: func(ctx *sql.Context, paramsAndReturn [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
113+
if val2 == nil {
114+
return []any{val1}, nil
115+
}
116+
return append([]any{val1}, val2.([]any)...), nil
117+
},
118+
}
119+
58120
// byteacat_callable is the callable logic for the byteacat function.
59121
func byteacat_callable(ctx *sql.Context, paramsAndReturn [3]*pgtypes.DoltgresType, val1 any, val2 any) (any, error) {
60122
v1 := val1.([]byte)

server/functions/init.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ func Init() {
7474
initAcosh()
7575
initAdvisoryLockFunctions()
7676
initAge()
77-
initArrayAppend()
78-
initArrayCat()
7977
initArrayLength()
8078
initArrayPosition()
8179
initArrayToString()

server/functions/time.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package functions
1616

1717
import (
18+
"strings"
19+
1820
"github.com/dolthub/go-mysql-server/sql"
1921
"github.com/jackc/pgtype"
2022

@@ -43,15 +45,18 @@ var time_in = framework.Function3{
4345
Parameters: [3]*pgtypes.DoltgresType{pgtypes.Cstring, pgtypes.Oid, pgtypes.Int32},
4446
Strict: true,
4547
Callable: func(ctx *sql.Context, _ [4]*pgtypes.DoltgresType, val1, val2, val3 any) (any, error) {
46-
input := val1.(string)
47-
//oid := val2.(id.Id)
48-
//typmod := val3.(int32)
49-
// TODO: decode typmod to precision
50-
p := 6
51-
//if b.Precision == -1 {
52-
// p = b.Precision
53-
//}
54-
t, _, err := tree.ParseDTime(nil, input, tree.TimeFamilyPrecisionToRoundDuration(int32(p)))
48+
input := strings.TrimSpace(val1.(string))
49+
typmod := val3.(int32)
50+
if typmod == -1 {
51+
typmod = 6
52+
}
53+
precision := tree.TimeFamilyPrecisionToRoundDuration(typmod)
54+
if strings.EqualFold(input, "now") {
55+
t := ctx.QueryTime()
56+
t = t.Round(precision)
57+
return timeofday.New(t.Hour(), t.Minute(), t.Second(), t.Nanosecond()/1000), nil
58+
}
59+
t, _, err := tree.ParseDTime(nil, input, precision)
5560
if err != nil {
5661
return nil, err
5762
}

server/functions/timetz.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package functions
1616

1717
import (
18+
"strings"
1819
"time"
1920

2021
"github.com/dolthub/go-mysql-server/sql"
@@ -45,16 +46,22 @@ var timetz_in = framework.Function3{
4546
Parameters: [3]*pgtypes.DoltgresType{pgtypes.Cstring, pgtypes.Oid, pgtypes.Int32},
4647
Strict: true,
4748
Callable: func(ctx *sql.Context, _ [4]*pgtypes.DoltgresType, val1, val2, val3 any) (any, error) {
48-
input := val1.(string)
49-
//oid := val2.(id.Id)
50-
//typmod := val3.(int32)
51-
// TODO: decode typmod to precision
52-
p := 6
49+
input := strings.TrimSpace(val1.(string))
50+
typmod := val3.(int32)
51+
if typmod == -1 {
52+
typmod = 6
53+
}
54+
precision := tree.TimeFamilyPrecisionToRoundDuration(typmod)
55+
if strings.EqualFold(input, "now") {
56+
t := ctx.QueryTime()
57+
t = t.Round(precision)
58+
return timetz.MakeTimeTZFromLocation(timeofday.New(t.Hour(), t.Minute(), t.Second(), t.Nanosecond()/1000), t.Location()), nil
59+
}
5360
loc, err := GetServerLocation(ctx)
5461
if err != nil {
5562
return nil, err
5663
}
57-
t, _, err := timetz.ParseTimeTZ(time.Now().In(loc), input, tree.TimeFamilyPrecisionToRoundDuration(int32(p)))
64+
t, _, err := timetz.ParseTimeTZ(time.Now().In(loc), input, precision)
5865
if err != nil {
5966
return nil, err
6067
}

testing/go/functions_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,27 @@ func TestArrayFunctions(t *testing.T) {
16711671
},
16721672
},
16731673
},
1674+
{
1675+
Name: "array_prepend",
1676+
Assertions: []ScriptTestAssertion{
1677+
{
1678+
Query: `SELECT array_prepend(NULL, NULL);`,
1679+
Expected: []sql.Row{{"{NULL}"}},
1680+
},
1681+
{
1682+
Query: `SELECT array_prepend(NULL, ARRAY[6]);`,
1683+
Expected: []sql.Row{{"{NULL,6}"}},
1684+
},
1685+
{
1686+
Query: `SELECT array_prepend(5, NULL);`,
1687+
Expected: []sql.Row{{"{5}"}},
1688+
},
1689+
{
1690+
Query: `SELECT array_prepend(5, ARRAY[6]);`,
1691+
Expected: []sql.Row{{"{5,6}"}},
1692+
},
1693+
},
1694+
},
16741695
})
16751696
}
16761697

@@ -3108,6 +3129,14 @@ func TestDateAndTimeFunction(t *testing.T) {
31083129
Query: `SELECT now()::timetz(4)::text = current_time(5)::text;`,
31093130
Expected: []sql.Row{{false}},
31103131
},
3132+
{
3133+
Query: `SELECT length('now'::timetz::text);`,
3134+
Expected: []sql.Row{{18}},
3135+
},
3136+
{
3137+
Query: `SELECT length('now'::time::text);`,
3138+
Expected: []sql.Row{{15}},
3139+
},
31113140
},
31123141
},
31133142
{

testing/go/issues_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,31 @@ limit 1`,
436436
},
437437
},
438438
},
439+
{
440+
Name: "Issue #2604",
441+
SetUpScript: []string{
442+
"CREATE TABLE t (id INT PRIMARY KEY, a TEXT, b TEXT DEFAULT 'x');",
443+
"CREATE UNIQUE INDEX idx_t_a ON t(a);",
444+
"SELECT dolt_add('-A');",
445+
"SELECT dolt_commit('-m', 'schema');",
446+
"SELECT dolt_branch('f', 'main');",
447+
"SELECT dolt_checkout('f');",
448+
"INSERT INTO t (id, a) VALUES (1, 'feat');",
449+
"SELECT dolt_add('-A');",
450+
"SELECT dolt_commit('-m', 'feat');",
451+
"SELECT dolt_checkout('main');",
452+
"INSERT INTO t (id, a) VALUES (2, 'main');",
453+
"SELECT dolt_add('-A');",
454+
"SELECT dolt_commit('-m', 'main');",
455+
"SELECT dolt_checkout('f');",
456+
},
457+
Assertions: []ScriptTestAssertion{
458+
{
459+
Query: "SELECT length(dolt_merge('main')::text) = 57;",
460+
Expected: []sql.Row{{"t"}},
461+
},
462+
},
463+
},
439464
})
440465
}
441466

0 commit comments

Comments
 (0)