Fixed DELIMITER

This commit is contained in:
Daylon Wilkins
2022-12-15 07:08:37 -08:00
parent f56f3f3736
commit 52f44b0a2c
7 changed files with 58 additions and 88 deletions

View File

@@ -21,7 +21,6 @@ import (
"os"
"os/signal"
"path/filepath"
"regexp"
"strings"
"syscall"
@@ -111,8 +110,6 @@ const (
# "exit" or "quit" (or Ctrl-D) to exit.`
)
var delimiterRegex = regexp.MustCompile(`(?i)^\s*DELIMITER\s+(\S+)\s*(\s+\S+\s*)?$`)
func init() {
dsqle.AddDoltSystemVariables()
}
@@ -809,47 +806,39 @@ func runMultiStatementMode(ctx *sql.Context, se *engine.SqlEngine, input io.Read
if len(query) == 0 || query == "\n" {
continue
}
shouldProcessQuery := true
if matches := delimiterRegex.FindStringSubmatch(query); len(matches) == 3 {
// If we don't match from anything, then we just pass to the SQL engine and let it complain.
scanner.Delimiter = matches[1]
shouldProcessQuery = false
sqlStatement, err := sqlparser.Parse(query)
if err == sqlparser.ErrEmpty {
continue
} else if err != nil {
handleError(scanner.statementStartLine, query, err)
// If continueOnErr is set keep executing the remaining queries but print the error out anyway.
if !continueOnErr {
return err
}
}
if shouldProcessQuery {
sqlStatement, err := sqlparser.Parse(query)
if err == sqlparser.ErrEmpty {
continue
} else if err != nil {
handleError(scanner.statementStartLine, query, err)
// If continueOnErr is set keep executing the remaining queries but print the error out anyway.
if !continueOnErr {
return err
sqlSch, rowIter, err := processParsedQuery(ctx, query, se, sqlStatement)
if err != nil {
handleError(scanner.statementStartLine, query, err)
// If continueOnErr is set keep executing the remaining queries but print the error out anyway.
if !continueOnErr {
return err
}
}
if rowIter != nil {
switch sqlStatement.(type) {
case *sqlparser.Select, *sqlparser.Insert, *sqlparser.Update, *sqlparser.Delete,
*sqlparser.OtherRead, *sqlparser.Show, *sqlparser.Explain, *sqlparser.Union:
// For any statement that prints out result, print a newline to put the regular output on its own line
if fileReadProg != nil {
fileReadProg.printNewLineIfNeeded()
}
}
sqlSch, rowIter, err := processParsedQuery(ctx, query, se, sqlStatement)
err = engine.PrettyPrintResults(ctx, se.GetResultFormat(), sqlSch, rowIter)
if err != nil {
handleError(scanner.statementStartLine, query, err)
// If continueOnErr is set keep executing the remaining queries but print the error out anyway.
if !continueOnErr {
return err
}
}
if rowIter != nil {
switch sqlStatement.(type) {
case *sqlparser.Select, *sqlparser.Insert, *sqlparser.Update, *sqlparser.Delete,
*sqlparser.OtherRead, *sqlparser.Show, *sqlparser.Explain, *sqlparser.Union:
// For any statement that prints out result, print a newline to put the regular output on its own line
if fileReadProg != nil {
fileReadProg.printNewLineIfNeeded()
}
}
err = engine.PrettyPrintResults(ctx, se.GetResultFormat(), sqlSch, rowIter)
if err != nil {
handleError(scanner.statementStartLine, query, err)
return err
}
return err
}
}
query = ""
@@ -881,22 +870,14 @@ func runBatchMode(ctx *sql.Context, se *engine.SqlEngine, input io.Reader, conti
if len(query) == 0 || query == "\n" {
continue
}
shouldProcessQuery := true
if matches := delimiterRegex.FindStringSubmatch(query); len(matches) == 3 {
// If we don't match from anything, then we just pass to the SQL engine and let it complain.
scanner.Delimiter = matches[1]
shouldProcessQuery = false
}
if shouldProcessQuery {
if err := processBatchQuery(ctx, query, se); err != nil {
// TODO: this line number will not be accurate for errors that occur when flushing a batch of inserts (as opposed
// to processing the query)
verr := formatQueryError(fmt.Sprintf("error on line %d for query %s", scanner.statementStartLine, query), err)
cli.PrintErrln(verr.Verbose())
// If continueOnErr is set keep executing the remaining queries but print the error out anyway.
if !continueOnErr {
return err
}
if err := processBatchQuery(ctx, query, se); err != nil {
// TODO: this line number will not be accurate for errors that occur when flushing a batch of inserts (as opposed
// to processing the query)
verr := formatQueryError(fmt.Sprintf("error on line %d for query %s", scanner.statementStartLine, query), err)
cli.PrintErrln(verr.Verbose())
// If continueOnErr is set keep executing the remaining queries but print the error out anyway.
if !continueOnErr {
return err
}
}
query = ""
@@ -1002,30 +983,18 @@ func runShell(ctx context.Context, se *engine.SqlEngine, mrEnv *env.MultiRepoEnv
query = strings.TrimSuffix(query, shell.LineTerminator())
resultFormat := se.GetResultFormat()
// TODO: it would be better to build this into the statement parser rahter than special case it here
// TODO: it would be better to build this into the statement parser rather than special case it here
for _, terminator := range verticalOutputLineTerminators {
if strings.HasSuffix(query, "\\G") {
if strings.HasSuffix(query, terminator) {
resultFormat = engine.FormatVertical
}
query = strings.TrimSuffix(query, terminator)
}
//TODO: Handle comments and enforce the current line terminator
if matches := delimiterRegex.FindStringSubmatch(query); len(matches) == 3 {
// If we don't match from anything, then we just pass to the SQL engine and let it complain.
shell.SetLineTerminator(matches[1])
return
}
var nextPrompt string
var sqlSch sql.Schema
var rowIter sql.RowIter
// The SQL parser does not understand any other terminator besides semicolon, so we remove it.
if shell.LineTerminator() != ";" && strings.HasSuffix(query, shell.LineTerminator()) {
query = query[:len(query)-len(shell.LineTerminator())]
}
cont := func() bool {
subCtx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
defer stop()

View File

@@ -54,7 +54,7 @@ const (
backtick = '`'
)
var scannerDelimiterRegex = regexp.MustCompile(`(?i)^\s*DELIMITER\s+(\S+)[ \t]*([\n]+|\S+\s*)?`)
var scannerDelimiterRegex = regexp.MustCompile(`(?i)^\s*DELIMITER\s+(\S+)\s*`)
// ScanStatements is a split function for a Scanner that returns each SQL statement in the input as a token.
func (s *statementScanner) scanStatements(data []byte, atEOF bool) (advance int, token []byte, err error) {
@@ -74,7 +74,9 @@ func (s *statementScanner) scanStatements(data []byte, atEOF bool) (advance int,
s.startLineNum = s.lineNum
if idxs := scannerDelimiterRegex.FindIndex(data); len(idxs) == 2 {
return idxs[1], data[0:idxs[1]], nil
s.Delimiter = scannerDelimiterRegex.FindStringSubmatch(string(data))[1]
// Returning a nil token is interpreted as an error condition, so we return an empty token instead
return idxs[1], []byte{}, nil
}
for i := 0; i < len(data); i++ {

View File

@@ -13,7 +13,7 @@ require (
github.com/denisbrodbeck/machineid v1.0.1
github.com/dolthub/dolt/go/gen/proto/dolt/services/eventsapi v0.0.0-20201005193433-3ee972b1d078
github.com/dolthub/fslock v0.0.3
github.com/dolthub/ishell v0.0.0-20220112232610-14e753f0f371
github.com/dolthub/ishell v0.0.0-20221214210346-d7db0b066488
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81
github.com/dolthub/vitess v0.0.0-20221213234424-b21f99e8027d
github.com/dustin/go-humanize v1.0.0

View File

@@ -59,7 +59,6 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg=
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db h1:CjPUSXOiYptLbTdr1RceuZgSFDQ7U15ITERUGrUORx8=
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db/go.mod h1:rB3B4rKii8V21ydCbIzH5hZiCQE7f5E9SzUb/ZZx530=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
@@ -164,8 +163,8 @@ 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-mysql-server v0.14.1-0.20221214210115-e28aad108618 h1:OrRT31UIC2VmBfEOt2tSSAAwicKPQU8dXcrfgS3XmXY=
github.com/dolthub/go-mysql-server v0.14.1-0.20221214210115-e28aad108618/go.mod h1:8zZpRD3uXPUwK8jWm+exPjANHW/DVbGX2//cpVSZoD4=
github.com/dolthub/ishell v0.0.0-20220112232610-14e753f0f371 h1:oyPHJlzumKta1vnOQqUnfdz+pk3EmnHS3Nd0cCT0I2g=
github.com/dolthub/ishell v0.0.0-20220112232610-14e753f0f371/go.mod h1:dhGBqcCEfK5kuFmeO5+WOx3hqc1k3M29c1oS/R7N4ms=
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.0-20210609232853-d49537a30474 h1:xTrR+l5l+1Lfq0NvhiEsctylXinUMFhhsqaEcl414p8=
github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474/go.mod h1:kMz7uXOXq4qRriCEyZ/LUeTqraLJCjf0WVZcUi6TxUY=
github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE=

View File

@@ -13,7 +13,7 @@ expect {
failed { exit 1; }
}
expect {
"doltsql> " { send "DELIMITER $$ ;\r"; }
"doltsql> " { send "DELIMITER $$\r"; }
timeout { exit 1; }
failed { exit 1; }
}
@@ -23,7 +23,7 @@ expect {
failed { exit 1; }
}
expect {
"doltsql> " { send "delimiter # $$\r"; }
"doltsql> " { send "delimiter #\r"; }
timeout { exit 1; }
failed { exit 1; }
}
@@ -53,7 +53,7 @@ expect {
failed { exit 1; }
}
expect {
"doltsql> " { send "DeLiMiTeR ; #\r"; }
"doltsql> " { send "DeLiMiTeR ;\r"; }
timeout { exit 1; }
failed { exit 1; }
}

View File

@@ -8,7 +8,7 @@ expect {
failed { exit 1; }
}
expect {
"*: one_pk*" { send "DELIMITER $$\\g\r"; }
"*: one_pk*" { send "DELIMITER $$\r"; }
timeout { exit 1; }
failed { exit 1; }
}
@@ -18,12 +18,12 @@ expect {
failed { exit 1; }
}
expect {
"*| one_pk *" { send "show tables\\g\r"; }
"*| one_pk*" { send "show tables\\g\r"; }
timeout { exit 1; }
failed { exit 1; }
}
expect {
"*| one_pk *" { send "DELIMITER ;\\g\r"; }
"*: one_pk*" { send "DELIMITER ;\r"; }
timeout { exit 1; }
failed { exit 1; }
}
@@ -38,7 +38,7 @@ expect {
failed { exit 1; }
}
expect {
"*JSON_OBJECT('id', 87, 'name', 'carrot'): {"id":87,"name":"carrot"}*" { exit 0 ; }
"*JSON_OBJECT('id', 87, 'name', 'carrot'): {\"id\":87,\"name\":\"carrot\"}*" { exit 0 ; }
timeout { exit 1; }
failed { exit 1; }
}

View File

@@ -2091,14 +2091,14 @@ SQL
@test "sql: batch delimiter" {
dolt sql <<SQL
DELIMITER // ;
DELIMITER //
CREATE TABLE test (
pk BIGINT PRIMARY KEY,
v1 BIGINT,
v2 BIGINT
)//
INSERT INTO test VALUES (1, 1, 1) //
DELIMITER $ //
DELIMITER $
INSERT INTO test VALUES (2, 2, 2)$ $
CREATE PROCEDURE p1(x BIGINT)
BEGIN
@@ -2107,9 +2107,9 @@ BEGIN
END IF;
SELECT pk+x, v1+x, v2+x FROM test ORDER BY 1;
END$
DELIMITER ; $
DELIMITER ;
INSERT INTO test VALUES (3, 3, 3);
DELIMITER ********** ;
DELIMITER **********
INSERT INTO test VALUES (4, 4, 4)**********
DELIMITER &
INSERT INTO test VALUES (5, 5, 5)&
@@ -2138,7 +2138,7 @@ SQL
[[ "${#lines[@]}" = "7" ]] || false
dolt sql <<SQL
DELIMITER // ;
DELIMITER //
CREATE TABLE test2(
pk BIGINT PRIMARY KEY,
v1 VARCHAR(20)
@@ -2254,7 +2254,7 @@ SQL
@test "sql: stored procedures creation check" {
dolt sql -q "
DELIMITER // ;
DELIMITER //
CREATE PROCEDURE p1(s VARCHAR(200), N DOUBLE, m DOUBLE)
BEGIN
SET s = '';