Skip to content

Commit 30951fc

Browse files
authored
Merge pull request #1826 from dolthub/jennifer/datestyle
support datestyle parameter use
2 parents 280c0de + 1dc3e8d commit 30951fc

File tree

14 files changed

+348
-44
lines changed

14 files changed

+348
-44
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ require (
99
github.com/dolthub/dolt/go v0.40.5-0.20250916084833-f121f4db6fdd
1010
github.com/dolthub/eventsapi_schema v0.0.0-20250915094920-eadfd39051ca
1111
github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2
12-
github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790
13-
github.com/dolthub/go-mysql-server v0.20.1-0.20250916073142-59b34ad42ad7
12+
github.com/dolthub/go-mysql-server v0.20.1-0.20250916214234-32c0ab73f498
1413
github.com/dolthub/sqllogictest/go v0.0.0-20240618184124-ca47f9354216
1514
github.com/dolthub/vitess v0.0.0-20250915221346-753c44800850
1615
github.com/fatih/color v1.13.0
@@ -99,6 +98,7 @@ require (
9998
github.com/dolthub/aws-sdk-go-ini-parser v0.0.0-20250305001723-2821c37f6c12 // indirect
10099
github.com/dolthub/dolt-mcp v0.2.1-0.20250827202412-9d0f6e658fba // indirect
101100
github.com/dolthub/fslock v0.0.3 // indirect
101+
github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 // indirect
102102
github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63 // indirect
103103
github.com/dolthub/ishell v0.0.0-20240701202509-2b217167d718 // indirect
104104
github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ github.com/dolthub/fslock v0.0.3 h1:iLMpUIvJKMKm92+N1fmHVdxJP5NdyDK5bK7z7Ba2s2U=
258258
github.com/dolthub/fslock v0.0.3/go.mod h1:QWql+P17oAAMLnL4HGB5tiovtDuAjdDTPbuqx7bYfa0=
259259
github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 h1:zxMsH7RLiG+dlZ/y0LgJHTV26XoiSJcuWq+em6t6VVc=
260260
github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE=
261-
github.com/dolthub/go-mysql-server v0.20.1-0.20250916073142-59b34ad42ad7 h1:VgmY6t806cVmFRZ5YcE5awJ8YW2opk1roQhjm5Bx260=
262-
github.com/dolthub/go-mysql-server v0.20.1-0.20250916073142-59b34ad42ad7/go.mod h1:fkgI5RU7ABC5gknW+5Q6LUMv12Y2zlkXuDQX7n7su88=
261+
github.com/dolthub/go-mysql-server v0.20.1-0.20250916214234-32c0ab73f498 h1:XaYtlmLwSa6PwWzKQBvXi8TVIEaOsRyryAq17tT48fQ=
262+
github.com/dolthub/go-mysql-server v0.20.1-0.20250916214234-32c0ab73f498/go.mod h1:fkgI5RU7ABC5gknW+5Q6LUMv12Y2zlkXuDQX7n7su88=
263263
github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63 h1:OAsXLAPL4du6tfbBgK0xXHZkOlos63RdKYS3Sgw/dfI=
264264
github.com/dolthub/gozstd v0.0.0-20240423170813-23a2903bca63/go.mod h1:lV7lUeuDhH5thVGDCKXbatwKy2KW80L4rMT46n+Y2/Q=
265265
github.com/dolthub/ishell v0.0.0-20240701202509-2b217167d718 h1:lT7hE5k+0nkBdj/1UOSFwjWpNxf+LCApbRHgnCA17XE=

server/cast/timestamp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func timestampAssignment() {
4444
FromType: pgtypes.Timestamp,
4545
ToType: pgtypes.Time,
4646
Function: func(ctx *sql.Context, val any, targetType *pgtypes.DoltgresType) (any, error) {
47-
return timeofday.FromTime(val.(time.Time)), nil
47+
return timeofday.FromTime(val.(time.Time)).ToTime(), nil
4848
},
4949
})
5050
}

