Skip to content

Commit

Permalink
Fix literals format (#237)
Browse files Browse the repository at this point in the history
* Fix literals format

* Fit to align FORMAT("%T", input)

* Update testdata

* Fix bug

* Add comments

* Fix argument order

* Fix tests

* Remove empty branch
  • Loading branch information
apstndb authored Dec 19, 2024
1 parent 1efca7f commit 0230ae2
Show file tree
Hide file tree
Showing 26 changed files with 132 additions and 76 deletions.
2 changes: 1 addition & 1 deletion char/is.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package char

func IsPrint(b byte) bool {
return 0x21 <= b && b <= 0x7D
return 0x20 <= b && b <= 0x7E // ' ' to '~'
}

func IsDigit(c byte) bool {
Expand Down
8 changes: 6 additions & 2 deletions char/is_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ import (
)

func TestIsPrint(t *testing.T) {
if IsPrint(' ') {
t.Errorf("IsPrint(' ') != false")
if IsPrint('\x19') {
t.Errorf(`IsPrint('\x19') != false`)
}

if IsPrint('\x80') {
t.Errorf(`IsPrint('\x80') != false`)
}

if !IsPrint('a') {
Expand Down
1 change: 1 addition & 0 deletions testdata/input/expr/bytes_literal_seven_bits.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
1 change: 1 addition & 0 deletions testdata/input/expr/string_literal_seven_bits.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
8 changes: 4 additions & 4 deletions testdata/result/ddl/create_table_for_format_test.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ create table if not exists foo (
Value: "255",
},
},
NotNull: true,
GeneratedExpr: &ast.GeneratedColumnExpr{
NotNull: true,
DefaultSemantics: &ast.GeneratedColumnExpr{
As: 172,
Stored: 194,
Rparen: 192,
Expand Down Expand Up @@ -152,8 +152,8 @@ create table if not exists foo (
NamePos: 394,
Name: "TIMESTAMP",
},
NotNull: true,
DefaultExpr: &ast.ColumnDefaultExpr{
NotNull: true,
DefaultSemantics: &ast.ColumnDefaultExpr{
Default: 413,
Rparen: 441,
Expr: &ast.CallExpr{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,9 @@ create table foo (
}

--- SQL
CREATE TABLE foo (id INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000 SKIP RANGE 1, 12345), startCount INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000), skipRange INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE SKIP RANGE 1000, 2000), simple INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE)) PRIMARY KEY (id)
CREATE TABLE foo (
id INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000 SKIP RANGE 1, 12345),
startCount INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000),
skipRange INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE SKIP RANGE 1000, 2000),
simple INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE)
) PRIMARY KEY (id)
19 changes: 19 additions & 0 deletions testdata/result/expr/bytes_literal_seven_bits.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--- bytes_literal_seven_bits.sql
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
--- AST
&ast.BytesLiteral{
ValueEnd: 232,
Value: []uint8{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
},
}

--- SQL
b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
2 changes: 1 addition & 1 deletion testdata/result/expr/cast_as_typename.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ CAST('order_number: "123"' AS examples.shipping.`Order`)
}

--- SQL
CAST("order_number: \"123\"" AS examples.shipping.`Order`)
CAST('order_number: "123"' AS examples.shipping.`Order`)
2 changes: 1 addition & 1 deletion testdata/result/expr/json_literal.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ JSON '{"s": "foo", "n": 42}'
}

--- SQL
JSON "{\"s\": \"foo\", \"n\": 42}"
JSON '{"s": "foo", "n": 42}'
10 changes: 10 additions & 0 deletions testdata/result/expr/string_literal_seven_bits.sql.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--- string_literal_seven_bits.sql
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
--- AST
&ast.StringLiteral{
ValueEnd: 225,
Value: "\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f",
}

--- SQL
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f"
2 changes: 1 addition & 1 deletion testdata/result/query/select_from_ml_predict_hint.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,4 @@ FROM ML.PREDICT(
}

--- SQL
SELECT content FROM ML.PREDICT(MODEL TextBison, (SELECT "Is 13 prime\?" AS prompt), STRUCT(256 AS maxOutputTokens, 0.2 AS temperature, 40 AS topK, 0.95 AS topP)) @{remote_udf_max_rows_per_rpc=1}
SELECT content FROM ML.PREDICT(MODEL TextBison, (SELECT "Is 13 prime?" AS prompt), STRUCT(256 AS maxOutputTokens, 0.2 AS temperature, 40 AS topK, 0.95 AS topP)) @{remote_udf_max_rows_per_rpc=1}
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,4 @@ FROM ML.PREDICT(
}

