Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6fcda9a

Browse filesBrowse files
committed
Non-decimal integer literals
Add support for hexadecimal, octal, and binary integer literals: 0x42F 0o273 0b100101 per SQL:202x draft. This adds support in the lexer as well as in the integer type input functions. Reviewed-by: John Naylor <john.naylor@enterprisedb.com> Reviewed-by: Zhihong Yu <zyu@yugabyte.com> Reviewed-by: David Rowley <dgrowleyml@gmail.com> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/b239564c-cad0-b23e-c57e-166d883cb97d@enterprisedb.com
1 parent 60684dd commit 6fcda9a
Copy full SHA for 6fcda9a

File tree

16 files changed

+1028
-118
lines changed
Filter options

16 files changed

+1028
-118
lines changed

‎doc/src/sgml/syntax.sgml

Copy file name to clipboardExpand all lines: doc/src/sgml/syntax.sgml
+34Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,40 @@ $function$
694694
</literallayout>
695695
</para>
696696

697+
<para>
698+
Additionally, non-decimal integer constants can be used in these forms:
699+
<synopsis>
700+
0x<replaceable>hexdigits</replaceable>
701+
0o<replaceable>octdigits</replaceable>
702+
0b<replaceable>bindigits</replaceable>
703+
</synopsis>
704+
<replaceable>hexdigits</replaceable> is one or more hexadecimal digits
705+
(0-9, A-F), <replaceable>octdigits</replaceable> is one or more octal
706+
digits (0-7), <replaceable>bindigits</replaceable> is one or more binary
707+
digits (0 or 1). Hexadecimal digits and the radix prefixes can be in
708+
upper or lower case. Note that only integers can have non-decimal forms,
709+
not numbers with fractional parts.
710+
</para>
711+
712+
<para>
713+
These are some examples of this:
714+
<literallayout>0b100101
715+
0B10011001
716+
0o273
717+
0O755
718+
0x42f
719+
0XFFFF
720+
</literallayout>
721+
</para>
722+
723+
<note>
724+
<para>
725+
Nondecimal integer constants are currently only supported in the range
726+
of the <type>bigint</type> type (see <xref
727+
linkend="datatype-numeric-table"/>).
728+
</para>
729+
</note>
730+
697731
<para>
698732
<indexterm><primary>integer</primary></indexterm>
699733
<indexterm><primary>bigint</primary></indexterm>

‎src/backend/catalog/information_schema.sql

Copy file name to clipboardExpand all lines: src/backend/catalog/information_schema.sql
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ RETURN
119119
WHEN 1700 /*numeric*/ THEN
120120
CASE WHEN $2 = -1
121121
THEN null
122-
ELSE (($2 - 4) >> 16) & 65535
122+
ELSE (($2 - 4) >> 16) & 0xFFFF
123123
END
124124
WHEN 700 /*float4*/ THEN 24 /*FLT_MANT_DIG*/
125125
WHEN 701 /*float8*/ THEN 53 /*DBL_MANT_DIG*/
@@ -147,7 +147,7 @@ RETURN
147147
WHEN $1 IN (1700) THEN
148148
CASE WHEN $2 = -1
149149
THEN null
150-
ELSE ($2 - 4) & 65535
150+
ELSE ($2 - 4) & 0xFFFF
151151
END
152152
ELSE null
153153
END;
@@ -163,7 +163,7 @@ RETURN
163163
WHEN $1 IN (1083, 1114, 1184, 1266) /* time, timestamp, same + tz */
164164
THEN CASE WHEN $2 < 0 THEN 6 ELSE $2 END
165165
WHEN $1 IN (1186) /* interval */
166-
THEN CASE WHEN $2 < 0 OR $2 & 65535 = 65535 THEN 6 ELSE $2 & 65535 END
166+
THEN CASE WHEN $2 < 0 OR $2 & 0xFFFF = 0xFFFF THEN 6 ELSE $2 & 0xFFFF END
167167
ELSE null
168168
END;
169169

‎src/backend/catalog/sql_features.txt

