Repository: cloudspannerecosystem/memefish
Pull request #237 (2024-12-19 08:04:06)

Fix literals format
This PR align literals format to Spanner/ZetaSQL `FORMAT("%T", input)` functions.

- Generic quoted literals and quoted identifiers
  - `' '` and `'~'` should be printable characters.
  - Use lowercased hex rather than uppercased hex
  - Don't escape quotes except currently used.
  - Only `\` is always escaped printable character.
  - Use single quote if double quote is not suitable.
- String literals
  - Use `\x%02x` for non-printable runes of `r <= 0x7f`.
  - Use only `\t`, `\r`, `\n` in `r < 0x20` instead of `\x%02x`.
- Bytes literals
  - Use `b""` rather than `B""` for bytes literal

- close https://github.com/cloudspannerecosystem/memefish/issues/236


Patch:
diff --git a/char/is.go b/char/is.go
index b5944e1..71bd988 100644
--- a/char/is.go
+++ b/char/is.go
@@ -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 {
diff --git a/token/quote.go b/token/quote.go
index 6ded321..78187b2 100644
--- a/token/quote.go
+++ b/token/quote.go
@@ -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) {
@@ -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
@@ -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 ""
 }


Test patch:
diff --git a/char/is_test.go b/char/is_test.go
index c3738e0..73ddc70 100644
--- a/char/is_test.go
+++ b/char/is_test.go
@@ -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') {
diff --git a/testdata/input/expr/bytes_literal_seven_bits.sql b/testdata/input/expr/bytes_literal_seven_bits.sql
new file mode 100644
index 0000000..e6edb14
--- /dev/null
+++ b/testdata/input/expr/bytes_literal_seven_bits.sql
@@ -0,0 +1,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"
\ No newline at end of file
diff --git a/testdata/input/expr/string_literal_seven_bits.sql b/testdata/input/expr/string_literal_seven_bits.sql
new file mode 100644
index 0000000..799f906
--- /dev/null
+++ b/testdata/input/expr/string_literal_seven_bits.sql
@@ -0,0 +1,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"
\ No newline at end of file
diff --git a/testdata/result/ddl/create_table_for_format_test.sql.txt b/testdata/result/ddl/create_table_for_format_test.sql.txt
index fe292d4..bba5100 100644
--- a/testdata/result/ddl/create_table_for_format_test.sql.txt
+++ b/testdata/result/ddl/create_table_for_format_test.sql.txt
@@ -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,
@@ -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{
diff --git a/testdata/result/ddl/create_table_with_identity_columns.sql.txt b/testdata/result/ddl/create_table_with_identity_columns.sql.txt
index a88f5ba..41dbf3e 100644
--- a/testdata/result/ddl/create_table_with_identity_columns.sql.txt
+++ b/testdata/result/ddl/create_table_with_identity_columns.sql.txt
@@ -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)
diff --git a/testdata/result/expr/bytes_literal_seven_bits.sql.txt b/testdata/result/expr/bytes_literal_seven_bits.sql.txt
new file mode 100644
index 0000000..24dd8a7
--- /dev/null
+++ b/testdata/result/expr/bytes_literal_seven_bits.sql.txt
@@ -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"
diff --git a/testdata/result/expr/cast_as_typename.sql.txt b/testdata/result/expr/cast_as_typename.sql.txt
index 6f45397..295f0ef 100644
--- a/testdata/result/expr/cast_as_typename.sql.txt
+++ b/testdata/result/expr/cast_as_typename.sql.txt
@@ -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`)
diff --git a/testdata/result/expr/json_literal.sql.txt b/testdata/result/expr/json_literal.sql.txt
index 6e358b4..ade4d74 100644
--- a/testdata/result/expr/json_literal.sql.txt
+++ b/testdata/result/expr/json_literal.sql.txt
@@ -10,4 +10,4 @@ JSON '{"s": "foo", "n": 42}'
 }
 
 --- SQL