--- SQL
SELECT product_id, product_name, content FROM ML.PREDICT(MODEL TextBison, (SELECT product.id AS product_id, product.name AS product_name, CONCAT("Is this product safe for infants\?", "\n", "Product Name: ", product.name, "\n", "Category Name: ", category.name, "\n", "Product Description:", product.description) AS prompt FROM Products AS product INNER JOIN Categories AS category ON product.category_id = category.id), STRUCT(100 AS maxOutputTokens)) @{remote_udf_max_rows_per_rpc=1}
SELECT product_id, product_name, content FROM ML.PREDICT(MODEL TextBison, (SELECT product.id AS product_id, product.name AS product_name, CONCAT("Is this product safe for infants?", "\n", "Product Name: ", product.name, "\n", "Category Name: ", category.name, "\n", "Product Description:", product.description) AS prompt FROM Products AS product INNER JOIN Categories AS category ON product.category_id = category.id), STRUCT(100 AS maxOutputTokens)) @{remote_udf_max_rows_per_rpc=1}
2 changes: 1 addition & 1 deletion testdata/result/query/select_literals_all.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -597,4 +597,4 @@ lines''',
}

--- SQL
SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT (1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
SELECT "abc", "it's", "it's", 'Title: "Boy"', "abc", "it's", 'Title:"Boy"', "two\nlines", "why?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", b"abc", b"abc", b"abc", b"abc+", b"abc+", b"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT (1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
2 changes: 1 addition & 1 deletion testdata/result/query/select_literals_bytes.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,4 @@ SELECT
}

--- SQL
SELECT B"abc", B"abc", B"abc", B"abc\n", B"abc+", B"abc+", B"abc", B"abc\\n", B"\x00", B"\?\?\?"
SELECT b"abc", b"abc", b"abc", b"abc\x0a", b"abc+", b"abc+", b"abc", b"abc\\n", b"\x00", b"???"
2 changes: 1 addition & 1 deletion testdata/result/query/select_literals_string.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,4 @@ lines''',
}

--- SQL
SELECT "abc!", "a\nb!", "=!", "=!", "=!", "=!", "=!", "‼!", "🐈!", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)"
SELECT "abc!", "a\nb!", "=!", "=!", "=!", "=!", "=!", "‼!", "🐈!", "it's", "it's", 'Title: "Boy"', "abc", "it's", 'Title:"Boy"', "two\nlines", "why?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)"
2 changes: 1 addition & 1 deletion testdata/result/query/select_subscript_operators.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -492,4 +492,4 @@ select
}

--- SQL
SELECT [1, 2, 3][OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][SAFE_OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][1], STRUCT(1, 2, 3)[OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[SAFE_OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[1], JSON "[1, 2, 3]"[1], JSON "{\"a\": 1, \"b\": 2, \"c\": 3}"["a"]
SELECT [1, 2, 3][OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][SAFE_OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][1], STRUCT(1, 2, 3)[OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[SAFE_OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[1], JSON "[1, 2, 3]"[1], JSON '{"a": 1, "b": 2, "c": 3}'["a"]
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ create table if not exists foo (
Value: "255",
},
},
NotNull: true,
GeneratedExpr: &ast.GeneratedColumnExpr{
NotNull: true,
DefaultSemantics: &ast.GeneratedColumnExpr{
As: 172,
Stored: 194,
Rparen: 192,
Expand Down Expand Up @@ -152,8 +152,8 @@ create table if not exists foo (
NamePos: 394,
Name: "TIMESTAMP",
},
NotNull: true,
DefaultExpr: &ast.ColumnDefaultExpr{
NotNull: true,
DefaultSemantics: &ast.ColumnDefaultExpr{
Default: 413,
Rparen: 441,
Expr: &ast.CallExpr{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,9 @@ create table foo (
}

--- SQL
CREATE TABLE foo (id INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000 SKIP RANGE 1, 12345), startCount INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000), skipRange INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE SKIP RANGE 1000, 2000), simple INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE)) PRIMARY KEY (id)
CREATE TABLE foo (
id INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000 SKIP RANGE 1, 12345),
startCount INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE START COUNTER WITH 1000),
skipRange INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE SKIP RANGE 1000, 2000),
simple INT64 GENERATED BY DEFAULT AS IDENTITY (BIT_REVERSED_POSITIVE)
) PRIMARY KEY (id)
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,4 @@ FROM ML.PREDICT(
}

--- SQL
SELECT content FROM ML.PREDICT(MODEL TextBison, (SELECT "Is 13 prime\?" AS prompt), STRUCT(256 AS maxOutputTokens, 0.2 AS temperature, 40 AS topK, 0.95 AS topP)) @{remote_udf_max_rows_per_rpc=1}
SELECT content FROM ML.PREDICT(MODEL TextBison, (SELECT "Is 13 prime?" AS prompt), STRUCT(256 AS maxOutputTokens, 0.2 AS temperature, 40 AS topK, 0.95 AS topP)) @{remote_udf_max_rows_per_rpc=1}
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,4 @@ FROM ML.PREDICT(
}

--- SQL
SELECT product_id, product_name, content FROM ML.PREDICT(MODEL TextBison, (SELECT product.id AS product_id, product.name AS product_name, CONCAT("Is this product safe for infants\?", "\n", "Product Name: ", product.name, "\n", "Category Name: ", category.name, "\n", "Product Description:", product.description) AS prompt FROM Products AS product INNER JOIN Categories AS category ON product.category_id = category.id), STRUCT(100 AS maxOutputTokens)) @{remote_udf_max_rows_per_rpc=1}
SELECT product_id, product_name, content FROM ML.PREDICT(MODEL TextBison, (SELECT product.id AS product_id, product.name AS product_name, CONCAT("Is this product safe for infants?", "\n", "Product Name: ", product.name, "\n", "Category Name: ", category.name, "\n", "Product Description:", product.description) AS prompt FROM Products AS product INNER JOIN Categories AS category ON product.category_id = category.id), STRUCT(100 AS maxOutputTokens)) @{remote_udf_max_rows_per_rpc=1}
2 changes: 1 addition & 1 deletion testdata/result/statement/select_literals_all.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -597,4 +597,4 @@ lines''',
}

--- SQL
SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT (1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
SELECT "abc", "it's", "it's", 'Title: "Boy"', "abc", "it's", 'Title:"Boy"', "two\nlines", "why?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", b"abc", b"abc", b"abc", b"abc+", b"abc+", b"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT (1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
2 changes: 1 addition & 1 deletion testdata/result/statement/select_literals_bytes.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,4 @@ SELECT
}

--- SQL
SELECT B"abc", B"abc", B"abc", B"abc\n", B"abc+", B"abc+", B"abc", B"abc\\n", B"\x00", B"\?\?\?"
SELECT b"abc", b"abc", b"abc", b"abc\x0a", b"abc+", b"abc+", b"abc", b"abc\\n", b"\x00", b"???"
2 changes: 1 addition & 1 deletion testdata/result/statement/select_literals_string.sql.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,4 @@ lines''',
}

