From 2f3206c4159f2b31b6b8c29e4bceb94c5fd770d8 Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 16:58:37 +0900
Subject: [PATCH 1/8] Fix literals format

---
 testdata/result/expr/cast_as_typename.sql.txt |  2 +-
 testdata/result/expr/json_literal.sql.txt     |  2 +-
 .../result/query/select_literals_all.sql.txt  |  2 +-
 .../query/select_literals_bytes.sql.txt       |  2 +-
 .../query/select_literals_string.sql.txt      |  2 +-
 .../query/select_subscript_operators.sql.txt  |  2 +-
 .../statement/select_literals_all.sql.txt     |  2 +-
 .../statement/select_literals_bytes.sql.txt   |  2 +-
 .../statement/select_literals_string.sql.txt  |  2 +-
 .../select_subscript_operators.sql.txt        |  2 +-
 token/quote.go                                | 79 ++++++++++++-------
 token/quote_test.go                           | 14 ++--
 12 files changed, 67 insertions(+), 46 deletions(-)

diff --git a/testdata/result/expr/cast_as_typename.sql.txt b/testdata/result/expr/cast_as_typename.sql.txt
index 6f45397d..295f0ef1 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 6e358b4a..ade4d746 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/query/select_literals_all.sql.txt b/testdata/result/query/select_literals_all.sql.txt
index da902945..371cad18 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 498b1214..c4803601 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\n", 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 8686fd58..2f76d240 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 0ee39c7b..54276770 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/select_literals_all.sql.txt b/testdata/result/statement/select_literals_all.sql.txt
index da902945..371cad18 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 498b1214..c4803601 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\n", 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 8686fd58..2f76d240 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 0ee39c7b..54276770 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.go b/token/quote.go
index 6ded3213..9f510510 100644
--- a/token/quote.go
+++ b/token/quote.go
@@ -10,30 +10,53 @@ 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(quote, s, &buf)
+	buf.WriteRune(quote)
 	return buf.String()
 }
 
+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 '"'
+}
+
 // QuoteSQLString 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(quote, rune(b))
 		if q != "" {
 			buf.WriteString(q)
 			continue
 		}
-		if char.IsPrint(b) {
+
+		// Note: char.IsPrint(' ') is false
+		if b == ' ' || 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()
 }
 