Copy file name to clipboardExpand all lines: src/backend/catalog/sql_features.txt
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ T652 SQL-dynamic statements in SQL routines NO
527527
T653 SQL-schema statements in external routines YES
528528
T654 SQL-dynamic statements in external routines NO
529529
T655 Cyclically dependent routines YES
530+
T661 Non-decimal integer literals YES SQL:202x draft
530531
T811 Basic SQL/JSON constructor functions NO
531532
T812 SQL/JSON: JSON_OBJECTAGG NO
532533
T813 SQL/JSON: JSON_ARRAYAGG with ORDER BY NO

‎src/backend/parser/parse_node.c

Copy file name to clipboardExpand all lines: src/backend/parser/parse_node.c
+36-1Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,11 +385,46 @@ make_const(ParseState *pstate, A_Const *aconst)
385385
{
386386
/* could be an oversize integer as well as a float ... */
387387

388+
int base = 10;
389+
char *startptr;
390+
int sign;
391+
char *testvalue;
388392
int64 val64;
389393
char *endptr;
390394

395+
startptr = aconst->val.fval.fval;
396+
if (startptr[0] == '-')
397+
{
398+
sign = -1;
399+
startptr++;
400+
}
401+
else
402+
sign = +1;
403+
if (startptr[0] == '0')
404+
{
405+
if (startptr[1] == 'b' || startptr[1] == 'B')
406+
{
407+
base = 2;
408+
startptr += 2;
409+
}
410+
else if (startptr[1] == 'o' || startptr[1] == 'O')
411+
{
412+
base = 8;
413+
startptr += 2;
414+
}
415+
if (startptr[1] == 'x' || startptr[1] == 'X')
416+
{
417+
base = 16;
418+
startptr += 2;
419+
}
420+
}
421+
422+
if (sign == +1)
423+
testvalue = startptr;
424+
else
425+
testvalue = psprintf("-%s", startptr);
391426
errno = 0;
392-
val64 = strtoi64(aconst->val.fval.fval, &endptr, 10);
427+
val64 = strtoi64(testvalue, &endptr, base);
393428
if (errno == 0 && *endptr == '\0')
394429
{
395430
/*

‎src/backend/parser/scan.l

Copy file name to clipboardExpand all lines: src/backend/parser/scan.l
+76-25Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ static void addlit(char *ytext, int yleng, core_yyscan_t yyscanner);
124124
static void addlitchar(unsigned char ychar, core_yyscan_t yyscanner);
125125
static char *litbufdup(core_yyscan_t yyscanner);
126126
static unsigned char unescape_single_char(unsigned char c, core_yyscan_t yyscanner);
127-
static int process_integer_literal(const char *token, YYSTYPE *lval);
127+
static int process_integer_literal(const char *token, YYSTYPE *lval, int base);
128128
static void addunicode(pg_wchar c, yyscan_t yyscanner);
129129

130130
#define yyerror(msg) scanner_yyerror(msg, yyscanner)
@@ -385,25 +385,40 @@ operator {op_chars}+
385385
* Unary minus is not part of a number here. Instead we pass it separately to
386386
* the parser, and there it gets coerced via doNegate().
387387
*
388-
* {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
388+
* {numericfail} is used because we would like "1..10" to lex as 1, dot_dot, 10.
389389
*
390390
* {realfail} is added to prevent the need for scanner
391391
* backup when the {real} rule fails to match completely.
392392
*/
393-
digit [0-9]
394-
395-
integer {digit}+
396-
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
397-
decimalfail {digit}+\.\.
398-
real ({integer}|{decimal})[Ee][-+]?{digit}+
399-
realfail ({integer}|{decimal})[Ee][-+]
400-
401-
integer_junk {integer}{ident_start}
402-
decimal_junk {decimal}{ident_start}
393+
decdigit [0-9]
394+
hexdigit [0-9A-Fa-f]
395+
octdigit [0-7]
396+
bindigit [0-1]
397+
398+
decinteger {decdigit}+
399+
hexinteger 0[xX]{hexdigit}+
400+
octinteger 0[oO]{octdigit}+
401+
bininteger 0[bB]{bindigit}+
402+
403+
hexfail 0[xX]
404+
octfail 0[oO]
405+
binfail 0[bB]
406+
407+
numeric (({decinteger}\.{decinteger}?)|(\.{decinteger}))
408+
numericfail {decdigit}+\.\.
409+
410+
real ({decinteger}|{numeric})[Ee][-+]?{decdigit}+
411+
realfail ({decinteger}|{numeric})[Ee][-+]
412+
413+
decinteger_junk {decinteger}{ident_start}
414+
hexinteger_junk {hexinteger}{ident_start}
415+
octinteger_junk {octinteger}{ident_start}
416+
bininteger_junk {bininteger}{ident_start}
417+
numeric_junk {numeric}{ident_start}
403418
real_junk {real}{ident_start}
404419

405-
param \${integer}
406-
param_junk \${integer}{ident_start}
420+
param \${decinteger}
421+
param_junk \${decinteger}{ident_start}
407422

408423
other .
409424

@@ -983,20 +998,44 @@ other .
983998
yyerror("trailing junk after parameter");
984999
}
9851000

986-
{integer} {
1001+
{decinteger} {
1002+
SET_YYLLOC();
1003+
return process_integer_literal(yytext, yylval, 10);
1004+
}
1005+
{hexinteger} {
1006+
SET_YYLLOC();
1007+
return process_integer_literal(yytext, yylval, 16);
1008+
}
1009+
{octinteger} {
1010+
SET_YYLLOC();
1011+
return process_integer_literal(yytext, yylval, 8);
1012+
}
1013+
{bininteger} {
1014+
SET_YYLLOC();
1015+
return process_integer_literal(yytext, yylval, 2);
1016+
}
1017+
{hexfail} {
1018+
SET_YYLLOC();
1019+
yyerror("invalid hexadecimal integer");
1020+
}
1021+
{octfail} {
9871022
SET_YYLLOC();
988-
return process_integer_literal(yytext, yylval);
1023+
yyerror("invalid octal integer");
9891024
}
990-
{decimal} {
1025+
{binfail} {
1026+
SET_YYLLOC();
1027+
yyerror("invalid binary integer");
1028+
}
1029+
{numeric} {
9911030
SET_YYLLOC();
9921031
yylval->str = pstrdup(yytext);
9931032
return FCONST;
9941033
}
995-
{decimalfail} {
1034+
{numericfail} {
9961035
/* throw back the .., and treat as integer */
9971036
yyless(yyleng - 2);
9981037
SET_YYLLOC();
999-
return process_integer_literal(yytext, yylval);
1038+
return process_integer_literal(yytext, yylval, 10);
10001039
}
10011040
{real} {
10021041
SET_YYLLOC();
@@ -1007,11 +1046,23 @@ other .
10071046
SET_YYLLOC();
10081047
yyerror("trailing junk after numeric literal");
10091048
}
1010-
{integer_junk} {
1049+
{decinteger_junk} {
1050+
SET_YYLLOC();
1051+
yyerror("trailing junk after numeric literal");
1052+
}
1053+
{hexinteger_junk} {
1054+
SET_YYLLOC();
1055+
yyerror("trailing junk after numeric literal");
1056+
}
1057+
{octinteger_junk} {
1058+
SET_YYLLOC();
1059+
yyerror("trailing junk after numeric literal");
1060+
}
1061+
{bininteger_junk} {
10111062
SET_YYLLOC();
10121063
yyerror("trailing junk after numeric literal");
10131064
}
1014-
{decimal_junk} {
1065+
{numeric_junk} {
10151066
SET_YYLLOC();
10161067
yyerror("trailing junk after numeric literal");
10171068
}
@@ -1307,17 +1358,17 @@ litbufdup(core_yyscan_t yyscanner)
13071358
}
13081359

13091360
/*
1310-
* Process {integer}. Note this will also do the right thing with {decimal},
1311-
* ie digits and a decimal point.
1361+
* Process {decinteger}, {hexinteger}, etc. Note this will also do the right
1362+
* thing with {numeric}, ie digits and a decimal point.
13121363
*/
13131364
static int
1314-
process_integer_literal(const char *token, YYSTYPE *lval)
1365+
process_integer_literal(const char *token, YYSTYPE *lval, int base)
13151366
{
13161367
int val;
13171368
char *endptr;
13181369

13191370
errno = 0;
1320-
val = strtoint(token, &endptr, 10);
1371+
val = strtoint(base == 10 ? token : token + 2, &endptr, base);
13211372
if (*endptr != '\0' || errno == ERANGE)
13221373
{
13231374
/* integer too large (or contains decimal pt), treat it as a float */

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.