-JSON "{\"s\": \"foo\", \"n\": 42}"
+JSON '{"s": "foo", "n": 42}'
diff --git a/testdata/result/expr/string_literal_seven_bits.sql.txt b/testdata/result/expr/string_literal_seven_bits.sql.txt
new file mode 100644
index 0000000..04fee57
--- /dev/null
+++ b/testdata/result/expr/string_literal_seven_bits.sql.txt
@@ -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"
diff --git a/testdata/result/query/select_from_ml_predict_hint.sql.txt b/testdata/result/query/select_from_ml_predict_hint.sql.txt
index cc99b9a..78b338b 100644
--- a/testdata/result/query/select_from_ml_predict_hint.sql.txt
+++ b/testdata/result/query/select_from_ml_predict_hint.sql.txt
@@ -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}
diff --git a/testdata/result/query/select_from_ml_predict_textbison.sql.txt b/testdata/result/query/select_from_ml_predict_textbison.sql.txt
index 1d267c7..9d2cd59 100644
--- a/testdata/result/query/select_from_ml_predict_textbison.sql.txt
+++ b/testdata/result/query/select_from_ml_predict_textbison.sql.txt
@@ -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}
diff --git a/testdata/result/query/select_literals_all.sql.txt b/testdata/result/query/select_literals_all.sql.txt
index da90294..2e48807 100644
--- a/testdata/result/query/select_literals_all.sql.txt
+++ b/testdata/result/query/select_literals_all.sql.txt
@@ -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
diff --git a/testdata/result/query/select_literals_bytes.sql.txt b/testdata/result/query/select_literals_bytes.sql.txt
index 498b121..75cc4af 100644
--- a/testdata/result/query/select_literals_bytes.sql.txt
+++ b/testdata/result/query/select_literals_bytes.sql.txt
@@ -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"???"
diff --git a/testdata/result/query/select_literals_string.sql.txt b/testdata/result/query/select_literals_string.sql.txt
index 8686fd5..3ee1890 100644
--- a/testdata/result/query/select_literals_string.sql.txt
+++ b/testdata/result/query/select_literals_string.sql.txt
@@ -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\\)"
diff --git a/testdata/result/query/select_subscript_operators.sql.txt b/testdata/result/query/select_subscript_operators.sql.txt
index 0ee39c7..5427677 100644
--- a/testdata/result/query/select_subscript_operators.sql.txt
+++ b/testdata/result/query/select_subscript_operators.sql.txt
@@ -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"]
diff --git a/testdata/result/statement/create_table_for_format_test.sql.txt b/testdata/result/statement/create_table_for_format_test.sql.txt
index fe292d4..bba5100 100644
--- a/testdata/result/statement/create_table_for_format_test.sql.txt
+++ b/testdata/result/statement/create_table_for_format_test.sql.txt
@@ -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,
@@ -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{
diff --git a/testdata/result/statement/create_table_with_identity_columns.sql.txt b/testdata/result/statement/create_table_with_identity_columns.sql.txt
index a88f5ba..41dbf3e 100644
--- a/testdata/result/statement/create_table_with_identity_columns.sql.txt
+++ b/testdata/result/statement/create_table_with_identity_columns.sql.txt
@@ -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)
diff --git a/testdata/result/statement/select_from_ml_predict_hint.sql.txt b/testdata/result/statement/select_from_ml_predict_hint.sql.txt
index cc99b9a..78b338b 100644
--- a/testdata/result/statement/select_from_ml_predict_hint.sql.txt
+++ b/testdata/result/statement/select_from_ml_predict_hint.sql.txt
@@ -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}
diff --git a/testdata/result/statement/select_from_ml_predict_textbison.sql.txt b/testdata/result/statement/select_from_ml_predict_textbison.sql.txt
index 1d267c7..9d2cd59 100644
--- a/testdata/result/statement/select_from_ml_predict_textbison.sql.txt
+++ b/testdata/result/statement/select_from_ml_predict_textbison.sql.txt
@@ -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}
diff --git a/testdata/result/statement/select_literals_all.sql.txt b/testdata/result/statement/select_literals_all.sql.txt
index da90294..2e48807 100644
--- a/testdata/result/statement/select_literals_all.sql.txt
+++ b/testdata/result/statement/select_literals_all.sql.txt
@@ -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
diff --git a/testdata/result/statement/select_literals_bytes.sql.txt b/testdata/result/statement/select_literals_bytes.sql.txt
index 498b121..75cc4af 100644
--- a/testdata/result/statement/select_literals_bytes.sql.txt
+++ b/testdata/result/statement/select_literals_bytes.sql.txt
@@ -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"???"
diff --git a/testdata/result/statement/select_literals_string.sql.txt b/testdata/result/statement/select_literals_string.sql.txt
index 8686fd5..3ee1890 100644
--- a/testdata/result/statement/select_literals_string.sql.txt
+++ b/testdata/result/statement/select_literals_string.sql.txt
@@ -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\\)"
diff --git a/testdata/result/statement/select_subscript_operators.sql.txt b/testdata/result/statement/select_subscript_operators.sql.txt
index 0ee39c7..5427677 100644
--- a/testdata/result/statement/select_subscript_operators.sql.txt
+++ b/testdata/result/statement/select_subscript_operators.sql.txt
@@ -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"]
diff --git a/token/quote_test.go b/token/quote_test.go
index 051f497..adcad8c 100644
--- a/token/quote_test.go
+++ b/token/quote_test.go
@@ -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) {