@@ -46,14 +69,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(quote rune, s string, buf *bytes.Buffer) {
 	for _, r := range s {
-		q := quoteSingleEscape(r)
+		q := quoteSingleEscape(quote, r)
 		if q != "" {
 			buf.WriteString(q)
 			continue
@@ -63,39 +86,37 @@ func quoteSQLStringContent(s string, buf *bytes.Buffer) {
 			continue
 		}
 		if r > 0xFFFF {
-			fmt.Fprintf(buf, "\\U%08X", uint64(r))
+			fmt.Fprintf(buf, `\U%08x`, uint64(r))
 		} else {
-			fmt.Fprintf(buf, "\\u%04X", uint64(r))
+			fmt.Fprintf(buf, `\u%04x`, uint64(r))
 		}
 	}
 }
 
-func quoteSingleEscape(r rune) string {
+func quoteSingleEscape(quote, r rune) string {
+	if quote == r {
+		return `\` + string(r)
+	}
+
 	switch r {
 	case '\a':
-		return "\\a"
+		return `\a`
 	case '\b':
-		return "\\b"
+		return `\b`
 	case '\f':
-		return "\\f"
+		return `\f`
 	case '\n':
-		return "\\n"
+		return `\n`
 	case '\r':
-		return "\\r"
+		return `\r`
 	case '\t':
-		return "\\t"
+		return `\t`
 	case '\v':
-		return "\\v"
-	case '"':
-		return "\\\""
-	case '\'':
-		return "\\'"
-	case '`':
-		return "\\`"
+		return `\v`
 	case '?':
-		return "\\?"
+		return `\?`
 	case '\\':
-		return "\\\\"
+		return `\\`
 	}
 	return ""
 }
diff --git a/token/quote_test.go b/token/quote_test.go
index 051f4973..00bea4fd 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", `"\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\"`\"", "`\\``"},
 }
 
 func TestQuote(t *testing.T) {

From a95f042ae2cb4db17614fe2eb4ab07f84e8fadc7 Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:25:46 +0900
Subject: [PATCH 2/8] Fit to align FORMAT("%T", input)

---
 char/is.go     |  2 +-
 token/quote.go | 41 +++++++++++++++++------------------------
 2 files changed, 18 insertions(+), 25 deletions(-)

diff --git a/char/is.go b/char/is.go
index b5944e18..71bd9883 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 9f510510..642b7700 100644
--- a/token/quote.go
+++ b/token/quote.go
@@ -43,14 +43,13 @@ func QuoteSQLBytes(bs []byte) string {
 	buf.WriteString("b")
 	buf.WriteRune(quote)
 	for _, b := range bs {
-		q := quoteSingleEscape(quote, rune(b))
+		q := quoteSingleEscape(rune(b), quote, false)
 		if q != "" {
 			buf.WriteString(q)
 			continue
 		}
 
-		// Note: char.IsPrint(' ') is false
-		if b == ' ' || char.IsPrint(b) {
+		if char.IsPrint(b) {
 			buf.WriteByte(b)
 			continue
 		}
@@ -60,7 +59,7 @@ func QuoteSQLBytes(bs []byte) string {
 	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) {
@@ -76,7 +75,7 @@ func QuoteSQLIdent(s string) string {
 
 func quoteSQLStringContent(quote rune, s string, buf *bytes.Buffer) {
 	for _, r := range s {
-		q := quoteSingleEscape(quote, r)
+		q := quoteSingleEscape(r, quote, /* isString */ true)
 		if q != "" {
 			buf.WriteString(q)
 			continue
@@ -85,37 +84,31 @@ func quoteSQLStringContent(quote rune, s string, buf *bytes.Buffer) {
 			buf.WriteRune(r)
 			continue
 		}
-		if r > 0xFFFF {
+		switch {
+		case r < 0x80:
+			fmt.Fprintf(buf, `\x%02x`, uint64(r))
+		case r > 0xFFFF:
 			fmt.Fprintf(buf, `\U%08x`, uint64(r))
-		} else {
+		default:
 			fmt.Fprintf(buf, `\u%04x`, uint64(r))
 		}
 	}
 }
 
-func quoteSingleEscape(quote, r rune) string {
+func quoteSingleEscape(r, quote rune, isString bool) string {
 	if quote == r {
-		return `\` + string(r)
 	}
 
-	switch r {
-	case '\a':
-		return `\a`
-	case '\b':
-		return `\b`
-	case '\f':
-		return `\f`
-	case '\n':
+	switch {
+	case r == quote:
+		return `\` + string(r)
+	case isString && r == '\n':
 		return `\n`
-	case '\r':
+	case isString && r == '\r':
 		return `\r`
-	case '\t':
+	case isString && r == '\t':
 		return `\t`
-	case '\v':
-		return `\v`
-	case '?':
-		return `\?`
-	case '\\':
+	case isString && r == '\\':
 		return `\\`
 	}
 	return ""

From acb26ea5e2159f6ff9a935ed085a9356207afa44 Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:26:06 +0900
Subject: [PATCH 3/8] Update testdata

---
 .../input/expr/bytes_literal_seven_bits.sql   |  1 +
 .../input/expr/string_literal_seven_bits.sql  |  1 +
 .../ddl/create_table_for_format_test.sql.txt  |  8 ++++----
 ...create_table_with_identity_columns.sql.txt |  7 ++++++-
 .../expr/bytes_literal_seven_bits.sql.txt     | 19 +++++++++++++++++++
 .../expr/string_literal_seven_bits.sql.txt    | 10 ++++++++++
 .../query/select_from_ml_predict_hint.sql.txt |  2 +-
 .../select_from_ml_predict_textbison.sql.txt  |  2 +-
 .../result/query/select_literals_all.sql.txt  |  2 +-
 .../query/select_literals_bytes.sql.txt       |  2 +-
 .../query/select_literals_string.sql.txt      |  2 +-
 .../create_table_for_format_test.sql.txt      |  8 ++++----
 ...create_table_with_identity_columns.sql.txt |  7 ++++++-
 .../select_from_ml_predict_hint.sql.txt       |  2 +-
 .../select_from_ml_predict_textbison.sql.txt  |  2 +-
 .../statement/select_literals_all.sql.txt     |  2 +-
 .../statement/select_literals_bytes.sql.txt   |  2 +-
 .../statement/select_literals_string.sql.txt  |  2 +-
 18 files changed, 61 insertions(+), 20 deletions(-)
 create mode 100644 testdata/input/expr/bytes_literal_seven_bits.sql
 create mode 100644 testdata/input/expr/string_literal_seven_bits.sql
 create mode 100644 testdata/result/expr/bytes_literal_seven_bits.sql.txt
 create mode 100644 testdata/result/expr/string_literal_seven_bits.sql.txt

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 00000000..e6edb149
--- /dev/null
+++ b/testdata/input/expr/bytes_literal_seven_bits.sql
@@ -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"
\ 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 00000000..799f906a
--- /dev/null
+++ b/testdata/input/expr/string_literal_seven_bits.sql
@@ -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"
\ 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 fe292d4f..bba51007 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 a88f5ba6..41dbf3eb 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 00000000..e8e4aaf8
--- /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/string_literal_seven_bits.sql.txt b/testdata/result/expr/string_literal_seven_bits.sql.txt
new file mode 100644
index 00000000..04fee57c
--- /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 cc99b9a8..78b338b2 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 1d267c79..9d2cd598 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 371cad18..2e488079 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 c4803601..e7d8c8d7 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 2f76d240..3ee18903 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/statement/create_table_for_format_test.sql.txt b/testdata/result/statement/create_table_for_format_test.sql.txt
index fe292d4f..bba51007 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 a88f5ba6..41dbf3eb 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 cc99b9a8..78b338b2 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 1d267c79..9d2cd598 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 371cad18..2e488079 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 c4803601..e7d8c8d7 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 2f76d240..3ee18903 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\\)"

From c78c0996847267225367a62e7b427e493d376598 Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:33:34 +0900
Subject: [PATCH 4/8] Fix bug

---
 testdata/result/expr/bytes_literal_seven_bits.sql.txt   | 2 +-
 testdata/result/query/select_literals_bytes.sql.txt     | 2 +-
 testdata/result/statement/select_literals_bytes.sql.txt | 2 +-
 token/quote.go                                          | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/testdata/result/expr/bytes_literal_seven_bits.sql.txt b/testdata/result/expr/bytes_literal_seven_bits.sql.txt
index e8e4aaf8..24dd8a7a 100644
--- a/testdata/result/expr/bytes_literal_seven_bits.sql.txt
+++ b/testdata/result/expr/bytes_literal_seven_bits.sql.txt
@@ -16,4 +16,4 @@ b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x
 }
 
 --- 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"
+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/query/select_literals_bytes.sql.txt b/testdata/result/query/select_literals_bytes.sql.txt
index e7d8c8d7..75cc4af4 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\x0a", 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_bytes.sql.txt b/testdata/result/statement/select_literals_bytes.sql.txt
index e7d8c8d7..75cc4af4 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\x0a", 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/token/quote.go b/token/quote.go
index 642b7700..fef88549 100644
--- a/token/quote.go
+++ b/token/quote.go
@@ -108,7 +108,7 @@ func quoteSingleEscape(r, quote rune, isString bool) string {
 		return `\r`
 	case isString && r == '\t':
 		return `\t`
-	case isString && r == '\\':
+	case r == '\\':
 		return `\\`
 	}
 	return ""

From 6dc994c780d133dbab12ba2c2a7a514afd6b5eae Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:35:55 +0900
Subject: [PATCH 5/8] Add comments

---
 token/quote.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/token/quote.go b/token/quote.go
index fef88549..5e946cae 100644
--- a/token/quote.go
+++ b/token/quote.go
@@ -35,7 +35,7 @@ func suitableQuote(b []byte) rune {
 	return '"'
 }
 
-// QuoteSQLString returns quoted string with SQL bytes escaping.
+// QuoteSQLBytes returns quoted string with SQL bytes escaping.
 func QuoteSQLBytes(bs []byte) string {
 	quote := suitableQuote(bs)
 
@@ -43,7 +43,7 @@ func QuoteSQLBytes(bs []byte) string {
 	buf.WriteString("b")
 	buf.WriteRune(quote)
 	for _, b := range bs {
-		q := quoteSingleEscape(rune(b), quote, false)
+		q := quoteSingleEscape(rune(b), quote, /* isString */ false)
 		if q != "" {
 			buf.WriteString(q)
 			continue

From 6b776492b38e7c13c8702c2d8b5385c1a5275900 Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:37:08 +0900
Subject: [PATCH 6/8] Fix argument order

---
 token/quote.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/token/quote.go b/token/quote.go
index 5e946cae..8b1a0462 100644
--- a/token/quote.go
+++ b/token/quote.go
@@ -14,7 +14,7 @@ func QuoteSQLString(s string) string {
 
 	var buf bytes.Buffer
 	buf.WriteRune(quote)
-	quoteSQLStringContent(quote, s, &buf)
+	quoteSQLStringContent(s, quote, &buf)
 	buf.WriteRune(quote)
 	return buf.String()
 }
@@ -68,12 +68,12 @@ func QuoteSQLIdent(s string) string {
 
 	var buf bytes.Buffer
 	buf.WriteByte('`')
-	quoteSQLStringContent('`', s, &buf)
+	quoteSQLStringContent(s, '`', &buf)
 	buf.WriteByte('`')
 	return buf.String()
 }
 
-func quoteSQLStringContent(quote rune, s string, buf *bytes.Buffer) {
+func quoteSQLStringContent(s string, quote rune, buf *bytes.Buffer) {
 	for _, r := range s {
 		q := quoteSingleEscape(r, quote, /* isString */ true)
 		if q != "" {

From 5f338e68f906802a200b2c34fbc071f5dd6bf0a4 Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:45:00 +0900
Subject: [PATCH 7/8] Fix tests

---
 char/is_test.go     | 8 ++++++--
 token/quote_test.go | 4 ++--
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/char/is_test.go b/char/is_test.go
index c3738e01..73ddc70f 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/token/quote_test.go b/token/quote_test.go
index 00bea4fd..adcad8c5 100644
--- a/token/quote_test.go
+++ b/token/quote_test.go
@@ -10,10 +10,10 @@ var quoteTestCases = []struct {
 }{
 	{"foo", `"foo"`, `b"foo"`, "foo"},
 	{"if", `"if"`, `b"if"`, "`if`"},
-	{"\u0000", `"\u0000"`, `b"\x00"`, "`\\u0000`"},
+	{"\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\"'?\\", `"\a\b\f\n\r\t\v\"'\?\\"`, `b"\a\b\f\n\r\t\v\"'\?\\"`, "`\\a\\b\\f\\n\\r\\t\\v\"'\\?\\\\`"},
+	{"\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\"`\"", "`\\``"},
 }
 

From 395981c61dfe6cdcd509fbc62019af90bcf884f7 Mon Sep 17 00:00:00 2001
From: apstndb <803393+apstndb@users.noreply.github.com>
Date: Thu, 19 Dec 2024 18:50:58 +0900
Subject: [PATCH 8/8] Remove empty branch

---
 token/quote.go | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/token/quote.go b/token/quote.go
index 8b1a0462..78187b2f 100644
--- a/token/quote.go
+++ b/token/quote.go
@@ -96,9 +96,6 @@ func quoteSQLStringContent(s string, quote rune, buf *bytes.Buffer) {
 }
 
 func quoteSingleEscape(r, quote rune, isString bool) string {
-	if quote == r {
-	}
-
 	switch {
 	case r == quote:
 		return `\` + string(r)