--- SQL
SELECT "abc!", "a\nb!", "=!", "=!", "=!", "=!", "=!", "‼!", "🐈!", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)"
SELECT "abc!", "a\nb!", "=!", "=!", "=!", "=!", "=!", "‼!", "🐈!", "it's", "it's", 'Title: "Boy"', "abc", "it's", 'Title:"Boy"', "two\nlines", "why?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)"
Original file line number Diff line number Diff line change
Expand Up @@ -492,4 +492,4 @@ select
}

--- SQL
SELECT [1, 2, 3][OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][SAFE_OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][1], STRUCT(1, 2, 3)[OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[SAFE_OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[1], JSON "[1, 2, 3]"[1], JSON "{\"a\": 1, \"b\": 2, \"c\": 3}"["a"]
SELECT [1, 2, 3][OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][SAFE_OFFSET(1)], [1, 2, 3][ORDINAL(1)], [1, 2, 3][1], STRUCT(1, 2, 3)[OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[SAFE_OFFSET(1)], STRUCT(1, 2, 3)[ORDINAL(1)], STRUCT(1, 2, 3)[1], JSON "[1, 2, 3]"[1], JSON '{"a": 1, "b": 2, "c": 3}'["a"]
95 changes: 53 additions & 42 deletions token/quote.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,56 @@ import (

// QuoteSQLString returns quoted string with SQL string escaping.
func QuoteSQLString(s string) string {
quote := suitableQuote([]byte(s))

var buf bytes.Buffer
buf.WriteByte('"')
quoteSQLStringContent(s, &buf)
buf.WriteByte('"')
buf.WriteRune(quote)
quoteSQLStringContent(s, quote, &buf)
buf.WriteRune(quote)
return buf.String()
}

// QuoteSQLString returns quoted string with SQL bytes escaping.
func suitableQuote(b []byte) rune {
var hasSingle, hasDouble bool
for _, b := range b {
switch b {
case '\'':
hasSingle = true
case '"':
hasDouble = true
}
}
if !hasSingle && hasDouble {
return '\''
}
return '"'
}

// QuoteSQLBytes returns quoted string with SQL bytes escaping.
func QuoteSQLBytes(bs []byte) string {
quote := suitableQuote(bs)

var buf bytes.Buffer
buf.WriteString("B\"")
buf.WriteString("b")
buf.WriteRune(quote)
for _, b := range bs {
q := quoteSingleEscape(rune(b))
q := quoteSingleEscape(rune(b), quote, /* isString */ false)
if q != "" {
buf.WriteString(q)
continue
}

if char.IsPrint(b) {
buf.WriteByte(b)
continue
}
fmt.Fprintf(&buf, "\\x%02X", uint64(b))
fmt.Fprintf(&buf, `\x%02x`, uint64(b))
}
buf.WriteRune('"')
buf.WriteRune(quote)
return buf.String()
}

// QuoteSQLString returns quoted string with SQL bytes escaping if needed,
// QuoteSQLIdent returns quoted identifier if needed,
// otherwise it returns the input string.
func QuoteSQLIdent(s string) string {
if !needQuoteSQLIdent(s) {
Expand All @@ -46,14 +68,14 @@ func QuoteSQLIdent(s string) string {

var buf bytes.Buffer
buf.WriteByte('`')
quoteSQLStringContent(s, &buf)
quoteSQLStringContent(s, '`', &buf)
buf.WriteByte('`')
return buf.String()
}

func quoteSQLStringContent(s string, buf *bytes.Buffer) {
func quoteSQLStringContent(s string, quote rune, buf *bytes.Buffer) {
for _, r := range s {
q := quoteSingleEscape(r)
q := quoteSingleEscape(r, quote, /* isString */ true)
if q != "" {
buf.WriteString(q)
continue
Expand All @@ -62,40 +84,29 @@ func quoteSQLStringContent(s string, buf *bytes.Buffer) {
buf.WriteRune(r)
continue
}
if r > 0xFFFF {
fmt.Fprintf(buf, "\\U%08X", uint64(r))
} else {
fmt.Fprintf(buf, "\\u%04X", uint64(r))
switch {
case r < 0x80:
fmt.Fprintf(buf, `\x%02x`, uint64(r))
case r > 0xFFFF:
fmt.Fprintf(buf, `\U%08x`, uint64(r))
default:
fmt.Fprintf(buf, `\u%04x`, uint64(r))
}
}
}

func quoteSingleEscape(r rune) string {
switch r {
case '\a':
return "\\a"
case '\b':
return "\\b"
case '\f':
return "\\f"
case '\n':
return "\\n"
case '\r':
return "\\r"
case '\t':
return "\\t"
case '\v':
return "\\v"
case '"':
return "\\\""
case '\'':
return "\\'"
case '`':
return "\\`"
case '?':
return "\\?"
case '\\':
return "\\\\"
func quoteSingleEscape(r, quote rune, isString bool) string {
switch {
case r == quote:
return `\` + string(r)
case isString && r == '\n':
return `\n`
case isString && r == '\r':
return `\r`
case isString && r == '\t':
return `\t`
case r == '\\':
return `\\`
}
return ""
}
Expand Down
14 changes: 7 additions & 7 deletions token/quote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ var quoteTestCases = []struct {
input string
str, bytes, id string
}{
{"foo", `"foo"`, `B"foo"`, "foo"},
{"if", `"if"`, `B"if"`, "`if`"},
{"\u0000", `"\u0000"`, `B"\x00"`, "`\\u0000`"},
{"\U0010FFFF", `"\U0010FFFF"`, `B"\xF4\x8F\xBF\xBF"`, "`\\U0010FFFF`"},
{"a\u2060b", `"a\u2060b"`, `B"a\xE2\x81\xA0b"`, "`a\\u2060b`"},
{"\a\b\f\n\r\t\v\"'?\\", `"\a\b\f\n\r\t\v\"\'\?\\"`, `B"\a\b\f\n\r\t\v\"\'\?\\"`, "`\\a\\b\\f\\n\\r\\t\\v\\\"\\'\\?\\\\`"},
{"`", "\"\\`\"", "B\"\\`\"", "`\\``"},
{"foo", `"foo"`, `b"foo"`, "foo"},
{"if", `"if"`, `b"if"`, "`if`"},
{"\u0000", `"\x00"`, `b"\x00"`, "`\\x00`"},
{"\U0010FFFF", `"\U0010ffff"`, `b"\xf4\x8f\xbf\xbf"`, "`\\U0010ffff`"},
{"a\u2060b", `"a\u2060b"`, `b"a\xe2\x81\xa0b"`, "`a\\u2060b`"},
{"\a\b\f\n\r\t\v\"'?\\", `"\x07\x08\x0c\n\r\t\x0b\"'?\\"`, `b"\x07\x08\x0c\x0a\x0d\x09\x0b\"'?\\"`, "`\\x07\\x08\\x0c\\n\\r\\t\\x0b\"'?\\\\`"},
{"`", "\"`\"", "b\"`\"", "`\\``"},
}

func TestQuote(t *testing.T) {
Expand Down

0 comments on commit 0230ae2

Please sign in to comment.