Skip to content

Commit

Permalink
bigquery identifier escaping
Browse files Browse the repository at this point in the history
  • Loading branch information
atzoum committed Jul 23, 2024
1 parent 451439b commit 8947576
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 6 deletions.
17 changes: 14 additions & 3 deletions sqlconnect/internal/bigquery/dialect.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package bigquery

import (
"regexp"
"strings"

"github.com/rudderlabs/sqlconnect-go/sqlconnect"
Expand All @@ -9,6 +10,11 @@ import (

type dialect struct{}

var (
escape = regexp.MustCompile("('|\"|`)")
unescape = regexp.MustCompile("\\\\('|\")")
)

// QuoteTable quotes a table name
func (d dialect) QuoteTable(table sqlconnect.RelationRef) string {
if table.Schema != "" {
Expand All @@ -19,7 +25,7 @@ func (d dialect) QuoteTable(table sqlconnect.RelationRef) string {

// QuoteIdentifier quotes an identifier, e.g. a column name
func (d dialect) QuoteIdentifier(name string) string {
return "`" + strings.ReplaceAll(name, "`", "``") + "`"
return "`" + escape.ReplaceAllString(name, "\\$1") + "`"
}

// FormatTableName formats a table name, typically by lower or upper casing it, depending on the database
Expand All @@ -31,11 +37,16 @@ var identityFn = func(s string) string { return s }

// NormaliseIdentifier normalises identifier parts that are unquoted, typically by lower or upper casing them, depending on the database
func (d dialect) NormaliseIdentifier(identifier string) string {
return base.NormaliseIdentifier(identifier, '`', identityFn)
return base.NormaliseIdentifier(normalise(identifier), '`', identityFn)
}

// ParseRelationRef parses a string into a RelationRef after normalising the identifier and stripping out surrounding quotes.
// The result is a RelationRef with case-sensitive fields, i.e. it can be safely quoted (see [QuoteTable] and, for instance, used for matching against the database's information schema.
func (d dialect) ParseRelationRef(identifier string) (sqlconnect.RelationRef, error) {
return base.ParseRelationRef(identifier, '`', identityFn)
return base.ParseRelationRef(normalise(identifier), '`', identityFn)
}

func normalise(identifier string) string {
identifier = strings.ReplaceAll(identifier, "\\`", "``")
return unescape.ReplaceAllString(identifier, "$1")
}
6 changes: 4 additions & 2 deletions sqlconnect/internal/bigquery/dialect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func TestDialect(t *testing.T) {
t.Run("quote identifier", func(t *testing.T) {
quoted := d.QuoteIdentifier("column")
require.Equal(t, "`column`", quoted, "column name should be quoted with backticks")

require.Equal(t, "`col\\`umn`", d.QuoteIdentifier("col`umn"), "column name with backtick should be escaped")
})

t.Run("quote table", func(t *testing.T) {
Expand Down Expand Up @@ -62,8 +64,8 @@ func TestDialect(t *testing.T) {
require.NoError(t, err)
require.Equal(t, sqlconnect.RelationRef{Schema: "ScHeMA", Name: "TaBle"}, parsed)

parsed, err = d.ParseRelationRef("`CaTa``LoG`.ScHeMA.`TaBle`")
parsed, err = d.ParseRelationRef("`CaTa``LoG`.ScHeMA.`TaB\\`\\\"\\'le`")
require.NoError(t, err)
require.Equal(t, sqlconnect.RelationRef{Catalog: "CaTa`LoG", Schema: "ScHeMA", Name: "TaBle"}, parsed)
require.Equal(t, sqlconnect.RelationRef{Catalog: "CaTa`LoG", Schema: "ScHeMA", Name: "TaB`\"'le"}, parsed)
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func TestDatabaseScenarios(t *testing.T, warehouse string, configJSON json.RawMe
t.Run("with quoted table", func(t *testing.T) {
identifier := db.QuoteIdentifier(schema.Name) + "." + db.QuoteIdentifier("Quoted_TablE")
_, err := db.Exec("CREATE TABLE " + identifier + " (c1 int)")
require.NoError(t, err, "it should be able to create a quoted table")
require.NoErrorf(t, err, "it should be able to create a quoted table: %s", identifier)

table, err := db.ParseRelationRef(identifier)
require.NoError(t, err, "it should be able to parse a quoted table")
Expand Down

0 comments on commit 8947576

Please sign in to comment.