Skip to content

Commit 60a7f34

Browse files
authored
Merge pull request #3222 from dolthub/angela/sqlmode
[no-release-notes] Clean up SQL modes
2 parents 59b34ad + 116026d commit 60a7f34

File tree

5 files changed

+65
-29
lines changed

5 files changed

+65
-29
lines changed

sql/analyzer/validation_rules.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ func validateGroupBy(ctx *sql.Context, a *Analyzer, n sql.Node, scope *plan.Scop
246246
defer span.End()
247247

248248
// only enforce strict group by when this variable is set
249-
if !sql.LoadSqlMode(ctx).ModeEnabled(sql.OnlyFullGroupBy) {
249+
if !sql.LoadSqlMode(ctx).OnlyFullGroupBy() {
250250
return n, transform.SameTree, nil
251251
}
252252

sql/sql_mode.go

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,31 @@ import (
2424
const (
2525
SqlModeSessionVar = "SQL_MODE"
2626

27-
ANSI = "ANSI"
28-
ANSIQuotes = "ANSI_QUOTES"
29-
OnlyFullGroupBy = "ONLY_FULL_GROUP_BY"
30-
NoAutoValueOnZero = "NO_AUTO_VALUE_ON_ZERO"
31-
NoEngineSubstitution = "NO_ENGINE_SUBSTITUTION"
32-
StrictTransTables = "STRICT_TRANS_TABLES"
33-
PipesAsConcat = "PIPES_AS_CONCAT"
34-
DefaultSqlMode = "NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES"
27+
AllowInvalidDates = "ALLOW_INVALID_DATES"
28+
ANSIQuotes = "ANSI_QUOTES"
29+
ErrorForDivisionByZero = "ERROR_FOR_DIVISION_BY_ZERO"
30+
HighNotPrecedence = "HIGH_NOT_PRECEDENCE"
31+
IgnoreSpaces = "IGNORE_SPACE"
32+
NoAutoValueOnZero = "NO_AUTO_VALUE_ON_ZERO"
33+
NoBackslashEscapes = "NO_BACKSLASH_ESCAPES"
34+
NoDirInCreate = "NO_DIR_IN_CREATE"
35+
NoEngineSubstitution = "NO_ENGINE_SUBSTITUTION"
36+
NoUnsignedSubtraction = "NO_UNSIGNED_SUBTRACTION"
37+
NoZeroInDate = "NO_ZERO_IN_DATE"
38+
OnlyFullGroupBy = "ONLY_FULL_GROUP_BY"
39+
PadCharToFullLength = "PAD_CHAR_TO_FULL_LENGTH"
40+
PipesAsConcat = "PIPES_AS_CONCAT"
41+
RealAsFloat = "REAL_AS_FLOAT"
42+
StrictTransTables = "STRICT_TRANS_TABLES"
43+
StrictAllTables = "STRICT_ALL_TABLES"
44+
TimeTruncateFractional = "TIME_TRUNCATE_FRACTIONAL"
45+
46+
// ANSI mode includes REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, and ONLY_FULL_GROUP_BY
47+
ANSI = "ANSI"
48+
// Traditional mode includes STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, ERROR_FOR_DIVISION_BY_ZERO,
49+
// and NO_ENGINE_SUBSTITUTION
50+
Traditional = "TRADITIONAL"
51+
DefaultSqlMode = "NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES"
3552
)
3653

3754
var defaultMode *SqlMode
@@ -74,7 +91,7 @@ func LoadSqlMode(ctx *Context) *SqlMode {
7491
}
7592

7693
// NewSqlModeFromString returns a new SqlMode instance, constructed from the specified |sqlModeString| that
77-
// has a comma delimited list of SQL modes (e.g. "ONLY_FULLY_GROUP_BY,ANSI_QUOTES").
94+
// has a comma-delimited list of SQL modes (e.g. "ONLY_FULLY_GROUP_BY,ANSI_QUOTES").
7895
func NewSqlModeFromString(sqlModeString string) *SqlMode {
7996
if sqlModeString == DefaultSqlMode {
8097
return defaultMode
@@ -99,9 +116,36 @@ func (s *SqlMode) AnsiQuotes() bool {
99116
return s.ModeEnabled(ANSIQuotes) || s.ModeEnabled(ANSI)
100117
}
101118

102-
// PipesAsConcat returns true if PIPES_AS_CONCAT SQL mode is enabled.
119+
// OnlyFullGroupBy returns true is ONLY_TRUE_GROUP_BY SQL mode is enabled. Note that ANSI mode is a compound mode that
120+
// includes ONLY_FULL_GROUP_BY and other options, so if ANSI or ONLY_TRUE_GROUP_BY is enabled, this function will
121+
// return true.
122+
func (s *SqlMode) OnlyFullGroupBy() bool {
123+
return s.ModeEnabled(OnlyFullGroupBy) || s.ModeEnabled(ANSI)
124+
}
125+
126+
// PipesAsConcat returns true if PIPES_AS_CONCAT SQL mode is enabled. Note that ANSI mode is a compound mode that
127+
// includes PIPES_AS_CONCAT and other options, so if ANSI or PIPES_AS_CONCAT is enabled, this function will return true.
103128
func (s *SqlMode) PipesAsConcat() bool {
104-
return s.ModeEnabled(PipesAsConcat)
129+
return s.ModeEnabled(PipesAsConcat) || s.ModeEnabled(ANSI)
130+
}
131+
132+
// StrictTransTables returns true if STRICT_TRANS_TABLES SQL mode is enabled. Note that TRADITIONAL mode is a compound
133+
// mode that includes STRICT_TRANS_TABLES and other options, so if TRADITIONAL or STRICT_TRANS_TABLES is enabled, this
134+
// function will return true.
135+
func (s *SqlMode) StrictTransTables() bool {
136+
return s.ModeEnabled(StrictTransTables) || s.ModeEnabled(Traditional)
137+
}
138+
139+
// StrictAllTables returns true if STRICT_ALL_TABLES SQL mode is enabled. Note that TRADITIONAL mode is a compound
140+
// mode that includes STRICT_ALL_TABLES and other options, so if TRADITIONAL or STRICT_ALL_TABLES is enabled, this
141+
// function will return true.
142+
func (s *SqlMode) StrictAllTables() bool {
143+
return s.ModeEnabled(StrictAllTables) || s.ModeEnabled(Traditional)
144+
}
145+
146+
// Strict mode is enabled when either STRICT_TRANS_TABLES or STRICT_ALL_TABLES is enabled.
147+
func (s *SqlMode) Strict() bool {
148+
return s.StrictAllTables() || s.StrictTransTables()
105149
}
106150

107151
// ModeEnabled returns true if |mode| was explicitly specified in the SQL_MODE string that was used to
@@ -126,12 +170,3 @@ func (s *SqlMode) ParserOptions() sqlparser.ParserOptions {
126170
func (s *SqlMode) String() string {
127171
return s.modeString
128172
}
129-
130-
// ValidateStrictMode returns true if either STRICT_TRANS_TABLES or STRICT_ALL_TABLES is enabled
131-
func ValidateStrictMode(ctx *Context) bool {
132-
if ctx == nil {
133-
return false
134-
}
135-
sqlMode := LoadSqlMode(ctx)
136-
return sqlMode.ModeEnabled("STRICT_TRANS_TABLES") || sqlMode.ModeEnabled("STRICT_ALL_TABLES")
137-
}

sql/sql_mode_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ import (
2121
)
2222

2323
func TestSqlMode(t *testing.T) {
24-
// Test that ANSI mode includes ANSI_QUOTES mode
25-
sqlMode := NewSqlModeFromString("only_full_group_by,ansi")
24+
// Test that ANSI mode includes ANSI_QUOTES, PIPES_AS_CONCAT, and ONLY_FULL_GROUP_BY mode
25+
sqlMode := NewSqlModeFromString("ansi")
2626
assert.True(t, sqlMode.AnsiQuotes())
2727
assert.True(t, sqlMode.ModeEnabled("ansi"))
2828
assert.True(t, sqlMode.ModeEnabled("ANSI"))
29-
assert.True(t, sqlMode.ModeEnabled("ONLY_FULL_GROUP_BY"))
3029
assert.False(t, sqlMode.ModeEnabled("fake_mode"))
3130
assert.True(t, sqlMode.ParserOptions().AnsiQuotes)
32-
assert.Equal(t, "ANSI,ONLY_FULL_GROUP_BY", sqlMode.String())
33-
assert.False(t, sqlMode.PipesAsConcat())
31+
assert.Equal(t, "ANSI", sqlMode.String())
32+
assert.True(t, sqlMode.PipesAsConcat()) // PIPES_AS_CONCAT is included in ANSI mode
33+
assert.True(t, sqlMode.OnlyFullGroupBy()) // ONLY_FULL_GROUP_BY is included in ANSI mode
3434
assert.False(t, sqlMode.ModeEnabled("pipes_as_concat"))
3535

3636
// Test a mixed case SQL_MODE string where only ANSI_QUOTES is enabled
@@ -44,13 +44,14 @@ func TestSqlMode(t *testing.T) {
4444
assert.False(t, sqlMode.PipesAsConcat())
4545
assert.False(t, sqlMode.ModeEnabled("pipes_as_concat"))
4646

47-
// Test when SQL_MODE does not include ANSI_QUOTES, includes PIPES_AS_CONCAT
47+
// Test when SQL_MODE does not include ANSI_QUOTES, includes PIPES_AS_CONCAT and STRICT_TRANS_TABLES
4848
sqlMode = NewSqlModeFromString("ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,PIPES_AS_CONCAT")
4949
assert.False(t, sqlMode.AnsiQuotes())
5050
assert.True(t, sqlMode.ModeEnabled("STRICT_TRANS_TABLES"))
5151
assert.False(t, sqlMode.ModeEnabled("ansi_quotes"))
5252
assert.False(t, sqlMode.ParserOptions().AnsiQuotes)
5353
assert.True(t, sqlMode.PipesAsConcat())
5454
assert.True(t, sqlMode.ModeEnabled("pipes_as_concat"))
55+
assert.True(t, sqlMode.Strict())
5556
assert.Equal(t, "ONLY_FULL_GROUP_BY,PIPES_AS_CONCAT,STRICT_TRANS_TABLES", sqlMode.String())
5657
}

sql/types/enum.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func (t EnumType) Convert(ctx context.Context, v interface{}) (interface{}, sql.
167167
case int:
168168
// MySQL rejects 0 values in strict mode regardless of enum definition
169169
if value == 0 {
170-
if sqlCtx, ok := ctx.(*sql.Context); ok && sql.ValidateStrictMode(sqlCtx) {
170+
if sqlCtx, ok := ctx.(*sql.Context); ok && sql.LoadSqlMode(sqlCtx).Strict() {
171171
return nil, sql.OutOfRange, ErrConvertingToEnum.New(value)
172172
}
173173
}

sql/types/strings.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ func ConvertToBytes(ctx context.Context, v interface{}, t sql.StringType, dest [
502502
if !IsBinaryType(t) && !utf8.Valid(bytesVal) {
503503
charset := t.CharacterSet()
504504
if charset == sql.CharacterSet_utf8mb4 {
505-
if sqlCtx, ok := ctx.(*sql.Context); ok && sql.ValidateStrictMode(sqlCtx) {
505+
if sqlCtx, ok := ctx.(*sql.Context); ok && sql.LoadSqlMode(sqlCtx).Strict() {
506506
// Strict mode: reject invalid UTF8
507507
invalidByte := formatInvalidByteForError(bytesVal)
508508
colName, rowNum := getColumnContext(ctx)

0 commit comments

Comments
 (0)