diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h index 5544d7f..58f4a71 100644 --- a/src/include/parser/gramparse.h +++ b/src/include/parser/gramparse.h @@ -8,8 +8,8 @@ * Definitions that are needed outside the core parser should be in parser.h. * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/gramparse.h @@ -24,6 +24,7 @@ #include "scanner.h" #define AMTYPE_INDEX 'i' /* index access method */ +#define AMTYPE_TABLE 't' /* table access method */ /* * NB: include gram.h only AFTER including scanner.h, because scanner.h @@ -68,8 +69,8 @@ typedef struct base_yy_extra_type /* from parser.c */ -extern int base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, - core_yyscan_t yyscanner); +extern int base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, + core_yyscan_t yyscanner); /* from gram.y */ extern void parser_init(base_yy_extra_type *yyext); diff --git a/src/include/parser/keywords.h b/src/include/parser/keywords.h index e2f44d0..9dd5fc2 100644 --- a/src/include/parser/keywords.h +++ b/src/include/parser/keywords.h @@ -1,39 +1,34 @@ /*------------------------------------------------------------------------- * * keywords.h - * lexical token lookup for key words in PostgreSQL + * PostgreSQL's list of SQL keywords * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * src/include/parser/keywords.h + * src/include/common/keywords.h * *------------------------------------------------------------------------- */ #ifndef KEYWORDS_H #define KEYWORDS_H +#include "kwlookup.h" + /* Keyword categories --- should match lists in gram.y */ #define UNRESERVED_KEYWORD 0 #define COL_NAME_KEYWORD 1 #define TYPE_FUNC_NAME_KEYWORD 2 #define RESERVED_KEYWORD 3 - -typedef struct ScanKeyword -{ - const char *name; /* in lower case */ - int16 value; /* grammar's token code */ - int16 category; /* see codes above */ -} ScanKeyword; - -extern PGDLLIMPORT const ScanKeyword ScanKeywords[]; -extern PGDLLIMPORT const int NumScanKeywords; - -extern const ScanKeyword *ScanKeywordLookup(const char *text, - const ScanKeyword *keywords, - int num_keywords); +#ifndef FRONTEND +extern PGDLLIMPORT const ScanKeywordList ScanKeywords; +extern PGDLLIMPORT const uint8 ScanKeywordCategories[]; +#else +extern const ScanKeywordList ScanKeywords; +extern const uint8 ScanKeywordCategories[]; +#endif #endif /* KEYWORDS_H */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 8e07e97..0e5d1f6 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -2,13 +2,13 @@ * * kwlist.h * - * The keyword list is kept in its own source file for possible use by + * The keyword lists are kept in their own source files for use by * automatic tools. The exact representation of a keyword is determined * by the PG_KEYWORD macro, which is not defined in this file; it can * be defined by the caller for special purposes. * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -22,8 +22,7 @@ /* * List of keyword (name, token-value, category) entries. * - * !!WARNING!!: This list must be sorted by ASCII name, because binary - * search is used to locate entries. + * Note: gen_keywordlist.pl requires the entries to appear in ASCII order. */ /* name, value, category */ @@ -386,10 +385,12 @@ PG_KEYWORD("statistics", STATISTICS, UNRESERVED_KEYWORD) PG_KEYWORD("stdin", STDIN, UNRESERVED_KEYWORD) PG_KEYWORD("stdout", STDOUT, UNRESERVED_KEYWORD) PG_KEYWORD("storage", STORAGE, UNRESERVED_KEYWORD) +PG_KEYWORD("stored", STORED, UNRESERVED_KEYWORD) PG_KEYWORD("strict", STRICT_P, UNRESERVED_KEYWORD) PG_KEYWORD("strip", STRIP_P, UNRESERVED_KEYWORD) PG_KEYWORD("subscription", SUBSCRIPTION, UNRESERVED_KEYWORD) PG_KEYWORD("substring", SUBSTRING, COL_NAME_KEYWORD) +PG_KEYWORD("support", SUPPORT, UNRESERVED_KEYWORD) PG_KEYWORD("symmetric", SYMMETRIC, RESERVED_KEYWORD) PG_KEYWORD("sysid", SYSID, UNRESERVED_KEYWORD) PG_KEYWORD("system", SYSTEM_P, UNRESERVED_KEYWORD) diff --git a/src/include/parser/kwlist_d.h b/src/include/parser/kwlist_d.h index e69de29..50a5eb6 100644 --- a/src/include/parser/kwlist_d.h +++ b/src/include/parser/kwlist_d.h @@ -0,0 +1,1057 @@ +/*------------------------------------------------------------------------- + * + * kwlist_d.h + * List of keywords represented as a ScanKeywordList. + * + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * NOTES + * ****************************** + * *** DO NOT EDIT THIS FILE! *** + * ****************************** + * + * It has been GENERATED by src/tools/gen_keywordlist.pl + * + *------------------------------------------------------------------------- + */ + +#ifndef KWLIST_D_H +#define KWLIST_D_H + +#include "kwlookup.h" + +static const char ScanKeywords_kw_string[] = + "abort\0" + "absolute\0" + "access\0" + "action\0" + "add\0" + "admin\0" + "after\0" + "aggregate\0" + "all\0" + "also\0" + "alter\0" + "always\0" + "analyse\0" + "analyze\0" + "and\0" + "any\0" + "array\0" + "as\0" + "asc\0" + "assertion\0" + "assignment\0" + "asymmetric\0" + "at\0" + "attach\0" + "attribute\0" + "authorization\0" + "backward\0" + "before\0" + "begin\0" + "between\0" + "bigint\0" + "binary\0" + "bit\0" + "boolean\0" + "both\0" + "by\0" + "cache\0" + "call\0" + "called\0" + "cascade\0" + "cascaded\0" + "case\0" + "cast\0" + "catalog\0" + "chain\0" + "char\0" + "character\0" + "characteristics\0" + "check\0" + "checkpoint\0" + "class\0" + "close\0" + "cluster\0" + "coalesce\0" + "collate\0" + "collation\0" + "column\0" + "columns\0" + "comment\0" + "comments\0" + "commit\0" + "committed\0" + "concurrently\0" + "configuration\0" + "conflict\0" + "connection\0" + "constraint\0" + "constraints\0" + "content\0" + "continue\0" + "conversion\0" + "copy\0" + "cost\0" + "create\0" + "cross\0" + "csv\0" + "cube\0" + "current\0" + "current_catalog\0" + "current_date\0" + "current_role\0" + "current_schema\0" + "current_time\0" + "current_timestamp\0" + "current_user\0" + "cursor\0" + "cycle\0" + "data\0" + "database\0" + "day\0" + "deallocate\0" + "dec\0" + "decimal\0" + "declare\0" + "default\0" + "defaults\0" + "deferrable\0" + "deferred\0" + "definer\0" + "delete\0" + "delimiter\0" + "delimiters\0" + "depends\0" + "desc\0" + "detach\0" + "dictionary\0" + "disable\0" + "discard\0" + "distinct\0" + "do\0" + "document\0" + "domain\0" + "double\0" + "drop\0" + "each\0" + "else\0" + "enable\0" + "encoding\0" + "encrypted\0" + "end\0" + "enum\0" + "escape\0" + "event\0" + "except\0" + "exclude\0" + "excluding\0" + "exclusive\0" + "execute\0" + "exists\0" + "explain\0" + "extension\0" + "external\0" + "extract\0" + "false\0" + "family\0" + "fetch\0" + "filter\0" + "first\0" + "float\0" + "following\0" + "for\0" + "force\0" + "foreign\0" + "forward\0" + "freeze\0" + "from\0" + "full\0" + "function\0" + "functions\0" + "generated\0" + "global\0" + "grant\0" + "granted\0" + "greatest\0" + "group\0" + "grouping\0" + "groups\0" + "handler\0" + "having\0" + "header\0" + "hold\0" + "hour\0" + "identity\0" + "if\0" + "ilike\0" + "immediate\0" + "immutable\0" + "implicit\0" + "import\0" + "in\0" + "include\0" + "including\0" + "increment\0" + "index\0" + "indexes\0" + "inherit\0" + "inherits\0" + "initially\0" + "inline\0" + "inner\0" + "inout\0" + "input\0" + "insensitive\0" + "insert\0" + "instead\0" + "int\0" + "integer\0" + "intersect\0" + "interval\0" + "into\0" + "invoker\0" + "is\0" + "isnull\0" + "isolation\0" + "join\0" + "key\0" + "label\0" + "language\0" + "large\0" + "last\0" + "lateral\0" + "leading\0" + "leakproof\0" + "least\0" + "left\0" + "level\0" + "like\0" + "limit\0" + "listen\0" + "load\0" + "local\0" + "localtime\0" + "localtimestamp\0" + "location\0" + "lock\0" + "locked\0" + "logged\0" + "mapping\0" + "match\0" + "materialized\0" + "maxvalue\0" + "method\0" + "minute\0" + "minvalue\0" + "mode\0" + "month\0" + "move\0" + "name\0" + "names\0" + "national\0" + "natural\0" + "nchar\0" + "new\0" + "next\0" + "no\0" + "none\0" + "not\0" + "nothing\0" + "notify\0" + "notnull\0" + "nowait\0" + "null\0" + "nullif\0" + "nulls\0" + "numeric\0" + "object\0" + "of\0" + "off\0" + "offset\0" + "oids\0" + "old\0" + "on\0" + "only\0" + "operator\0" + "option\0" + "options\0" + "or\0" + "order\0" + "ordinality\0" + "others\0" + "out\0" + "outer\0" + "over\0" + "overlaps\0" + "overlay\0" + "overriding\0" + "owned\0" + "owner\0" + "parallel\0" + "parser\0" + "partial\0" + "partition\0" + "passing\0" + "password\0" + "pgpool\0" + "placing\0" + "plans\0" + "policy\0" + "position\0" + "preceding\0" + "precision\0" + "prepare\0" + "prepared\0" + "preserve\0" + "primary\0" + "prior\0" + "privileges\0" + "procedural\0" + "procedure\0" + "procedures\0" + "program\0" + "publication\0" + "quote\0" + "range\0" + "read\0" + "real\0" + "reassign\0" + "recheck\0" + "recursive\0" + "ref\0" + "references\0" + "referencing\0" + "refresh\0" + "reindex\0" + "relative\0" + "release\0" + "rename\0" + "repeatable\0" + "replace\0" + "replica\0" + "reset\0" + "restart\0" + "restrict\0" + "returning\0" + "returns\0" + "revoke\0" + "right\0" + "role\0" + "rollback\0" + "rollup\0" + "routine\0" + "routines\0" + "row\0" + "rows\0" + "rule\0" + "savepoint\0" + "schema\0" + "schemas\0" + "scroll\0" + "search\0" + "second\0" + "security\0" + "select\0" + "sequence\0" + "sequences\0" + "serializable\0" + "server\0" + "session\0" + "session_user\0" + "set\0" + "setof\0" + "sets\0" + "share\0" + "show\0" + "similar\0" + "simple\0" + "skip\0" + "smallint\0" + "snapshot\0" + "some\0" + "sql\0" + "stable\0" + "standalone\0" + "start\0" + "statement\0" + "statistics\0" + "stdin\0" + "stdout\0" + "storage\0" + "stored\0" + "strict\0" + "strip\0" + "subscription\0" + "substring\0" + "support\0" + "symmetric\0" + "sysid\0" + "system\0" + "table\0" + "tables\0" + "tablesample\0" + "tablespace\0" + "temp\0" + "template\0" + "temporary\0" + "text\0" + "then\0" + "ties\0" + "time\0" + "timestamp\0" + "to\0" + "trailing\0" + "transaction\0" + "transform\0" + "treat\0" + "trigger\0" + "trim\0" + "true\0" + "truncate\0" + "trusted\0" + "type\0" + "types\0" + "unbounded\0" + "uncommitted\0" + "unencrypted\0" + "union\0" + "unique\0" + "unknown\0" + "unlisten\0" + "unlogged\0" + "until\0" + "update\0" + "user\0" + "using\0" + "vacuum\0" + "valid\0" + "validate\0" + "validator\0" + "value\0" + "values\0" + "varchar\0" + "variadic\0" + "varying\0" + "verbose\0" + "version\0" + "view\0" + "views\0" + "volatile\0" + "when\0" + "where\0" + "whitespace\0" + "window\0" + "with\0" + "within\0" + "without\0" + "work\0" + "wrapper\0" + "write\0" + "xml\0" + "xmlattributes\0" + "xmlconcat\0" + "xmlelement\0" + "xmlexists\0" + "xmlforest\0" + "xmlnamespaces\0" + "xmlparse\0" + "xmlpi\0" + "xmlroot\0" + "xmlserialize\0" + "xmltable\0" + "year\0" + "yes\0" + "zone"; + +static const uint16 ScanKeywords_kw_offsets[] = { + 0, + 6, + 15, + 22, + 29, + 33, + 39, + 45, + 55, + 59, + 64, + 70, + 77, + 85, + 93, + 97, + 101, + 107, + 110, + 114, + 124, + 135, + 146, + 149, + 156, + 166, + 180, + 189, + 196, + 202, + 210, + 217, + 224, + 228, + 236, + 241, + 244, + 250, + 255, + 262, + 270, + 279, + 284, + 289, + 297, + 303, + 308, + 318, + 334, + 340, + 351, + 357, + 363, + 371, + 380, + 388, + 398, + 405, + 413, + 421, + 430, + 437, + 447, + 460, + 474, + 483, + 494, + 505, + 517, + 525, + 534, + 545, + 550, + 555, + 562, + 568, + 572, + 577, + 585, + 601, + 614, + 627, + 642, + 655, + 673, + 686, + 693, + 699, + 704, + 713, + 717, + 728, + 732, + 740, + 748, + 756, + 765, + 776, + 785, + 793, + 800, + 810, + 821, + 829, + 834, + 841, + 852, + 860, + 868, + 877, + 880, + 889, + 896, + 903, + 908, + 913, + 918, + 925, + 934, + 944, + 948, + 953, + 960, + 966, + 973, + 981, + 991, + 1001, + 1009, + 1016, + 1024, + 1034, + 1043, + 1051, + 1057, + 1064, + 1070, + 1077, + 1083, + 1089, + 1099, + 1103, + 1109, + 1117, + 1125, + 1132, + 1137, + 1142, + 1151, + 1161, + 1171, + 1178, + 1184, + 1192, + 1201, + 1207, + 1216, + 1223, + 1231, + 1238, + 1245, + 1250, + 1255, + 1264, + 1267, + 1273, + 1283, + 1293, + 1302, + 1309, + 1312, + 1320, + 1330, + 1340, + 1346, + 1354, + 1362, + 1371, + 1381, + 1388, + 1394, + 1400, + 1406, + 1418, + 1425, + 1433, + 1437, + 1445, + 1455, + 1464, + 1469, + 1477, + 1480, + 1487, + 1497, + 1502, + 1506, + 1512, + 1521, + 1527, + 1532, + 1540, + 1548, + 1558, + 1564, + 1569, + 1575, + 1580, + 1586, + 1593, + 1598, + 1604, + 1614, + 1629, + 1638, + 1643, + 1650, + 1657, + 1665, + 1671, + 1684, + 1693, + 1700, + 1707, + 1716, + 1721, + 1727, + 1732, + 1737, + 1743, + 1752, + 1760, + 1766, + 1770, + 1775, + 1778, + 1783, + 1787, + 1795, + 1802, + 1810, + 1817, + 1822, + 1829, + 1835, + 1843, + 1850, + 1853, + 1857, + 1864, + 1869, + 1873, + 1876, + 1881, + 1890, + 1897, + 1905, + 1908, + 1914, + 1925, + 1932, + 1936, + 1942, + 1947, + 1956, + 1964, + 1975, + 1981, + 1987, + 1996, + 2003, + 2011, + 2021, + 2029, + 2038, + 2045, + 2053, + 2059, + 2066, + 2075, + 2085, + 2095, + 2103, + 2112, + 2121, + 2129, + 2135, + 2146, + 2157, + 2167, + 2178, + 2186, + 2198, + 2204, + 2210, + 2215, + 2220, + 2229, + 2237, + 2247, + 2251, + 2262, + 2274, + 2282, + 2290, + 2299, + 2307, + 2314, + 2325, + 2333, + 2341, + 2347, + 2355, + 2364, + 2374, + 2382, + 2389, + 2395, + 2400, + 2409, + 2416, + 2424, + 2433, + 2437, + 2442, + 2447, + 2457, + 2464, + 2472, + 2479, + 2486, + 2493, + 2502, + 2509, + 2518, + 2528, + 2541, + 2548, + 2556, + 2569, + 2573, + 2579, + 2584, + 2590, + 2595, + 2603, + 2610, + 2615, + 2624, + 2633, + 2638, + 2642, + 2649, + 2660, + 2666, + 2676, + 2687, + 2693, + 2700, + 2708, + 2715, + 2722, + 2728, + 2741, + 2751, + 2759, + 2769, + 2775, + 2782, + 2788, + 2795, + 2807, + 2818, + 2823, + 2832, + 2842, + 2847, + 2852, + 2857, + 2862, + 2872, + 2875, + 2884, + 2896, + 2906, + 2912, + 2920, + 2925, + 2930, + 2939, + 2947, + 2952, + 2958, + 2968, + 2980, + 2992, + 2998, + 3005, + 3013, + 3022, + 3031, + 3037, + 3044, + 3049, + 3055, + 3062, + 3068, + 3077, + 3087, + 3093, + 3100, + 3108, + 3117, + 3125, + 3133, + 3141, + 3146, + 3152, + 3161, + 3166, + 3172, + 3183, + 3190, + 3195, + 3202, + 3210, + 3215, + 3223, + 3229, + 3233, + 3247, + 3257, + 3268, + 3278, + 3288, + 3302, + 3311, + 3317, + 3325, + 3338, + 3347, + 3352, + 3356, +}; + +#define SCANKEYWORDS_NUM_KEYWORDS 443 + +static int +ScanKeywords_hash_func(const void *key, size_t keylen) +{ + static const int16 h[887] = { + 39, 0, 254, 436, 32767, 32767, 32767, 0, + 32767, 253, 32767, 51, 32767, 32767, 32767, -488, + 32767, 269, -252, 457, 32767, 32767, 32767, 133, + -265, 3, 32767, -46, 32767, -4, 32767, 32767, + 156, 11, -212, 32767, 408, 128, -77, 413, + 31, 401, 32767, 287, -119, 118, 32767, 429, + 0, 32767, 632, 77, 223, 413, 32767, 320, + 264, 246, 0, 7, 142, -109, 368, 32767, + 259, 134, 32767, -284, 4, -231, 391, -233, + -88, 27, -128, 32767, 0, 0, 32767, -256, + 503, 32767, 32767, 418, 0, 32767, 32767, 66, + 0, 272, -250, 131, 0, 112, 32767, 555, + 111, 0, 509, 32767, 32767, -154, 0, 32767, + 29, 195, 32767, 32767, 32767, 173, 88, 0, + 554, 189, 502, -56, 400, -33, 32767, 32767, + 90, 32767, 32767, 32767, -247, 332, 0, 32767, + 241, 347, 432, 338, 0, 159, -55, 32767, + 0, 104, -225, 300, 484, 32767, 0, 107, + 32767, -223, 298, 0, -105, 32767, 32767, 211, + -269, -251, -157, 439, 32767, 32767, 507, 380, + 32767, 103, 32767, 117, 423, 400, 357, -263, + 32767, 154, 64, 32767, 32767, 32767, 66, 104, + 261, 741, -185, 502, -80, 209, 256, 32767, + 32767, 20, 0, 0, 342, 32767, 171, 32767, + 32767, -149, 32767, 32767, 32767, 32767, 9, 32767, + 167, 0, 32767, -369, -239, -326, 116, -287, + 73, 32767, 32767, 279, 206, 192, 310, 32767, + 0, 32767, 32767, 32767, 0, -20, 411, 0, + 32767, 32767, 75, 135, 32767, 36, 32767, 136, + 0, 32767, 58, 0, 32767, 32767, 392, 0, + 32767, 86, 385, 360, 32767, 292, 45, -76, + 32767, 42, 32767, 32767, 32767, -145, 0, 0, + 32767, 32767, 32767, 32767, 0, 32767, 187, 369, + 32767, 32767, 0, 32767, 32767, 32767, 222, 32767, + -277, 386, 32767, 145, 427, -88, 19, 742, + 32767, 13, 128, -353, 0, -320, 32767, 32767, + 149, 412, 32767, 32767, 276, 285, 131, 0, + 129, 351, 32767, 32767, 204, 32767, 32767, 0, + 32767, 32767, 32767, 225, 132, 32767, 71, 32767, + -232, 162, 115, 32767, -196, 40, 32767, 32767, + 128, 0, -208, 32767, 32767, 112, 32767, 32767, + -199, 32767, 424, 32767, 265, -30, -388, -267, + 332, 414, 319, 32767, 84, -319, 32767, -142, + 147, 32767, 32767, 32767, 39, 32767, 32767, 0, + 146, -59, 226, 32767, 0, 32767, 244, 110, + -68, 0, 506, 139, 32767, 131, 90, 313, + -300, 32767, 0, 65, 131, 427, 32767, 32767, + 243, 444, 0, 32767, 104, 146, -294, 0, + 273, 32767, 32767, 204, 97, 0, 32767, -55, + 32767, 32767, 47, 100, 46, 161, 72, 32767, + 32767, 71, 32767, 13, 0, 32767, 43, 0, + 389, 32767, 0, 60, 32767, 32767, 563, 32767, + 264, 0, 32767, 239, 0, 32767, 32767, 32767, + 433, 0, 260, 9, 32767, 32767, 32767, 462, + 0, 161, 0, 0, 10, 32767, 152, 32767, + 32767, 341, 321, 32767, 32767, 0, -174, 32767, + -235, 32767, -6, 660, 32767, 32767, 246, 231, + 0, 32767, 32767, 140, 0, -485, 102, 32767, + 0, -420, 32767, 0, 32767, 32767, 32767, 217, + 83, 274, 32767, 0, 162, 133, 157, 0, + -300, 91, 304, 32767, 32767, 0, 32767, 76, + 291, 32767, -80, -320, 0, 32767, -180, 32767, + 32767, 544, 267, 55, 262, 93, 332, 32767, + 520, -305, 32767, 32767, 201, 32767, 0, -121, + 32767, 32767, 32767, 32767, 32767, 0, -331, 0, + 32767, -244, 315, 32767, 175, 32767, -218, 0, + -87, -124, 0, 413, 200, 272, 307, 507, + 32767, 0, 32767, 430, 274, 32767, 32767, 236, + 0, 254, 32767, 32767, 32767, 0, 109, -72, + 32767, 32767, 244, 32767, 0, 32767, 204, 32767, + 32767, 33, 392, -411, 168, 0, 434, 32767, + 32767, 0, 32767, 32767, 38, 235, 32767, 0, + -159, 314, 49, 0, 32767, 32767, 32767, 32767, + 32767, 150, 32767, 32767, -10, 0, -36, 553, + 32767, 0, 32767, 297, 14, 115, 409, 127, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 0, 458, 618, 32767, 352, 0, 32767, + 413, 32767, 32767, 262, 32767, 4, -304, 0, + 401, 0, 104, -193, 316, 8, -397, 294, + -80, 32767, 370, 0, 228, 133, 0, 4, + 32767, 0, 220, -137, 121, 32767, 0, 32767, + 269, 32767, 139, -202, 185, 32767, 22, 61, + 50, 9, 32767, 76, -219, 25, 32767, 462, + 0, 32767, 32767, 32767, 944, 143, -38, 93, + 416, 32767, 70, 35, 32767, 382, 32767, 0, + 32767, 32767, -312, 383, 32767, 386, 32767, 32767, + 153, 0, -224, 32767, 41, 0, 151, 32767, + 163, 107, 0, 32767, 32767, 144, 32767, 32767, + 169, 350, 32767, 0, 32767, 59, 32767, 32767, + 383, 97, 138, 442, 0, 32767, 32767, 289, + 0, 32767, 32767, 32767, 32767, 32767, 274, 369, + 32767, 640, 765, 32767, 32767, 276, 87, 371, + 32767, 32767, -89, 309, -27, 0, 32767, 32767, + 0, 32767, -106, -17, 402, -264, 32767, 0, + 302, 340, 32767, 62, 406, 0, -499, 32767, + 147, 32767, 0, 32767, 0, 32767, 524, 32767, + 32767, 221, 0, 39, 267, 32767, 32767, 2, + 268, 32767, 0, 32767, 0, 440, 0, 32767, + 25, -231, 23, 429, 0, 335, 32767, 32767, + -199, 265, 32767, 172, 32767, 0, 32767, 296, + -320, 379, 32767, 227, 0, 32767, 297, 32767, + 32767, 489, 0, 32767, 0, -97, 0, 384, + 32767, 32767, 311, 307, 32767, 137, 32767, 206, + 0, 220, -184, 0, 32767, 32767, 32767, 32767, + 612, 0, 247, 537, 233, 32767, 316, 182, + 0, 32767, 0, 404, 32767, 32767, 0, 32767, + 32767, 32767, 52, 581, 380, 32767, 32767, 383, + 32767, 32767, 42, 240, 11, 32767, 32767, 0, + -514, 0, -214, 0, 53, 0, -145, 32767, + 76, 91, 32767, 32767, 232, 8, 0, 0, + 0, 57, 182, 32767, 0, 32767, 0, + }; + + const unsigned char *k = (const unsigned char *) key; + uint32 a = 0; + uint32 b = 1; + + while (keylen--) + { + unsigned char c = *k++ | 0x20; + + a = a * 31 + c; + b = b * 127 + c; + } + return h[a % 887] + h[b % 887]; +} + +const ScanKeywordList ScanKeywords = { + ScanKeywords_kw_string, + ScanKeywords_kw_offsets, + ScanKeywords_hash_func, + SCANKEYWORDS_NUM_KEYWORDS, + 17 +}; + +#endif /* KWLIST_D_H */ diff --git a/src/include/parser/kwlookup.h b/src/include/parser/kwlookup.h index e69de29..1c2f7f8 100644 --- a/src/include/parser/kwlookup.h +++ b/src/include/parser/kwlookup.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- + * + * kwlookup.h + * Key word lookup for PostgreSQL + * + * + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/common/kwlookup.h + * + *------------------------------------------------------------------------- + */ +#ifndef KWLOOKUP_H +#define KWLOOKUP_H + +#include "pool_type.h" + +/* Hash function used by ScanKeywordLookup */ +typedef int (*ScanKeywordHashFunc) (const void *key, size_t keylen); + +/* + * This struct contains the data needed by ScanKeywordLookup to perform a + * search within a set of keywords. The contents are typically generated by + * src/tools/gen_keywordlist.pl from a header containing PG_KEYWORD macros. + */ +typedef struct ScanKeywordList +{ + const char *kw_string; /* all keywords in order, separated by \0 */ + const uint16 *kw_offsets; /* offsets to the start of each keyword */ + ScanKeywordHashFunc hash; /* perfect hash function for keywords */ + int num_keywords; /* number of keywords */ + int max_kw_len; /* length of longest keyword */ +} ScanKeywordList; + + +extern int ScanKeywordLookup(const char *text, const ScanKeywordList *keywords); + +/* Code that wants to retrieve the text of the N'th keyword should use this. */ +static inline const char * +GetScanKeyword(int n, const ScanKeywordList *keywords) +{ + return keywords->kw_string + keywords->kw_offsets[n]; +} + +#endif /* KWLOOKUP_H */ diff --git a/src/include/parser/makefuncs.h b/src/include/parser/makefuncs.h index b39c19e..51bcecd 100644 --- a/src/include/parser/makefuncs.h +++ b/src/include/parser/makefuncs.h @@ -4,8 +4,8 @@ * prototypes for the creator functions (for primitive nodes) * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/makefuncs.h @@ -19,42 +19,42 @@ extern A_Expr *makeA_Expr(A_Expr_Kind kind, List *name, - Node *lexpr, Node *rexpr, int location); + Node *lexpr, Node *rexpr, int location); extern A_Expr *makeSimpleA_Expr(A_Expr_Kind kind, char *name, - Node *lexpr, Node *rexpr, int location); + Node *lexpr, Node *rexpr, int location); extern Var *makeVar(Index varno, - AttrNumber varattno, - Oid vartype, - int32 vartypmod, - Oid varcollid, - Index varlevelsup); + AttrNumber varattno, + Oid vartype, + int32 vartypmod, + Oid varcollid, + Index varlevelsup); extern Var *makeVarFromTargetEntry(Index varno, - TargetEntry *tle); + TargetEntry *tle); extern Var *makeWholeRowVar(RangeTblEntry *rte, - Index varno, - Index varlevelsup, - bool allowScalar); + Index varno, + Index varlevelsup, + bool allowScalar); extern TargetEntry *makeTargetEntry(Expr *expr, - AttrNumber resno, - char *resname, - bool resjunk); + AttrNumber resno, + char *resname, + bool resjunk); extern TargetEntry *flatCopyTargetEntry(TargetEntry *src_tle); extern FromExpr *makeFromExpr(List *fromlist, Node *quals); extern Const *makeConst(Oid consttype, - int32 consttypmod, - Oid constcollid, - int constlen, - Datum constvalue, - bool constisnull, - bool constbyval); + int32 consttypmod, + Oid constcollid, + int constlen, + Datum constvalue, + bool constisnull, + bool constbyval); extern Const *makeNullConst(Oid consttype, int32 consttypmod, Oid constcollid); @@ -65,7 +65,7 @@ extern Expr *makeBoolExpr(BoolExprType boolop, List *args, int location); extern Alias *makeAlias(const char *aliasname, List *colnames); extern RelabelType *makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, - Oid rcollid, CoercionForm rformat); + Oid rcollid, CoercionForm rformat); extern RangeVar *makeRangeVar(char *schemaname, char *relname, int location); @@ -74,16 +74,16 @@ extern TypeName *makeTypeNameFromNameList(List *names); extern TypeName *makeTypeNameFromOid(Oid typeOid, int32 typmod); extern ColumnDef *makeColumnDef(const char *colname, - Oid typeOid, int32 typmod, Oid collOid); + Oid typeOid, int32 typmod, Oid collOid); extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype, List *args, - Oid funccollid, Oid inputcollid, CoercionForm fformat); + Oid funccollid, Oid inputcollid, CoercionForm fformat); extern FuncCall *makeFuncCall(List *name, List *args, int location); extern DefElem *makeDefElem(char *name, Node *arg, int location); extern DefElem *makeDefElemExtended(char *nameSpace, char *name, Node *arg, - DefElemAction defaction, int location); + DefElemAction defaction, int location); extern GroupingSet *makeGroupingSet(GroupingSetKind kind, List *content, int location); diff --git a/src/include/parser/nodes.h b/src/include/parser/nodes.h index 4df7e13..41abd5e 100644 --- a/src/include/parser/nodes.h +++ b/src/include/parser/nodes.h @@ -4,8 +4,8 @@ * Definitions for tagged nodes. * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/nodes.h @@ -157,7 +157,7 @@ typedef enum NodeTag T_Aggref, T_GroupingFunc, T_WindowFunc, - T_ArrayRef, + T_SubscriptingRef, T_FuncExpr, T_NamedArgExpr, T_OpExpr, @@ -218,7 +218,7 @@ typedef enum NodeTag T_DomainConstraintState, /* - * TAGS FOR PLANNER NODES (relation.h) + * TAGS FOR PLANNER NODES (pathnodes.h) */ T_PlannerInfo, T_PlannerGlobal, @@ -240,7 +240,7 @@ typedef enum NodeTag T_HashPath, T_AppendPath, T_MergeAppendPath, - T_ResultPath, + T_GroupResultPath, T_MaterialPath, T_UniquePath, T_GatherPath, @@ -265,6 +265,7 @@ typedef enum NodeTag T_PathKey, T_PathTarget, T_RestrictInfo, + T_IndexClause, T_PlaceHolderVar, T_SpecialJoinInfo, T_AppendRelInfo, @@ -506,6 +507,7 @@ typedef enum NodeTag T_InlineCodeBlock, /* in nodes/parsenodes.h */ T_FdwRoutine, /* in foreign/fdwapi.h */ T_IndexAmRoutine, /* in access/amapi.h */ + T_TableAmRoutine, /* in access/tableam.h */ TsmRoutine , /* in access/tsmapi.h */ T_ForeignKeyCacheInfo, /* in utils/rel.h */ T_CallContext, /* in nodes/parsenodes.h */ @@ -608,16 +610,19 @@ struct StringInfoData; /* not to include stringinfo.h here */ extern void outNode(struct StringInfoData *str, const void *obj); extern void outToken(struct StringInfoData *str, const char *s); extern void outBitmapset(struct StringInfoData *str, - const struct Bitmapset *bms); + const struct Bitmapset *bms); extern void outDatum(struct StringInfoData *str, uintptr_t value, - int typlen, bool typbyval); + int typlen, bool typbyval); extern char *nodeToString(const void *obj); extern char *bmsToString(const struct Bitmapset *bms); /* * nodes/{readfuncs.c,read.c} */ -extern void *stringToNode(char *str); +extern void *stringToNode(const char *str); +#ifdef WRITE_READ_PARSE_PLAN_TREES +extern void *stringToNodeWithLocations(const char *str); +#endif extern struct Bitmapset *readBitmapset(void); extern uintptr_t readDatum(bool typbyval); extern bool *readBoolCols(int numCols); @@ -745,7 +750,7 @@ typedef enum JoinType * AggStrategy - * overall execution strategies for Agg plan nodes * - * This is needed in both plannodes.h and relation.h, so put it here... + * This is needed in both pathnodes.h and plannodes.h, so put it here... */ typedef enum AggStrategy { @@ -759,7 +764,7 @@ typedef enum AggStrategy * AggSplit - * splitting (partial aggregation) modes for Agg plan nodes * - * This is needed in both plannodes.h and relation.h, so put it here... + * This is needed in both pathnodes.h and plannodes.h, so put it here... */ /* Primitive options supported by nodeAgg.c: */ @@ -789,7 +794,7 @@ typedef enum AggSplit * SetOpCmd and SetOpStrategy - * overall semantics and execution strategies for SetOp plan nodes * - * This is needed in both plannodes.h and relation.h, so put it here... + * This is needed in both pathnodes.h and plannodes.h, so put it here... */ typedef enum SetOpCmd { diff --git a/src/include/parser/parsenodes.h b/src/include/parser/parsenodes.h index 438b76a..433e0a7 100644 --- a/src/include/parser/parsenodes.h +++ b/src/include/parser/parsenodes.h @@ -12,8 +12,8 @@ * identifying statement boundaries in multi-statement source strings. * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/parsenodes.h @@ -167,9 +167,8 @@ typedef struct Query List *constraintDeps; /* a list of pg_constraint OIDs that the query * depends on to be semantically valid */ - List *withCheckOptions; /* a list of WithCheckOption's, which are - * only added during rewrite and therefore - * are not written out as part of Query. */ + List *withCheckOptions; /* a list of WithCheckOption's (added + * during rewrite) */ /* * The following two fields identify the portion of the source text string @@ -224,7 +223,7 @@ typedef struct TypeName * Currently, A_Star must appear only as the last list element --- the grammar * is responsible for enforcing this! * - * Note: any array subscripting or selection of fields from composite columns + * Note: any container subscripting or selection of fields from composite columns * is represented by an A_Indirection node above the ColumnRef. However, * for simplicity in the normal case, initial field selection from a table * name is represented within ColumnRef and not by adding A_Indirection. @@ -649,13 +648,13 @@ typedef struct ColumnDef bool is_local; /* column has local (non-inherited) def'n */ bool is_not_null; /* NOT NULL constraint specified? */ bool is_from_type; /* column definition came from table type */ - bool is_from_parent; /* column def came from partition parent */ char storage; /* attstorage setting, or 0 for default */ Node *raw_default; /* default value (untransformed parse tree) */ Node *cooked_default; /* default value (transformed expr tree) */ char identity; /* attidentity setting */ RangeVar *identitySequence; /* to store identity sequence name for * ALTER TABLE ... ADD COLUMN */ + char generated; /* attgenerated setting */ CollateClause *collClause; /* untransformed COLLATE spec, if any */ Oid collOid; /* collation OID (InvalidOid if not set) */ List *constraints; /* other constraints on column */ @@ -678,10 +677,11 @@ typedef enum TableLikeOption CREATE_TABLE_LIKE_COMMENTS = 1 << 0, CREATE_TABLE_LIKE_CONSTRAINTS = 1 << 1, CREATE_TABLE_LIKE_DEFAULTS = 1 << 2, - CREATE_TABLE_LIKE_IDENTITY = 1 << 3, - CREATE_TABLE_LIKE_INDEXES = 1 << 4, - CREATE_TABLE_LIKE_STATISTICS = 1 << 5, - CREATE_TABLE_LIKE_STORAGE = 1 << 6, + CREATE_TABLE_LIKE_GENERATED = 1 << 3, + CREATE_TABLE_LIKE_IDENTITY = 1 << 4, + CREATE_TABLE_LIKE_INDEXES = 1 << 5, + CREATE_TABLE_LIKE_STATISTICS = 1 << 6, + CREATE_TABLE_LIKE_STORAGE = 1 << 7, CREATE_TABLE_LIKE_ALL = PG_INT32_MAX } TableLikeOption; @@ -934,6 +934,15 @@ typedef struct PartitionCmd * them in these fields. A whole-row Var reference is represented by * setting the bit for InvalidAttrNumber. * + * updatedCols is also used in some other places, for example, to determine + * which triggers to fire and in FDWs to know which changed columns they + * need to ship off. Generated columns that are caused to be updated by an + * update to a base column are collected in extraUpdatedCols. This is not + * considered for permission checking, but it is useful in those places + * that want to know the full set of columns being updated as opposed to + * only the ones the user explicitly mentioned in the query. (There is + * currently no need for an extraInsertedCols, but it could exist.) + * * securityQuals is a list of security barrier quals (boolean expressions), * to be tested in the listed order before returning a row from the * relation. It is always NIL in parser output. Entries are added by the @@ -951,7 +960,10 @@ typedef enum RTEKind RTE_TABLEFUNC, /* TableFunc(.., column list) */ RTE_VALUES, /* VALUES (), (), ... */ RTE_CTE, /* common table expr (WITH list element) */ - RTE_NAMEDTUPLESTORE /* tuplestore, e.g. for AFTER triggers */ + RTE_NAMEDTUPLESTORE, /* tuplestore, e.g. for AFTER triggers */ + RTE_RESULT /* RTE represents an empty FROM clause; such + * RTEs are added by the planner, they're not + * present during parsing or rewriting */ } RTEKind; typedef struct RangeTblEntry @@ -973,9 +985,21 @@ typedef struct RangeTblEntry * that the tuple format of the tuplestore is the same as the referenced * relation. This allows plans referencing AFTER trigger transition * tables to be invalidated if the underlying table is altered. + * + * rellockmode is really LOCKMODE, but it's declared int to avoid having + * to include lock-related headers here. It must be RowExclusiveLock if + * the RTE is an INSERT/UPDATE/DELETE target, else RowShareLock if the RTE + * is a SELECT FOR UPDATE/FOR SHARE target, else AccessShareLock. + * + * Note: in some cases, rule expansion may result in RTEs that are marked + * with RowExclusiveLock even though they are not the target of the + * current query; this happens if a DO ALSO rule simply scans the original + * target table. We leave such RTEs with their original lockmode so as to + * avoid getting an additional, lesser lock. */ Oid relid; /* OID of the relation */ char relkind; /* relation kind (see pg_class.relkind) */ + int rellockmode; /* lock level that query requires on the rel */ struct TableSampleClause *tablesample; /* sampling info, or NULL */ /* @@ -1033,7 +1057,7 @@ typedef struct RangeTblEntry bool self_reference; /* is this a recursive self-reference? */ /* - * Fields valid for table functions, values, CTE and ENR RTEs (else NIL): + * Fields valid for CTE, VALUES, ENR, and TableFunc RTEs (else NIL): * * We need these for CTE RTEs so that the types of self-referential * columns are well-defined. For VALUES RTEs, storing these explicitly @@ -1041,7 +1065,9 @@ typedef struct RangeTblEntry * ENRs, we store the types explicitly here (we could get the information * from the catalogs if 'relid' was supplied, but we'd still need these * for TupleDesc-based ENRs, so we might as well always store the type - * info here). + * info here). For TableFuncs, these fields are redundant with data in + * the TableFunc node, but keeping them here allows some code sharing with + * the other cases. * * For ENRs only, we have to consider the possibility of dropped columns. * A dropped column is included in these lists, but it will have zeroes in @@ -1071,6 +1097,7 @@ typedef struct RangeTblEntry Bitmapset *selectedCols; /* columns needing SELECT permission */ Bitmapset *insertedCols; /* columns needing INSERT permission */ Bitmapset *updatedCols; /* columns needing UPDATE permission */ + Bitmapset *extraUpdatedCols; /* generated columns being updated */ List *securityQuals; /* security barrier quals to apply, if any */ } RangeTblEntry; @@ -1386,11 +1413,19 @@ typedef struct OnConflictClause * * We don't currently support the SEARCH or CYCLE clause. */ +typedef enum CTEMaterialize +{ + CTEMaterializeDefault, /* no option specified */ + CTEMaterializeAlways, /* MATERIALIZED */ + CTEMaterializeNever /* NOT MATERIALIZED */ +} CTEMaterialize; + typedef struct CommonTableExpr { NodeTag type; char *ctename; /* query name (never qualified) */ List *aliascolnames; /* optional list of column names */ + CTEMaterialize ctematerialized; /* is this an optimization fence? */ /* SelectStmt/InsertStmt/etc before parse analysis, Query afterwards: */ Node *ctequery; /* the CTE's subquery */ int location; /* token location, or -1 if unknown */ @@ -1728,6 +1763,7 @@ typedef enum AlterTableType AT_ColumnDefault, /* alter column default */ AT_DropNotNull, /* alter column drop not null */ AT_SetNotNull, /* alter column set not null */ + AT_CheckNotNull, /* check column is already marked not null */ AT_SetStatistics, /* alter column set statistics */ AT_SetOptions, /* alter column set ( options ) */ AT_ResetOptions, /* alter column reset ( options ) */ @@ -1756,8 +1792,6 @@ typedef enum AlterTableType AT_DropCluster, /* SET WITHOUT CLUSTER */ AT_SetLogged, /* SET LOGGED */ AT_SetUnLogged, /* SET UNLOGGED */ - AT_AddOids, /* SET WITH OIDS */ - AT_AddOidsRecurse, /* internal to commands/tablecmds.c */ AT_DropOids, /* SET WITHOUT OIDS */ AT_SetTableSpace, /* SET TABLESPACE */ AT_SetRelOptions, /* SET (...) -- AM specific parameters */ @@ -1958,6 +1992,7 @@ typedef struct CopyStmt bool is_program; /* is 'filename' a program to popen? */ char *filename; /* filename, or NULL for STDIN/STDOUT */ List *options; /* List of DefElem nodes */ + Node *whereClause; /* WHERE condition (or NULL) */ } CopyStmt; /* ---------------------- @@ -2021,6 +2056,7 @@ typedef struct CreateStmt List *options; /* options from WITH clause */ OnCommitAction oncommit; /* what do we do at COMMIT? */ char *tablespacename; /* table space to use, or NULL */ + char *accessMethod; /* table access method */ bool if_not_exists; /* just do nothing if it already exists? */ } CreateStmt; @@ -2062,6 +2098,7 @@ typedef enum ConstrType /* types of constraints */ CONSTR_NOTNULL, CONSTR_DEFAULT, CONSTR_IDENTITY, + CONSTR_GENERATED, CONSTR_CHECK, CONSTR_PRIMARY, CONSTR_UNIQUE, @@ -2100,7 +2137,7 @@ typedef struct Constraint bool is_no_inherit; /* is constraint non-inheritable? */ Node *raw_expr; /* expr, as untransformed parse tree */ char *cooked_expr; /* expr, as nodeToString representation */ - char generated_when; + char generated_when; /* ALWAYS or BY DEFAULT */ /* Fields used for unique constraints (UNIQUE and PRIMARY KEY): */ List *keys; /* String nodes naming referenced key @@ -2115,6 +2152,8 @@ typedef struct Constraint List *options; /* options from WITH clause */ char *indexname; /* existing index to use; otherwise NULL */ char *indexspace; /* index tablespace; NULL for default */ + bool reset_default_tblspc; /* reset default_tablespace prior to + * creating the index */ /* These could be, but currently are not, used for UNIQUE/PKEY: */ char *access_method; /* index access method; NULL for default */ Node *where_clause; /* partial index predicate */ @@ -2410,8 +2449,7 @@ typedef struct AlterEventTrigStmt } AlterEventTrigStmt; /* ---------------------- - * Create/Drop PROCEDURAL LANGUAGE Statements - * Create PROCEDURAL LANGUAGE Statements + * Create LANGUAGE Statements * ---------------------- */ typedef struct CreatePLangStmt @@ -2509,6 +2547,7 @@ typedef struct DefineStmt List *args; /* a list of TypeName (if needed) */ List *definition; /* a list of DefElem */ bool if_not_exists; /* just do nothing if it already exists? */ + bool replace; /* replace if already exists? */ } DefineStmt; /* ---------------------- @@ -2704,10 +2743,6 @@ typedef struct FetchStmt * index, just a UNIQUE/PKEY constraint using an existing index. isconstraint * must always be true in this case, and the fields describing the index * properties are empty. - * - * The relation to build the index on can be represented either by name - * (in which case the RangeVar indicates whether to recurse or not) or by OID - * (in which case the command is always recursive). * ---------------------- */ typedef struct IndexStmt @@ -2715,7 +2750,6 @@ typedef struct IndexStmt NodeTag type; char *idxname; /* name of new index, or NULL for default */ RangeVar *relation; /* relation to build index on */ - Oid relationId; /* OID of relation to build index on */ char *accessMethod; /* name of access method (eg. btree) */ char *tableSpace; /* tablespace, or NULL for default */ List *indexParams; /* columns to index: a list of IndexElem */ @@ -2735,6 +2769,8 @@ typedef struct IndexStmt bool transformed; /* true when transformIndexStmt is finished */ bool concurrent; /* should this be a concurrent index build? */ bool if_not_exists; /* just do nothing if index already exists? */ + bool reset_default_tblspc; /* reset default_tablespace prior to + * executing */ } IndexStmt; /* ---------------------- @@ -2975,6 +3011,7 @@ typedef struct TransactionStmt List *options; /* for BEGIN/START commands */ char *savepoint_name; /* for savepoint commands */ char *gid; /* for two-phase-commit related commands */ + bool chain; /* AND CHAIN option */ } TransactionStmt; /* ---------------------- @@ -3111,20 +3148,25 @@ typedef struct AlterSystemStmt * Cluster Statement (support pbrown's cluster index implementation) * ---------------------- */ +typedef enum ClusterOption +{ + CLUOPT_RECHECK = 1 << 0, /* recheck relation state */ + CLUOPT_VERBOSE = 1 << 1 /* print progress info */ +} ClusterOption; + typedef struct ClusterStmt { NodeTag type; RangeVar *relation; /* relation being indexed, or NULL if all */ char *indexname; /* original index defined */ - bool verbose; /* print progress info */ + int options; /* OR of ClusterOption flags */ } ClusterStmt; /* ---------------------- * Vacuum and Analyze Statements * * Even though these are nominally two statements, it's convenient to use - * just one node type for both. Note that at least one of VACOPT_VACUUM - * and VACOPT_ANALYZE must be set in options. + * just one node type for both. * ---------------------- */ typedef enum VacuumOption @@ -3134,11 +3176,57 @@ typedef enum VacuumOption VACOPT_VERBOSE = 1 << 2, /* print progress info */ VACOPT_FREEZE = 1 << 3, /* FREEZE option */ VACOPT_FULL = 1 << 4, /* FULL (non-concurrent) vacuum */ - VACOPT_NOWAIT = 1 << 5, /* don't wait to get lock (autovacuum only) */ + VACOPT_SKIP_LOCKED = 1 << 5, /* skip if cannot get lock */ VACOPT_SKIPTOAST = 1 << 6, /* don't process the TOAST table, if any */ VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7 /* don't skip any pages */ } VacuumOption; +typedef struct VacuumStmt +{ + NodeTag type; + List *options; /* list of DefElem nodes */ + List *rels; /* list of VacuumRelation, or NIL for all */ + bool is_vacuumcmd; /* true for VACUUM, false for ANALYZE */ +} VacuumStmt; + +/* + * A ternary value used by vacuum parameters. + * + * DEFAULT value is used to determine the value based on other + * configurations, e.g. reloptions. + */ +typedef enum VacOptTernaryValue +{ + VACOPT_TERNARY_DEFAULT = 0, + VACOPT_TERNARY_DISABLED, + VACOPT_TERNARY_ENABLED, +} VacOptTernaryValue; + +/* + * Parameters customizing behavior of VACUUM and ANALYZE. + * + * Note that at least one of VACOPT_VACUUM and VACOPT_ANALYZE must be set + * in options. + */ +typedef struct VacuumParams +{ + int options; /* bitmask of VacuumOption */ + int freeze_min_age; /* min freeze age, -1 to use default */ + int freeze_table_age; /* age at which to scan whole table */ + int multixact_freeze_min_age; /* min multixact freeze age, -1 to + * use default */ + int multixact_freeze_table_age; /* multixact age at which to scan + * whole table */ + bool is_wraparound; /* force a for-wraparound vacuum */ + int log_min_duration; /* minimum execution threshold in ms at + * which verbose logs are activated, -1 + * to use default */ + VacOptTernaryValue index_cleanup; /* Do index vacuum and cleanup, + * default value depends on reloptions */ + VacOptTernaryValue truncate; /* Truncate empty pages at the end, + * default value depends on reloptions */ +} VacuumParams; + /* * Info about a single target table of VACUUM/ANALYZE. * @@ -3154,13 +3242,6 @@ typedef struct VacuumRelation List *va_cols; /* list of column names, or NIL for all */ } VacuumRelation; -typedef struct VacuumStmt -{ - NodeTag type; - int options; /* OR of VacuumOption flags */ - List *rels; /* list of VacuumRelation, or NIL for all */ -} VacuumStmt; - /* ---------------------- * Explain Statement * @@ -3287,6 +3368,7 @@ typedef struct ReindexStmt RangeVar *relation; /* Table or index to reindex */ const char *name; /* name of database to reindex */ int options; /* Reindex options flags */ + bool concurrent; /* reindex concurrently? */ } ReindexStmt; /* ---------------------- diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index c5af026..d97a9b7 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -5,8 +5,8 @@ * * This is the external API for the raw lexing/parsing functions. * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/parser.h diff --git a/src/include/parser/pg_class.h b/src/include/parser/pg_class.h index 466c588..8a017a1 100644 --- a/src/include/parser/pg_class.h +++ b/src/include/parser/pg_class.h @@ -4,8 +4,8 @@ * definition of the "relation" system catalog (pg_class) * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_class.h @@ -31,56 +31,113 @@ */ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,RelationRelation_Rowtype_Id) BKI_SCHEMA_MACRO { - NameData relname; /* class name */ - Oid relnamespace; /* OID of namespace containing this class */ - Oid reltype; /* OID of entry in pg_type for table's - * implicit row type */ - Oid reloftype; /* OID of entry in pg_type for underlying - * composite type */ - Oid relowner; /* class owner */ - Oid relam; /* index access method; 0 if not an index */ - Oid relfilenode; /* identifier of physical storage file */ + /* oid */ + Oid oid; + /* class name */ + NameData relname; + + /* OID of namespace containing this class */ + Oid relnamespace BKI_DEFAULT(PGNSP); + + /* OID of entry in pg_type for table's implicit row type */ + Oid reltype BKI_LOOKUP(pg_type); + + /* OID of entry in pg_type for underlying composite type */ + Oid reloftype BKI_DEFAULT(0) BKI_LOOKUP(pg_type); + + /* class owner */ + Oid relowner BKI_DEFAULT(PGUID); + + /* access method; 0 if not a table / index */ + Oid relam BKI_LOOKUP(pg_am); + + /* identifier of physical storage file */ /* relfilenode == 0 means it is a "mapped" relation, see relmapper.c */ - Oid reltablespace; /* identifier of table space for relation */ - int32 relpages; /* # of blocks (not always up-to-date) */ - float4 reltuples; /* # of tuples (not always up-to-date) */ - int32 relallvisible; /* # of all-visible blocks (not always - * up-to-date) */ - Oid reltoastrelid; /* OID of toast table; 0 if none */ - bool relhasindex; /* T if has (or has had) any indexes */ - bool relisshared; /* T if shared across databases */ - char relpersistence; /* see RELPERSISTENCE_xxx constants below */ - char relkind; /* see RELKIND_xxx constants below */ - int16 relnatts; /* number of user attributes */ + Oid relfilenode; + + /* identifier of table space for relation (0 means default for database) */ + Oid reltablespace BKI_DEFAULT(0) BKI_LOOKUP(pg_tablespace); + + /* # of blocks (not always up-to-date) */ + int32 relpages; + + /* # of tuples (not always up-to-date) */ + float4 reltuples; + + /* # of all-visible blocks (not always up-to-date) */ + int32 relallvisible; + + /* OID of toast table; 0 if none */ + Oid reltoastrelid; + + /* T if has (or has had) any indexes */ + bool relhasindex; + + /* T if shared across databases */ + bool relisshared; + + /* see RELPERSISTENCE_xxx constants below */ + char relpersistence; + + /* see RELKIND_xxx constants below */ + char relkind; + + /* number of user attributes */ + int16 relnatts; /* * Class pg_attribute must contain exactly "relnatts" user attributes * (with attnums ranging from 1 to relnatts) for this class. It may also * contain entries with negative attnums for system attributes. */ - int16 relchecks; /* # of CHECK constraints for class */ - bool relhasoids; /* T if we generate OIDs for rows of rel */ - bool relhasrules; /* has (or has had) any rules */ - bool relhastriggers; /* has (or has had) any TRIGGERs */ - bool relhassubclass; /* has (or has had) derived classes */ - bool relrowsecurity; /* row security is enabled or not */ - bool relforcerowsecurity; /* row security forced for owners or - * not */ - bool relispopulated; /* matview currently holds query results */ - char relreplident; /* see REPLICA_IDENTITY_xxx constants */ - bool relispartition; /* is relation a partition? */ - Oid relrewrite; /* heap for rewrite during DDL, link to - * original rel */ - TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */ - TransactionId relminmxid; /* all multixacts in this rel are >= this. - * this is really a MultiXactId */ + + /* # of CHECK constraints for class */ + int16 relchecks; + + /* has (or has had) any rules */ + bool relhasrules; + + /* has (or has had) any TRIGGERs */ + bool relhastriggers; + + /* has (or has had) child tables or indexes */ + bool relhassubclass; + + /* row security is enabled or not */ + bool relrowsecurity; + + /* row security forced for owners or not */ + bool relforcerowsecurity; + + /* matview currently holds query results */ + bool relispopulated; + + /* see REPLICA_IDENTITY_xxx constants */ + char relreplident; + + /* is relation a partition? */ + bool relispartition; + + /* heap for rewrite during DDL, link to original rel */ + Oid relrewrite BKI_DEFAULT(0); + + /* all Xids < this are frozen in this rel */ + TransactionId relfrozenxid; + + /* all multixacts in this rel are >= this; it is really a MultiXactId */ + TransactionId relminmxid; #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* NOTE: These fields are not present in a relcache entry's rd_rel field. */ - aclitem relacl[1]; /* access permissions */ - text reloptions[1]; /* access-method-specific options */ - pg_node_tree relpartbound; /* partition bound node tree */ + /* access permissions */ + aclitem relacl[1]; + + /* access-method-specific options */ + text reloptions[1]; + + /* partition bound node tree */ + pg_node_tree relpartbound; #endif } FormData_pg_class; @@ -130,6 +187,19 @@ typedef FormData_pg_class *Form_pg_class; */ #define REPLICA_IDENTITY_INDEX 'i' +/* + * Relation kinds that have physical storage. These relations normally have + * relfilenode set to non-zero, but it can also be zero if the relation is + * mapped. + */ +#define RELKIND_HAS_STORAGE(relkind) \ + ((relkind) == RELKIND_RELATION || \ + (relkind) == RELKIND_INDEX || \ + (relkind) == RELKIND_SEQUENCE || \ + (relkind) == RELKIND_TOASTVALUE || \ + (relkind) == RELKIND_MATVIEW) + + #endif /* NOT_USED_IN_PGPOOL */ #endif /* PG_CLASS_H */ diff --git a/src/include/parser/pg_config_manual.h b/src/include/parser/pg_config_manual.h index b4ba6f4..b6328d6 100644 --- a/src/include/parser/pg_config_manual.h +++ b/src/include/parser/pg_config_manual.h @@ -6,8 +6,8 @@ * for developers. If you edit any of these, be sure to do a *full* * rebuild (and an initdb if noted). * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/pg_config_manual.h @@ -41,8 +41,8 @@ #define pg_attribute_printf(f,a) #endif /* - * This is default value for wal_segment_size to be used at initdb when run - * without --walsegsize option. Must be a valid segment size. + * This is the default value for wal_segment_size to be used when initdb is run + * without the --wal-segsize option. It must be a valid segment size. */ #define DEFAULT_XLOG_SEG_SIZE (16*1024*1024) @@ -163,7 +163,9 @@ /* * USE_PREFETCH code should be compiled only if we have a way to implement * prefetching. (This is decoupled from USE_POSIX_FADVISE because there - * might in future be support for alternative low-level prefetch APIs.) + * might in future be support for alternative low-level prefetch APIs. + * If you change this, you probably need to adjust the error message in + * check_effective_io_concurrency.) */ #ifdef USE_POSIX_FADVISE #define USE_PREFETCH @@ -315,6 +317,13 @@ /* #define COPY_PARSE_PLAN_TREES */ /* + * Define this to force all parse and plan trees to be passed through + * outfuncs.c/readfuncs.c, to facilitate catching errors and omissions in + * those modules. + */ +/* #define WRITE_READ_PARSE_PLAN_TREES */ + +/* * Define this to force all raw parse trees for DML statements to be scanned * by raw_expression_tree_walker(), to facilitate catching errors and * omissions in that function. diff --git a/src/include/parser/pg_list.h b/src/include/parser/pg_list.h index afb2fbb..b820cca 100644 --- a/src/include/parser/pg_list.h +++ b/src/include/parser/pg_list.h @@ -27,8 +27,8 @@ * always be so; try to be careful to maintain the distinction.) * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/pg_list.h @@ -207,6 +207,32 @@ list_length(const List *l) (cell1) != NULL && (cell2) != NULL && (cell3) != NULL; \ (cell1) = lnext(cell1), (cell2) = lnext(cell2), (cell3) = lnext(cell3)) +/* + * forfour - + * the same for four lists + */ +#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4) \ + for ((cell1) = list_head(list1), (cell2) = list_head(list2), \ + (cell3) = list_head(list3), (cell4) = list_head(list4); \ + (cell1) != NULL && (cell2) != NULL && \ + (cell3) != NULL && (cell4) != NULL; \ + (cell1) = lnext(cell1), (cell2) = lnext(cell2), \ + (cell3) = lnext(cell3), (cell4) = lnext(cell4)) + +/* + * forfive - + * the same for five lists + */ +#define forfive(cell1, list1, cell2, list2, cell3, list3, cell4, list4, cell5, list5) \ + for ((cell1) = list_head(list1), (cell2) = list_head(list2), \ + (cell3) = list_head(list3), (cell4) = list_head(list4), \ + (cell5) = list_head(list5); \ + (cell1) != NULL && (cell2) != NULL && (cell3) != NULL && \ + (cell4) != NULL && (cell5) != NULL; \ + (cell1) = lnext(cell1), (cell2) = lnext(cell2), \ + (cell3) = lnext(cell3), (cell4) = lnext(cell4), \ + (cell5) = lnext(cell5)) + extern List *lappend(List *list, void *datum); extern List *lappend_int(List *list, int datum); extern List *lappend_oid(List *list, Oid datum); diff --git a/src/include/parser/pg_trigger.h b/src/include/parser/pg_trigger.h index 3d41b55..bc24d4d 100644 --- a/src/include/parser/pg_trigger.h +++ b/src/include/parser/pg_trigger.h @@ -4,8 +4,8 @@ * definition of the "trigger" system catalog (pg_trigger) * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/catalog/pg_trigger.h @@ -35,6 +35,7 @@ */ CATALOG(pg_trigger,2620,TriggerRelationId) { + Oid oid; /* oid */ Oid tgrelid; /* relation trigger is attached to */ NameData tgname; /* trigger's name */ Oid tgfoid; /* OID of function to be called */ diff --git a/src/include/parser/pg_wchar.h b/src/include/parser/pg_wchar.h index 58f353d..6ed96ef 100644 --- a/src/include/parser/pg_wchar.h +++ b/src/include/parser/pg_wchar.h @@ -3,8 +3,8 @@ * pg_wchar.h * multibyte-character support * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/mb/pg_wchar.h @@ -523,12 +523,12 @@ extern int pg_valid_server_encoding_id(int encoding); */ extern int pg_mb2wchar(const char *from, pg_wchar *to); extern int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len); -extern int pg_encoding_mb2wchar_with_len(int encoding, - const char *from, pg_wchar *to, int len); +extern int pg_encoding_mb2wchar_with_len(int encoding, + const char *from, pg_wchar *to, int len); extern int pg_wchar2mb(const pg_wchar *from, char *to); extern int pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len); -extern int pg_encoding_wchar2mb_with_len(int encoding, - const pg_wchar *from, char *to, int len); +extern int pg_encoding_wchar2mb_with_len(int encoding, + const pg_wchar *from, char *to, int len); extern int pg_char_and_wchar_strcmp(const char *s1, const pg_wchar *s2); extern int pg_wchar_strncmp(const pg_wchar *s1, const pg_wchar *s2, size_t n); extern int pg_char_and_wchar_strncmp(const char *s1, const pg_wchar *s2, size_t n); @@ -543,8 +543,8 @@ extern int pg_mic_mblen(const unsigned char *mbstr); extern int pg_mbstrlen(const char *mbstr); extern int pg_mbstrlen_with_len(const char *mbstr, int len); extern int pg_mbcliplen(const char *mbstr, int len, int limit); -extern int pg_encoding_mbcliplen(int encoding, const char *mbstr, - int len, int limit); +extern int pg_encoding_mbcliplen(int encoding, const char *mbstr, + int len, int limit); extern int pg_mbcharcliplen(const char *mbstr, int len, int imit); extern int pg_encoding_max_length(int encoding); extern int pg_database_encoding_max_length(void); @@ -573,8 +573,8 @@ extern unsigned char *unicode_to_utf8(pg_wchar c, unsigned char *utf8string); extern pg_wchar utf8_to_unicode(const unsigned char *c); extern int pg_utf_mblen(const unsigned char *); extern unsigned char *pg_do_encoding_conversion(unsigned char *src, int len, - int src_encoding, - int dest_encoding); + int src_encoding, + int dest_encoding); extern char *pg_client_to_server(const char *s, int len); extern char *pg_server_to_client(const char *s, int len); @@ -585,48 +585,48 @@ extern unsigned short BIG5toCNS(unsigned short big5, unsigned char *lc); extern unsigned short CNStoBIG5(unsigned short cns, unsigned char lc); extern void UtfToLocal(const unsigned char *utf, int len, - unsigned char *iso, - const pg_mb_radix_tree *map, - const pg_utf_to_local_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding); + unsigned char *iso, + const pg_mb_radix_tree *map, + const pg_utf_to_local_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding); extern void LocalToUtf(const unsigned char *iso, int len, - unsigned char *utf, - const pg_mb_radix_tree *map, - const pg_local_to_utf_combined *cmap, int cmapsize, - utf_local_conversion_func conv_func, - int encoding); + unsigned char *utf, + const pg_mb_radix_tree *map, + const pg_local_to_utf_combined *cmap, int cmapsize, + utf_local_conversion_func conv_func, + int encoding); extern bool pg_verifymbstr(const char *mbstr, int len, bool noError); extern bool pg_verify_mbstr(int encoding, const char *mbstr, int len, - bool noError); -extern int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, - bool noError); + bool noError); +extern int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, + bool noError); extern void check_encoding_conversion_args(int src_encoding, - int dest_encoding, - int len, - int expected_src_encoding, - int expected_dest_encoding); + int dest_encoding, + int len, + int expected_src_encoding, + int expected_dest_encoding); extern void report_invalid_encoding(int encoding, const char *mbstr, int len) pg_attribute_noreturn(); extern void report_untranslatable_char(int src_encoding, int dest_encoding, - const char *mbstr, int len) pg_attribute_noreturn(); + const char *mbstr, int len) pg_attribute_noreturn(); extern void local2local(const unsigned char *l, unsigned char *p, int len, - int src_encoding, int dest_encoding, const unsigned char *tab); + int src_encoding, int dest_encoding, const unsigned char *tab); extern void pg_ascii2mic(const unsigned char *l, unsigned char *p, int len); extern void pg_mic2ascii(const unsigned char *mic, unsigned char *p, int len); extern void latin2mic(const unsigned char *l, unsigned char *p, int len, - int lc, int encoding); + int lc, int encoding); extern void mic2latin(const unsigned char *mic, unsigned char *p, int len, - int lc, int encoding); + int lc, int encoding); extern void latin2mic_with_table(const unsigned char *l, unsigned char *p, - int len, int lc, int encoding, - const unsigned char *tab); + int len, int lc, int encoding, + const unsigned char *tab); extern void mic2latin_with_table(const unsigned char *mic, unsigned char *p, - int len, int lc, int encoding, - const unsigned char *tab); + int len, int lc, int encoding, + const unsigned char *tab); extern bool pg_utf8_islegal(const unsigned char *source, int length); diff --git a/src/include/parser/primnodes.h b/src/include/parser/primnodes.h index a277bbb..83e23b1 100644 --- a/src/include/parser/primnodes.h +++ b/src/include/parser/primnodes.h @@ -6,8 +6,8 @@ * Currently, these are mostly nodes for executable expressions * and join trees. * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group * - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group * + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/nodes/primnodes.h @@ -88,12 +88,15 @@ typedef struct RangeVar /* * TableFunc - node for a table function, such as XMLTABLE. + * + * Entries in the ns_names list are either string Value nodes containing + * literal namespace names, or NULL pointers to represent DEFAULT. */ typedef struct TableFunc { NodeTag type; - List *ns_uris; /* list of namespace uri */ - List *ns_names; /* list of namespace names */ + List *ns_uris; /* list of namespace URI expressions */ + List *ns_names; /* list of namespace names or NULL */ Node *docexpr; /* input document expression */ Node *rowexpr; /* row filter expression */ List *colnames; /* column names (list of String) */ @@ -121,6 +124,7 @@ typedef struct IntoClause RangeVar *rel; /* target relation name */ List *colNames; /* column names to assign, or NIL */ + char *accessMethod; /* table access method */ List *options; /* options from WITH clause */ OnCommitAction onCommit; /* what do we do at COMMIT? */ char *tableSpaceName; /* table space to use, or NULL */ @@ -378,18 +382,19 @@ typedef struct WindowFunc } WindowFunc; /* ---------------- - * ArrayRef: describes an array subscripting operation - * - * An ArrayRef can describe fetching a single element from an array, - * fetching a subarray (array slice), storing a single element into - * an array, or storing a slice. The "store" cases work with an - * initial array value and a source value that is inserted into the - * appropriate part of the array; the result of the operation is an - * entire new modified array value. - * - * If reflowerindexpr = NIL, then we are fetching or storing a single array - * element at the subscripts given by refupperindexpr. Otherwise we are - * fetching or storing an array slice, that is a rectangular subarray + * SubscriptingRef: describes a subscripting operation over a container + * (array, etc). + * + * A SubscriptingRef can describe fetching a single element from a container, + * fetching a part of container (e.g. array slice), storing a single element into + * a container, or storing a slice. The "store" cases work with an + * initial container value and a source value that is inserted into the + * appropriate part of the container; the result of the operation is an + * entire new modified container value. + * + * If reflowerindexpr = NIL, then we are fetching or storing a single container + * element at the subscripts given by refupperindexpr. Otherwise we are + * fetching or storing a container slice, that is a rectangular subcontainer * with lower and upper bounds given by the index expressions. * reflowerindexpr must be the same length as refupperindexpr when it * is not NIL. @@ -401,28 +406,29 @@ typedef struct WindowFunc * element; but it is the array type when doing subarray fetch or either * type of store. * - * Note: for the cases where an array is returned, if refexpr yields a R/W - * expanded array, then the implementation is allowed to modify that object + * Note: for the cases where a container is returned, if refexpr yields a R/W + * expanded container, then the implementation is allowed to modify that object * in-place and return the same object.) * ---------------- */ -typedef struct ArrayRef +typedef struct SubscriptingRef { Expr xpr; - Oid refarraytype; /* type of the array proper */ - Oid refelemtype; /* type of the array elements */ - int32 reftypmod; /* typmod of the array (and elements too) */ + Oid refcontainertype; /* type of the container proper */ + Oid refelemtype; /* type of the container elements */ + int32 reftypmod; /* typmod of the container (and elements too) */ Oid refcollid; /* OID of collation, or InvalidOid if none */ List *refupperindexpr; /* expressions that evaluate to upper - * array indexes */ + * container indexes */ List *reflowerindexpr; /* expressions that evaluate to lower - * array indexes, or NIL for single array - * element */ - Expr *refexpr; /* the expression that evaluates to an array - * value */ + * container indexes, or NIL for single + * container element */ + Expr *refexpr; /* the expression that evaluates to a + * container value */ + Expr *refassgnexpr; /* expression for the source value, or NULL if * fetch */ -} ArrayRef; +} SubscriptingRef; /* * CoercionContext - distinguishes the allowed set of type casts @@ -765,7 +771,7 @@ typedef struct FieldSelect * * FieldStore represents the operation of modifying one field in a tuple * value, yielding a new tuple value (the input is not touched!). Like - * the assign case of ArrayRef, this is used to implement UPDATE of a + * the assign case of SubscriptingRef, this is used to implement UPDATE of a * portion of a column. * * resulttype is always a named composite type (not a domain). To update @@ -944,8 +950,20 @@ typedef struct CaseWhen * This is effectively like a Param, but can be implemented more simply * since we need only one replacement value at a time. * - * We also use this in nested UPDATE expressions. - * See transformAssignmentIndirection(). + * We also abuse this node type for some other purposes, including: + * * Placeholder for the current array element value in ArrayCoerceExpr; + * see build_coercion_expression(). + * * Nested FieldStore/ArrayRef assignment expressions in INSERT/UPDATE; + * see transformAssignmentIndirection(). + * + * The uses in CaseExpr and ArrayCoerceExpr are safe only to the extent that + * there is not any other CaseExpr or ArrayCoerceExpr between the value source + * node and its child CaseTestExpr(s). This is true in the parse analysis + * output, but the planner's function-inlining logic has to be careful not to + * break it. + * + * The nested-assignment-expression case is safe because the only node types + * that can be above such CaseTestExprs are FieldStore and ArrayRef. */ typedef struct CaseTestExpr { diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h index 91f5636..a555e17 100644 --- a/src/include/parser/scanner.h +++ b/src/include/parser/scanner.h @@ -8,8 +8,8 @@ * higher-level API provided by parser.h. * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scanner.h @@ -74,10 +74,10 @@ typedef struct core_yy_extra_type Size scanbuflen; /* - * The keyword list to use. + * The keyword list to use, and the associated grammar token codes. */ - const ScanKeyword *keywords; - int num_keywords; + const ScanKeywordList *keywordlist; + const uint16 *keyword_tokens; /* * Scanner settings to use. These are initialized from the corresponding @@ -117,14 +117,17 @@ typedef struct core_yy_extra_type typedef void *core_yyscan_t; +/* Constant data exported from parser/scan.l */ +extern PGDLLIMPORT const uint16 ScanKeywordTokens[]; + /* Entry points in parser/scan.l */ extern core_yyscan_t scanner_init(const char *str, - core_yy_extra_type *yyext, - const ScanKeyword *keywords, - int num_keywords); + core_yy_extra_type *yyext, + const ScanKeywordList *keywordlist, + const uint16 *keyword_tokens); extern void scanner_finish(core_yyscan_t yyscanner); -extern int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, - core_yyscan_t yyscanner); +extern int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, + core_yyscan_t yyscanner); extern int scanner_errposition(int location, core_yyscan_t yyscanner); extern void scanner_yyerror(const char *message, core_yyscan_t yyscanner) pg_attribute_noreturn(); diff --git a/src/include/parser/scansup.h b/src/include/parser/scansup.h index f73862c..a7d5f89 100644 --- a/src/include/parser/scansup.h +++ b/src/include/parser/scansup.h @@ -4,8 +4,8 @@ * scanner support routines. used by both the bootstrap lexer * as well as the normal lexer * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/parser/scansup.h @@ -19,10 +19,10 @@ extern char *scanstr(const char *s); extern char *downcase_truncate_identifier(const char *ident, int len, - bool warn); + bool warn); extern char *downcase_identifier(const char *ident, int len, - bool warn, bool truncate); + bool warn, bool truncate); extern void truncate_identifier(char *ident, int len, bool warn); diff --git a/src/include/parser/stringinfo.h b/src/include/parser/stringinfo.h index ec42916..52966bb 100644 --- a/src/include/parser/stringinfo.h +++ b/src/include/parser/stringinfo.h @@ -7,8 +7,8 @@ * It can be used to buffer either ordinary C strings (null-terminated text) * or arbitrary binary data. All storage is allocated with palloc(). * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/lib/stringinfo.h @@ -190,7 +190,7 @@ extern void appendStringInfoSpaces(StringInfo str, int count); * if necessary. */ extern void appendBinaryStringInfo(StringInfo str, - const char *data, int datalen); + const char *data, int datalen); /*------------------------ * appendBinaryStringInfoNT @@ -198,7 +198,7 @@ extern void appendBinaryStringInfo(StringInfo str, * if necessary. Does not ensure a trailing null-byte exists. */ extern void appendBinaryStringInfoNT(StringInfo str, - const char *data, int datalen); + const char *data, int datalen); /*------------------------ * enlargeStringInfo diff --git a/src/include/parser/value.h b/src/include/parser/value.h index 39ee6be..434e971 100644 --- a/src/include/parser/value.h +++ b/src/include/parser/value.h @@ -4,8 +4,8 @@ * interface for Value nodes * * - * Copyright (c) 2003-2018, PgPool Global Development Group - * Copyright (c) 2003-2018, PostgreSQL Global Development Group + * Copyright (c) 2003-2019, PgPool Global Development Group + * Copyright (c) 2003-2019, PostgreSQL Global Development Group * * src/include/nodes/value.h * diff --git a/src/include/protocol/protocol_defs.h b/src/include/protocol/protocol_defs.h index 14da4c4..cb9016c 100644 --- a/src/include/protocol/protocol_defs.h +++ b/src/include/protocol/protocol_defs.h @@ -17,11 +17,17 @@ #ifndef pgpool_protocol_defs_h #define pgpool_protocol_defs_h -#define SEQUENCETABLEQUERY "SELECT d.adsrc FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.relname = '%s' AND d.adsrc ~ 'nextval'" +#define SEQUENCETABLEQUERY (Pgversion(backend)->major >= 73 ? \ + "SELECT pg_get_expr(d.adbin, d.adrelid) FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.relname = '%s' AND d.pg_get_expr(d.adbin, d.adrelid) ~ 'nextval'" : \ + "SELECT d.adsrc FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.relname = '%s' AND d.adsrc ~ 'nextval'") -#define SEQUENCETABLEQUERY2 "SELECT d.adsrc FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pgpool_regclass('%s') AND d.adsrc ~ 'nextval'" +#define SEQUENCETABLEQUERY2 (Pgversion(backend)->major >= 73 ? \ + "SELECT pg_get_expr(d.adbin, d.adrelid) FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pgpool_regclass('%s') AND pg_get_expr(d.adbin, d.adrelid) ~ 'nextval'" : \ + "SELECT d.adsrc FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pgpool_regclass('%s') AND d.adsrc ~ 'nextval'") -#define SEQUENCETABLEQUERY3 "SELECT d.adsrc FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pg_catalog.to_regclass('%s') AND d.adsrc ~ 'nextval'" +#define SEQUENCETABLEQUERY3 (Pgversion(backend)->major >= 73 ? \ + "SELECT pg_get_expr(d.adbin, d.adrelid) FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pg_catalog.to_regclass('%s') AND pg_get_expr(d.adbin, d.adrelid) ~ 'nextval'" : \ + "SELECT d.adsrc FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum) WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pg_catalog.to_regclass('%s') AND d.adsrc ~ 'nextval'") /* query to lock a row by only the specified table name without regard to the schema */ #define ROWLOCKQUERY "SELECT 1 FROM pgpool_catalog.insert_lock WHERE reloid = (SELECT oid FROM pg_catalog.pg_class WHERE relname = '%s' ORDER BY oid LIMIT 1) FOR UPDATE" diff --git a/src/parser/Makefile.am b/src/parser/Makefile.am index 47e8a57..8b55a9c 100644 --- a/src/parser/Makefile.am +++ b/src/parser/Makefile.am @@ -6,6 +6,7 @@ libsql_parser_a_SOURCES = \ copyfuncs.c \ gram.y \ keywords.c \ + kwlookup.c \ list.c \ makefuncs.c \ nodes.c \ diff --git a/src/parser/Makefile.in b/src/parser/Makefile.in index 78b8db6..2d15bc9 100644 --- a/src/parser/Makefile.in +++ b/src/parser/Makefile.in @@ -104,18 +104,19 @@ am__v_AR_1 = libsql_parser_a_AR = $(AR) $(ARFLAGS) libsql_parser_a_LIBADD = am__libsql_parser_a_SOURCES_DIST = copyfuncs.c gram.y keywords.c \ - list.c makefuncs.c nodes.c outfuncs.c parser.c pool_string.c \ - scansup.c stringinfo.c value.c \ + kwlookup.c list.c makefuncs.c nodes.c outfuncs.c parser.c \ + pool_string.c scansup.c stringinfo.c value.c \ $(top_srcdir)/src/utils/mmgr/mcxt.c \ $(top_srcdir)/src/utils/mmgr/aset.c \ $(top_srcdir)/src/utils/error/elog.c wchar.c scan.c snprintf.c am__dirstamp = $(am__leading_dot)dirstamp @use_repl_snprintf_TRUE@am__objects_1 = snprintf.$(OBJEXT) am_libsql_parser_a_OBJECTS = copyfuncs.$(OBJEXT) gram.$(OBJEXT) \ - keywords.$(OBJEXT) list.$(OBJEXT) makefuncs.$(OBJEXT) \ - nodes.$(OBJEXT) outfuncs.$(OBJEXT) parser.$(OBJEXT) \ - pool_string.$(OBJEXT) scansup.$(OBJEXT) stringinfo.$(OBJEXT) \ - value.$(OBJEXT) $(top_srcdir)/src/utils/mmgr/mcxt.$(OBJEXT) \ + keywords.$(OBJEXT) kwlookup.$(OBJEXT) list.$(OBJEXT) \ + makefuncs.$(OBJEXT) nodes.$(OBJEXT) outfuncs.$(OBJEXT) \ + parser.$(OBJEXT) pool_string.$(OBJEXT) scansup.$(OBJEXT) \ + stringinfo.$(OBJEXT) value.$(OBJEXT) \ + $(top_srcdir)/src/utils/mmgr/mcxt.$(OBJEXT) \ $(top_srcdir)/src/utils/mmgr/aset.$(OBJEXT) \ $(top_srcdir)/src/utils/error/elog.$(OBJEXT) wchar.$(OBJEXT) \ scan.$(OBJEXT) $(am__objects_1) @@ -334,8 +335,8 @@ top_srcdir = @top_srcdir@ parser_incdir = $(top_srcdir)/src/include/parser AM_CPPFLAGS = -D_GNU_SOURCE -I $(parser_incdir) -I @PGSQL_INCLUDE_DIR@ noinst_LIBRARIES = libsql-parser.a -libsql_parser_a_SOURCES = copyfuncs.c gram.y keywords.c list.c \ - makefuncs.c nodes.c outfuncs.c parser.c pool_string.c \ +libsql_parser_a_SOURCES = copyfuncs.c gram.y keywords.c kwlookup.c \ + list.c makefuncs.c nodes.c outfuncs.c parser.c pool_string.c \ scansup.c stringinfo.c value.c \ $(top_srcdir)/src/utils/mmgr/mcxt.c \ $(top_srcdir)/src/utils/mmgr/aset.c \ diff --git a/src/parser/copyfuncs.c b/src/parser/copyfuncs.c index da43fa6..579c923 100644 --- a/src/parser/copyfuncs.c +++ b/src/parser/copyfuncs.c @@ -11,8 +11,8 @@ * be handled easily in a simple depth-first traversal. * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -93,7 +93,6 @@ _copyPlannedStmt(const PlannedStmt *from) COPY_NODE_FIELD(planTree); COPY_NODE_FIELD(rtable); COPY_NODE_FIELD(resultRelations); - COPY_NODE_FIELD(nonleafResultRelations); COPY_NODE_FIELD(rootResultRelations); COPY_NODE_FIELD(subplans); COPY_BITMAPSET_FIELD(rewindPlanIDs); @@ -206,7 +205,7 @@ _copyModifyTable(const ModifyTable *from) COPY_SCALAR_FIELD(operation); COPY_SCALAR_FIELD(canSetTag); COPY_SCALAR_FIELD(nominalRelation); - COPY_NODE_FIELD(partitioned_rels); + COPY_SCALAR_FIELD(rootRelation); COPY_SCALAR_FIELD(partColsUpdated); COPY_NODE_FIELD(resultRelations); COPY_SCALAR_FIELD(resultRelIndex); @@ -246,7 +245,6 @@ _copyAppend(const Append *from) */ COPY_NODE_FIELD(appendplans); COPY_SCALAR_FIELD(first_partial_plan); - COPY_NODE_FIELD(partitioned_rels); COPY_NODE_FIELD(part_prune_info); return newnode; @@ -268,13 +266,13 @@ _copyMergeAppend(const MergeAppend *from) /* * copy remainder of node */ - COPY_NODE_FIELD(partitioned_rels); COPY_NODE_FIELD(mergeplans); COPY_SCALAR_FIELD(numCols); COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(sortOperators, from->numCols * sizeof(Oid)); COPY_POINTER_FIELD(collations, from->numCols * sizeof(Oid)); COPY_POINTER_FIELD(nullsFirst, from->numCols * sizeof(bool)); + COPY_NODE_FIELD(part_prune_info); return newnode; } @@ -301,6 +299,7 @@ _copyRecursiveUnion(const RecursiveUnion *from) { COPY_POINTER_FIELD(dupColIdx, from->numCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(dupOperators, from->numCols * sizeof(Oid)); + COPY_POINTER_FIELD(dupCollations, from->numCols * sizeof(Oid)); } COPY_SCALAR_FIELD(numGroups); @@ -958,6 +957,7 @@ _copyGroup(const Group *from) COPY_SCALAR_FIELD(numCols); COPY_POINTER_FIELD(grpColIdx, from->numCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(grpOperators, from->numCols * sizeof(Oid)); + COPY_POINTER_FIELD(grpCollations, from->numCols * sizeof(Oid)); return newnode; } @@ -979,6 +979,7 @@ _copyAgg(const Agg *from) { COPY_POINTER_FIELD(grpColIdx, from->numCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(grpOperators, from->numCols * sizeof(Oid)); + COPY_POINTER_FIELD(grpCollations, from->numCols * sizeof(Oid)); } COPY_SCALAR_FIELD(numGroups); COPY_BITMAPSET_FIELD(aggParams); @@ -1004,12 +1005,14 @@ _copyWindowAgg(const WindowAgg *from) { COPY_POINTER_FIELD(partColIdx, from->partNumCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(partOperators, from->partNumCols * sizeof(Oid)); + COPY_POINTER_FIELD(partCollations, from->partNumCols * sizeof(Oid)); } COPY_SCALAR_FIELD(ordNumCols); if (from->ordNumCols > 0) { COPY_POINTER_FIELD(ordColIdx, from->ordNumCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(ordOperators, from->ordNumCols * sizeof(Oid)); + COPY_POINTER_FIELD(ordCollations, from->ordNumCols * sizeof(Oid)); } COPY_SCALAR_FIELD(frameOptions); COPY_NODE_FIELD(startOffset); @@ -1042,6 +1045,7 @@ _copyUnique(const Unique *from) COPY_SCALAR_FIELD(numCols); COPY_POINTER_FIELD(uniqColIdx, from->numCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(uniqOperators, from->numCols * sizeof(Oid)); + COPY_POINTER_FIELD(uniqCollations, from->numCols * sizeof(Oid)); return newnode; } @@ -1091,6 +1095,7 @@ _copySetOp(const SetOp *from) COPY_SCALAR_FIELD(numCols); COPY_POINTER_FIELD(dupColIdx, from->numCols * sizeof(AttrNumber)); COPY_POINTER_FIELD(dupOperators, from->numCols * sizeof(Oid)); + COPY_POINTER_FIELD(dupCollations, from->numCols * sizeof(Oid)); COPY_SCALAR_FIELD(flagColIdx); COPY_SCALAR_FIELD(firstFlag); COPY_SCALAR_FIELD(numGroups); @@ -1192,16 +1197,14 @@ _copyPartitionedRelPruneInfo(const PartitionedRelPruneInfo *from) { PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo); - COPY_SCALAR_FIELD(reloid); - COPY_NODE_FIELD(pruning_steps); + COPY_SCALAR_FIELD(rtindex); COPY_BITMAPSET_FIELD(present_parts); COPY_SCALAR_FIELD(nparts); - COPY_SCALAR_FIELD(nexprs); COPY_POINTER_FIELD(subplan_map, from->nparts * sizeof(int)); COPY_POINTER_FIELD(subpart_map, from->nparts * sizeof(int)); - COPY_POINTER_FIELD(hasexecparam, from->nexprs * sizeof(bool)); - COPY_SCALAR_FIELD(do_initial_prune); - COPY_SCALAR_FIELD(do_exec_prune); + COPY_POINTER_FIELD(relid_map, from->nparts * sizeof(Oid)); + COPY_NODE_FIELD(initial_pruning_steps); + COPY_NODE_FIELD(exec_pruning_steps); COPY_BITMAPSET_FIELD(execparamids); return newnode; @@ -1327,6 +1330,7 @@ _copyIntoClause(const IntoClause *from) COPY_NODE_FIELD(rel); COPY_NODE_FIELD(colNames); + COPY_STRING_FIELD(accessMethod); COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(onCommit); COPY_STRING_FIELD(tableSpaceName); @@ -1491,14 +1495,14 @@ _copyWindowFunc(const WindowFunc *from) } /* - * _copyArrayRef + * _copySubscriptingRef */ -static ArrayRef * -_copyArrayRef(const ArrayRef *from) +static SubscriptingRef * +_copySubscriptingRef(const SubscriptingRef *from) { - ArrayRef *newnode = makeNode(ArrayRef); + SubscriptingRef *newnode = makeNode(SubscriptingRef); - COPY_SCALAR_FIELD(refarraytype); + COPY_SCALAR_FIELD(refcontainertype); COPY_SCALAR_FIELD(refelemtype); COPY_SCALAR_FIELD(reftypmod); COPY_SCALAR_FIELD(refcollid); @@ -2201,7 +2205,7 @@ _copyOnConflictExpr(const OnConflictExpr *from) } /* **************************************************************** - * relation.h copy functions + * pathnodes.h copy functions * * We don't support copying RelOptInfo, IndexOptInfo, or Path nodes. * There are some subsidiary structs that are useful to copy, though. @@ -2360,6 +2364,7 @@ _copyRangeTblEntry(const RangeTblEntry *from) COPY_SCALAR_FIELD(rtekind); COPY_SCALAR_FIELD(relid); COPY_SCALAR_FIELD(relkind); + COPY_SCALAR_FIELD(rellockmode); COPY_NODE_FIELD(tablesample); COPY_NODE_FIELD(subquery); COPY_SCALAR_FIELD(security_barrier); @@ -2387,6 +2392,7 @@ _copyRangeTblEntry(const RangeTblEntry *from) COPY_BITMAPSET_FIELD(selectedCols); COPY_BITMAPSET_FIELD(insertedCols); COPY_BITMAPSET_FIELD(updatedCols); + COPY_BITMAPSET_FIELD(extraUpdatedCols); COPY_NODE_FIELD(securityQuals); return newnode; @@ -2542,6 +2548,7 @@ _copyCommonTableExpr(const CommonTableExpr *from) COPY_STRING_FIELD(ctename); COPY_NODE_FIELD(aliascolnames); + COPY_SCALAR_FIELD(ctematerialized); COPY_NODE_FIELD(ctequery); COPY_LOCATION_FIELD(location); COPY_SCALAR_FIELD(cterecursive); @@ -2879,12 +2886,12 @@ _copyColumnDef(const ColumnDef *from) COPY_SCALAR_FIELD(is_local); COPY_SCALAR_FIELD(is_not_null); COPY_SCALAR_FIELD(is_from_type); - COPY_SCALAR_FIELD(is_from_parent); COPY_SCALAR_FIELD(storage); COPY_NODE_FIELD(raw_default); COPY_NODE_FIELD(cooked_default); COPY_SCALAR_FIELD(identity); COPY_NODE_FIELD(identitySequence); + COPY_SCALAR_FIELD(generated); COPY_NODE_FIELD(collClause); COPY_SCALAR_FIELD(collOid); COPY_NODE_FIELD(constraints); @@ -2914,6 +2921,7 @@ _copyConstraint(const Constraint *from) COPY_NODE_FIELD(options); COPY_STRING_FIELD(indexname); COPY_STRING_FIELD(indexspace); + COPY_SCALAR_FIELD(reset_default_tblspc); COPY_STRING_FIELD(access_method); COPY_NODE_FIELD(where_clause); COPY_NODE_FIELD(pktable); @@ -3299,7 +3307,7 @@ _copyClusterStmt(const ClusterStmt *from) COPY_NODE_FIELD(relation); COPY_STRING_FIELD(indexname); - COPY_SCALAR_FIELD(verbose); + COPY_SCALAR_FIELD(options); return newnode; } @@ -3316,6 +3324,7 @@ _copyCopyStmt(const CopyStmt *from) COPY_SCALAR_FIELD(is_program); COPY_STRING_FIELD(filename); COPY_NODE_FIELD(options); + COPY_NODE_FIELD(whereClause); return newnode; } @@ -3339,6 +3348,7 @@ CopyCreateStmtFields(const CreateStmt *from, CreateStmt *newnode) COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(oncommit); COPY_STRING_FIELD(tablespacename); + COPY_STRING_FIELD(accessMethod); COPY_SCALAR_FIELD(if_not_exists); } @@ -3374,6 +3384,7 @@ _copyDefineStmt(const DefineStmt *from) COPY_NODE_FIELD(args); COPY_NODE_FIELD(definition); COPY_SCALAR_FIELD(if_not_exists); + COPY_SCALAR_FIELD(replace); return newnode; } @@ -3449,7 +3460,6 @@ _copyIndexStmt(const IndexStmt *from) COPY_STRING_FIELD(idxname); COPY_NODE_FIELD(relation); - COPY_SCALAR_FIELD(relationId); COPY_STRING_FIELD(accessMethod); COPY_STRING_FIELD(tableSpace); COPY_NODE_FIELD(indexParams); @@ -3468,6 +3478,7 @@ _copyIndexStmt(const IndexStmt *from) COPY_SCALAR_FIELD(transformed); COPY_SCALAR_FIELD(concurrent); COPY_SCALAR_FIELD(if_not_exists); + COPY_SCALAR_FIELD(reset_default_tblspc); return newnode; } @@ -3661,6 +3672,7 @@ _copyTransactionStmt(const TransactionStmt *from) COPY_NODE_FIELD(options); COPY_STRING_FIELD(savepoint_name); COPY_STRING_FIELD(gid); + COPY_SCALAR_FIELD(chain); return newnode; } @@ -3854,8 +3866,9 @@ _copyVacuumStmt(const VacuumStmt *from) { VacuumStmt *newnode = makeNode(VacuumStmt); - COPY_SCALAR_FIELD(options); + COPY_NODE_FIELD(options); COPY_NODE_FIELD(rels); + COPY_SCALAR_FIELD(is_vacuumcmd); return newnode; } @@ -4360,6 +4373,7 @@ _copyReindexStmt(const ReindexStmt *from) COPY_NODE_FIELD(relation); COPY_STRING_FIELD(name); COPY_SCALAR_FIELD(options); + COPY_SCALAR_FIELD(concurrent); return newnode; } @@ -4754,6 +4768,7 @@ _copyForeignKeyCacheInfo(const ForeignKeyCacheInfo *from) { ForeignKeyCacheInfo *newnode = makeNode(ForeignKeyCacheInfo); + COPY_SCALAR_FIELD(conoid); COPY_SCALAR_FIELD(conrelid); COPY_SCALAR_FIELD(confrelid); COPY_SCALAR_FIELD(nkeys); @@ -4978,8 +4993,8 @@ copyObjectImpl(const void *from) case T_WindowFunc: retval = _copyWindowFunc(from); break; - case T_ArrayRef: - retval = _copyArrayRef(from); + case T_SubscriptingRef: + retval = _copySubscriptingRef(from); break; case T_FuncExpr: retval = _copyFuncExpr(from); diff --git a/src/parser/gram.h b/src/parser/gram.h index c8c9576..daca70d 100644 --- a/src/parser/gram.h +++ b/src/parser/gram.h @@ -419,93 +419,95 @@ extern int base_yydebug; STDIN = 629, STDOUT = 630, STORAGE = 631, - STRICT_P = 632, - STRIP_P = 633, - SUBSCRIPTION = 634, - SUBSTRING = 635, - SYMMETRIC = 636, - SYSID = 637, - SYSTEM_P = 638, - TABLE = 639, - TABLES = 640, - TABLESAMPLE = 641, - TABLESPACE = 642, - TEMP = 643, - TEMPLATE = 644, - TEMPORARY = 645, - TEXT_P = 646, - THEN = 647, - TIES = 648, - TIME = 649, - TIMESTAMP = 650, - TO = 651, - TRAILING = 652, - TRANSACTION = 653, - TRANSFORM = 654, - TREAT = 655, - TRIGGER = 656, - TRIM = 657, - TRUE_P = 658, - TRUNCATE = 659, - TRUSTED = 660, - TYPE_P = 661, - TYPES_P = 662, - UNBOUNDED = 663, - UNCOMMITTED = 664, - UNENCRYPTED = 665, - UNION = 666, - UNIQUE = 667, - UNKNOWN = 668, - UNLISTEN = 669, - UNLOGGED = 670, - UNTIL = 671, - UPDATE = 672, - USER = 673, - USING = 674, - VACUUM = 675, - VALID = 676, - VALIDATE = 677, - VALIDATOR = 678, - VALUE_P = 679, - VALUES = 680, - VARCHAR = 681, - VARIADIC = 682, - VARYING = 683, - VERBOSE = 684, - VERSION_P = 685, - VIEW = 686, - VIEWS = 687, - VOLATILE = 688, - WHEN = 689, - WHERE = 690, - WHITESPACE_P = 691, - WINDOW = 692, - WITH = 693, - WITHIN = 694, - WITHOUT = 695, - WORK = 696, - WRAPPER = 697, - WRITE = 698, - XML_P = 699, - XMLATTRIBUTES = 700, - XMLCONCAT = 701, - XMLELEMENT = 702, - XMLEXISTS = 703, - XMLFOREST = 704, - XMLNAMESPACES = 705, - XMLPARSE = 706, - XMLPI = 707, - XMLROOT = 708, - XMLSERIALIZE = 709, - XMLTABLE = 710, - YEAR_P = 711, - YES_P = 712, - ZONE = 713, - NOT_LA = 714, - NULLS_LA = 715, - WITH_LA = 716, - POSTFIXOP = 717, - UMINUS = 718 + STORED = 632, + STRICT_P = 633, + STRIP_P = 634, + SUBSCRIPTION = 635, + SUBSTRING = 636, + SUPPORT = 637, + SYMMETRIC = 638, + SYSID = 639, + SYSTEM_P = 640, + TABLE = 641, + TABLES = 642, + TABLESAMPLE = 643, + TABLESPACE = 644, + TEMP = 645, + TEMPLATE = 646, + TEMPORARY = 647, + TEXT_P = 648, + THEN = 649, + TIES = 650, + TIME = 651, + TIMESTAMP = 652, + TO = 653, + TRAILING = 654, + TRANSACTION = 655, + TRANSFORM = 656, + TREAT = 657, + TRIGGER = 658, + TRIM = 659, + TRUE_P = 660, + TRUNCATE = 661, + TRUSTED = 662, + TYPE_P = 663, + TYPES_P = 664, + UNBOUNDED = 665, + UNCOMMITTED = 666, + UNENCRYPTED = 667, + UNION = 668, + UNIQUE = 669, + UNKNOWN = 670, + UNLISTEN = 671, + UNLOGGED = 672, + UNTIL = 673, + UPDATE = 674, + USER = 675, + USING = 676, + VACUUM = 677, + VALID = 678, + VALIDATE = 679, + VALIDATOR = 680, + VALUE_P = 681, + VALUES = 682, + VARCHAR = 683, + VARIADIC = 684, + VARYING = 685, + VERBOSE = 686, + VERSION_P = 687, + VIEW = 688, + VIEWS = 689, + VOLATILE = 690, + WHEN = 691, + WHERE = 692, + WHITESPACE_P = 693, + WINDOW = 694, + WITH = 695, + WITHIN = 696, + WITHOUT = 697, + WORK = 698, + WRAPPER = 699, + WRITE = 700, + XML_P = 701, + XMLATTRIBUTES = 702, + XMLCONCAT = 703, + XMLELEMENT = 704, + XMLEXISTS = 705, + XMLFOREST = 706, + XMLNAMESPACES = 707, + XMLPARSE = 708, + XMLPI = 709, + XMLROOT = 710, + XMLSERIALIZE = 711, + XMLTABLE = 712, + YEAR_P = 713, + YES_P = 714, + ZONE = 715, + NOT_LA = 716, + NULLS_LA = 717, + WITH_LA = 718, + POSTFIXOP = 719, + UMINUS = 720 }; #endif /* Tokens. */ @@ -883,93 +885,95 @@ extern int base_yydebug; #define STDIN 629 #define STDOUT 630 #define STORAGE 631 -#define STRICT_P 632 -#define STRIP_P 633 -#define SUBSCRIPTION 634 -#define SUBSTRING 635 -#define SYMMETRIC 636 -#define SYSID 637 -#define SYSTEM_P 638 -#define TABLE 639 -#define TABLES 640 -#define TABLESAMPLE 641 -#define TABLESPACE 642 -#define TEMP 643 -#define TEMPLATE 644 -#define TEMPORARY 645 -#define TEXT_P 646 -#define THEN 647 -#define TIES 648 -#define TIME 649 -#define TIMESTAMP 650 -#define TO 651 -#define TRAILING 652 -#define TRANSACTION 653 -#define TRANSFORM 654 -#define TREAT 655 -#define TRIGGER 656 -#define TRIM 657 -#define TRUE_P 658 -#define TRUNCATE 659 -#define TRUSTED 660 -#define TYPE_P 661 -#define TYPES_P 662 -#define UNBOUNDED 663 -#define UNCOMMITTED 664 -#define UNENCRYPTED 665 -#define UNION 666 -#define UNIQUE 667 -#define UNKNOWN 668 -#define UNLISTEN 669 -#define UNLOGGED 670 -#define UNTIL 671 -#define UPDATE 672 -#define USER 673 -#define USING 674 -#define VACUUM 675 -#define VALID 676 -#define VALIDATE 677 -#define VALIDATOR 678 -#define VALUE_P 679 -#define VALUES 680 -#define VARCHAR 681 -#define VARIADIC 682 -#define VARYING 683 -#define VERBOSE 684 -#define VERSION_P 685 -#define VIEW 686 -#define VIEWS 687 -#define VOLATILE 688 -#define WHEN 689 -#define WHERE 690 -#define WHITESPACE_P 691 -#define WINDOW 692 -#define WITH 693 -#define WITHIN 694 -#define WITHOUT 695 -#define WORK 696 -#define WRAPPER 697 -#define WRITE 698 -#define XML_P 699 -#define XMLATTRIBUTES 700 -#define XMLCONCAT 701 -#define XMLELEMENT 702 -#define XMLEXISTS 703 -#define XMLFOREST 704 -#define XMLNAMESPACES 705 -#define XMLPARSE 706 -#define XMLPI 707 -#define XMLROOT 708 -#define XMLSERIALIZE 709 -#define XMLTABLE 710 -#define YEAR_P 711 -#define YES_P 712 -#define ZONE 713 -#define NOT_LA 714 -#define NULLS_LA 715 -#define WITH_LA 716 -#define POSTFIXOP 717 -#define UMINUS 718 +#define STORED 632 +#define STRICT_P 633 +#define STRIP_P 634 +#define SUBSCRIPTION 635 +#define SUBSTRING 636 +#define SUPPORT 637 +#define SYMMETRIC 638 +#define SYSID 639 +#define SYSTEM_P 640 +#define TABLE 641 +#define TABLES 642 +#define TABLESAMPLE 643 +#define TABLESPACE 644 +#define TEMP 645 +#define TEMPLATE 646 +#define TEMPORARY 647 +#define TEXT_P 648 +#define THEN 649 +#define TIES 650 +#define TIME 651 +#define TIMESTAMP 652 +#define TO 653 +#define TRAILING 654 +#define TRANSACTION 655 +#define TRANSFORM 656 +#define TREAT 657 +#define TRIGGER 658 +#define TRIM 659 +#define TRUE_P 660 +#define TRUNCATE 661 +#define TRUSTED 662 +#define TYPE_P 663 +#define TYPES_P 664 +#define UNBOUNDED 665 +#define UNCOMMITTED 666 +#define UNENCRYPTED 667 +#define UNION 668 +#define UNIQUE 669 +#define UNKNOWN 670 +#define UNLISTEN 671 +#define UNLOGGED 672 +#define UNTIL 673 +#define UPDATE 674 +#define USER 675 +#define USING 676 +#define VACUUM 677 +#define VALID 678 +#define VALIDATE 679 +#define VALIDATOR 680 +#define VALUE_P 681 +#define VALUES 682 +#define VARCHAR 683 +#define VARIADIC 684 +#define VARYING 685 +#define VERBOSE 686 +#define VERSION_P 687 +#define VIEW 688 +#define VIEWS 689 +#define VOLATILE 690 +#define WHEN 691 +#define WHERE 692 +#define WHITESPACE_P 693 +#define WINDOW 694 +#define WITH 695 +#define WITHIN 696 +#define WITHOUT 697 +#define WORK 698 +#define WRAPPER 699 +#define WRITE 700 +#define XML_P 701 +#define XMLATTRIBUTES 702 +#define XMLCONCAT 703 +#define XMLELEMENT 704 +#define XMLEXISTS 705 +#define XMLFOREST 706 +#define XMLNAMESPACES 707 +#define XMLPARSE 708 +#define XMLPI 709 +#define XMLROOT 710 +#define XMLSERIALIZE 711 +#define XMLTABLE 712 +#define YEAR_P 713 +#define YES_P 714 +#define ZONE 715 +#define NOT_LA 716 +#define NULLS_LA 717 +#define WITH_LA 718 +#define POSTFIXOP 719 +#define UMINUS 720 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED @@ -1020,7 +1024,7 @@ union YYSTYPE PartitionBoundSpec *partboundspec; RoleSpec *rolespec; -#line 1024 "gram.h" /* yacc.c:1909 */ +#line 1028 "gram.h" /* yacc.c:1909 */ }; typedef union YYSTYPE YYSTYPE; diff --git a/src/parser/gram.y b/src/parser/gram.y index c8e5ca4..01ebd4d 100644 --- a/src/parser/gram.y +++ b/src/parser/gram.y @@ -6,8 +6,8 @@ * gram.y * POSTGRESQL BISON rules/actions * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -296,11 +296,11 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt CreateSchemaStmt CreateSeqStmt CreateStmt CreateStatsStmt CreateTableSpaceStmt CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt - CreateAssertStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt + CreateAssertionStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt - DropAssertStmt DropCastStmt DropRoleStmt + DropCastStmt DropRoleStmt DropdbStmt DropTableSpaceStmt DropTransformStmt DropUserMappingStmt ExplainStmt FetchStmt @@ -342,11 +342,14 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); create_extension_opt_item alter_extension_opt_item %type opt_lock lock_type cast_context -%type vacuum_option_list vacuum_option_elem - analyze_option_list analyze_option_elem +%type vac_analyze_option_name +%type vac_analyze_option_elem +%type vac_analyze_option_list +%type vac_analyze_option_arg %type opt_or_replace opt_grant_grant_option opt_grant_admin_option opt_nowait opt_if_exists opt_with_data + opt_transaction_chain %type opt_nowait_or_skip %type OptRoleList AlterOptRoleList @@ -359,6 +362,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type OptSchemaName %type OptSchemaEltList +%type am_type + %type TriggerForSpec TriggerForType %type TriggerActionTime %type TriggerEvents TriggerOneEvent @@ -374,7 +379,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type copy_file_name database_name access_method_clause access_method attr_name - name cursor_name file_name + table_access_method_clause name cursor_name file_name index_name opt_index_name cluster_index_specification %type func_name handler_name qual_Op qual_all_Op subquery_Op @@ -477,7 +482,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type opt_instead %type opt_unique opt_concurrently opt_verbose opt_full %type opt_freeze opt_analyze opt_default opt_recheck -%type opt_binary opt_oids copy_delimiter +%type opt_binary copy_delimiter %type copy_from opt_program @@ -516,7 +521,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type row explicit_row implicit_row type_list array_expr_list %type case_expr case_arg when_clause case_default %type when_clause_list -%type sub_type +%type sub_type opt_materialized %type NumericOnly %type NumericOnly_list %type alias_clause opt_alias_clause @@ -618,8 +623,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type part_elem %type part_params %type PartitionBoundSpec -%type partbound_datum PartitionRangeDatum -%type hash_partbound partbound_datum_list range_datum_list +%type hash_partbound %type hash_partbound_elem /* @@ -713,8 +717,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P - START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P - SUBSCRIPTION SUBSTRING SYMMETRIC SYSID SYSTEM_P + START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRIP_P + SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIES TIME TIMESTAMP TO TRAILING TRANSACTION TRANSFORM @@ -897,7 +901,7 @@ stmt : | CopyStmt | CreateAmStmt | CreateAsStmt - | CreateAssertStmt + | CreateAssertionStmt | CreateCastStmt | CreateConversionStmt | CreateDomainStmt @@ -933,7 +937,6 @@ stmt : | DeleteStmt | DiscardStmt | DoStmt - | DropAssertStmt | DropCastStmt | DropOpClassStmt | DropOpFamilyStmt @@ -1511,6 +1514,7 @@ generic_set: n->name = $1; $$ = n; } + ; set_rest_more: /* Generic SET syntaxes: */ generic_set {$$ = $1;} @@ -2376,14 +2380,7 @@ alter_table_cmd: n->missing_ok = false; $$ = (Node *)n; } - /* ALTER TABLE SET WITH OIDS */ - | SET WITH OIDS - { - AlterTableCmd *n = makeNode(AlterTableCmd); - n->subtype = AT_AddOids; - $$ = (Node *)n; - } - /* ALTER TABLE SET WITHOUT OIDS */ + /* ALTER TABLE SET WITHOUT OIDS, for backward compat */ | SET WITHOUT OIDS { AlterTableCmd *n = makeNode(AlterTableCmd); @@ -2749,7 +2746,7 @@ alter_identity_column_option: ; PartitionBoundSpec: - /* a HASH partition*/ + /* a HASH partition */ FOR VALUES WITH '(' hash_partbound ')' { ListCell *lc; @@ -2803,7 +2800,7 @@ PartitionBoundSpec: } /* a LIST partition */ - | FOR VALUES IN_P '(' partbound_datum_list ')' + | FOR VALUES IN_P '(' expr_list ')' { PartitionBoundSpec *n = makeNode(PartitionBoundSpec); @@ -2816,7 +2813,7 @@ PartitionBoundSpec: } /* a RANGE partition */ - | FOR VALUES FROM '(' range_datum_list ')' TO '(' range_datum_list ')' + | FOR VALUES FROM '(' expr_list ')' TO '(' expr_list ')' { PartitionBoundSpec *n = makeNode(PartitionBoundSpec); @@ -2859,59 +2856,6 @@ hash_partbound: } ; -partbound_datum: - Sconst { $$ = makeStringConst($1, @1); } - | NumericOnly { $$ = makeAConst($1, @1); } - | TRUE_P { $$ = makeStringConst(pstrdup("true"), @1); } - | FALSE_P { $$ = makeStringConst(pstrdup("false"), @1); } - | NULL_P { $$ = makeNullAConst(@1); } - ; - -partbound_datum_list: - partbound_datum { $$ = list_make1($1); } - | partbound_datum_list ',' partbound_datum - { $$ = lappend($1, $3); } - ; - -range_datum_list: - PartitionRangeDatum { $$ = list_make1($1); } - | range_datum_list ',' PartitionRangeDatum - { $$ = lappend($1, $3); } - ; - -PartitionRangeDatum: - MINVALUE - { - PartitionRangeDatum *n = makeNode(PartitionRangeDatum); - - n->kind = PARTITION_RANGE_DATUM_MINVALUE; - n->value = NULL; - n->location = @1; - - $$ = (Node *) n; - } - | MAXVALUE - { - PartitionRangeDatum *n = makeNode(PartitionRangeDatum); - - n->kind = PARTITION_RANGE_DATUM_MAXVALUE; - n->value = NULL; - n->location = @1; - - $$ = (Node *) n; - } - | partbound_datum - { - PartitionRangeDatum *n = makeNode(PartitionRangeDatum); - - n->kind = PARTITION_RANGE_DATUM_VALUE; - n->value = $1; - n->location = @1; - - $$ = (Node *) n; - } - ; - /***************************************************************************** * * ALTER TYPE @@ -3026,23 +2970,25 @@ ClosePortalStmt: * syntax had a hard-wired, space-separated set of options. * * Really old syntax, from versions 7.2 and prior: - * COPY [ BINARY ] table [ WITH OIDS ] FROM/TO file + * COPY [ BINARY ] table FROM/TO file * [ [ USING ] DELIMITERS 'delimiter' ] ] * [ WITH NULL AS 'null string' ] * This option placement is not supported with COPY (query...). * *****************************************************************************/ -CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids - copy_from opt_program copy_file_name copy_delimiter opt_with copy_options +CopyStmt: COPY opt_binary qualified_name opt_column_list + copy_from opt_program copy_file_name copy_delimiter opt_with + copy_options where_clause { CopyStmt *n = makeNode(CopyStmt); n->relation = $3; n->query = NULL; n->attlist = $4; - n->is_from = $6; - n->is_program = $7; - n->filename = $8; + n->is_from = $5; + n->is_program = $6; + n->filename = $7; + n->whereClause = $11; if (n->is_program && n->filename == NULL) ereport(ERROR, @@ -3050,16 +2996,20 @@ CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids errmsg("STDIN/STDOUT not allowed with PROGRAM"), parser_errposition(@8))); + if (!n->is_from && n->whereClause != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("WHERE clause not allowed with COPY TO"), + parser_errposition(@11))); + n->options = NIL; /* Concatenate user-supplied flags */ if ($2) n->options = lappend(n->options, $2); - if ($5) - n->options = lappend(n->options, $5); - if ($9) - n->options = lappend(n->options, $9); - if ($11) - n->options = list_concat(n->options, $11); + if ($8) + n->options = lappend(n->options, $8); + if ($10) + n->options = list_concat(n->options, $10); $$ = (Node *)n; } | COPY '(' PreparableStmt ')' TO opt_program copy_file_name opt_with copy_options @@ -3119,10 +3069,6 @@ copy_opt_item: { $$ = makeDefElem("format", (Node *)makeString("binary"), @1); } - | OIDS - { - $$ = makeDefElem("oids", (Node *)makeInteger(true), @1); - } | FREEZE { $$ = makeDefElem("freeze", (Node *)makeInteger(true), @1); @@ -3183,14 +3129,6 @@ opt_binary: | /*EMPTY*/ { $$ = NULL; } ; -opt_oids: - WITH OIDS - { - $$ = makeDefElem("oids", (Node *)makeInteger(true), @1); - } - | /*EMPTY*/ { $$ = NULL; } - ; - copy_delimiter: opt_using DELIMITERS Sconst { @@ -3256,7 +3194,8 @@ copy_generic_opt_arg_list_item: *****************************************************************************/ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' - OptInherit OptPartitionSpec OptWith OnCommitOption OptTableSpace + OptInherit OptPartitionSpec table_access_method_clause OptWith + OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; @@ -3266,15 +3205,16 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->partspec = $9; n->ofTypename = NULL; n->constraints = NIL; - n->options = $10; - n->oncommit = $11; - n->tablespacename = $12; + n->accessMethod = $10; + n->options = $11; + n->oncommit = $12; + n->tablespacename = $13; n->if_not_exists = false; $$ = (Node *)n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '(' - OptTableElementList ')' OptInherit OptPartitionSpec OptWith - OnCommitOption OptTableSpace + OptTableElementList ')' OptInherit OptPartitionSpec table_access_method_clause + OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; @@ -3284,15 +3224,16 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->partspec = $12; n->ofTypename = NULL; n->constraints = NIL; - n->options = $13; - n->oncommit = $14; - n->tablespacename = $15; + n->accessMethod = $13; + n->options = $14; + n->oncommit = $15; + n->tablespacename = $16; n->if_not_exists = true; $$ = (Node *)n; } | CREATE OptTemp TABLE qualified_name OF any_name - OptTypedTableElementList OptPartitionSpec OptWith OnCommitOption - OptTableSpace + OptTypedTableElementList OptPartitionSpec table_access_method_clause + OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; @@ -3303,15 +3244,16 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->ofTypename = makeTypeNameFromNameList($6); n->ofTypename->location = @6; n->constraints = NIL; - n->options = $9; - n->oncommit = $10; - n->tablespacename = $11; + n->accessMethod = $9; + n->options = $10; + n->oncommit = $11; + n->tablespacename = $12; n->if_not_exists = false; $$ = (Node *)n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name - OptTypedTableElementList OptPartitionSpec OptWith OnCommitOption - OptTableSpace + OptTypedTableElementList OptPartitionSpec table_access_method_clause + OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; @@ -3322,15 +3264,16 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->ofTypename = makeTypeNameFromNameList($9); n->ofTypename->location = @9; n->constraints = NIL; - n->options = $12; - n->oncommit = $13; - n->tablespacename = $14; + n->accessMethod = $12; + n->options = $13; + n->oncommit = $14; + n->tablespacename = $15; n->if_not_exists = true; $$ = (Node *)n; } | CREATE OptTemp TABLE qualified_name PARTITION OF qualified_name - OptTypedTableElementList PartitionBoundSpec OptPartitionSpec OptWith - OnCommitOption OptTableSpace + OptTypedTableElementList PartitionBoundSpec OptPartitionSpec + table_access_method_clause OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; @@ -3341,15 +3284,16 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->partspec = $10; n->ofTypename = NULL; n->constraints = NIL; - n->options = $11; - n->oncommit = $12; - n->tablespacename = $13; + n->accessMethod = $11; + n->options = $12; + n->oncommit = $13; + n->tablespacename = $14; n->if_not_exists = false; $$ = (Node *)n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec OptPartitionSpec - OptWith OnCommitOption OptTableSpace + table_access_method_clause OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; @@ -3360,9 +3304,10 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->partspec = $13; n->ofTypename = NULL; n->constraints = NIL; - n->options = $14; - n->oncommit = $15; - n->tablespacename = $16; + n->accessMethod = $14; + n->options = $15; + n->oncommit = $16; + n->tablespacename = $17; n->if_not_exists = true; $$ = (Node *)n; } @@ -3453,7 +3398,6 @@ columnDef: ColId Typename create_generic_options ColQualList n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->is_from_parent = false; n->storage = 0; n->raw_default = NULL; n->cooked_default = NULL; @@ -3475,7 +3419,6 @@ columnOptions: ColId ColQualList n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->is_from_parent = false; n->storage = 0; n->raw_default = NULL; n->cooked_default = NULL; @@ -3494,7 +3437,6 @@ columnOptions: ColId ColQualList n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->is_from_parent = false; n->storage = 0; n->raw_default = NULL; n->cooked_default = NULL; @@ -3620,6 +3562,29 @@ ColConstraintElem: n->location = @1; $$ = (Node *)n; } + | GENERATED generated_when AS '(' a_expr ')' STORED + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_GENERATED; + n->generated_when = $2; + n->raw_expr = $5; + n->cooked_expr = NULL; + n->location = @1; + + /* + * Can't do this in the grammar because of shift/reduce + * conflicts. (IDENTITY allows both ALWAYS and BY + * DEFAULT, but generated columns only allow ALWAYS.) We + * can also give a more useful error message and location. + */ + if ($2 != ATTRIBUTE_IDENTITY_ALWAYS) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("for a generated column, GENERATED ALWAYS must be specified"), + parser_errposition(@2))); + + $$ = (Node *)n; + } | REFERENCES qualified_name opt_column_list key_match key_actions { Constraint *n = makeNode(Constraint); @@ -3710,6 +3675,7 @@ TableLikeOption: | CONSTRAINTS { $$ = CREATE_TABLE_LIKE_CONSTRAINTS; } | DEFAULTS { $$ = CREATE_TABLE_LIKE_DEFAULTS; } | IDENTITY_P { $$ = CREATE_TABLE_LIKE_IDENTITY; } + | GENERATED { $$ = CREATE_TABLE_LIKE_GENERATED; } | INDEXES { $$ = CREATE_TABLE_LIKE_INDEXES; } | STATISTICS { $$ = CREATE_TABLE_LIKE_STATISTICS; } | STORAGE { $$ = CREATE_TABLE_LIKE_STORAGE; } @@ -4012,11 +3978,16 @@ part_elem: ColId opt_collate opt_class $$ = n; } ; -/* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */ + +table_access_method_clause: + USING access_method { $$ = $2; } + | /*EMPTY*/ { $$ = NULL; } + ; + +/* WITHOUT OIDS is legacy only */ OptWith: WITH reloptions { $$ = $2; } - | WITH OIDS { $$ = list_make1(makeDefElem("oids", (Node *) makeInteger(true), @1)); } - | WITHOUT OIDS { $$ = list_make1(makeDefElem("oids", (Node *) makeInteger(false), @1)); } + | WITHOUT OIDS { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; } ; @@ -4118,14 +4089,16 @@ CreateAsStmt: ; create_as_target: - qualified_name opt_column_list OptWith OnCommitOption OptTableSpace + qualified_name opt_column_list table_access_method_clause + OptWith OnCommitOption OptTableSpace { $$ = makeNode(IntoClause); $$->rel = $1; $$->colNames = $2; - $$->options = $3; - $$->onCommit = $4; - $$->tableSpaceName = $5; + $$->accessMethod = $3; + $$->options = $4; + $$->onCommit = $5; + $$->tableSpaceName = $6; $$->viewQuery = NULL; $$->skipData = false; /* might get changed later */ } @@ -4175,14 +4148,15 @@ CreateMatViewStmt: ; create_mv_target: - qualified_name opt_column_list opt_reloptions OptTableSpace + qualified_name opt_column_list table_access_method_clause opt_reloptions OptTableSpace { $$ = makeNode(IntoClause); $$->rel = $1; $$->colNames = $2; - $$->options = $3; + $$->accessMethod = $3; + $$->options = $4; $$->onCommit = ONCOMMIT_NOOP; - $$->tableSpaceName = $4; + $$->tableSpaceName = $5; $$->viewQuery = NULL; /* filled at analysis time */ $$->skipData = false; /* might get changed later */ } @@ -5390,16 +5364,21 @@ row_security_cmd: * *****************************************************************************/ -CreateAmStmt: CREATE ACCESS METHOD name TYPE_P INDEX HANDLER handler_name +CreateAmStmt: CREATE ACCESS METHOD name TYPE_P am_type HANDLER handler_name { CreateAmStmt *n = makeNode(CreateAmStmt); n->amname = $4; n->handler_name = $8; - n->amtype = AMTYPE_INDEX; + n->amtype = $6; $$ = (Node *) n; } ; +am_type: + INDEX { $$ = AMTYPE_INDEX; } + | TABLE { $$ = AMTYPE_TABLE; } + ; + /***************************************************************************** * * QUERIES : @@ -5410,7 +5389,7 @@ CreateAmStmt: CREATE ACCESS METHOD name TYPE_P INDEX HANDLER handler_name CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON qualified_name TriggerReferencing TriggerForSpec TriggerWhen - EXECUTE PROCEDURE func_name '(' TriggerFuncArgs ')' + EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')' { CreateTrigStmt *n = makeNode(CreateTrigStmt); n->trigname = $3; @@ -5432,7 +5411,7 @@ CreateTrigStmt: | CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON qualified_name OptConstrFromTable ConstraintAttributeSpec FOR EACH ROW TriggerWhen - EXECUTE PROCEDURE func_name '(' TriggerFuncArgs ')' + EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')' { CreateTrigStmt *n = makeNode(CreateTrigStmt); n->trigname = $4; @@ -5570,6 +5549,11 @@ TriggerWhen: | /*EMPTY*/ { $$ = NULL; } ; +FUNCTION_or_PROCEDURE: + FUNCTION + | PROCEDURE + ; + TriggerFuncArgs: TriggerFuncArg { $$ = list_make1($1); } | TriggerFuncArgs ',' TriggerFuncArg { $$ = lappend($1, $3); } @@ -5640,7 +5624,7 @@ ConstraintAttributeElem: CreateEventTrigStmt: CREATE EVENT TRIGGER name ON ColLabel - EXECUTE PROCEDURE func_name '(' ')' + EXECUTE FUNCTION_or_PROCEDURE func_name '(' ')' { CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt); n->trigname = $4; @@ -5651,7 +5635,7 @@ CreateEventTrigStmt: } | CREATE EVENT TRIGGER name ON ColLabel WHEN event_trigger_when_list - EXECUTE PROCEDURE func_name '(' ')' + EXECUTE FUNCTION_or_PROCEDURE func_name '(' ')' { CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt); n->trigname = $4; @@ -5700,43 +5684,19 @@ enable_trigger: /***************************************************************************** * - * QUERIES : + * QUERY : * CREATE ASSERTION ... - * DROP ASSERTION ... * *****************************************************************************/ -CreateAssertStmt: - CREATE ASSERTION name CHECK '(' a_expr ')' - ConstraintAttributeSpec +CreateAssertionStmt: + CREATE ASSERTION any_name CHECK '(' a_expr ')' ConstraintAttributeSpec { - CreateTrigStmt *n = makeNode(CreateTrigStmt); - n->trigname = $3; - n->args = list_make1($6); - n->isconstraint = true; - processCASbits($8, @8, "ASSERTION", - &n->deferrable, &n->initdeferred, NULL, - NULL, yyscanner); - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("CREATE ASSERTION is not yet implemented"))); - $$ = (Node *)n; - } - ; - -DropAssertStmt: - DROP ASSERTION name opt_drop_behavior - { - DropStmt *n = makeNode(DropStmt); - n->objects = NIL; - n->behavior = $4; - n->removeType = OBJECT_TRIGGER; /* XXX */ - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("DROP ASSERTION is not yet implemented"))); - $$ = (Node *) n; + $$ = NULL; } ; @@ -5749,25 +5709,27 @@ DropAssertStmt: *****************************************************************************/ DefineStmt: - CREATE AGGREGATE func_name aggr_args definition + CREATE opt_or_replace AGGREGATE func_name aggr_args definition { DefineStmt *n = makeNode(DefineStmt); n->kind = OBJECT_AGGREGATE; n->oldstyle = false; - n->defnames = $3; - n->args = $4; - n->definition = $5; + n->replace = $2; + n->defnames = $4; + n->args = $5; + n->definition = $6; $$ = (Node *)n; } - | CREATE AGGREGATE func_name old_aggr_definition + | CREATE opt_or_replace AGGREGATE func_name old_aggr_definition { /* old-style (pre-8.2) syntax for CREATE AGGREGATE */ DefineStmt *n = makeNode(DefineStmt); n->kind = OBJECT_AGGREGATE; n->oldstyle = true; - n->defnames = $3; + n->replace = $2; + n->defnames = $4; n->args = NIL; - n->definition = $4; + n->definition = $5; $$ = (Node *)n; } | CREATE OPERATOR any_operator definition @@ -6439,6 +6401,7 @@ attrs: '.' attr_name type_name_list: Typename { $$ = list_make1($1); } | type_name_list ',' Typename { $$ = lappend($1, $3); } + ; /***************************************************************************** * @@ -7449,7 +7412,6 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name n->concurrent = $4; n->idxname = $5; n->relation = $7; - n->relationId = InvalidOid; n->accessMethod = $8; n->indexParams = $10; n->indexIncludingParams = $12; @@ -7466,6 +7428,7 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name n->initdeferred = false; n->transformed = false; n->if_not_exists = false; + n->reset_default_tblspc = false; $$ = (Node *)n; } | CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS index_name @@ -7477,7 +7440,6 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name n->concurrent = $4; n->idxname = $8; n->relation = $10; - n->relationId = InvalidOid; n->accessMethod = $11; n->indexParams = $13; n->indexIncludingParams = $15; @@ -7494,6 +7456,7 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name n->initdeferred = false; n->transformed = false; n->if_not_exists = true; + n->reset_default_tblspc = false; $$ = (Node *)n; } ; @@ -7993,6 +7956,10 @@ common_func_opt_item: { $$ = makeDefElem("rows", (Node *)$2, @1); } + | SUPPORT any_name + { + $$ = makeDefElem("support", (Node *)$2, @1); + } | FunctionSetResetClause { /* we abuse the normal content of a DefElem here */ @@ -8425,42 +8392,46 @@ DropTransformStmt: DROP TRANSFORM opt_if_exists FOR Typename LANGUAGE name opt_d * * QUERY: * - * REINDEX [ (options) ] type + * REINDEX [ (options) ] type [CONCURRENTLY] *****************************************************************************/ ReindexStmt: - REINDEX reindex_target_type qualified_name + REINDEX reindex_target_type opt_concurrently qualified_name { ReindexStmt *n = makeNode(ReindexStmt); n->kind = $2; - n->relation = $3; + n->concurrent = $3; + n->relation = $4; n->name = NULL; n->options = 0; $$ = (Node *)n; } - | REINDEX reindex_target_multitable name + | REINDEX reindex_target_multitable opt_concurrently name { ReindexStmt *n = makeNode(ReindexStmt); n->kind = $2; - n->name = $3; + n->concurrent = $3; + n->name = $4; n->relation = NULL; n->options = 0; $$ = (Node *)n; } - | REINDEX '(' reindex_option_list ')' reindex_target_type qualified_name + | REINDEX '(' reindex_option_list ')' reindex_target_type opt_concurrently qualified_name { ReindexStmt *n = makeNode(ReindexStmt); n->kind = $5; - n->relation = $6; + n->concurrent = $6; + n->relation = $7; n->name = NULL; n->options = $3; $$ = (Node *)n; } - | REINDEX '(' reindex_option_list ')' reindex_target_multitable name + | REINDEX '(' reindex_option_list ')' reindex_target_multitable opt_concurrently name { ReindexStmt *n = makeNode(ReindexStmt); n->kind = $5; - n->name = $6; + n->concurrent = $6; + n->name = $7; n->relation = NULL; n->options = $3; $$ = (Node *)n; @@ -9918,11 +9889,12 @@ UnlistenStmt: *****************************************************************************/ TransactionStmt: - ABORT_P opt_transaction + ABORT_P opt_transaction opt_transaction_chain { TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_ROLLBACK; n->options = NIL; + n->chain = $3; $$ = (Node *)n; } | BEGIN_P opt_transaction transaction_mode_list_or_empty @@ -9939,25 +9911,28 @@ TransactionStmt: n->options = $3; $$ = (Node *)n; } - | COMMIT opt_transaction + | COMMIT opt_transaction opt_transaction_chain { TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_COMMIT; n->options = NIL; + n->chain = $3; $$ = (Node *)n; } - | END_P opt_transaction + | END_P opt_transaction opt_transaction_chain { TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_COMMIT; n->options = NIL; + n->chain = $3; $$ = (Node *)n; } - | ROLLBACK opt_transaction + | ROLLBACK opt_transaction opt_transaction_chain { TransactionStmt *n = makeNode(TransactionStmt); n->kind = TRANS_STMT_ROLLBACK; n->options = NIL; + n->chain = $3; $$ = (Node *)n; } | SAVEPOINT ColId @@ -10057,6 +10032,12 @@ transaction_mode_list_or_empty: { $$ = NIL; } ; +opt_transaction_chain: + AND CHAIN { $$ = true; } + | AND NO CHAIN { $$ = false; } + | /* EMPTY */ { $$ = false; } + ; + /***************************************************************************** * @@ -10544,7 +10525,9 @@ ClusterStmt: ClusterStmt *n = makeNode(ClusterStmt); n->relation = $3; n->indexname = $4; - n->verbose = $2; + n->options = 0; + if ($2) + n->options |= CLUOPT_VERBOSE; $$ = (Node*)n; } | CLUSTER opt_verbose @@ -10552,7 +10535,9 @@ ClusterStmt: ClusterStmt *n = makeNode(ClusterStmt); n->relation = NULL; n->indexname = NULL; - n->verbose = $2; + n->options = 0; + if ($2) + n->options |= CLUOPT_VERBOSE; $$ = (Node*)n; } /* kept for pre-8.3 compatibility */ @@ -10561,7 +10546,9 @@ ClusterStmt: ClusterStmt *n = makeNode(ClusterStmt); n->relation = $5; n->indexname = $3; - n->verbose = $2; + n->options = 0; + if ($2) + n->options |= CLUOPT_VERBOSE; $$ = (Node*)n; } ; @@ -10583,74 +10570,63 @@ cluster_index_specification: VacuumStmt: VACUUM opt_full opt_freeze opt_verbose opt_analyze opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_VACUUM; + n->options = NIL; if ($2) - n->options |= VACOPT_FULL; + n->options = lappend(n->options, + makeDefElem("full", NULL, @2)); if ($3) - n->options |= VACOPT_FREEZE; + n->options = lappend(n->options, + makeDefElem("freeze", NULL, @3)); if ($4) - n->options |= VACOPT_VERBOSE; + n->options = lappend(n->options, + makeDefElem("verbose", NULL, @4)); if ($5) - n->options |= VACOPT_ANALYZE; + n->options = lappend(n->options, + makeDefElem("analyze", NULL, @5)); n->rels = $6; + n->is_vacuumcmd = true; $$ = (Node *)n; } - | VACUUM '(' vacuum_option_list ')' opt_vacuum_relation_list + | VACUUM '(' vac_analyze_option_list ')' opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_VACUUM | $3; + n->options = $3; n->rels = $5; + n->is_vacuumcmd = true; $$ = (Node *) n; } ; -vacuum_option_list: - vacuum_option_elem { $$ = $1; } - | vacuum_option_list ',' vacuum_option_elem { $$ = $1 | $3; } - ; - -vacuum_option_elem: - analyze_keyword { $$ = VACOPT_ANALYZE; } - | VERBOSE { $$ = VACOPT_VERBOSE; } - | FREEZE { $$ = VACOPT_FREEZE; } - | FULL { $$ = VACOPT_FULL; } - | IDENT - { - if (strcmp($1, "disable_page_skipping") == 0) - $$ = VACOPT_DISABLE_PAGE_SKIPPING; - else - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("unrecognized VACUUM option \"%s\"", $1), - parser_errposition(@1))); - } - ; - AnalyzeStmt: analyze_keyword opt_verbose opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_ANALYZE; + n->options = NIL; if ($2) - n->options |= VACOPT_VERBOSE; + n->options = lappend(n->options, + makeDefElem("verbose", NULL, @2)); n->rels = $3; + n->is_vacuumcmd = false; $$ = (Node *)n; } - | analyze_keyword '(' analyze_option_list ')' opt_vacuum_relation_list + | analyze_keyword '(' vac_analyze_option_list ')' opt_vacuum_relation_list { VacuumStmt *n = makeNode(VacuumStmt); - n->options = VACOPT_ANALYZE | $3; + n->options = $3; n->rels = $5; + n->is_vacuumcmd = false; $$ = (Node *) n; } ; -analyze_option_list: - analyze_option_elem { $$ = $1; } - | analyze_option_list ',' analyze_option_elem { $$ = $1 | $3; } - ; - -analyze_option_elem: - VERBOSE { $$ = VACOPT_VERBOSE; } +vac_analyze_option_list: + vac_analyze_option_elem + { + $$ = list_make1($1); + } + | vac_analyze_option_list ',' vac_analyze_option_elem + { + $$ = lappend($1, $3); + } ; analyze_keyword: @@ -10658,6 +10634,24 @@ analyze_keyword: | ANALYSE /* British */ {} ; +vac_analyze_option_elem: + vac_analyze_option_name vac_analyze_option_arg + { + $$ = makeDefElem($1, $2, @1); + } + ; + +vac_analyze_option_name: + NonReservedWord { $$ = $1; } + | analyze_keyword { $$ = "analyze"; } + ; + +vac_analyze_option_arg: + opt_boolean_or_string { $$ = (Node *) makeString($1); } + | NumericOnly { $$ = (Node *) $1; } + | /* EMPTY */ { $$ = NULL; } + ; + opt_analyze: analyze_keyword { $$ = true; } | /*EMPTY*/ { $$ = false; } @@ -10837,11 +10831,29 @@ ExecuteStmt: EXECUTE name execute_param_clause ctas->into = $4; ctas->relkind = OBJECT_TABLE; ctas->is_select_into = false; + ctas->if_not_exists = false; /* cram additional flags into the IntoClause */ $4->rel->relpersistence = $2; $4->skipData = !($9); $$ = (Node *) ctas; } + | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS + EXECUTE name execute_param_clause opt_with_data + { + CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt); + ExecuteStmt *n = makeNode(ExecuteStmt); + n->name = $10; + n->params = $11; + ctas->query = (Node *) n; + ctas->into = $7; + ctas->relkind = OBJECT_TABLE; + ctas->is_select_into = false; + ctas->if_not_exists = true; + /* cram additional flags into the IntoClause */ + $7->rel->relpersistence = $2; + $7->skipData = !($12); + $$ = (Node *) ctas; + } ; execute_param_clause: '(' expr_list ')' { $$ = $2; } @@ -11463,17 +11475,24 @@ cte_list: | cte_list ',' common_table_expr { $$ = lappend($1, $3); } ; -common_table_expr: name opt_name_list AS '(' PreparableStmt ')' +common_table_expr: name opt_name_list AS opt_materialized '(' PreparableStmt ')' { CommonTableExpr *n = makeNode(CommonTableExpr); n->ctename = $1; n->aliascolnames = $2; - n->ctequery = $5; + n->ctematerialized = $4; + n->ctequery = $6; n->location = @1; $$ = (Node *) n; } ; +opt_materialized: + MATERIALIZED { $$ = CTEMaterializeAlways; } + | NOT MATERIALIZED { $$ = CTEMaterializeNever; } + | /*EMPTY*/ { $$ = CTEMaterializeDefault; } + ; + opt_with_clause: with_clause { $$ = $1; } | /*EMPTY*/ { $$ = NULL; } @@ -12335,7 +12354,6 @@ TableFuncElement: ColId Typename opt_collate_clause n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->is_from_parent = false; n->storage = 0; n->raw_default = NULL; n->cooked_default = NULL; @@ -14038,20 +14056,25 @@ xmlexists_argument: { $$ = $2; } - | PASSING c_expr BY REF + | PASSING c_expr xml_passing_mech { $$ = $2; } - | PASSING BY REF c_expr + | PASSING xml_passing_mech c_expr { - $$ = $4; + $$ = $3; } - | PASSING BY REF c_expr BY REF + | PASSING xml_passing_mech c_expr xml_passing_mech { - $$ = $4; + $$ = $3; } ; +xml_passing_mech: + BY REF + | BY VALUE_P + ; + /* * Aggregate decoration clauses @@ -15303,9 +15326,11 @@ unreserved_keyword: | STDIN | STDOUT | STORAGE + | STORED | STRICT_P | STRIP_P | SUBSCRIPTION + | SUPPORT | SYSID | SYSTEM_P | TABLES @@ -16355,6 +16380,7 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) /* create common table expression */ cte->ctename = relname; cte->aliascolnames = aliases; + cte->ctematerialized = CTEMaterializeDefault; cte->ctequery = query; cte->location = -1; diff --git a/src/parser/keywords.c b/src/parser/keywords.c index 9fded54..240363b 100644 --- a/src/parser/keywords.c +++ b/src/parser/keywords.c @@ -1,109 +1,32 @@ /*------------------------------------------------------------------------- * * keywords.c - * lexical token lookup for key words in PostgreSQL + * PostgreSQL's list of SQL keywords * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * src/backend/parser/keywords.c + * src/common/keywords.c * *------------------------------------------------------------------------- */ -#include -#include "parsenodes.h" -#ifndef FRONTEND - -#include "gramparse.h" /* required before parser/parse.h! */ - -#define PG_KEYWORD(a,b,c) {a,b,c}, - -#else - #include "keywords.h" -/* - * We don't need the token number for frontend uses, so leave it out to avoid - * requiring backend headers that won't compile cleanly here. - */ -#define PG_KEYWORD(a,b,c) {a,0,c}, +/* ScanKeywordList lookup data for SQL keywords */ + +#include "kwlist_d.h" -#endif /* FRONTEND */ +/* Keyword categories for SQL keywords */ -#include "gram.h" +#define PG_KEYWORD(kwname, value, category) category, -const ScanKeyword ScanKeywords[] = { +const uint8 ScanKeywordCategories[SCANKEYWORDS_NUM_KEYWORDS] = { #include "kwlist.h" }; -const int NumScanKeywords = lengthof(ScanKeywords); - -/* - * ScanKeywordLookup - see if a given word is a keyword - * - * Returns a pointer to the ScanKeyword table entry, or NULL if no match. - * - * The match is done case-insensitively. Note that we deliberately use a - * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z', - * even if we are in a locale where tolower() would produce more or different - * translations. This is to conform to the SQL99 spec, which says that - * keywords are to be matched in this way even though non-keyword identifiers - * receive a different case-normalization mapping. - */ -const ScanKeyword * -ScanKeywordLookup(const char *text, - const ScanKeyword *keywords, - int num_keywords) -{ - int len, - i; - char word[NAMEDATALEN]; - const ScanKeyword *low; - const ScanKeyword *high; - - len = strlen(text); - /* We assume all keywords are shorter than NAMEDATALEN. */ - if (len >= NAMEDATALEN) - return NULL; - - /* - * Apply an ASCII-only downcasing. We must not use tolower() since it may - * produce the wrong translation in some locales (eg, Turkish). - */ - for (i = 0; i < len; i++) - { - char ch = text[i]; - - if (ch >= 'A' && ch <= 'Z') - ch += 'a' - 'A'; - word[i] = ch; - } - word[len] = '\0'; - - /* - * Now do a binary search using plain strcmp() comparison. - */ - low = keywords; - high = keywords + (num_keywords - 1); - while (low <= high) - { - const ScanKeyword *middle; - int difference; - - middle = low + (high - low) / 2; - difference = strcmp(middle->name, word); - if (difference == 0) - return middle; - else if (difference < 0) - low = middle + 1; - else - high = middle - 1; - } - - return NULL; -} +#undef PG_KEYWORD diff --git a/src/parser/kwlookup.c b/src/parser/kwlookup.c index e69de29..b017b22 100644 --- a/src/parser/kwlookup.c +++ b/src/parser/kwlookup.c @@ -0,0 +1,86 @@ +/*------------------------------------------------------------------------- + * + * kwlookup.c + * Key word lookup for PostgreSQL + * + * + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/common/kwlookup.c + * + *------------------------------------------------------------------------- + */ + +#include +#include "kwlookup.h" + + +/* + * ScanKeywordLookup - see if a given word is a keyword + * + * The list of keywords to be matched against is passed as a ScanKeywordList. + * + * Returns the keyword number (0..N-1) of the keyword, or -1 if no match. + * Callers typically use the keyword number to index into information + * arrays, but that is no concern of this code. + * + * The match is done case-insensitively. Note that we deliberately use a + * dumbed-down case conversion that will only translate 'A'-'Z' into 'a'-'z', + * even if we are in a locale where tolower() would produce more or different + * translations. This is to conform to the SQL99 spec, which says that + * keywords are to be matched in this way even though non-keyword identifiers + * receive a different case-normalization mapping. + */ +int +ScanKeywordLookup(const char *str, + const ScanKeywordList *keywords) +{ + size_t len; + int h; + const char *kw; + + /* + * Reject immediately if too long to be any keyword. This saves useless + * hashing and downcasing work on long strings. + */ + len = strlen(str); + if (len > keywords->max_kw_len) + return -1; + + /* + * Compute the hash function. We assume it was generated to produce + * case-insensitive results. Since it's a perfect hash, we need only + * match to the specific keyword it identifies. + */ + h = keywords->hash(str, len); + + /* An out-of-range result implies no match */ + if (h < 0 || h >= keywords->num_keywords) + return -1; + + /* + * Compare character-by-character to see if we have a match, applying an + * ASCII-only downcasing to the input characters. We must not use + * tolower() since it may produce the wrong translation in some locales + * (eg, Turkish). + */ + kw = GetScanKeyword(h, keywords); + while (*str != '\0') + { + char ch = *str++; + + if (ch >= 'A' && ch <= 'Z') + ch += 'a' - 'A'; + if (ch != *kw++) + return -1; + } + if (*kw != '\0') + return -1; + + /* Success! */ + return h; +} diff --git a/src/parser/list.c b/src/parser/list.c index 9c1e71c..b19544d 100644 --- a/src/parser/list.c +++ b/src/parser/list.c @@ -4,8 +4,8 @@ * implementation for PostgreSQL generic linked list package * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -1026,8 +1026,11 @@ list_append_unique_oid(List *list, Oid datum) * via equal(). * * This is almost the same functionality as list_union(), but list1 is - * modified in-place rather than being copied. Note also that list2's cells - * are not inserted in list1, so the analogy to list_concat() isn't perfect. + * modified in-place rather than being copied. However, callers of this + * function may have strict ordering expectations -- i.e. that the relative + * order of those list2 elements that are not duplicates is preserved. Note + * also that list2's cells are not inserted in list1, so the analogy to + * list_concat() isn't perfect. */ List * list_concat_unique(List *list1, List *list2) diff --git a/src/parser/makefuncs.c b/src/parser/makefuncs.c index e73ad05..55dbb17 100644 --- a/src/parser/makefuncs.c +++ b/src/parser/makefuncs.c @@ -4,8 +4,8 @@ * creator functions for primitive nodes. The functions here are for * the most frequently created nodes. * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -494,7 +494,6 @@ makeColumnDef(const char *colname, Oid typeOid, int32 typmod, Oid collOid) n->is_local = true; n->is_not_null = false; n->is_from_type = false; - n->is_from_parent = false; n->storage = 0; n->raw_default = NULL; n->cooked_default = NULL; diff --git a/src/parser/nodes.c b/src/parser/nodes.c index c682d0f..81b1705 100644 --- a/src/parser/nodes.c +++ b/src/parser/nodes.c @@ -4,8 +4,8 @@ * support code for nodes (now that we have removed the home-brew * inheritance system, our support code for nodes is much simpler) * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/parser/outfuncs.c b/src/parser/outfuncs.c index 73b6d07..4e26269 100644 --- a/src/parser/outfuncs.c +++ b/src/parser/outfuncs.c @@ -3,8 +3,8 @@ * outfuncs.c * Output functions for Postgres tree nodes. * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@ -47,7 +47,7 @@ static void _outConst(String * str, Const *node); static void _outParam(String * str, Param *node); static void _outAggref(String * str, Aggref *node); static void _outGroupingFunc(String * str, GroupingFunc *node); -static void _outArrayRef(String * str, ArrayRef *node); +static void _outSubscriptingRef(String * str, SubscriptingRef *node); static void _outFuncExpr(String * str, FuncExpr *node); static void _outNamedArgExpr(String * str, NamedArgExpr *node); static void _outOpExpr(String * str, OpExpr *node); @@ -401,8 +401,9 @@ _outGroupingFunc(String * str, GroupingFunc *node) } static void -_outArrayRef(String * str, ArrayRef *node) +_outSubscriptingRef(String * str, SubscriptingRef *node) { + } static void @@ -1736,6 +1737,15 @@ _outAExpr(String * str, A_Expr *node) } } +/* + * Node types found in raw parse trees (supported for debug purposes) + */ + +static void +_outRawStmt(String * str, const RawStmt *node) +{ +} + static void _outValue(String * str, Value *value) { @@ -2500,23 +2510,33 @@ _outTruncateStmt(String * str, TruncateStmt *node) static void _outVacuumStmt(String * str, VacuumStmt *node) { - if (node->options & VACOPT_VACUUM) + + VacuumParams params; + params.options = node->is_vacuumcmd ? VACOPT_VACUUM : VACOPT_ANALYZE; + + if (params.options & VACOPT_VACUUM) string_append_char(str, "VACUUM "); - else if (node->options & VACOPT_ANALYZE) + else string_append_char(str, "ANALYZE "); - if (node->options & VACOPT_FULL) + if (params.options & VACOPT_FULL) string_append_char(str, "FULL "); - if (node->options & VACOPT_FREEZE) + if (params.options & VACOPT_FREEZE) string_append_char(str, "FREEZE "); - if (node->options & VACOPT_VERBOSE) + if (params.options & VACOPT_VERBOSE) string_append_char(str, "VERBOSE "); - if (node->options & VACOPT_VACUUM && node->options & VACOPT_ANALYZE) + if (params.options & VACOPT_VACUUM && params.options & VACOPT_ANALYZE) string_append_char(str, "ANALYZE "); + if (params.options & VACOPT_DISABLE_PAGE_SKIPPING) + string_append_char(str, "DISABLE_PAGE_SKIPPING "); + + if (params.options & VACOPT_SKIP_LOCKED) + string_append_char(str, "SKIP_LOCKED "); + ListCell *lc; foreach(lc, node->rels) { @@ -2776,6 +2796,12 @@ _outCopyStmt(String * str, CopyStmt *node) string_append_char(str, ")"); } } + + if (node->whereClause) + { + string_append_char(str, " WHERE "); + _outNode(str, node->whereClause); + } } static void @@ -5600,6 +5626,11 @@ _outPartitionRangeDatum(String * str, PartitionRangeDatum *node) void _outNode(String * str, void *obj) { + /* Guard against stack overflow due to overly complex expressions */ + /* + * check_stack_depth(); + */ + if (obj == NULL) return; else if (IsA(obj, List) ||IsA(obj, IntList) || IsA(obj, OidList)) @@ -5645,8 +5676,8 @@ _outNode(String * str, void *obj) /* * case T_WindowFunc: _outWindowFunc(str, obj); break; */ - case T_ArrayRef: - _outArrayRef(str, obj); + case T_SubscriptingRef: + _outSubscriptingRef(str, obj); break; case T_FuncExpr: _outFuncExpr(str, obj); @@ -5861,6 +5892,9 @@ _outNode(String * str, void *obj) case T_ParamRef: _outParamRef(str, obj); break; + case T_RawStmt: + _outRawStmt(str, obj); + break; case T_A_Const: _outAConst(str, obj); break; diff --git a/src/parser/parser.c b/src/parser/parser.c index 26735e3..3329919 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -10,8 +10,8 @@ * analyze.c and related files. * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -26,6 +26,7 @@ #include "gramparse.h" /* required before parser/gram.h! */ #include "gram.h" #include "parser.h" +#include "kwlist_d.h" #include "pg_wchar.h" #include "utils/elog.h" @@ -58,7 +59,7 @@ raw_parser(const char *str, bool *error) /* initialize the flex scanner */ yyscanner = scanner_init(str, &yyextra.core_yy_extra, - ScanKeywords, NumScanKeywords); + &ScanKeywords, ScanKeywordTokens); /* base_yylex() only needs this much initialization */ yyextra.have_lookahead = false; diff --git a/src/parser/scan.l b/src/parser/scan.l index 93097ba..8d3342e 100644 --- a/src/parser/scan.l +++ b/src/parser/scan.l @@ -6,7 +6,8 @@ * * NOTE NOTE NOTE: * - * The rules in this file must be kept in sync with src/fe_utils/psqlscan.l! + * The rules in this file must be kept in sync with src/fe_utils/psqlscan.l + * and src/interfaces/ecpg/preproc/pgc.l! * * The rules are designed so that the scanner never has to backtrack, * in the sense that there is always a rule that can match the input @@ -21,8 +22,8 @@ * Postgres 9.2, this check is made automatically by the Makefile.) * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION @@ -39,6 +40,7 @@ #include "scanner.h" #include "gramparse.h" #include "scansup.h" +#include "kwlookup.h" #include "pg_wchar.h" #include "gram.h" @@ -71,6 +73,21 @@ bool escape_string_warning = true; bool standard_conforming_strings = true; /* + * Constant data exported from this file. This array maps from the + * zero-based keyword numbers returned by ScanKeywordLookup to the + * Bison token numbers needed by gram.y. This is exported because + * callers need to pass it to scanner_init, if they are using the + * standard keyword list ScanKeywords. + */ +#define PG_KEYWORD(kwname, value, category) value, + +const uint16 ScanKeywordTokens[] = { +#include "kwlist.h" +}; + +#undef PG_KEYWORD + +/* * Set the type of YYSTYPE. */ #define YYSTYPE core_YYSTYPE @@ -173,8 +190,8 @@ extern void core_yyset_column(int column_no, yyscan_t yyscanner); %x xc %x xd %x xh -%x xe %x xq +%x xe %x xdolq %x xui %x xuiend @@ -197,7 +214,7 @@ extern void core_yyset_column(int column_no, yyscan_t yyscanner); * XXX perhaps \f (formfeed) should be treated as a newline as well? * * XXX if you change the set of whitespace characters, fix scanner_isspace() - * to agree, and see also the plpgsql lexer. + * to agree. */ space [ \t\n\r\f] @@ -344,6 +361,15 @@ identifier {ident_start}{ident_cont}* typecast "::" dot_dot \.\. colon_equals ":=" + +/* + * These operator-like tokens (unlike the above ones) also match the {operator} + * rule, which means that they might be overridden by a longer match if they + * are followed by a comment start or a + or - character. Accordingly, if you + * add to this list, you must also add corresponding code to the {operator} + * block to return the correct token in such cases. (This is not needed in + * psqlscan.l since the token value is ignored there.) + */ equals_greater "=>" less_equals "<=" greater_equals ">=" @@ -413,32 +439,36 @@ other . yyless(2); } -{xcstart} { +{ +{xcstart} { (yyextra->xcdepth)++; /* Put back any characters past slash-star; see above */ yyless(2); } -{xcstop} { +{xcstop} { if (yyextra->xcdepth <= 0) BEGIN(INITIAL); else (yyextra->xcdepth)--; } -{xcinside} { +{xcinside} { /* ignore */ } -{op_chars} { +{op_chars} { /* ignore */ } -\*+ { +\*+ { /* ignore */ } -<> { yyerror("unterminated /* comment"); } +<> { + yyerror("unterminated /* comment"); + } +} /* */ {xbstart} { /* Binary bit type. @@ -495,18 +525,18 @@ other . * We will pass this along as a normal character string, * but preceded with an internally-generated "NCHAR". */ - const ScanKeyword *keyword; + int kwnum; SET_YYLLOC(); yyless(1); /* eat only 'n' this time */ - keyword = ScanKeywordLookup("nchar", - yyextra->keywords, - yyextra->num_keywords); - if (keyword != NULL) + kwnum = ScanKeywordLookup("nchar", + yyextra->keywordlist); + if (kwnum >= 0) { - yylval->keyword = keyword->name; - return keyword->value; + yylval->keyword = GetScanKeyword(kwnum, + yyextra->keywordlist); + return yyextra->keyword_tokens[kwnum]; } else { @@ -892,20 +922,33 @@ other . * to forbid operator names like '?-' that could not be * sequences of SQL operators. */ - while (nchars > 1 && - (yytext[nchars - 1] == '+' || - yytext[nchars - 1] == '-')) + if (nchars > 1 && + (yytext[nchars - 1] == '+' || + yytext[nchars - 1] == '-')) { int ic; for (ic = nchars - 2; ic >= 0; ic--) { - if (strchr("~!@#^&|`?%", yytext[ic])) + char c = yytext[ic]; + if (c == '~' || c == '!' || c == '@' || + c == '#' || c == '^' || c == '&' || + c == '|' || c == '`' || c == '?' || + c == '%') break; } - if (ic >= 0) - break; /* found a char that makes it OK */ - nchars--; /* else remove the +/-, and check again */ + if (ic < 0) + { + /* + * didn't find a qualifying character, so remove + * all trailing [+-] + */ + do { + nchars--; + } while (nchars > 1 && + (yytext[nchars - 1] == '+' || + yytext[nchars - 1] == '-')); + } } SET_YYLLOC(); @@ -923,6 +966,25 @@ other . if (nchars == 1 && strchr(",()[].;:+-*/%^<>=", yytext[0])) return yytext[0]; + /* + * Likewise, if what we have left is two chars, and + * those match the tokens ">=", "<=", "=>", "<>" or + * "!=", then we must return the appropriate token + * rather than the generic Op. + */ + if (nchars == 2) + { + if (yytext[0] == '=' && yytext[1] == '>') + return EQUALS_GREATER; + if (yytext[0] == '>' && yytext[1] == '=') + return GREATER_EQUALS; + if (yytext[0] == '<' && yytext[1] == '=') + return LESS_EQUALS; + if (yytext[0] == '<' && yytext[1] == '>') + return NOT_EQUALS; + if (yytext[0] == '!' && yytext[1] == '=') + return NOT_EQUALS; + } } /* @@ -966,39 +1028,35 @@ other . } {realfail1} { /* - * throw back the [Ee], and treat as {decimal}. Note - * that it is possible the input is actually {integer}, - * but since this case will almost certainly lead to a - * syntax error anyway, we don't bother to distinguish. + * throw back the [Ee], and figure out whether what + * remains is an {integer} or {decimal}. */ yyless(yyleng - 1); SET_YYLLOC(); - yylval->str = pstrdup(yytext); - return FCONST; + return process_integer_literal(yytext, yylval); } {realfail2} { /* throw back the [Ee][+-], and proceed as above */ yyless(yyleng - 2); SET_YYLLOC(); - yylval->str = pstrdup(yytext); - return FCONST; + return process_integer_literal(yytext, yylval); } {identifier} { - const ScanKeyword *keyword; + int kwnum; char *ident; SET_YYLLOC(); /* Is it a keyword? */ - keyword = ScanKeywordLookup(yytext, - yyextra->keywords, - yyextra->num_keywords); - if (keyword != NULL) + kwnum = ScanKeywordLookup(yytext, + yyextra->keywordlist); + if (kwnum >= 0) { - yylval->keyword = keyword->name; - return keyword->value; + yylval->keyword = GetScanKeyword(kwnum, + yyextra->keywordlist); + return yyextra->keyword_tokens[kwnum]; } /* @@ -1110,8 +1168,8 @@ scanner_yyerror(const char *message, core_yyscan_t yyscanner) core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, - const ScanKeyword *keywords, - int num_keywords) + const ScanKeywordList *keywordlist, + const uint16 *keyword_tokens) { Size slen = strlen(str); yyscan_t scanner; @@ -1121,8 +1179,8 @@ scanner_init(const char *str, core_yyset_extra(yyext, scanner); - yyext->keywords = keywords; - yyext->num_keywords = num_keywords; + yyext->keywordlist = keywordlist; + yyext->keyword_tokens = keyword_tokens; yyext->backslash_quote = backslash_quote; yyext->escape_string_warning = escape_string_warning; @@ -1219,6 +1277,10 @@ litbufdup(core_yyscan_t yyscanner) return new; } +/* + * Process {integer}. Note this will also do the right thing with {decimal}, + * ie digits and a decimal point. + */ static int process_integer_literal(const char *token, YYSTYPE *lval) { @@ -1237,7 +1299,7 @@ process_integer_literal(const char *token, YYSTYPE *lval) #endif ) { - /* integer too large, treat it as a float */ + /* integer too large (or contains decimal pt), treat it as a float */ lval->str = pstrdup(token); return FCONST; } diff --git a/src/parser/scansup.c b/src/parser/scansup.c index 16c4faf..fccc255 100644 --- a/src/parser/scansup.c +++ b/src/parser/scansup.c @@ -4,8 +4,8 @@ * support routines for the lex/flex scanner, used by both the normal * backend as well as the bootstrap backend * - * Portions Copyright (c) 1996-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * diff --git a/src/parser/snprintf.c b/src/parser/snprintf.c index e73048f..7cf941b 100644 --- a/src/parser/snprintf.c +++ b/src/parser/snprintf.c @@ -1,8 +1,9 @@ /* - * Copyright (c) 2003-2015, PgPool Global Development Group + * Copyright (c) 2003-2019, PgPool Global Development Group * Copyright (c) 1983, 1995, 1996 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -35,22 +36,6 @@ #include "c.h" #endif -#include -#ifdef _MSC_VER -#include /* for _isnan */ -#endif -#include -#include -#ifndef WIN32 -#include -#endif -#include - - -#ifndef NL_ARGMAX -#define NL_ARGMAX 16 -#endif - #include #include #include @@ -62,6 +47,14 @@ #include "stringinfo.h" #include "utils/palloc.h" +/* + * We used to use the platform's NL_ARGMAX here, but that's a bad idea, + * first because the point of this module is to remove platform dependencies + * not perpetuate them, and second because some platforms use ridiculously + * large values, leading to excessive stack consumption in dopr(). + */ +#define PG_NL_ARGMAX 31 + /* --------------------------------------------------------------------- */ /* c.h */ /* --------------------------------------------------------------------- */ @@ -112,8 +105,8 @@ * SNPRINTF, VSNPRINTF and friends * * These versions have been grabbed off the net. They have been - * cleaned up to compile properly and support for most of the Single Unix - * Specification has been added. Remaining unimplemented features are: + * cleaned up to compile properly and support for most of the C99 + * specification has been added. Remaining unimplemented features are: * * 1. No locale support: the radix character is always '.' and the ' * (single quote) format flag is ignored. @@ -126,26 +119,33 @@ * * 5. Space and '#' flags are not implemented. * + * In addition, we support some extensions over C99: + * + * 1. Argument order control through "%n$" and "*n$", as required by POSIX. + * + * 2. "%m" expands to the value of strerror(errno), where errno is the + * value that variable had at the start of the call. This is a glibc + * extension, but a very useful one. * - * The result values of these functions are not the same across different - * platforms. This implementation is compatible with the Single Unix Spec: * - * 1. -1 is returned only if processing is abandoned due to an invalid - * parameter, such as incorrect format string. (Although not required by - * the spec, this happens only when no characters have yet been transmitted - * to the destination.) + * Historically the result values of sprintf/snprintf varied across platforms. + * This implementation now follows the C99 standard: * - * 2. For snprintf and sprintf, 0 is returned if str == NULL or count == 0; - * no data has been stored. + * 1. -1 is returned if an error is detected in the format string, or if + * a write to the target stream fails (as reported by fwrite). Note that + * overrunning snprintf's target buffer is *not* an error. * - * 3. Otherwise, the number of bytes actually transmitted to the destination - * is returned (excluding the trailing '\0' for snprintf and sprintf). + * 2. For successful writes to streams, the actual number of bytes written + * to the stream is returned. * - * For snprintf with nonzero count, the result cannot be more than count-1 - * (a trailing '\0' is always stored); it is not possible to distinguish - * buffer overrun from exact fit. This is unlike some implementations that - * return the number of bytes that would have been needed for the complete - * result string. + * 3. For successful sprintf/snprintf, the number of bytes that would have + * been written to an infinite-size buffer (excluding the trailing '\0') + * is returned. snprintf will truncate its output to fit in the buffer + * (ensuring a trailing '\0' unless count == 0), but this is not reflected + * in the function result. + * + * snprintf buffer overrun can be detected by checking for function result + * greater than or equal to the supplied count. */ /************************************************************** @@ -159,20 +159,34 @@ /* Prevent recursion */ #undef vsnprintf #undef snprintf +#undef vsprintf #undef sprintf #undef vfprintf #undef fprintf +#undef vprintf #undef printf -/* Info about where the formatted output is going */ +/* + * Info about where the formatted output is going. + * + * dopr and subroutines will not write at/past bufend, but snprintf + * reserves one byte, ensuring it may place the trailing '\0' there. + * + * In snprintf, we use nchars to count the number of bytes dropped on the + * floor due to buffer overrun. The correct result of snprintf is thus + * (bufptr - bufstart) + nchars. (This isn't as inconsistent as it might + * seem: nchars is the number of emitted bytes that are not in the buffer now, + * either because we sent them to the stream or because we couldn't fit them + * into the buffer to begin with.) + */ typedef struct { char *bufptr; /* next buffer output position */ char *bufstart; /* first buffer element */ - char *bufend; /* last buffer element, or NULL */ + char *bufend; /* last+1 buffer element, or NULL */ /* bufend == NULL is for sprintf, where we assume buf is big enough */ FILE *stream; /* eventual output destination, or NULL */ - int nchars; /* # chars already sent to stream */ + int nchars; /* # chars sent to stream, or dropped */ bool failed; /* call is a failure; errno is set */ } PrintfTarget; @@ -196,7 +210,7 @@ typedef union { int i; long l; - int64 ll; + long long ll; double d; char *cptr; } PrintfArgValue; @@ -206,21 +220,39 @@ static void flushbuffer(PrintfTarget *target); static void dopr(PrintfTarget *target, const char *format, va_list args); +/* + * Externally visible entry points. + * + * All of these are just wrappers around dopr(). Note it's essential that + * they not change the value of "errno" before reaching dopr(). + */ + int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { PrintfTarget target; + char onebyte[1]; - if (str == NULL || count == 0) - return 0; + /* + * C99 allows the case str == NULL when count == 0. Rather than + * special-casing this situation further down, we substitute a one-byte + * local buffer. Callers cannot tell, since the function result doesn't + * depend on count. + */ + if (count == 0) + { + str = onebyte; + count = 1; + } target.bufstart = target.bufptr = str; target.bufend = str + count - 1; target.stream = NULL; - /* target.nchars is unused in this case */ + target.nchars = 0; target.failed = false; dopr(&target, fmt, args); *(target.bufptr) = '\0'; - return target.failed ? -1 : (target.bufptr - target.bufstart); + return target.failed ? -1 : (target.bufptr - target.bufstart + + target.nchars); } #if 0 @@ -236,21 +268,20 @@ pg_snprintf(char *str, size_t count, const char *fmt,...) return len; } -static int +int pg_vsprintf(char *str, const char *fmt, va_list args) { PrintfTarget target; - if (str == NULL) - return 0; target.bufstart = target.bufptr = str; target.bufend = NULL; target.stream = NULL; - /* target.nchars is unused in this case */ + target.nchars = 0; /* not really used in this case */ target.failed = false; dopr(&target, fmt, args); *(target.bufptr) = '\0'; - return target.failed ? -1 : (target.bufptr - target.bufstart); + return target.failed ? -1 : (target.bufptr - target.bufstart + + target.nchars); } int @@ -277,7 +308,7 @@ pg_vfprintf(FILE *stream, const char *fmt, va_list args) return -1; } target.bufstart = target.bufptr = buffer; - target.bufend = buffer + sizeof(buffer) - 1; + target.bufend = buffer + sizeof(buffer); /* use the whole buffer */ target.stream = stream; target.nchars = 0; target.failed = false; @@ -300,6 +331,12 @@ pg_fprintf(FILE *stream, const char *fmt,...) } int +pg_vprintf(const char *fmt, va_list args) +{ + return pg_vfprintf(stdout, fmt, args); +} + +int pg_printf(const char *fmt,...) { int len; @@ -321,6 +358,10 @@ flushbuffer(PrintfTarget *target) { size_t nc = target->bufptr - target->bufstart; + /* + * Don't write anything if we already failed; this is to ensure we + * preserve the original failure's errno. + */ if (!target->failed && nc > 0) { size_t written; @@ -334,35 +375,69 @@ flushbuffer(PrintfTarget *target) } -static void fmtstr(char *value, int leftjust, int minlen, int maxwidth, - int pointflag, PrintfTarget *target); +static bool find_arguments(const char *format, va_list args, + PrintfArgValue *argvalues); +static void fmtstr(const char *value, int leftjust, int minlen, int maxwidth, + int pointflag, PrintfTarget *target); static void fmtptr(void *value, PrintfTarget *target); -static void fmtint(int64 value, char type, int forcesign, - int leftjust, int minlen, int zpad, int precision, int pointflag, - PrintfTarget *target); +static void fmtint(long long value, char type, int forcesign, + int leftjust, int minlen, int zpad, int precision, int pointflag, + PrintfTarget *target); static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target); static void fmtfloat(double value, char type, int forcesign, - int leftjust, int minlen, int zpad, int precision, int pointflag, - PrintfTarget *target); + int leftjust, int minlen, int zpad, int precision, int pointflag, + PrintfTarget *target); static void dostr(const char *str, int slen, PrintfTarget *target); static void dopr_outch(int c, PrintfTarget *target); +static void dopr_outchmulti(int c, int slen, PrintfTarget *target); static int adjust_sign(int is_negative, int forcesign, int *signvalue); -static void adjust_padlen(int minlen, int vallen, int leftjust, int *padlen); -static void leading_pad(int zpad, int *signvalue, int *padlen, - PrintfTarget *target); -static void trailing_pad(int *padlen, PrintfTarget *target); +static int compute_padlen(int minlen, int vallen, int leftjust); +static void leading_pad(int zpad, int signvalue, int *padlen, + PrintfTarget *target); +static void trailing_pad(int padlen, PrintfTarget *target); + +/* + * If strchrnul exists (it's a glibc-ism), it's a good bit faster than the + * equivalent manual loop. If it doesn't exist, provide a replacement. + * + * Note: glibc declares this as returning "char *", but that would require + * casting away const internally, so we don't follow that detail. + */ +#ifndef HAVE_STRCHRNUL + +static inline const char * +strchrnul(const char *s, int c) +{ + while (*s != '\0' && *s != c) + s++; + return s; +} + +#else + +/* + * glibc's declares strchrnul only if _GNU_SOURCE is defined. + * While we typically use that on glibc platforms, configure will set + * HAVE_STRCHRNUL whether it's used or not. Fill in the missing declaration + * so that this file will compile cleanly with or without _GNU_SOURCE. + */ +#ifndef _GNU_SOURCE +extern char *strchrnul(const char *s, int c); +#endif + +#endif /* HAVE_STRCHRNUL */ /* - * dopr(): poor man's version of doprintf + * dopr(): the guts of *printf for all cases. */ static void dopr(PrintfTarget *target, const char *format, va_list args) { - const char *format_start = format; + int save_errno = errno; + const char *first_pct = NULL; int ch; bool have_dollar; - bool have_non_dollar; bool have_star; bool afterstar; int accum; @@ -374,233 +449,68 @@ dopr(PrintfTarget *target, const char *format, va_list args) int precision; int zpad; int forcesign; - int last_dollar; int fmtpos; int cvalue; - int64 numvalue; + long long numvalue; double fvalue; char *strvalue; - int i; - PrintfArgType argtypes[NL_ARGMAX + 1]; - PrintfArgValue argvalues[NL_ARGMAX + 1]; + PrintfArgValue argvalues[PG_NL_ARGMAX + 1]; /* - * Parse the format string to determine whether there are %n$ format - * specs, and identify the types and order of the format parameters. + * Initially, we suppose the format string does not use %n$. The first + * time we come to a conversion spec that has that, we'll call + * find_arguments() to check for consistent use of %n$ and fill the + * argvalues array with the argument values in the correct order. */ - have_dollar = have_non_dollar = false; - last_dollar = 0; - MemSet(argtypes, 0, sizeof(argtypes)); + have_dollar = false; - while ((ch = *format++) != '\0') + while (*format != '\0') { - if (ch != '%') - continue; - longflag = longlongflag = pointflag = 0; - fmtpos = accum = 0; - afterstar = false; -nextch1: - ch = *format++; - if (ch == '\0') - break; /* illegal, but we don't complain */ - switch (ch) + /* Locate next conversion specifier */ + if (*format != '%') { - case '-': - case '+': - goto nextch1; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - accum = accum * 10 + (ch - '0'); - goto nextch1; - case '.': - pointflag = 1; - accum = 0; - goto nextch1; - case '*': - if (afterstar) - have_non_dollar = true; /* multiple stars */ - afterstar = true; - accum = 0; - goto nextch1; - case '$': - have_dollar = true; - if (accum <= 0 || accum > NL_ARGMAX) - goto bad_format; - if (afterstar) - { - if (argtypes[accum] && - argtypes[accum] != ATYPE_INT) - goto bad_format; - argtypes[accum] = ATYPE_INT; - last_dollar = Max(last_dollar, accum); - afterstar = false; - } - else - fmtpos = accum; - accum = 0; - goto nextch1; - case 'l': - if (longflag) - longlongflag = 1; - else - longflag = 1; - goto nextch1; - case 'z': -#if SIZEOF_SIZE_T == 8 -#ifdef HAVE_LONG_INT_64 - longflag = 1; -#elif defined(HAVE_LONG_LONG_INT_64) - longlongflag = 1; -#else -#error "Don't know how to print 64bit integers" -#endif -#else - /* assume size_t is same size as int */ -#endif - goto nextch1; - case 'h': - case '\'': - /* ignore these */ - goto nextch1; - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - if (fmtpos) - { - PrintfArgType atype; + /* Scan to next '%' or end of string */ + const char *next_pct = strchrnul(format + 1, '%'); - if (longlongflag) - atype = ATYPE_LONGLONG; - else if (longflag) - atype = ATYPE_LONG; - else - atype = ATYPE_INT; - if (argtypes[fmtpos] && - argtypes[fmtpos] != atype) - goto bad_format; - argtypes[fmtpos] = atype; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; - break; - case 'c': - if (fmtpos) - { - if (argtypes[fmtpos] && - argtypes[fmtpos] != ATYPE_INT) - goto bad_format; - argtypes[fmtpos] = ATYPE_INT; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; - break; - case 's': - case 'p': - if (fmtpos) - { - if (argtypes[fmtpos] && - argtypes[fmtpos] != ATYPE_CHARPTR) - goto bad_format; - argtypes[fmtpos] = ATYPE_CHARPTR; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (fmtpos) - { - if (argtypes[fmtpos] && - argtypes[fmtpos] != ATYPE_DOUBLE) - goto bad_format; - argtypes[fmtpos] = ATYPE_DOUBLE; - last_dollar = Max(last_dollar, fmtpos); - } - else - have_non_dollar = true; + /* Dump literal data we just scanned over */ + dostr(format, next_pct - format, target); + if (target->failed) break; - case '%': + + if (*next_pct == '\0') break; + format = next_pct; } /* - * If we finish the spec with afterstar still set, there's a - * non-dollar star in there. + * Remember start of first conversion spec; if we find %n$, then it's + * sufficient for find_arguments() to start here, without rescanning + * earlier literal text. */ - if (afterstar) - have_non_dollar = true; - } + if (first_pct == NULL) + first_pct = format; - /* Per spec, you use either all dollar or all not. */ - if (have_dollar && have_non_dollar) - goto bad_format; + /* Process conversion spec starting at *format */ + format++; - /* - * In dollar mode, collect the arguments in physical order. - */ - for (i = 1; i <= last_dollar; i++) - { - switch (argtypes[i]) + /* Fast path for conversion spec that is exactly %s */ + if (*format == 's') { - case ATYPE_NONE: - goto bad_format; - case ATYPE_INT: - argvalues[i].i = va_arg(args, int); - break; - case ATYPE_LONG: - argvalues[i].l = va_arg(args, long); - break; - case ATYPE_LONGLONG: - argvalues[i].ll = va_arg(args, int64); + format++; + strvalue = va_arg(args, char *); + Assert(strvalue != NULL); + dostr(strvalue, strlen(strvalue), target); + if (target->failed) break; - case ATYPE_DOUBLE: - argvalues[i].d = va_arg(args, double); - break; - case ATYPE_CHARPTR: - argvalues[i].cptr = va_arg(args, char *); - break; - } - } - - /* - * At last we can parse the format for real. - */ - format = format_start; - while ((ch = *format++) != '\0') - { - if (target->failed) - break; - - if (ch != '%') - { - dopr_outch(ch, target); continue; } + fieldwidth = precision = zpad = leftjust = forcesign = 0; longflag = longlongflag = pointflag = 0; fmtpos = accum = 0; have_star = afterstar = false; nextch2: ch = *format++; - if (ch == '\0') - break; /* illegal, but we don't complain */ switch (ch) { case '-': @@ -636,7 +546,11 @@ nextch2: case '*': if (have_dollar) { - /* process value after reading n$ */ + /* + * We'll process value after reading n$. Note it's OK to + * assume have_dollar is set correctly, because in a valid + * format string the initial % must have had n$ if * does. + */ afterstar = true; } else @@ -667,6 +581,14 @@ nextch2: accum = 0; goto nextch2; case '$': + /* First dollar sign? */ + if (!have_dollar) + { + /* Yup, so examine all conversion specs in format */ + if (!find_arguments(first_pct, args, argvalues)) + goto bad_format; + have_dollar = true; + } if (afterstar) { /* fetch and process star value */ @@ -740,7 +662,7 @@ nextch2: else { if (longlongflag) - numvalue = va_arg(args, int64); + numvalue = va_arg(args, long long); else if (longflag) numvalue = va_arg(args, long); else @@ -763,7 +685,7 @@ nextch2: if (have_dollar) { if (longlongflag) - numvalue = (uint64) argvalues[fmtpos].ll; + numvalue = (unsigned long long) argvalues[fmtpos].ll; else if (longflag) numvalue = (unsigned long) argvalues[fmtpos].l; else @@ -772,7 +694,7 @@ nextch2: else { if (longlongflag) - numvalue = (uint64) va_arg(args, int64); + numvalue = (unsigned long long) va_arg(args, long long); else if (longflag) numvalue = (unsigned long) va_arg(args, long); else @@ -841,10 +763,30 @@ nextch2: precision, pointflag, target); break; + case 'm': + { + char errbuf[PG_STRERROR_R_BUFLEN]; + const char *errm = strerror_r(save_errno, + errbuf, sizeof(errbuf)); + + dostr(errm, strlen(errm), target); + } + break; case '%': dopr_outch('%', target); break; + default: + + /* + * Anything else --- in particular, '\0' indicating end of + * format string --- is bogus. + */ + goto bad_format; } + + /* Check for failure after each conversion spec */ + if (target->failed) + break; } return; @@ -854,33 +796,261 @@ bad_format: target->failed = true; } -static void -fmtstr(char *value, int leftjust, int minlen, int maxwidth, - int pointflag, PrintfTarget *target) +/* + * find_arguments(): sort out the arguments for a format spec with %n$ + * + * If format is valid, return true and fill argvalues[i] with the value + * for the conversion spec that has %i$ or *i$. Else return false. + */ +static bool +find_arguments(const char *format, va_list args, + PrintfArgValue *argvalues) { - int padlen, - vallen; /* amount to pad */ + int ch; + bool afterstar; + int accum; + int longlongflag; + int longflag; + int fmtpos; + int i; + int last_dollar; + PrintfArgType argtypes[PG_NL_ARGMAX + 1]; + + /* Initialize to "no dollar arguments known" */ + last_dollar = 0; + MemSet(argtypes, 0, sizeof(argtypes)); /* - * If a maxwidth (precision) is specified, we must not fetch more bytes - * than that. + * This loop must accept the same format strings as the one in dopr(). + * However, we don't need to analyze them to the same level of detail. + * + * Since we're only called if there's a dollar-type spec somewhere, we can + * fail immediately if we find a non-dollar spec. Per the C99 standard, + * all argument references in the format string must be one or the other. */ - if (pointflag) - vallen = strnlen(value, maxwidth); - else - vallen = strlen(value); - - adjust_padlen(minlen, vallen, leftjust, &padlen); - - while (padlen > 0) + while (*format != '\0') { - dopr_outch(' ', target); - --padlen; + /* Locate next conversion specifier */ + if (*format != '%') + { + /* Unlike dopr, we can just quit if there's no more specifiers */ + format = strchr(format + 1, '%'); + if (format == NULL) + break; + } + + /* Process conversion spec starting at *format */ + format++; + longflag = longlongflag = 0; + fmtpos = accum = 0; + afterstar = false; +nextch1: + ch = *format++; + switch (ch) + { + case '-': + case '+': + goto nextch1; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + accum = accum * 10 + (ch - '0'); + goto nextch1; + case '.': + accum = 0; + goto nextch1; + case '*': + if (afterstar) + return false; /* previous star missing dollar */ + afterstar = true; + accum = 0; + goto nextch1; + case '$': + if (accum <= 0 || accum > PG_NL_ARGMAX) + return false; + if (afterstar) + { + if (argtypes[accum] && + argtypes[accum] != ATYPE_INT) + return false; + argtypes[accum] = ATYPE_INT; + last_dollar = Max(last_dollar, accum); + afterstar = false; + } + else + fmtpos = accum; + accum = 0; + goto nextch1; + case 'l': + if (longflag) + longlongflag = 1; + else + longflag = 1; + goto nextch1; + case 'z': +#if SIZEOF_SIZE_T == 8 +#ifdef HAVE_LONG_INT_64 + longflag = 1; +#elif defined(HAVE_LONG_LONG_INT_64) + longlongflag = 1; +#else +#error "Don't know how to print 64bit integers" +#endif +#else + /* assume size_t is same size as int */ +#endif + goto nextch1; + case 'h': + case '\'': + /* ignore these */ + goto nextch1; + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + if (fmtpos) + { + PrintfArgType atype; + + if (longlongflag) + atype = ATYPE_LONGLONG; + else if (longflag) + atype = ATYPE_LONG; + else + atype = ATYPE_INT; + if (argtypes[fmtpos] && + argtypes[fmtpos] != atype) + return false; + argtypes[fmtpos] = atype; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 'c': + if (fmtpos) + { + if (argtypes[fmtpos] && + argtypes[fmtpos] != ATYPE_INT) + return false; + argtypes[fmtpos] = ATYPE_INT; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 's': + case 'p': + if (fmtpos) + { + if (argtypes[fmtpos] && + argtypes[fmtpos] != ATYPE_CHARPTR) + return false; + argtypes[fmtpos] = ATYPE_CHARPTR; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (fmtpos) + { + if (argtypes[fmtpos] && + argtypes[fmtpos] != ATYPE_DOUBLE) + return false; + argtypes[fmtpos] = ATYPE_DOUBLE; + last_dollar = Max(last_dollar, fmtpos); + } + else + return false; /* non-dollar conversion spec */ + break; + case 'm': + case '%': + break; + default: + return false; /* bogus format string */ + } + + /* + * If we finish the spec with afterstar still set, there's a + * non-dollar star in there. + */ + if (afterstar) + return false; /* non-dollar conversion spec */ + } + + /* + * Format appears valid so far, so collect the arguments in physical + * order. (Since we rejected any non-dollar specs that would have + * collected arguments, we know that dopr() hasn't collected any yet.) + */ + for (i = 1; i <= last_dollar; i++) + { + switch (argtypes[i]) + { + case ATYPE_NONE: + return false; + case ATYPE_INT: + argvalues[i].i = va_arg(args, int); + break; + case ATYPE_LONG: + argvalues[i].l = va_arg(args, long); + break; + case ATYPE_LONGLONG: + argvalues[i].ll = va_arg(args, long long); + break; + case ATYPE_DOUBLE: + argvalues[i].d = va_arg(args, double); + break; + case ATYPE_CHARPTR: + argvalues[i].cptr = va_arg(args, char *); + break; + } + } + + return true; +} + +static void +fmtstr(const char *value, int leftjust, int minlen, int maxwidth, + int pointflag, PrintfTarget *target) +{ + int padlen, + vallen; /* amount to pad */ + + /* + * If a maxwidth (precision) is specified, we must not fetch more bytes + * than that. + */ + if (pointflag) + vallen = strnlen(value, maxwidth); + else + vallen = strlen(value); + + padlen = compute_padlen(minlen, vallen, leftjust); + + if (padlen > 0) + { + dopr_outchmulti(' ', padlen, target); + padlen = 0; } dostr(value, vallen, target); - trailing_pad(&padlen, target); + trailing_pad(padlen, target); } static void @@ -898,17 +1068,18 @@ fmtptr(void *value, PrintfTarget *target) } static void -fmtint(int64 value, char type, int forcesign, int leftjust, +fmtint(long long value, char type, int forcesign, int leftjust, int minlen, int zpad, int precision, int pointflag, PrintfTarget *target) { - uint64 base; + unsigned long long base; + unsigned long long uvalue; int dosign; const char *cvt = "0123456789abcdef"; int signvalue = 0; char convert[64]; int vallen = 0; - int padlen = 0; /* amount to pad */ + int padlen; /* amount to pad */ int zeropad; /* extra leading zeroes */ switch (type) @@ -939,9 +1110,19 @@ fmtint(int64 value, char type, int forcesign, int leftjust, return; /* keep compiler quiet */ } + /* disable MSVC warning about applying unary minus to an unsigned value */ +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4146) +#endif /* Handle +/- */ if (dosign && adjust_sign((value < 0), forcesign, &signvalue)) - value = -value; + uvalue = -(unsigned long long) value; + else + uvalue = (unsigned long long) value; +#if _MSC_VER +#pragma warning(pop) +#endif /* * SUS: the result of converting 0 with an explicit precision of 0 is no @@ -952,46 +1133,43 @@ fmtint(int64 value, char type, int forcesign, int leftjust, else { /* make integer string */ - uint64 uvalue = (uint64) value; - do { - convert[vallen++] = cvt[uvalue % base]; + convert[sizeof(convert) - (++vallen)] = cvt[uvalue % base]; uvalue = uvalue / base; } while (uvalue); } zeropad = Max(0, precision - vallen); - adjust_padlen(minlen, vallen + zeropad, leftjust, &padlen); + padlen = compute_padlen(minlen, vallen + zeropad, leftjust); - leading_pad(zpad, &signvalue, &padlen, target); + leading_pad(zpad, signvalue, &padlen, target); - while (zeropad-- > 0) - dopr_outch('0', target); + if (zeropad > 0) + dopr_outchmulti('0', zeropad, target); - while (vallen > 0) - dopr_outch(convert[--vallen], target); + dostr(convert + sizeof(convert) - vallen, vallen, target); - trailing_pad(&padlen, target); + trailing_pad(padlen, target); } static void fmtchar(int value, int leftjust, int minlen, PrintfTarget *target) { - int padlen = 0; /* amount to pad */ + int padlen; /* amount to pad */ - adjust_padlen(minlen, 1, leftjust, &padlen); + padlen = compute_padlen(minlen, 1, leftjust); - while (padlen > 0) + if (padlen > 0) { - dopr_outch(' ', target); - --padlen; + dopr_outchmulti(' ', padlen, target); + padlen = 0; } dopr_outch(value, target); - trailing_pad(&padlen, target); + trailing_pad(padlen, target); } static void @@ -1002,10 +1180,10 @@ fmtfloat(double value, char type, int forcesign, int leftjust, int signvalue = 0; int prec; int vallen; - char fmt[32]; + char fmt[8]; char convert[1024]; int zeropadlen = 0; /* amount to pad with zeroes */ - int padlen = 0; /* amount to pad with spaces */ + int padlen; /* amount to pad with spaces */ /* * We rely on the regular C library's sprintf to do the basic conversion, @@ -1020,34 +1198,82 @@ fmtfloat(double value, char type, int forcesign, int leftjust, * bytes and limit requested precision to 350 digits; this should prevent * buffer overrun even with non-IEEE math. If the original precision * request was more than 350, separately pad with zeroes. + * + * We handle infinities and NaNs specially to ensure platform-independent + * output. */ if (precision < 0) /* cover possible overflow of "accum" */ precision = 0; prec = Min(precision, 350); - if (pointflag) + if (isnan(value)) { - if (sprintf(fmt, "%%.%d%c", prec, type) < 0) - goto fail; - zeropadlen = precision - prec; + strcpy(convert, "NaN"); + vallen = 3; + /* no zero padding, regardless of precision spec */ } - else if (sprintf(fmt, "%%%c", type) < 0) - goto fail; + else + { + /* + * Handle sign (NaNs have no sign, so we don't do this in the case + * above). "value < 0.0" will not be true for IEEE minus zero, so we + * detect that by looking for the case where value equals 0.0 + * according to == but not according to memcmp. + */ + static const double dzero = 0.0; - if (!isnan(value) && adjust_sign((value < 0), forcesign, &signvalue)) - value = -value; + if (adjust_sign((value < 0.0 || + (value == 0.0 && + memcmp(&value, &dzero, sizeof(double)) != 0)), + forcesign, &signvalue)) + value = -value; - vallen = sprintf(convert, fmt, value); - if (vallen < 0) - goto fail; + if (isinf(value)) + { + strcpy(convert, "Infinity"); + vallen = 8; + /* no zero padding, regardless of precision spec */ + } + else if (pointflag) + { + zeropadlen = precision - prec; + fmt[0] = '%'; + fmt[1] = '.'; + fmt[2] = '*'; + fmt[3] = type; + fmt[4] = '\0'; + vallen = sprintf(convert, fmt, prec, value); + } + else + { + fmt[0] = '%'; + fmt[1] = type; + fmt[2] = '\0'; + vallen = sprintf(convert, fmt, value); + } + if (vallen < 0) + goto fail; - /* If it's infinity or NaN, forget about doing any zero-padding */ - if (zeropadlen > 0 && !isdigit((unsigned char) convert[vallen - 1])) - zeropadlen = 0; + /* + * Windows, alone among our supported platforms, likes to emit + * three-digit exponent fields even when two digits would do. Hack + * such results to look like the way everyone else does it. + */ +#ifdef WIN32 + if (vallen >= 6 && + convert[vallen - 5] == 'e' && + convert[vallen - 3] == '0') + { + convert[vallen - 3] = convert[vallen - 2]; + convert[vallen - 2] = convert[vallen - 1]; + vallen--; + } +#endif + } - adjust_padlen(minlen, vallen + zeropadlen, leftjust, &padlen); + padlen = compute_padlen(minlen, vallen + zeropadlen, leftjust); - leading_pad(zpad, &signvalue, &padlen, target); + leading_pad(zpad, signvalue, &padlen, target); if (zeropadlen > 0) { @@ -1058,18 +1284,18 @@ fmtfloat(double value, char type, int forcesign, int leftjust, epos = strrchr(convert, 'E'); if (epos) { - /* pad after exponent */ + /* pad before exponent */ dostr(convert, epos - convert, target); - while (zeropadlen-- > 0) - dopr_outch('0', target); + if (zeropadlen > 0) + dopr_outchmulti('0', zeropadlen, target); dostr(epos, vallen - (epos - convert), target); } else { /* no exponent, pad after the digits */ dostr(convert, vallen, target); - while (zeropadlen-- > 0) - dopr_outch('0', target); + if (zeropadlen > 0) + dopr_outchmulti('0', zeropadlen, target); } } else @@ -1078,16 +1304,124 @@ fmtfloat(double value, char type, int forcesign, int leftjust, dostr(convert, vallen, target); } - trailing_pad(&padlen, target); + trailing_pad(padlen, target); return; fail: target->failed = true; } +/* + * Nonstandard entry point to print a double value efficiently. + * + * This is approximately equivalent to strfromd(), but has an API more + * adapted to what float8out() wants. The behavior is like snprintf() + * with a format of "%.ng", where n is the specified precision. + * However, the target buffer must be nonempty (i.e. count > 0), and + * the precision is silently bounded to a sane range. + */ +int +pg_strfromd(char *str, size_t count, int precision, double value) +{ + PrintfTarget target; + int signvalue = 0; + int vallen; + char fmt[8]; + char convert[64]; + + /* Set up the target like pg_snprintf, but require nonempty buffer */ + Assert(count > 0); + target.bufstart = target.bufptr = str; + target.bufend = str + count - 1; + target.stream = NULL; + target.nchars = 0; + target.failed = false; + + /* + * We bound precision to a reasonable range; the combination of this and + * the knowledge that we're using "g" format without padding allows the + * convert[] buffer to be reasonably small. + */ + if (precision < 1) + precision = 1; + else if (precision > 32) + precision = 32; + + /* + * The rest is just an inlined version of the fmtfloat() logic above, + * simplified using the knowledge that no padding is wanted. + */ + if (isnan(value)) + { + strcpy(convert, "NaN"); + vallen = 3; + } + else + { + static const double dzero = 0.0; + + if (value < 0.0 || + (value == 0.0 && + memcmp(&value, &dzero, sizeof(double)) != 0)) + { + signvalue = '-'; + value = -value; + } + + if (isinf(value)) + { + strcpy(convert, "Infinity"); + vallen = 8; + } + else + { + fmt[0] = '%'; + fmt[1] = '.'; + fmt[2] = '*'; + fmt[3] = 'g'; + fmt[4] = '\0'; + vallen = sprintf(convert, fmt, precision, value); + if (vallen < 0) + { + target.failed = true; + goto fail; + } + +#ifdef WIN32 + if (vallen >= 6 && + convert[vallen - 5] == 'e' && + convert[vallen - 3] == '0') + { + convert[vallen - 3] = convert[vallen - 2]; + convert[vallen - 2] = convert[vallen - 1]; + vallen--; + } +#endif + } + } + + if (signvalue) + dopr_outch(signvalue, &target); + + dostr(convert, vallen, &target); + +fail: + *(target.bufptr) = '\0'; + return target.failed ? -1 : (target.bufptr - target.bufstart + + target.nchars); +} + + static void dostr(const char *str, int slen, PrintfTarget *target) { + /* fast path for common case of slen == 1 */ + if (slen == 1) + { + dopr_outch(*str, target); + return; + } + while (slen > 0) { int avail; @@ -1100,7 +1434,10 @@ dostr(const char *str, int slen, PrintfTarget *target) { /* buffer full, can we dump to stream? */ if (target->stream == NULL) - return; /* no, lose the data */ + { + target->nchars += slen; /* no, lose the data */ + return; + } flushbuffer(target); continue; } @@ -1119,12 +1456,51 @@ dopr_outch(int c, PrintfTarget *target) { /* buffer full, can we dump to stream? */ if (target->stream == NULL) - return; /* no, lose the data */ + { + target->nchars++; /* no, lose the data */ + return; + } flushbuffer(target); } *(target->bufptr++) = c; } +static void +dopr_outchmulti(int c, int slen, PrintfTarget *target) +{ + /* fast path for common case of slen == 1 */ + if (slen == 1) + { + dopr_outch(c, target); + return; + } + + while (slen > 0) + { + int avail; + + if (target->bufend != NULL) + avail = target->bufend - target->bufptr; + else + avail = slen; + if (avail <= 0) + { + /* buffer full, can we dump to stream? */ + if (target->stream == NULL) + { + target->nchars += slen; /* no, lose the data */ + return; + } + flushbuffer(target); + continue; + } + avail = Min(avail, slen); + memset(target->bufptr, c, avail); + target->bufptr += avail; + slen -= avail; + } +} + static int adjust_sign(int is_negative, int forcesign, int *signvalue) @@ -1140,42 +1516,48 @@ adjust_sign(int is_negative, int forcesign, int *signvalue) } -static void -adjust_padlen(int minlen, int vallen, int leftjust, int *padlen) +static int +compute_padlen(int minlen, int vallen, int leftjust) { - *padlen = minlen - vallen; - if (*padlen < 0) - *padlen = 0; + int padlen; + + padlen = minlen - vallen; + if (padlen < 0) + padlen = 0; if (leftjust) - *padlen = -(*padlen); + padlen = -padlen; + return padlen; } static void -leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target) +leading_pad(int zpad, int signvalue, int *padlen, PrintfTarget *target) { + int maxpad; + if (*padlen > 0 && zpad) { - if (*signvalue) + if (signvalue) { - dopr_outch(*signvalue, target); + dopr_outch(signvalue, target); --(*padlen); - *signvalue = 0; + signvalue = 0; } - while (*padlen > 0) + if (*padlen > 0) { - dopr_outch(zpad, target); - --(*padlen); + dopr_outchmulti(zpad, *padlen, target); + *padlen = 0; } } - while (*padlen > (*signvalue != 0)) + maxpad = (signvalue != 0); + if (*padlen > maxpad) { - dopr_outch(' ', target); - --(*padlen); + dopr_outchmulti(' ', *padlen - maxpad, target); + *padlen = maxpad; } - if (*signvalue) + if (signvalue) { - dopr_outch(*signvalue, target); + dopr_outch(signvalue, target); if (*padlen > 0) --(*padlen); else if (*padlen < 0) @@ -1185,11 +1567,8 @@ leading_pad(int zpad, int *signvalue, int *padlen, PrintfTarget *target) static void -trailing_pad(int *padlen, PrintfTarget *target) +trailing_pad(int padlen, PrintfTarget *target) { - while (*padlen < 0) - { - dopr_outch(' ', target); - ++(*padlen); - } + if (padlen < 0) + dopr_outchmulti(' ', -padlen, target); } diff --git a/src/parser/stringinfo.c b/src/parser/stringinfo.c index 646d704..d8b7615 100644 --- a/src/parser/stringinfo.c +++ b/src/parser/stringinfo.c @@ -6,8 +6,8 @@ * It can be used to buffer either ordinary C strings (null-terminated text) * or arbitrary binary data. All storage is allocated with palloc(). * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/backend/lib/stringinfo.c @@ -16,6 +16,7 @@ */ #include #include +#include #include "pool_type.h" #include "stringinfo.h" #include "utils/palloc.h" @@ -78,12 +79,15 @@ resetStringInfo(StringInfo str) void appendStringInfo(StringInfo str, const char *fmt,...) { + int save_errno = errno; + for (;;) { va_list args; int needed; /* Try to format the data. */ + errno = save_errno; va_start(args, fmt); needed = appendStringInfoVA(str, fmt, args); va_end(args); @@ -106,6 +110,9 @@ appendStringInfo(StringInfo str, const char *fmt,...) * pass the return value to enlargeStringInfo() before trying again; see * appendStringInfo for standard usage pattern. * + * Caution: callers must be sure to preserve their entry-time errno + * when looping, in case the fmt contains "%m". + * * XXX This API is ugly, but there seems no alternative given the C spec's * restrictions on what can portably be done with va_list arguments: you have * to redo va_start before you can rescan the argument list, and we can't do diff --git a/src/parser/value.c b/src/parser/value.c index 644fd5d..870842c 100644 --- a/src/parser/value.c +++ b/src/parser/value.c @@ -4,8 +4,8 @@ * implementation of Value nodes * * - * Portions Copyright (c) 2003-2018, PgPool Global Development Group - * Copyright (c) 2003-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 2003-2019, PgPool Global Development Group + * Copyright (c) 2003-2019, PostgreSQL Global Development Group * * * IDENTIFICATION diff --git a/src/parser/wchar.c b/src/parser/wchar.c index e489f60..a5e1ae0 100644 --- a/src/parser/wchar.c +++ b/src/parser/wchar.c @@ -117,16 +117,23 @@ const pg_enc2gettext pg_enc2gettext_tbl[] = /* - * conversion to pg_wchar is done by "table driven." - * to add an encoding support, define mb2wchar_with_len(), mblen(), dsplen() - * for the particular encoding. Note that if the encoding is only - * supported in the client, you don't need to define - * mb2wchar_with_len() function (SJIS is the case). + * Operations on multi-byte encodings are driven by a table of helper + * functions. + * + * To add an encoding support, define mblen(), dsplen() and verifier() for + * the encoding. For server-encodings, also define mb2wchar() and wchar2mb() + * conversion functions. * * These functions generally assume that their input is validly formed. * The "verifier" functions, further down in the file, have to be more - * paranoid. We expect that mblen() does not need to examine more than - * the first byte of the character to discover the correct length. + * paranoid. + * + * We expect that mblen() does not need to examine more than the first byte + * of the character to discover the correct length. GB18030 is an exception + * to that rule, though, as it also looks at second byte. But even that + * behaves in a predictable way, if you only pass the first byte: it will + * treat 4-byte encoded characters as two 2-byte encoded characters, which is + * good enough for all current uses. * * Note: for the display output of psql to work properly, the return values * of the dsplen functions must conform to the Unicode standard. In particular @@ -1175,6 +1182,17 @@ pg_uhc_dsplen(const unsigned char *s) * GB18030 * Added by Bill Huang , */ + +/* + * Unlike all other mblen() functions, this also looks at the second byte of + * the input. However, if you only pass the first byte of a multi-byte + * string, and \0 as the second byte, this still works in a predictable way: + * a 4-byte character will be reported as two 2-byte characters. That's + * enough for all current uses, as a client-only encoding. It works that + * way, because in any valid 4-byte GB18030-encoded character, the third and + * fourth byte look like a 2-byte encoded character, when looked at + * separately. + */ static int pg_gb18030_mblen(const unsigned char *s) { diff --git a/src/protocol/pool_process_query.c b/src/protocol/pool_process_query.c index 28f9c0b..230722e 100644 --- a/src/protocol/pool_process_query.c +++ b/src/protocol/pool_process_query.c @@ -2403,11 +2403,17 @@ need_insert_lock(POOL_CONNECTION_POOL * backend, char *query, Node *node) * Query to know if the target table has SERIAL column or not. * This query is valid through PostgreSQL 7.3 or higher. */ -#define NEXTVALQUERY "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND d.adsrc ~ 'nextval' AND c.relname = '%s'" +#define NEXTVALQUERY (Pgversion(backend)->major >= 73 ? \ + "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND pg_get_expr(d.adbin, d.adrelid) ~ 'nextval' AND c.relname = '%s'" : \ + "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND d.adsrc ~ 'nextval' AND c.relname = '%s'") -#define NEXTVALQUERY2 "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND d.adsrc ~ 'nextval' AND c.oid = pgpool_regclass('%s')" +#define NEXTVALQUERY2 (Pgversion(backend)->major >= 73 ? \ + "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND pg_get_expr(d.adbin, d.adrelid) ~ 'nextval' AND c.oid = pgpool_regclass('%s')" : \ + "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND d.adsrc ~ 'nextval' AND c.oid = pgpool_regclass('%s')") -#define NEXTVALQUERY3 "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND d.adsrc ~ 'nextval' AND c.oid = pg_catalog.to_regclass('%s')" +#define NEXTVALQUERY3 (Pgversion(backend)->major >= 73 ? \ + "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND pg_get_expr(d.adbin, d.adrelid) ~ 'nextval' AND c.oid = pg_catalog.to_regclass('%s')" : \ + "SELECT count(*) FROM pg_catalog.pg_attrdef AS d, pg_catalog.pg_class AS c WHERE d.adrelid = c.oid AND d.adsrc ~ 'nextval' AND c.oid = pg_catalog.to_regclass('%s')") char *table; int result; diff --git a/src/rewrite/pool_timestamp.c b/src/rewrite/pool_timestamp.c index 3c98442..01192ea 100644 --- a/src/rewrite/pool_timestamp.c +++ b/src/rewrite/pool_timestamp.c @@ -136,7 +136,21 @@ ts_unregister_func(void *data) static TSRel * relcache_lookup(TSRewriteContext * ctx) { -#define ATTRDEFQUERY "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%' OR" \ +#define ATTRDEFQUERY (Pgversion(ctx->backend)->major >= 73 ? \ + "SELECT attname, pg_get_expr(d.adbin, d.adrelid), coalesce((pg_get_expr(d.adbin, d.adrelid) LIKE '%%now()%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%''now''::text%%' OR" \ + " pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_TIMESTAMP%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_TIME%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_DATE%%' OR" \ + " pg_get_expr(d.adbin, d.adrelid) LIKE '%%LOCALTIME%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%LOCALTIMESTAMP%%')" \ + " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ + " a.atttypid = 'timestamp with time zone'::regtype::oid OR" \ + " a.atttypid = 'date'::regtype::oid OR" \ + " a.atttypid = 'time'::regtype::oid OR" \ + " a.atttypid = 'time with time zone'::regtype::oid)" \ + " , false)" \ + " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " \ + " LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum)" \ + " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.relname = '%s'" \ + " ORDER BY a.attnum" : \ + "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%' OR" \ " d.adsrc LIKE '%%CURRENT_TIMESTAMP%%' OR d.adsrc LIKE '%%CURRENT_TIME%%' OR d.adsrc LIKE '%%CURRENT_DATE%%' OR" \ " d.adsrc LIKE '%%LOCALTIME%%' OR d.adsrc LIKE '%%LOCALTIMESTAMP%%')" \ " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ @@ -148,9 +162,23 @@ relcache_lookup(TSRewriteContext * ctx) " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " \ " LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum)" \ " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.relname = '%s'" \ - " ORDER BY a.attnum" + " ORDER BY a.attnum") -#define ATTRDEFQUERY2 "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%' OR" \ +#define ATTRDEFQUERY2 (Pgversion(ctx->backend)->major >= 73 ? \ + "SELECT attname, pg_get_expr(d.adbin, d.adrelid), coalesce((pg_get_expr(d.adbin, d.adrelid) LIKE '%%now()%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%''now''::text%%' OR" \ + " pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_TIMESTAMP%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_TIME%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_DATE%%' OR" \ + " pg_get_expr(d.adbin, d.adrelid) LIKE '%%LOCALTIME%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%LOCALTIMESTAMP%%')" \ + " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ + " a.atttypid = 'timestamp with time zone'::regtype::oid OR" \ + " a.atttypid = 'date'::regtype::oid OR" \ + " a.atttypid = 'time'::regtype::oid OR" \ + " a.atttypid = 'time with time zone'::regtype::oid)" \ + " , false)" \ + " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " \ + " LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum)" \ + " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pgpool_regclass('%s')" \ + " ORDER BY a.attnum" : \ + "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%' OR" \ " d.adsrc LIKE '%%CURRENT_TIMESTAMP%%' OR d.adsrc LIKE '%%CURRENT_TIME%%' OR d.adsrc LIKE '%%CURRENT_DATE%%' OR" \ " d.adsrc LIKE '%%LOCALTIME%%' OR d.adsrc LIKE '%%LOCALTIMESTAMP%%')" \ " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ @@ -162,9 +190,23 @@ relcache_lookup(TSRewriteContext * ctx) " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " \ " LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum)" \ " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = pgpool_regclass('%s')" \ - " ORDER BY a.attnum" + " ORDER BY a.attnum") -#define ATTRDEFQUERY3 "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%' OR" \ +#define ATTRDEFQUERY3 (Pgversion(ctx->backend)->major >= 73 ? \ + "SELECT attname, pg_get_expr(d.adbin, d.adrelid), coalesce((pg_get_expr(d.adbin, d.adrelid) LIKE '%%now()%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%''now''::text%%' OR" \ + " pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_TIMESTAMP%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_TIME%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%CURRENT_DATE%%' OR" \ + " pg_get_expr(d.adbin, d.adrelid) LIKE '%%LOCALTIME%%' OR pg_get_expr(d.adbin, d.adrelid) LIKE '%%LOCALTIMESTAMP%%')" \ + " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ + " a.atttypid = 'timestamp with time zone'::regtype::oid OR" \ + " a.atttypid = 'date'::regtype::oid OR" \ + " a.atttypid = 'time'::regtype::oid OR" \ + " a.atttypid = 'time with time zone'::regtype::oid)" \ + " , false)" \ + " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " \ + " LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum)" \ + " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = to_regclass('%s')" \ + " ORDER BY a.attnum" : \ + "SELECT attname, d.adsrc, coalesce((d.adsrc LIKE '%%now()%%' OR d.adsrc LIKE '%%''now''::text%%' OR" \ " d.adsrc LIKE '%%CURRENT_TIMESTAMP%%' OR d.adsrc LIKE '%%CURRENT_TIME%%' OR d.adsrc LIKE '%%CURRENT_DATE%%' OR" \ " d.adsrc LIKE '%%LOCALTIME%%' OR d.adsrc LIKE '%%LOCALTIMESTAMP%%')" \ " AND (a.atttypid = 'timestamp'::regtype::oid OR" \ @@ -176,7 +218,7 @@ relcache_lookup(TSRewriteContext * ctx) " FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " \ " LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid = d.adrelid AND a.attnum = d.adnum)" \ " WHERE c.oid = a.attrelid AND a.attnum >= 1 AND a.attisdropped = 'f' AND c.oid = to_regclass('%s')" \ - " ORDER BY a.attnum" + " ORDER BY a.attnum") char *query; char *table_name; @@ -814,6 +856,25 @@ rewrite_timestamp(POOL_CONNECTION_POOL * backend, Node *node, rewrite = ctx.rewrite; } + else if (IsA(stmt, CopyStmt)) + { + CopyStmt *c_stmt = (CopyStmt *) stmt; + + raw_expression_tree_walker( + (Node *) c_stmt->attlist, + rewrite_timestamp_walker, (void *) &ctx); + + raw_expression_tree_walker( + (Node *) c_stmt->options, + rewrite_timestamp_walker, (void *) &ctx); + + raw_expression_tree_walker( + (Node *) c_stmt->whereClause, + rewrite_timestamp_walker, (void *) &ctx); + + rewrite = ctx.rewrite; + + } else if (IsA(stmt, ExecuteStmt)) { ExecuteStmt *e_stmt = (ExecuteStmt *) stmt; @@ -1208,8 +1269,8 @@ raw_expression_tree_walker(Node *node, if (node == NULL) return false; - /* Guard against stack overflow due to overly complex expressions */ + /* Guard against stack overflow due to overly complex expressions */ /* * check_stack_depth(); */ diff --git a/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c b/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c index 1bef907..974dd51 100644 --- a/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c +++ b/src/test/regression/tests/010.rewrite_timestamp/timestamp/main.c @@ -74,6 +74,19 @@ pool_get_major_version(void) return PROTO_MAJOR_V3; } + +PGVersion * +Pgversion(POOL_CONNECTION_POOL * backend) +{ +#define VERSION_BUF_SIZE 10 + static PGVersion pgversion; + + pgversion.major = 12; + pgversion.minor = 0; + + return &pgversion; +} + POOL_RELCACHE * pool_create_relcache(int cachesize, char *sql, func_ptr register_func, func_ptr unregister_func, bool issessionlocal) {