diff options
author | Peter Eisentraut <peter_e@gmx.net> | 2006-12-21 16:05:16 +0000 |
---|---|---|
committer | Peter Eisentraut <peter_e@gmx.net> | 2006-12-21 16:05:16 +0000 |
commit | 8c1de5fb0010ae712568f1706b737270c3609bd8 (patch) | |
tree | bc328a654c41ea3eb1a9a27b76fd5215fb698608 /src/backend/parser | |
parent | ed1e9cd501b4dc89a6a7e5cef702f2f6830ae829 (diff) |
Initial SQL/XML support: xml data type and initial set of functions.
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 198 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 19 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 42 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 61 | ||||
-rw-r--r-- | src/backend/parser/parse_target.c | 17 |
5 files changed, 323 insertions, 14 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index c90743a1017..cc400407363 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.568 2006/11/05 22:42:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.569 2006/12/21 16:05:14 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -106,6 +106,7 @@ static void insertSelectOptions(SelectStmt *stmt, static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg); static Node *doNegate(Node *n, int location); static void doNegateFloat(Value *v); +static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args); %} @@ -345,6 +346,11 @@ static void doNegateFloat(Value *v); %type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner %type <list> opt_check_option +%type <target> xml_attribute_el +%type <list> xml_attribute_list xml_attributes +%type <node> xml_root_version +%type <ival> opt_xml_root_standalone document_or_content xml_whitespace_option + /* * If you make any token changes, update the keyword table in @@ -365,13 +371,13 @@ static void doNegateFloat(Value *v); CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS - CONVERSION_P CONVERT COPY CREATE CREATEDB + CONTENT CONVERSION_P CONVERT COPY CREATE CREATEDB CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS - DESC DISABLE_P DISTINCT DO DOMAIN_P DOUBLE_P DROP + DESC DISABLE_P DISTINCT DO DOCUMENT DOMAIN_P DOUBLE_P DROP EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT @@ -398,7 +404,7 @@ static void doNegateFloat(Value *v); MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE - NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB + NAME NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC @@ -417,8 +423,8 @@ static void doNegateFloat(Value *v); SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE - SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT - STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC + SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE START STATEMENT + STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP SUBSTRING SUPERUSER_P SYMMETRIC SYSID SYSTEM_P TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP @@ -428,12 +434,15 @@ static void doNegateFloat(Value *v); UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL UPDATE USER USING - VACUUM VALID VALIDATOR VALUES VARCHAR VARYING - VERBOSE VIEW VOLATILE + VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING + VERBOSE VERSION VIEW VOLATILE + + WHEN WHERE WHITESPACE WITH WITHOUT WORK WRITE - WHEN WHERE WITH WITHOUT WORK WRITE + XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE + XMLPI XMLROOT XMLSERIALIZE - YEAR_P + YEAR_P YES ZONE @@ -484,6 +493,7 @@ static void doNegateFloat(Value *v); * left-associativity among the JOIN rules themselves. */ %left JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL +%right PRESERVE STRIP %% /* @@ -7868,6 +7878,146 @@ func_expr: func_name '(' ')' v->op = IS_LEAST; $$ = (Node *)v; } + | XMLCONCAT '(' expr_list ')' + { + $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3); + } + | XMLELEMENT '(' NAME ColLabel ')' + { + $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NULL); + } + | XMLELEMENT '(' NAME ColLabel ',' xml_attributes ')' + { + $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NULL); + } + | XMLELEMENT '(' NAME ColLabel ',' expr_list ')' + { + $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, $6); + } + | XMLELEMENT '(' NAME ColLabel ',' xml_attributes ',' expr_list ')' + { + $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8); + } + | XMLFOREST '(' xml_attribute_list ')' + { + $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NULL); + } + | XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = SystemFuncName("xmlparse"); + n->args = list_make3(makeBoolAConst($3 == DOCUMENT), $4, makeBoolAConst($5 == PRESERVE)); + n->agg_star = FALSE; + n->agg_distinct = FALSE; + n->location = @1; + $$ = (Node *)n; + } + | XMLPI '(' NAME ColLabel ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = SystemFuncName("xmlpi"); + n->args = list_make1(makeStringConst($4, NULL)); + n->agg_star = FALSE; + n->agg_distinct = FALSE; + n->location = @1; + $$ = (Node *)n; + } + | XMLPI '(' NAME ColLabel ',' a_expr ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = SystemFuncName("xmlpi"); + n->args = list_make2(makeStringConst($4, NULL), $6); + n->agg_star = FALSE; + n->agg_distinct = FALSE; + n->location = @1; + $$ = (Node *)n; + } + | XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')' + { + FuncCall *n = makeNode(FuncCall); + Node *ver; + A_Const *sa; + + if ($5) + ver = $5; + else + { + A_Const *val; + + val = makeNode(A_Const); + val->val.type = T_Null; + ver = (Node *) val; + } + + if ($6) + sa = makeBoolAConst($6 == 1); + else + { + sa = makeNode(A_Const); + sa->val.type = T_Null; + } + + n->funcname = SystemFuncName("xmlroot"); + n->args = list_make3($3, ver, sa); + n->agg_star = FALSE; + n->agg_distinct = FALSE; + n->location = @1; + $$ = (Node *)n; + } + | XMLSERIALIZE '(' document_or_content a_expr AS Typename ')' + { + /* + * FIXME: This should be made distinguishable from + * CAST (for reverse compilation at least). + */ + $$ = makeTypeCast($4, $6); + } + ; + +/* + * SQL/XML support + */ +xml_root_version: VERSION a_expr { $$ = $2; } + | VERSION NO VALUE { $$ = NULL; } + ; + +opt_xml_root_standalone: ',' STANDALONE YES { $$ = 1; } + | ',' STANDALONE NO { $$ = -1; } + | ',' STANDALONE NO VALUE { $$ = 0; } + | /*EMPTY*/ { $$ = 0; } + ; + +xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; } + ; + +xml_attribute_list: xml_attribute_el { $$ = list_make1($1); } + | xml_attribute_list ',' xml_attribute_el { $$ = lappend($1, $3); } + ; + +xml_attribute_el: a_expr AS ColLabel + { + $$ = makeNode(ResTarget); + $$->name = $3; + $$->indirection = NULL; + $$->val = (Node *) $1; + + } + | a_expr + { + $$ = makeNode(ResTarget); + $$->name = NULL; + $$->indirection = NULL; + $$->val = (Node *) $1; + } + ; + +document_or_content: DOCUMENT { $$ = DOCUMENT; } + | CONTENT { $$ = CONTENT; } + ; + +xml_whitespace_option: PRESERVE WHITESPACE { $$ = PRESERVE; } + | STRIP WHITESPACE { $$ = STRIP; } + | /*EMPTY*/ { $$ = STRIP; } ; /* @@ -8562,6 +8712,7 @@ unreserved_keyword: | CONCURRENTLY | CONNECTION | CONSTRAINTS + | CONTENT | CONVERSION_P | COPY | CREATEDB @@ -8581,6 +8732,7 @@ unreserved_keyword: | DELIMITER | DELIMITERS | DISABLE_P + | DOCUMENT | DOMAIN_P | DOUBLE_P | DROP @@ -8640,6 +8792,7 @@ unreserved_keyword: | MODE | MONTH_P | MOVE + | NAME | NAMES | NEXT | NO @@ -8700,12 +8853,14 @@ unreserved_keyword: | SHOW | SIMPLE | STABLE + | STANDALONE | START | STATEMENT | STATISTICS | STDIN | STDOUT | STORAGE + | STRIP | SUPERUSER_P | SYSID | SYSTEM_P @@ -8729,13 +8884,17 @@ unreserved_keyword: | VALID | VALIDATOR | VARYING + | VERSION | VIEW + | VALUE | VOLATILE + | WHITESPACE | WITH | WITHOUT | WORK | WRITE | YEAR_P + | YES | ZONE ; @@ -8788,6 +8947,14 @@ col_name_keyword: | TRIM | VALUES | VARCHAR + | XMLATTRIBUTES + | XMLELEMENT + | XMLCONCAT + | XMLFOREST + | XMLPARSE + | XMLPI + | XMLROOT + | XMLSERIALIZE ; /* Function identifier --- keywords that can be function names. @@ -9322,6 +9489,17 @@ doNegateFloat(Value *v) } } +static Node * +makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) +{ + XmlExpr *x = makeNode(XmlExpr); + x->op = op; + x->name = name; + x->named_args = named_args; + x->args = args; + return (Node *) x; +} + /* * Must undefine base_yylex before including scan.c, since we want it * to create the function base_yylex not filtered_base_yylex. diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 50fd3aac405..b5e49e955fc 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.177 2006/10/07 21:51:02 petere Exp $ + * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.178 2006/12/21 16:05:14 petere Exp $ * *------------------------------------------------------------------------- */ @@ -89,6 +89,7 @@ static const ScanKeyword ScanKeywords[] = { {"connection", CONNECTION}, {"constraint", CONSTRAINT}, {"constraints", CONSTRAINTS}, + {"content", CONTENT}, {"conversion", CONVERSION_P}, {"convert", CONVERT}, {"copy", COPY}, @@ -123,6 +124,7 @@ static const ScanKeyword ScanKeywords[] = { {"disable", DISABLE_P}, {"distinct", DISTINCT}, {"do", DO}, + {"document", DOCUMENT}, {"domain", DOMAIN_P}, {"double", DOUBLE_P}, {"drop", DROP}, @@ -218,6 +220,7 @@ static const ScanKeyword ScanKeywords[] = { {"mode", MODE}, {"month", MONTH_P}, {"move", MOVE}, + {"name", NAME}, {"names", NAMES}, {"national", NATIONAL}, {"natural", NATURAL}, @@ -314,6 +317,7 @@ static const ScanKeyword ScanKeywords[] = { {"smallint", SMALLINT}, {"some", SOME}, {"stable", STABLE}, + {"standalone", STANDALONE}, {"start", START}, {"statement", STATEMENT}, {"statistics", STATISTICS}, @@ -321,6 +325,7 @@ static const ScanKeyword ScanKeywords[] = { {"stdout", STDOUT}, {"storage", STORAGE}, {"strict", STRICT_P}, + {"strip", STRIP}, {"substring", SUBSTRING}, {"superuser", SUPERUSER_P}, {"symmetric", SYMMETRIC}, @@ -357,19 +362,31 @@ static const ScanKeyword ScanKeywords[] = { {"vacuum", VACUUM}, {"valid", VALID}, {"validator", VALIDATOR}, + {"value", VALUE}, {"values", VALUES}, {"varchar", VARCHAR}, {"varying", VARYING}, {"verbose", VERBOSE}, + {"version", VERSION}, {"view", VIEW}, {"volatile", VOLATILE}, {"when", WHEN}, {"where", WHERE}, + {"whitespace", WHITESPACE}, {"with", WITH}, {"without", WITHOUT}, {"work", WORK}, {"write", WRITE}, + {"xmlattributes", XMLATTRIBUTES}, + {"xmlconcat", XMLCONCAT}, + {"xmlelement", XMLELEMENT}, + {"xmlforest", XMLFOREST}, + {"xmlparse", XMLPARSE}, + {"xmlpi", XMLPI}, + {"xmlroot", XMLROOT}, + {"xmlserialize", XMLSERIALIZE}, {"year", YEAR_P}, + {"yes", YES}, {"zone", ZONE}, }; diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 2a468c68271..5670ed4fe74 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.147 2006/12/10 22:13:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.148 2006/12/21 16:05:14 petere Exp $ * *------------------------------------------------------------------------- */ @@ -919,6 +919,46 @@ coerce_to_bigint(ParseState *pstate, Node *node, return node; } +/* + * coerce_to_xml() + * Coerce an argument of a construct that requires xml input. + * Also check that input is not a set. + * + * Returns the possibly-transformed node tree. + * + * As with coerce_type, pstate may be NULL if no special unknown-Param + * processing is wanted. + */ +Node * +coerce_to_xml(ParseState *pstate, Node *node, + const char *constructName) +{ + Oid inputTypeId = exprType(node); + + if (inputTypeId != XMLOID) + { + node = coerce_to_target_type(pstate, node, inputTypeId, + XMLOID, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST); + if (node == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + /* translator: first %s is name of a SQL construct, eg LIMIT */ + errmsg("argument of %s must be type xml, not type %s", + constructName, format_type_be(inputTypeId)))); + } + + if (expression_returns_set(node)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + /* translator: %s is name of a SQL construct, eg LIMIT */ + errmsg("argument of %s must not return a set", + constructName))); + + return node; +} + /* select_common_type() * Determine the common supertype of a list of input expression types. diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index b1b6ea81456..234a15b6afb 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.199 2006/12/10 22:13:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.200 2006/12/21 16:05:14 petere Exp $ * *------------------------------------------------------------------------- */ @@ -33,6 +33,7 @@ #include "parser/parse_type.h" #include "utils/builtins.h" #include "utils/lsyscache.h" +#include "utils/xml.h" bool Transform_null_equals = false; @@ -55,6 +56,7 @@ static Node *transformArrayExpr(ParseState *pstate, ArrayExpr *a); static Node *transformRowExpr(ParseState *pstate, RowExpr *r); static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c); static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m); +static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x); static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b); static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, @@ -232,6 +234,10 @@ transformExpr(ParseState *pstate, Node *expr) result = transformBooleanTest(pstate, (BooleanTest *) expr); break; + case T_XmlExpr: + result = transformXmlExpr(pstate, (XmlExpr *) expr); + break; + /********************************************* * Quietly accept node types that may be presented when we are * called on an already-transformed tree. @@ -1409,6 +1415,56 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b) return (Node *) b; } +static Node * +transformXmlExpr(ParseState *pstate, XmlExpr *x) +{ + ListCell *lc; + XmlExpr *newx = makeNode(XmlExpr); + + newx->op = x->op; + if (x->name) + newx->name = map_sql_identifier_to_xml_name(x->name, false); + else + newx->name = NULL; + + foreach(lc, x->named_args) + { + ResTarget *r = (ResTarget *) lfirst(lc); + Node *expr = transformExpr(pstate, r->val); + char *argname = NULL; + + if (r->name) + argname = map_sql_identifier_to_xml_name(r->name, false); + else if (IsA(r->val, ColumnRef)) + argname = map_sql_identifier_to_xml_name(FigureColname(r->val), true); + else + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + x->op == IS_XMLELEMENT + ? errmsg("unnamed attribute value must be a column reference") + : errmsg("unnamed element value must be a column reference"))); + + newx->named_args = lappend(newx->named_args, + makeTargetEntry((Expr *) expr, 0, argname, false)); + } + + foreach(lc, x->args) + { + Node *e = (Node *) lfirst(lc); + Node *newe; + + newe = coerce_to_xml(pstate, transformExpr(pstate, e), + (x->op == IS_XMLCONCAT + ? "XMLCONCAT" + : (x->op == IS_XMLELEMENT + ? "XMLELEMENT" + : "XMLFOREST"))); + newx->args = lappend(newx->args, newe); + } + + return (Node *) newx; +} + /* * Construct a whole-row reference to represent the notation "relation.*". * @@ -1668,6 +1724,9 @@ exprType(Node *expr) case T_BooleanTest: type = BOOLOID; break; + case T_XmlExpr: + type = XMLOID; + break; case T_CoerceToDomain: type = ((CoerceToDomain *) expr)->resulttype; break; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index bb4b065eebb..906d96e45c6 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.149 2006/10/04 00:29:56 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.150 2006/12/21 16:05:14 petere Exp $ * *------------------------------------------------------------------------- */ @@ -1315,6 +1315,21 @@ FigureColnameInternal(Node *node, char **name) return 2; } break; + case T_XmlExpr: + /* make SQL/XML functions act like a regular function */ + switch (((XmlExpr*) node)->op) + { + case IS_XMLCONCAT: + *name = "xmlconcat"; + return 2; + case IS_XMLELEMENT: + *name = "xmlelement"; + return 2; + case IS_XMLFOREST: + *name = "xmlforest"; + return 2; + } + break; default: break; } |