Skip to content

Commit

Permalink
Merge pull request #6465 from dolthub/fulghum/ansi_quotes
Browse files Browse the repository at this point in the history
`ANSI_QUOTES` support
  • Loading branch information
fulghum authored Aug 16, 2023
2 parents 59033c5 + 09f1c00 commit 4beaf52
Show file tree
Hide file tree
Showing 23 changed files with 480 additions and 33 deletions.
98 changes: 97 additions & 1 deletion go/cmd/dolt/commands/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ func dumpProcedures(sqlCtx *sql.Context, engine *engine.SqlEngine, root *doltdb.
}

stmtColIdx := sch.IndexOfColName(doltdb.ProceduresTableCreateStmtCol)
sqlModeIdx := sch.IndexOfColName(doltdb.ProceduresTableSqlModeCol)

defer func(iter sql.RowIter, context *sql.Context) {
err := iter.Close(context)
Expand All @@ -285,6 +286,18 @@ func dumpProcedures(sqlCtx *sql.Context, engine *engine.SqlEngine, root *doltdb.
return err
}

sqlMode := ""
if len(row) >= sqlModeIdx {
if s, ok := row[sqlModeIdx].(string); ok {
sqlMode = s
}
}

modeChanged, err := changeSqlMode(sqlCtx, writer, sqlMode)
if err != nil {
return err
}

err = iohelp.WriteLine(writer, "delimiter END_PROCEDURE")
if err != nil {
return err
Expand All @@ -299,6 +312,12 @@ func dumpProcedures(sqlCtx *sql.Context, engine *engine.SqlEngine, root *doltdb.
if err != nil {
return err
}

if modeChanged {
if err := resetSqlMode(writer); err != nil {
return err
}
}
}

return nil
Expand All @@ -321,6 +340,7 @@ func dumpTriggers(sqlCtx *sql.Context, engine *engine.SqlEngine, root *doltdb.Ro

typeColIdx := sch.IndexOfColName(doltdb.SchemasTablesTypeCol)
fragColIdx := sch.IndexOfColName(doltdb.SchemasTablesFragmentCol)
sqlModeIdx := sch.IndexOfColName(doltdb.SchemasTablesSqlModeCol)

defer func(iter sql.RowIter, context *sql.Context) {
err := iter.Close(context)
Expand All @@ -341,10 +361,26 @@ func dumpTriggers(sqlCtx *sql.Context, engine *engine.SqlEngine, root *doltdb.Ro
continue
}

sqlMode := ""
if s, ok := row[sqlModeIdx].(string); ok {
sqlMode = s
}

modeChanged, err := changeSqlMode(sqlCtx, writer, sqlMode)
if err != nil {
return err
}

err = iohelp.WriteLine(writer, fmt.Sprintf("%s;", row[fragColIdx]))
if err != nil {
return err
}

if modeChanged {
if err := resetSqlMode(writer); err != nil {
return err
}
}
}

return nil
Expand All @@ -368,6 +404,7 @@ func dumpViews(ctx *sql.Context, engine *engine.SqlEngine, root *doltdb.RootValu
typeColIdx := sch.IndexOfColName(doltdb.SchemasTablesTypeCol)
fragColIdx := sch.IndexOfColName(doltdb.SchemasTablesFragmentCol)
nameColIdx := sch.IndexOfColName(doltdb.SchemasTablesNameCol)
sqlModeIdx := sch.IndexOfColName(doltdb.SchemasTablesSqlModeCol)

defer func(iter sql.RowIter, context *sql.Context) {
err := iter.Close(context)
Expand All @@ -388,8 +425,18 @@ func dumpViews(ctx *sql.Context, engine *engine.SqlEngine, root *doltdb.RootValu
continue
}

sqlMode := ""
if s, ok := row[sqlModeIdx].(string); ok {
sqlMode = s
}

// We used to store just the SELECT part of a view, but now we store the entire CREATE VIEW statement
cv, err := parse.Parse(ctx, row[fragColIdx].(string))
cv, err := parse.ParseWithOptions(ctx, row[fragColIdx].(string), sql.NewSqlModeFromString(sqlMode).ParserOptions())
if err != nil {
return err
}

modeChanged, err := changeSqlMode(ctx, writer, sqlMode)
if err != nil {
return err
}
Expand All @@ -406,11 +453,60 @@ func dumpViews(ctx *sql.Context, engine *engine.SqlEngine, root *doltdb.RootValu
return err
}
}

if modeChanged {
if err := resetSqlMode(writer); err != nil {
return err
}
}
}

return nil
}

// changeSqlMode checks if the current SQL session's @@SQL_MODE is different from the requested |newSqlMode| and if so,
// outputs a SQL statement to |writer| to save the current @@SQL_MODE to the @previousSqlMode variable and then outputs
// a SQL statement to set the @@SQL_MODE to |sqlMode|. If |newSqlMode| is the identical to the current session's
// SQL_MODE (the default, global @@SQL_MODE), then no statements are written to |writer|. The boolean return code
// indicates if any statements were written.
func changeSqlMode(ctx *sql.Context, writer io.WriteCloser, newSqlMode string) (bool, error) {
if newSqlMode == "" {
return false, nil
}

variable, err := ctx.Session.GetSessionVariable(ctx, "SQL_MODE")
if err != nil {
return false, err
}
currentSqlMode, ok := variable.(string)
if !ok {
return false, fmt.Errorf("unable to read @@SQL_MODE system variable from value '%v'", currentSqlMode)
}

if currentSqlMode == newSqlMode {
return false, nil
}

err = iohelp.WriteLine(writer, "SET @previousSqlMode=@@SQL_MODE;")
if err != nil {
return false, err
}

err = iohelp.WriteLine(writer, fmt.Sprintf("SET @@SQL_MODE='%s';", newSqlMode))
if err != nil {
return false, err
}

return true, nil
}

// resetSqlMode outputs a SQL statement to |writer| to reset @@SQL_MODE back to the previous value stored
// by the last call to changeSqlMode. This function should only be called after changeSqlMode, otherwise the
// @previousSqlMode variable will not be set correctly.
func resetSqlMode(writer io.WriteCloser) error {
return iohelp.WriteLine(writer, "SET @@SQL_MODE=@previousSqlMode;")
}

type dumpOptions struct {
format string
schemaOnly bool
Expand Down
8 changes: 7 additions & 1 deletion go/cmd/dolt/commands/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,13 @@ func execBatchMode(ctx *sql.Context, qryist cli.Queryist, input io.Reader, conti
if len(query) == 0 || query == "\n" {
continue
}
sqlStatement, err := sqlparser.Parse(query)

sqlMode, err := sql.LoadSqlMode(ctx)
if err != nil {
return err
}

sqlStatement, err := sqlparser.ParseWithOptions(query, sqlMode.ParserOptions())
if err == sqlparser.ErrEmpty {
continue
} else if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ require (
github.com/cespare/xxhash v1.1.0
github.com/creasty/defaults v1.6.0
github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2
github.com/dolthub/go-mysql-server v0.16.1-0.20230815214024-88f41939e598
github.com/dolthub/go-mysql-server v0.16.1-0.20230815232241-704a2c0709d3
github.com/dolthub/swiss v0.1.0
github.com/goccy/go-json v0.10.2
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
Expand Down
6 changes: 4 additions & 2 deletions go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,10 @@ github.com/dolthub/fslock v0.0.3 h1:iLMpUIvJKMKm92+N1fmHVdxJP5NdyDK5bK7z7Ba2s2U=
github.com/dolthub/fslock v0.0.3/go.mod h1:QWql+P17oAAMLnL4HGB5tiovtDuAjdDTPbuqx7bYfa0=
github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e h1:kPsT4a47cw1+y/N5SSCkma7FhAPw7KeGmD6c9PBZW9Y=
github.com/dolthub/go-icu-regex v0.0.0-20230524105445-af7e7991c97e/go.mod h1:KPUcpx070QOfJK1gNe0zx4pA5sicIK1GMikIGLKC168=
github.com/dolthub/go-mysql-server v0.16.1-0.20230815214024-88f41939e598 h1:H/Q3ljiLmVjw0eoIJNsy/agKwzOBniSKuWNgxFziDVk=
github.com/dolthub/go-mysql-server v0.16.1-0.20230815214024-88f41939e598/go.mod h1:wK9co8FTJEstDv35ITVgCjYVqqBoN5MlDyVMsNCoWaw=
github.com/dolthub/go-mysql-server v0.16.1-0.20230807211358-5b6031f113ba h1:ImvGNMKqAA+KPH5rXTR1xmOVQYv9XC7p6AjX8RhkWMU=
github.com/dolthub/go-mysql-server v0.16.1-0.20230807211358-5b6031f113ba/go.mod h1:nY1J1sV2kuGJbAZ6bcZARw4dF8TD3KpEfYVVs/HK/JY=
github.com/dolthub/go-mysql-server v0.16.1-0.20230815232241-704a2c0709d3 h1:2puC5sgRHTdWapYMn4WrSH06/qq8Qfw1wW84eWHvC1Q=
github.com/dolthub/go-mysql-server v0.16.1-0.20230815232241-704a2c0709d3/go.mod h1:wK9co8FTJEstDv35ITVgCjYVqqBoN5MlDyVMsNCoWaw=
github.com/dolthub/ishell v0.0.0-20221214210346-d7db0b066488 h1:0HHu0GWJH0N6a6keStrHhUAK5/o9LVfkh44pvsV4514=
github.com/dolthub/ishell v0.0.0-20221214210346-d7db0b066488/go.mod h1:ehexgi1mPxRTk0Mok/pADALuHbvATulTh6gzr7NzZto=
github.com/dolthub/jsonpath v0.0.2-0.20230525180605-8dc13778fd72 h1:NfWmngMi1CYUWU4Ix8wM+USEhjc+mhPlT9JUR/anvbQ=
Expand Down
2 changes: 1 addition & 1 deletion go/libraries/doltcore/doltdb/root_val.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type FeatureVersion int64

// DoltFeatureVersion is described in feature_version.md.
// only variable for testing.
var DoltFeatureVersion FeatureVersion = 3 // last bumped when storing creation time for triggers
var DoltFeatureVersion FeatureVersion = 4 // last bumped when adding sql_mode column to dolt_schemas

// RootValue is the value of the Database and is the committed value in every Dolt commit.
type RootValue struct {
Expand Down
8 changes: 6 additions & 2 deletions go/libraries/doltcore/doltdb/system_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,9 @@ const (
// SchemasTablesExtraCol The name of the column that stores extra information about a schema element in the
// dolt_schemas table
SchemasTablesExtraCol = "extra"
//
SchemasTablesIndexName = "fragment_name"
// SchemasTablesSqlModeCol is the name of the column that stores the SQL_MODE string used when this fragment
// was originally defined. Mode settings, such as ANSI_QUOTES, are needed to correctly parse the fragment.
SchemasTablesSqlModeCol = "sql_mode"
)

const (
Expand Down Expand Up @@ -330,4 +331,7 @@ const (
ProceduresTableCreatedAtCol = "created_at"
// ProceduresTableModifiedAtCol is the time that the stored procedure was last modified, in UTC.
ProceduresTableModifiedAtCol = "modified_at"
// ProceduresTableSqlModeCol is the name of the column that stores the SQL_MODE string used when this fragment
// was originally defined. Mode settings, such as ANSI_QUOTES, are needed to correctly parse the fragment.
ProceduresTableSqlModeCol = "sql_mode"
)
2 changes: 2 additions & 0 deletions go/libraries/doltcore/schema/reserved_tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const (
DoltSchemasNameTag
DoltSchemasFragmentTag
DoltSchemasExtraTag
DoltSchemasSqlModeTag
)

// Tags for hidden columns in keyless rows
Expand All @@ -93,6 +94,7 @@ const (
DoltProceduresCreateStmtTag
DoltProceduresCreatedAtTag
DoltProceduresModifiedAtTag
DoltProceduresSqlModeTag
)

const (
Expand Down
16 changes: 13 additions & 3 deletions go/libraries/doltcore/sqle/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -1152,14 +1152,16 @@ func getViewDefinitionFromSchemaFragmentsOfView(ctx *sql.Context, tbl *WritableD
var viewDef sql.ViewDefinition
var views = make([]sql.ViewDefinition, len(fragments))
for i, fragment := range fragments {
cv, err := parse.Parse(ctx, fragments[i].fragment)
cv, err := parse.ParseWithOptions(ctx, fragments[i].fragment,
sql.NewSqlModeFromString(fragment.sqlMode).ParserOptions())
if err != nil {
return nil, sql.ViewDefinition{}, false, err
}

createView, ok := cv.(*plan.CreateView)
if ok {
views[i] = sql.ViewDefinition{Name: fragments[i].name, TextDefinition: createView.Definition.TextDefinition, CreateViewStatement: fragments[i].fragment}
views[i] = sql.ViewDefinition{Name: fragments[i].name, TextDefinition: createView.Definition.TextDefinition,
CreateViewStatement: fragments[i].fragment, SqlMode: fragment.sqlMode}
} else {
views[i] = sql.ViewDefinition{Name: fragments[i].name, TextDefinition: fragments[i].fragment, CreateViewStatement: fmt.Sprintf("CREATE VIEW %s AS %s", fragments[i].name, fragments[i].fragment)}
}
Expand Down Expand Up @@ -1228,6 +1230,7 @@ func (db Database) GetTriggers(ctx *sql.Context) ([]sql.TriggerDefinition, error
Name: frag.name,
CreateStatement: frag.fragment,
CreatedAt: frag.created,
SqlMode: frag.sqlMode,
})
}
if err != nil {
Expand Down Expand Up @@ -1275,6 +1278,7 @@ func (db Database) GetEvent(ctx *sql.Context, name string) (sql.EventDefinition,
Name: frag.name,
CreateStatement: frag.fragment,
CreatedAt: frag.created,
SqlMode: frag.sqlMode,
}, true, nil
}
}
Expand Down Expand Up @@ -1302,6 +1306,7 @@ func (db Database) GetEvents(ctx *sql.Context) ([]sql.EventDefinition, error) {
Name: frag.name,
CreateStatement: frag.fragment,
CreatedAt: frag.created,
SqlMode: frag.sqlMode,
})
}
return events, nil
Expand Down Expand Up @@ -1400,7 +1405,12 @@ func (db Database) addFragToSchemasTable(ctx *sql.Context, fragType, name, defin
return err
}

return inserter.Insert(ctx, sql.Row{fragType, name, definition, extraJSON})
sqlMode, err := sql.LoadSqlMode(ctx)
if err != nil {
return err
}

return inserter.Insert(ctx, sql.Row{fragType, name, definition, extraJSON, sqlMode.String()})
}

func (db Database) dropFragFromSchemasTable(ctx *sql.Context, fragType, name string, missingErr error) error {
Expand Down
8 changes: 8 additions & 0 deletions go/libraries/doltcore/sqle/enginetest/dolt_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,14 @@ func TestVersionedQueries(t *testing.T) {
enginetest.TestVersionedQueries(t, h)
}

func TestAnsiQuotesSqlMode(t *testing.T) {
enginetest.TestAnsiQuotesSqlMode(t, newDoltHarness(t))
}

func TestAnsiQuotesSqlModePrepared(t *testing.T) {
enginetest.TestAnsiQuotesSqlModePrepared(t, newDoltHarness(t))
}

// Tests of choosing the correct execution plan independent of result correctness. Mostly useful for confirming that
// the right indexes are being used for joining tables.
func TestQueryPlans(t *testing.T) {
Expand Down
Loading

0 comments on commit 4beaf52

Please sign in to comment.