aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2024-02-13 12:18:25 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2024-02-13 12:18:25 -0500
commitf15d01cb5dbdc44276f82178759586023896a3b7 (patch)
tree57d9a44cc14785818eac78abf722e2b574ace320 /src
parent103235888d9e74755ec4c7a72d640d4c7fabc596 (diff)
downloadpostgresql-f15d01cb5dbdc44276f82178759586023896a3b7.tar.gz
postgresql-f15d01cb5dbdc44276f82178759586023896a3b7.zip
Use a safer outfuncs/readfuncs representation for BitStrings.
For a long time, our outfuncs.c code has supposed that the string contents of a BitString node could just be printed literally with no concern for quoting/escaping. Now, that's okay if the string literal contains only valid binary or hex digits ... but our lexer doesn't check that, preferring to let bitin() be the sole authority on what's valid. So we could have raw parse trees that contain incorrect BitString literals, and that can result in failures when WRITE_READ_PARSE_PLAN_TREES debugging is enabled. Fix by using outToken() to print the string field, and debackslash() to read it. This results in a change in the emitted representation only in cases that would have failed before, and don't represent valid SQL in the first place. Between that and the fact that we don't store raw parse trees in the catalogs, I judge this safe to apply without a catversion bump. Per bug #18340 from Alexander Lakhin. Back-patch to v16; before that, we lacked readfuncs support for BitString nodes, so that the problem was only cosmetic. Discussion: https://postgr.es/m/18340-4aa1ae6ed4121912@postgresql.org
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/outfuncs.c9
-rw-r--r--src/backend/nodes/read.c11
-rw-r--r--src/test/regress/expected/bit.out17
-rw-r--r--src/test/regress/sql/bit.sql5
4 files changed, 32 insertions, 10 deletions
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 955286513d2..e56392e6f9d 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -680,8 +680,13 @@ _outString(StringInfo str, const String *node)
static void
_outBitString(StringInfo str, const BitString *node)
{
- /* internal representation already has leading 'b' */
- appendStringInfoString(str, node->bsval);
+ /*
+ * The lexer will always produce a string starting with 'b' or 'x'. There
+ * might be characters following that that need escaping, but outToken
+ * won't escape the 'b' or 'x'. This is relied on by nodeTokenType.
+ */
+ Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
+ outToken(str, node->bsval);
}
static void
diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c
index 813eda3e739..5d76f56e4e8 100644
--- a/src/backend/nodes/read.c
+++ b/src/backend/nodes/read.c
@@ -498,14 +498,9 @@ nodeRead(const char *token, int tok_len)
result = (Node *) makeString(debackslash(token + 1, tok_len - 2));
break;
case T_BitString:
- {
- char *val = palloc(tok_len + 1);
-
- memcpy(val, token, tok_len);
- val[tok_len] = '\0';
- result = (Node *) makeBitString(val);
- break;
- }
+ /* need to remove backslashes, but there are no quotes */
+ result = (Node *) makeBitString(debackslash(token, tok_len));
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) type);
result = NULL; /* keep compiler happy */
diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out
index 98c26550396..e17cbf42ca2 100644
--- a/src/test/regress/expected/bit.out
+++ b/src/test/regress/expected/bit.out
@@ -40,6 +40,23 @@ SELECT * FROM VARBIT_TABLE;
01010101010
(4 rows)
+-- Literals with syntax errors
+SELECT b' 0';
+ERROR: " " is not a valid binary digit
+LINE 1: SELECT b' 0';
+ ^
+SELECT b'0 ';
+ERROR: " " is not a valid binary digit
+LINE 1: SELECT b'0 ';
+ ^
+SELECT x' 0';
+ERROR: " " is not a valid hexadecimal digit
+LINE 1: SELECT x' 0';
+ ^
+SELECT x'0 ';
+ERROR: " " is not a valid hexadecimal digit
+LINE 1: SELECT x'0 ';
+ ^
-- Concatenation
SELECT v, b, (v || b) AS concat
FROM BIT_TABLE, VARBIT_TABLE
diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql
index 2cd550d27eb..34230b99fba 100644
--- a/src/test/regress/sql/bit.sql
+++ b/src/test/regress/sql/bit.sql
@@ -29,6 +29,11 @@ INSERT INTO VARBIT_TABLE VALUES (B'101011111010'); -- too long
--INSERT INTO VARBIT_TABLE VALUES ('X555');
SELECT * FROM VARBIT_TABLE;
+-- Literals with syntax errors
+SELECT b' 0';
+SELECT b'0 ';
+SELECT x' 0';
+SELECT x'0 ';
-- Concatenation
SELECT v, b, (v || b) AS concat