From 29b162a3abe8b57594b9d4ab5117dc2d69bcf24e Mon Sep 17 00:00:00 2001 From: Guillermo Prandi Date: Tue, 12 Nov 2019 00:48:20 +0000 Subject: [PATCH] Rewrite Engine.QuoteTo() to accept multi-part identifiers (#1476) --- engine.go | 43 ++++++++++++++++++++++++++++++++----------- engine_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 engine_test.go diff --git a/engine.go b/engine.go index 69f310ef..a7e52ea4 100644 --- a/engine.go +++ b/engine.go @@ -207,25 +207,46 @@ func (engine *Engine) QuoteTo(buf *strings.Builder, value string) { return } - quotePair := engine.dialect.Quote("") + quoteTo(buf, engine.dialect.Quote(""), value) +} - if value[0] == '`' || len(quotePair) < 2 || value[0] == quotePair[0] { // no quote +func quoteTo(buf *strings.Builder, quotePair string, value string) { + if len(quotePair) < 2 { // no quote _, _ = buf.WriteString(value) return - } else { - prefix, suffix := quotePair[0], quotePair[1] + } + + prefix, suffix := quotePair[0], quotePair[1] - _ = buf.WriteByte(prefix) - for i := 0; i < len(value); i++ { - if value[i] == '.' { - _ = buf.WriteByte(suffix) - _ = buf.WriteByte('.') - _ = buf.WriteByte(prefix) + i := 0 + for i < len(value) { + // start of a token; might be already quoted + if value[i] == '.' { + _ = buf.WriteByte('.') + i++ + } else if value[i] == prefix || value[i] == '`' { + // Has quotes; skip/normalize `name` to prefix+name+sufix + var ch byte + if value[i] == prefix { + ch = suffix } else { + ch = '`' + } + i++ + _ = buf.WriteByte(prefix) + for ; i < len(value) && value[i] != ch; i++ { _ = buf.WriteByte(value[i]) } + _ = buf.WriteByte(suffix) + i++ + } else { + // Requires quotes + _ = buf.WriteByte(prefix) + for ; i < len(value) && value[i] != '.'; i++ { + _ = buf.WriteByte(value[i]) + } + _ = buf.WriteByte(suffix) } - _ = buf.WriteByte(suffix) } } diff --git a/engine_test.go b/engine_test.go new file mode 100644 index 00000000..50522f5f --- /dev/null +++ b/engine_test.go @@ -0,0 +1,41 @@ +// Copyright 2019 The Xorm Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xorm + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestQuoteTo(t *testing.T) { + + test := func(t *testing.T, expected string, value string) { + buf := &strings.Builder{} + quoteTo(buf, "[]", value) + assert.EqualValues(t, expected, buf.String()) + } + + test(t, "[mytable]", "mytable") + test(t, "[mytable]", "`mytable`") + test(t, "[mytable]", `[mytable]`) + + test(t, `["mytable"]`, `"mytable"`) + + test(t, "[myschema].[mytable]", "myschema.mytable") + test(t, "[myschema].[mytable]", "`myschema`.mytable") + test(t, "[myschema].[mytable]", "myschema.`mytable`") + test(t, "[myschema].[mytable]", "`myschema`.`mytable`") + test(t, "[myschema].[mytable]", `[myschema].mytable`) + test(t, "[myschema].[mytable]", `myschema.[mytable]`) + test(t, "[myschema].[mytable]", `[myschema].[mytable]`) + + test(t, `["myschema].[mytable"]`, `"myschema.mytable"`) + + buf := &strings.Builder{} + quoteTo(buf, "", "noquote") + assert.EqualValues(t, "noquote", buf.String()) +}