server/cast/timestamptz.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func timestampTZAssignment() {
4444
FromType: pgtypes.TimestampTZ,
4545
ToType: pgtypes.Time,
4646
Function: func(ctx *sql.Context, val any, targetType *pgtypes.DoltgresType) (any, error) {
47-
return timeofday.FromTime(val.(time.Time)), nil
47+
return timeofday.FromTime(val.(time.Time)).ToTime(), nil
4848
},
4949
})
5050
framework.MustAddAssignmentTypeCast(framework.TypeCast{

server/config/parameters.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ type Parameter struct {
7070
Source ParameterSource
7171
ResetVal any
7272
Scope sql.SystemVariableScope
73-
ValidateFunc func(any) (any, bool)
73+
ValidateFunc func(currVal, newVal any) (any, bool)
7474
}
7575

7676
// GetName implements sql.SystemVariable.
@@ -90,7 +90,9 @@ func (p *Parameter) GetSessionScope() sql.SystemVariableScope {
9090

9191
// SetDefault implements sql.SystemVariable.
9292
func (p *Parameter) SetDefault(a any) {
93-
p.Default = a
93+
if validatedVal, ok := p.ValidateFunc(p.Default, a); ok {
94+
p.Default = validatedVal
95+
}
9496
}
9597

9698
// GetDefault implements sql.SystemVariable.
@@ -104,8 +106,12 @@ func (p *Parameter) InitValue(ctx *sql.Context, val any, global bool) (sql.Syste
104106
if err != nil {
105107
return sql.SystemVarValue{}, err
106108
}
109+
currVal, err := ctx.GetSessionVariable(ctx, p.Name)
110+
if err != nil {
111+
return sql.SystemVarValue{}, err
112+
}
107113
if p.ValidateFunc != nil {
108-
v, ok := p.ValidateFunc(convertedVal)
114+
v, ok := p.ValidateFunc(currVal, convertedVal)
109115
if !ok {
110116
return sql.SystemVarValue{}, ErrInvalidValue.New(p.Name, convertedVal)
111117
}

server/config/parameters_list.go

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

1717
import (
18+
"fmt"
1819
"math"
1920
"strings"
2021
"time"
@@ -699,6 +700,79 @@ var postgresConfigParameters = map[string]sql.SystemVariable{
699700
ResetVal: "ISO, MDY",
700701
// Sourcefile: postgresql.conf
701702
Scope: GetPgsqlScope(PsqlScopeSession),
703+
ValidateFunc: func(curr, new any) (any, bool) {
704+
ds := "ISO"
705+
do := "MDY"
706+
if oldVal, ok := curr.(string); ok {
707+
currentVal := strings.Split(strings.ReplaceAll(oldVal, " ", ""), ",")
708+
if len(currentVal) == 2 {
709+
// the first must be date style and second must be date ordering
710+
ds = currentVal[0]
711+
do = currentVal[1]
712+
}
713+
}
714+
newVal, ok := new.(string)
715+
if !ok {
716+
return "", false
717+
}
718+
719+
var dsSet, doSet bool
720+
values := strings.Split(strings.ReplaceAll(strings.ToLower(newVal), " ", ""), ",")
721+
for _, value := range values {
722+
switch value {
723+
case "iso":
724+
if dsSet {
725+
return "", false
726+
}
727+
ds = "ISO"
728+
dsSet = true
729+
case "sql":
730+
if dsSet {
731+
return "", false
732+
}
733+
ds = "SQL"
734+
dsSet = true
735+
case "postgres":
736+
if dsSet {
737+
return "", false
738+
}
739+
ds = "Postgres"
740+
dsSet = true
741+
case "german":
742+
if dsSet {
743+
return "", false
744+
}
745+
ds = "German"
746+
dsSet = true
747+
if !doSet {
748+
do = "DMY"
749+
}
750+
case "us", "noneuropean", "mdy":
751+
// MDY
752+
if doSet {
753+
return "", false
754+
}
755+
do = "MDY"
756+
doSet = true
757+
case "european", "dmy":
758+
// DMY
759+
if doSet {
760+
return "", false
761+
}
762+
do = "DMY"
763+
doSet = true
764+
case "ymd":
765+
if doSet {
766+
return "", false
767+
}
768+
do = "YMD"
769+
doSet = true
770+
default:
771+
return "", false
772+
}
773+
}
774+
return fmt.Sprintf(`%s, %s`, ds, do), true
775+
},
702776
},
703777
"db_user_namespace": &Parameter{
704778
Name: "db_user_namespace",
@@ -3464,8 +3538,8 @@ var postgresConfigParameters = map[string]sql.SystemVariable{
34643538
// BootVal: "GMT",
34653539
ResetVal: "America/Los_Angeles",
34663540
Scope: GetPgsqlScope(PsqlScopeSession),
3467-
ValidateFunc: func(a any) (any, bool) {
3468-
switch v := a.(type) {
3541+
ValidateFunc: func(_, new any) (any, bool) {
3542+
switch v := new.(type) {
34693543
case string:
34703544
if strings.ToLower(v) == "local" {
34713545
// TODO: fix this
@@ -3486,7 +3560,7 @@ var postgresConfigParameters = map[string]sql.SystemVariable{
34863560
return nil, false
34873561
}
34883562
}
3489-
return a, true
3563+
return new, true
34903564
},
34913565
},
34923566
"timezone_abbreviations": &Parameter{

server/connection_handler.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ func (h *ConnectionHandler) handleStartup() (bool, error) {
225225
if err = h.sendClientStartupMessages(); err != nil {
226226
return false, err
227227
}
228-
if err = h.chooseInitialDatabase(sm); err != nil {
228+
if err = h.chooseInitialParameters(sm); err != nil {
229229
return false, err
230230
}
231231
return true, h.send(&pgproto3.ReadyForQuery{
@@ -282,9 +282,20 @@ func (h *ConnectionHandler) sendClientStartupMessages() error {
282282
})
283283
}
284284

285-
// chooseInitialDatabase attempts to choose the initial database for the connection,
286-
// if one is specified in the startup message provided
287-
func (h *ConnectionHandler) chooseInitialDatabase(startupMessage *pgproto3.StartupMessage) error {
285+
// chooseInitialParameters attempts to choose the initial parameter settings for the connection,
286+
// if one is specified in the startup message provided.
287+
func (h *ConnectionHandler) chooseInitialParameters(startupMessage *pgproto3.StartupMessage) error {
288+
for name, value := range startupMessage.Parameters {
289+
// TODO: handle other parameters defined in StartupMessage
290+
switch strings.ToLower(name) {
291+
case "datestyle":
292+
err := h.doltgresHandler.InitSessionParameterDefault(context.Background(), h.mysqlConn, "DateStyle", value)
293+
if err != nil {
294+
return err
295+
}
296+
}
297+
}
298+
// set initial database
288299
db, ok := startupMessage.Parameters["database"]
289300
dbSpecified := ok && len(db) > 0
290301
if !dbSpecified {

server/doltgres_handler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@ func (h *DoltgresHandler) NewContext(ctx context.Context, c *mysql.Conn, query s
259259
return h.sm.NewContextWithQuery(ctx, c, query)
260260
}
261261

262+
// InitSessionParameterDefault sets a default value to specified parameter for a session.
263+
func (h *DoltgresHandler) InitSessionParameterDefault(ctx context.Context, c *mysql.Conn, name, value string) error {
264+
return h.sm.InitSessionDefaultVariable(ctx, c, name, value)
265+
}
266+
262267
// convertBindParameters handles the conversion from bind parameters to variable values.
263268
func (h *DoltgresHandler) convertBindParameters(ctx *sql.Context, types []uint32, formatCodes []int16, values [][]byte) (map[string]sqlparser.Expr, error) {
264269
bindings := make(map[string]sqlparser.Expr, len(values))

server/functions/date.go

Lines changed: 50 additions & 9 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"
@@ -41,15 +42,16 @@ var date_in = framework.Function1{
4142
Strict: true,
4243
Callable: func(ctx *sql.Context, _ [2]*pgtypes.DoltgresType, val any) (any, error) {
4344
input := val.(string)
44-
if date, _, err := pgdate.ParseDate(time.Now(), pgdate.ParseModeYMD, input); err == nil {
45-
return date.ToTime()
46-
} else if date, _, err = pgdate.ParseDate(time.Now(), pgdate.ParseModeDMY, input); err == nil {
47-
return date.ToTime()
48-
} else if date, _, err = pgdate.ParseDate(time.Now(), pgdate.ParseModeMDY, input); err == nil {
49-
return date.ToTime()
50-
} else {
51-
return nil, err
45+
formatsInOrder := getDateStyleInputFormat(ctx)
46+
var date pgdate.Date
47+
var err error
48+
for _, format := range formatsInOrder {
49+
date, _, err = pgdate.ParseDate(time.Now(), format, input)
50+
if err == nil {
51+
return date.ToTime()
52+
}
5253
}
54+
return nil, err
5355
},
5456
}
5557

@@ -60,7 +62,7 @@ var date_out = framework.Function1{
6062
Parameters: [1]*pgtypes.DoltgresType{pgtypes.Date},
6163
Strict: true,
6264
Callable: func(ctx *sql.Context, _ [2]*pgtypes.DoltgresType, val any) (any, error) {
63-
return FormatDateTimeWithBC(val.(time.Time), "2006-01-02", false), nil
65+
return FormatDateTimeWithBC(val.(time.Time), getLayoutStringFormat(ctx, true), false), nil
6466
},
6567
}
6668

@@ -106,3 +108,42 @@ var date_cmp = framework.Function2{
106108
return int32(ab.Compare(bb)), nil
107109
},
108110
}
111+
112+
// getDateStyleInputFormat sets the defined format in DateStyle config as the first in the ordered list of date parsing modes.
113+
// TODO: this or something similar should be used in postgres/parser/sem/tree/datum.go when parsing timestamp/timestamptz/date values.
114+
func getDateStyleInputFormat(ctx *sql.Context) []pgdate.ParseMode {
115+
formatsInOrder := []pgdate.ParseMode{pgdate.ParseModeMDY, pgdate.ParseModeDMY, pgdate.ParseModeYMD} // default
116+
if ctx == nil {
117+
return formatsInOrder
118+
}
119+
val, err := ctx.GetSessionVariable(ctx, "datestyle")
120+
if err != nil {
121+
return formatsInOrder
122+
}
123+
124+
ds := strings.ReplaceAll(val.(string), " ", "")
125+
values := strings.Split(ds, ",")
126+
setFormat := pgdate.ParseModeYMD
127+
for _, value := range values {
128+
switch value {
129+
case "MDY":
130+
setFormat = pgdate.ParseModeMDY
131+
case "DMY":
132+
setFormat = pgdate.ParseModeDMY
133+
case "YMD":
134+
setFormat = pgdate.ParseModeYMD
135+
}
136+
}
137+
if setFormat == formatsInOrder[0] {
138+
return formatsInOrder
139+
}
140+
141+
curFirst := formatsInOrder[0]
142+
for i, f := range formatsInOrder {
143+
if setFormat == f {
144+
formatsInOrder[i] = curFirst
145+
}
146+
}
147+
formatsInOrder[0] = setFormat
148+
return formatsInOrder
149+
}

0 commit comments

Comments
 (0)