8000 Non-decimal integer literals · postgres/postgres@6fcda9a · GitHub
[go: up one dir, main page]

Skip to content

Commit 6fcda9a

Browse 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

File tree

16 files changed

+1028
-118
lines changed
  • test/regress
  • 16 files changed

    +1028
    -118
    lines changed

    doc/src/sgml/syntax.sgml

    Lines 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

    Lines 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

    Lines 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

    Lines 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

    Lines 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}+
    385 10000 385
    * 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}{i 57AE dent_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