summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2006-12-21 16:05:16 +0000
committerPeter Eisentraut <peter_e@gmx.net>2006-12-21 16:05:16 +0000
commit8c1de5fb0010ae712568f1706b737270c3609bd8 (patch)
treebc328a654c41ea3eb1a9a27b76fd5215fb698608 /src/backend/parser
parented1e9cd501b4dc89a6a7e5cef702f2f6830ae829 (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.y198
-rw-r--r--src/backend/parser/keywords.c19
-rw-r--r--src/backend/parser/parse_coerce.c42
-rw-r--r--src/backend/parser/parse_expr.c61
-rw-r--r--src/backend/parser/parse_target.c17
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;
}