diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index fb828d507a0..745f54b996a 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -6842,15 +6842,21 @@ func VarScope(nameParts ...string) (string, SetScope, string, error) { return VarScope(nameParts[0][:dotIdx], nameParts[0][dotIdx+1:]) } // Session scope is inferred here, but not explicitly requested - return nameParts[0][2:], SetScope_Session, "", nil + return trimQuotes(nameParts[0][2:]), SetScope_Session, "", nil } else if strings.HasPrefix(nameParts[0], "@") { - return nameParts[0][1:], SetScope_User, "", nil + varName := nameParts[0][1:] + if len(varName) > 0 { + varName = trimQuotes(varName) + } + return varName, SetScope_User, "", nil } else { return nameParts[0], SetScope_None, "", nil } case 2: // `@user.var` is valid, so we check for it here. - if len(nameParts[0]) >= 2 && nameParts[0][0] == '@' && nameParts[0][1] != '@' && + if len(nameParts[0]) >= 2 && + nameParts[0][0] == '@' && + nameParts[0][1] != '@' && !strings.HasPrefix(nameParts[1], "@") { // `@user.@var` is invalid though. return fmt.Sprintf("%s.%s", nameParts[0][1:], nameParts[1]), SetScope_User, "", nil } @@ -6866,27 +6872,27 @@ func VarScope(nameParts ...string) (string, SetScope, string, error) { if strings.HasPrefix(nameParts[1], `"`) || strings.HasPrefix(nameParts[1], `'`) { return "", SetScope_None, "", fmt.Errorf("invalid system variable declaration `%s`", nameParts[1]) } - return nameParts[1], SetScope_Global, nameParts[0][2:], nil + return trimQuotes(nameParts[1]), SetScope_Global, nameParts[0][2:], nil case "@@persist": if strings.HasPrefix(nameParts[1], `"`) || strings.HasPrefix(nameParts[1], `'`) { return "", SetScope_None, "", fmt.Errorf("invalid system variable declaration `%s`", nameParts[1]) } - return nameParts[1], SetScope_Persist, nameParts[0][2:], nil + return trimQuotes(nameParts[1]), SetScope_Persist, nameParts[0][2:], nil case "@@persist_only": if strings.HasPrefix(nameParts[1], `"`) || strings.HasPrefix(nameParts[1], `'`) { return "", SetScope_None, "", fmt.Errorf("invalid system variable declaration `%s`", nameParts[1]) } - return nameParts[1], SetScope_PersistOnly, nameParts[0][2:], nil + return trimQuotes(nameParts[1]), SetScope_PersistOnly, nameParts[0][2:], nil case "@@session": if strings.HasPrefix(nameParts[1], `"`) || strings.HasPrefix(nameParts[1], `'`) { return "", SetScope_None, "", fmt.Errorf("invalid system variable declaration `%s`", nameParts[1]) } - return nameParts[1], SetScope_Session, nameParts[0][2:], nil + return trimQuotes(nameParts[1]), SetScope_Session, nameParts[0][2:], nil case "@@local": if strings.HasPrefix(nameParts[1], `"`) || strings.HasPrefix(nameParts[1], `'`) { return "", SetScope_None, "", fmt.Errorf("invalid system variable declaration `%s`", nameParts[1]) } - return nameParts[1], SetScope_Session, nameParts[0][2:], nil + return trimQuotes(nameParts[1]), SetScope_Session, nameParts[0][2:], nil default: // This catches `@@@GLOBAL.sys_var`. Due to the earlier check, this does not error on `@user.var`. if strings.HasPrefix(nameParts[0], "@") { diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 548b8eb2348..e730058cf10 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -1406,76 +1406,146 @@ var ( input: "set #simple\n b = 4", }, { input: "set character_set_results = utf8", - }, { + }, + { + input: "set @@`version` = true", + output: "set session version = true", + }, + { + input: "select @@`version` = true", + output: "select @@`version` = true", + }, + { input: "set @@session.autocommit = true", output: "set session autocommit = true", - }, { + }, + { input: "set @@session.`autocommit` = true", - output: "set session `autocommit` = true", - }, { + output: "set session autocommit = true", + }, + { + input: "select @@session.`autocommit` = true", + output: "select @@session.`autocommit` = true", + }, + { input: "set @@session.autocommit = ON", output: "set session autocommit = 'ON'", - }, { + }, + { input: "set @@session.autocommit= OFF", output: "set session autocommit = 'OFF'", - }, { + }, + { input: "set session autocommit = ON", output: "set session autocommit = 'ON'", - }, { + }, + { input: "set session autocommit := ON", output: "set session autocommit = 'ON'", - }, { + }, + { input: "set global autocommit = OFF", output: "set global autocommit = 'OFF'", - }, { + }, + { input: "set @@global.optimizer_prune_level = 1", output: "set global optimizer_prune_level = 1", - }, { + }, + { input: "set global optimizer_prune_level = 1", - }, { + }, + { input: "set @@persist.optimizer_prune_level = 1", output: "set persist optimizer_prune_level = 1", - }, { + }, + { input: "set persist optimizer_prune_level = 1", - }, { + }, + { input: "set @@persist_only.optimizer_prune_level = 1", output: "set persist_only optimizer_prune_level = 1", - }, { + }, + { input: "set persist_only optimizer_prune_level = 1", - }, { + }, + { input: "set @@local.optimizer_prune_level = 1", output: "set session optimizer_prune_level = 1", - }, { + }, + { input: "set local optimizer_prune_level = 1", output: "set session optimizer_prune_level = 1", - }, { + }, + { input: "set @@optimizer_prune_level = 1", output: "set session optimizer_prune_level = 1", - }, { + }, + { input: "set session optimizer_prune_level = 1", - }, { + }, + { input: "set @@optimizer_prune_level = 1, @@global.optimizer_search_depth = 62", output: "set session optimizer_prune_level = 1, global optimizer_search_depth = 62", - }, { + }, + { input: "set @@GlObAl.optimizer_prune_level = 1", output: "set global optimizer_prune_level = 1", - }, { + }, + { input: "set @user.var = 1", - }, { + }, + { input: "set @user.var.name = 1", - }, { + }, + { input: "set @user.var.name := 1", output: "set @user.var.name = 1", - }, { + }, + { + input: "set @`user var` = 1", + output: "set @user var = 1", + }, + { + input: "select @`user var`", + output: "select `@``user var```", + }, + { + input: "set @user.`var` = 1", + output: "set @user.var = 1", + }, + { + input: "select @user.`var`", + output: "select @user.var", + }, + { + input: "set @`user`.`var` = 1", + output: "set @`user`.var = 1", + }, + { + input: "select @`user`.`var`", + output: "select `@``user```.var", + }, + { + input: "set @abc.def.`ghi` = 300", + output: "set @abc.def.ghi = 300", + }, + { + input: "select @abc.def.`ghi`", + output: "select @abc.def.ghi", + }, + { input: "set autocommit = on", output: "set autocommit = 'on'", - }, { + }, + { input: "set autocommit = off", output: "set autocommit = 'off'", - }, { + }, + { input: "set autocommit = off, foo = 1", output: "set autocommit = 'off', foo = 1", - }, { + }, + { input: "set names utf8 collate foo", output: "set names 'utf8'", }, { diff --git a/go/vt/sqlparser/token.go b/go/vt/sqlparser/token.go index b57fa8a76c9..0dec4efcc8e 100644 --- a/go/vt/sqlparser/token.go +++ b/go/vt/sqlparser/token.go @@ -428,10 +428,25 @@ func (tkn *Tokenizer) scanIdentifier(firstByte byte, isDbSystemVariable bool) (i buffer.WriteByte(byte(tkn.lastChar)) tkn.next() } - for isLetter(tkn.lastChar) || isDigit(tkn.lastChar) || (isDbSystemVariable && isCarat(tkn.lastChar)) { + for isLetter(tkn.lastChar) || isDigit(tkn.lastChar) || (isDbSystemVariable && isCarat(tkn.lastChar)) /*|| (firstByte == '@' && isCarat(tkn.lastChar))*/ { buffer.WriteByte(byte(tkn.lastChar)) tkn.next() } + + // special case for user variables with backticks + if firstByte == '@' && tkn.lastChar == '`' { + buffer.WriteByte(byte(tkn.lastChar)) + tkn.next() + for isLetter(tkn.lastChar) || isDigit(tkn.lastChar) || isCarat(tkn.lastChar) || unicode.IsSpace(rune(tkn.lastChar)) { + buffer.WriteByte(byte(tkn.lastChar)) + if tkn.lastChar == '`' { + tkn.next() + break + } + tkn.next() + } + } + if tkn.lastChar == '@' { tkn.potentialAccountName = true }