From 975a4c34f8326cbd2e5b29e46d3f9dc821c8a2a6 Mon Sep 17 00:00:00 2001 From: Marcos Magueta Date: Wed, 21 Jan 2026 17:11:06 -0300 Subject: [PATCH 1/5] Add CREATE/ALTER/DROP XMLSCHEMA DDL commands --- src/backend/catalog/Makefile | 1 + src/backend/catalog/aclchk.c | 17 +++ src/backend/catalog/dependency.c | 31 +++++ src/backend/catalog/meson.build | 1 + src/backend/catalog/namespace.c | 56 ++++++++ src/backend/catalog/objectaddress.c | 84 ++++++++++++ src/backend/catalog/pg_xmlschema.c | 194 +++++++++++++++++++++++++++ src/backend/commands/Makefile | 3 +- src/backend/commands/alter.c | 8 ++ src/backend/commands/dropcmds.c | 7 + src/backend/commands/event_trigger.c | 2 + src/backend/commands/meson.build | 1 + src/backend/commands/seclabel.c | 1 + src/backend/commands/xmlschemacmds.c | 146 ++++++++++++++++++++ src/backend/parser/gram.y | 83 +++++++++++- src/backend/tcop/utility.c | 17 +++ src/backend/utils/adt/acl.c | 4 + src/backend/utils/adt/ruleutils.c | 16 ++- src/include/catalog/Makefile | 1 + src/include/catalog/meson.build | 1 + src/include/catalog/namespace.h | 1 + src/include/catalog/pg_xmlschema.h | 48 +++++++ src/include/commands/xmlschemacmds.h | 9 ++ src/include/nodes/parsenodes.h | 1 + src/include/parser/kwlist.h | 3 + src/include/tcop/cmdtaglist.h | 3 + src/include/utils/acl.h | 1 + 27 files changed, 734 insertions(+), 6 deletions(-) create mode 100644 src/backend/catalog/pg_xmlschema.c create mode 100644 src/backend/commands/xmlschemacmds.c create mode 100644 src/include/catalog/pg_xmlschema.h create mode 100644 src/include/commands/xmlschemacmds.h diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 26fa0c9b18c..ed9414ba638 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -46,6 +46,7 @@ OBJS = \ pg_subscription.o \ pg_tablespace.o \ pg_type.o \ + pg_xmlschema.o \ storage.o \ toasting.o diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index a431fc0926f..c5198ea6ec6 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -64,6 +64,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" +#include "catalog/pg_xmlschema.h" #include "commands/defrem.h" #include "commands/event_trigger.h" #include "commands/extension.h" @@ -290,6 +291,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, case OBJECT_PARAMETER_ACL: whole_mask = ACL_ALL_RIGHTS_PARAMETER_ACL; break; + case OBJECT_XMLSCHEMA: + whole_mask = ACL_ALL_RIGHTS_XMLSCHEMA; + break; default: elog(ERROR, "unrecognized object type: %d", objtype); /* not reached, but keep compiler quiet */ @@ -534,6 +538,10 @@ ExecuteGrantStmt(GrantStmt *stmt) all_privileges = ACL_ALL_RIGHTS_PARAMETER_ACL; errormsg = gettext_noop("invalid privilege type %s for parameter"); break; + case OBJECT_XMLSCHEMA: + all_privileges = ACL_ALL_RIGHTS_XMLSCHEMA; + errormsg = gettext_noop("invalid privilege type %s for XML schema"); + break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) stmt->objtype); @@ -639,6 +647,9 @@ ExecGrantStmt_oids(InternalGrant *istmt) case OBJECT_PARAMETER_ACL: ExecGrant_Parameter(istmt); break; + case OBJECT_XMLSCHEMA: + ExecGrant_common(istmt, XmlSchemaRelationId, ACL_ALL_RIGHTS_XMLSCHEMA, NULL); + break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) istmt->objtype); @@ -2677,6 +2688,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_CONVERSION: msg = gettext_noop("permission denied for conversion %s"); break; + case OBJECT_XMLSCHEMA: + msg = gettext_noop("permission denied for XML schema %s"); + break; case OBJECT_DATABASE: msg = gettext_noop("permission denied for database %s"); break; @@ -2809,6 +2823,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_CONVERSION: msg = gettext_noop("must be owner of conversion %s"); break; + case OBJECT_XMLSCHEMA: + msg = gettext_noop("must be owner of XML schema %s"); + break; case OBJECT_DATABASE: msg = gettext_noop("must be owner of database %s"); break; diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index f89267f0342..50ce3871e78 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -66,6 +66,7 @@ #include "catalog/pg_ts_template.h" #include "catalog/pg_type.h" #include "catalog/pg_user_mapping.h" +#include "catalog/pg_xmlschema.h" #include "commands/comment.h" #include "commands/defrem.h" #include "commands/event_trigger.h" @@ -79,6 +80,7 @@ #include "funcapi.h" #include "miscadmin.h" #include "nodes/nodeFuncs.h" +#include "nodes/primnodes.h" #include "parser/parsetree.h" #include "rewrite/rewriteRemove.h" #include "storage/lmgr.h" @@ -1514,6 +1516,7 @@ doDeletion(const ObjectAddress *object, int flags) case EventTriggerRelationId: case TransformRelationId: case AuthMemRelationId: + case XmlSchemaRelationId: DropObjectById(object); break; @@ -2416,6 +2419,34 @@ find_expr_references_walker(Node *node, context->addrs); /* fall through to examine arguments */ } + else if (IsA(node, XmlExpr)) + { + XmlExpr *xmlexpr = (XmlExpr *) node; + + /* + * XMLVALIDATE's second argument is a Const containing the schema OID. + * Record a dependency on it. + */ + if (xmlexpr->op == IS_XMLVALIDATE && list_length(xmlexpr->args) == 2) + { + Node *schema_arg = (Node *) lsecond(xmlexpr->args); + + if (IsA(schema_arg, Const)) + { + Const *schema_const = (Const *) schema_arg; + Oid schema_oid; + + if (!schema_const->constisnull && + schema_const->consttype == OIDOID) + { + schema_oid = DatumGetObjectId(schema_const->constvalue); + add_object_address(XmlSchemaRelationId, schema_oid, 0, + context->addrs); + } + } + } + /* fall through to examine arguments */ + } return expression_tree_walker(node, find_expr_references_walker, context); diff --git a/src/backend/catalog/meson.build b/src/backend/catalog/meson.build index 11d21c5ad6b..9ba15e71b72 100644 --- a/src/backend/catalog/meson.build +++ b/src/backend/catalog/meson.build @@ -33,6 +33,7 @@ backend_sources += files( 'pg_subscription.c', 'pg_tablespace.c', 'pg_type.c', + 'pg_xmlschema.c', 'storage.c', 'toasting.c', ) diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index c3b79a2ba48..89b124ceeec 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -30,6 +30,7 @@ #include "catalog/pg_collation.h" #include "catalog/pg_conversion.h" #include "catalog/pg_database.h" +#include "catalog/pg_xmlschema.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" @@ -4143,6 +4144,61 @@ get_conversion_oid(List *conname, bool missing_ok) return conoid; } +/* + * get_xmlschema_oid - find an XML schema by possibly qualified name + */ +Oid +get_xmlschema_oid(List *schemaname, bool missing_ok) +{ + char *nspname; + char *schema_name; + Oid namespaceId; + Oid schema_oid = InvalidOid; + ListCell *l; + + /* deconstruct the name list */ + DeconstructQualifiedName(schemaname, &nspname, &schema_name); + + if (nspname) + { + /* use exact schema given */ + namespaceId = LookupExplicitNamespace(nspname, missing_ok); + if (missing_ok && !OidIsValid(namespaceId)) + schema_oid = InvalidOid; + else + schema_oid = GetSysCacheOid2(XMLSCHEMANAMENSP, Anum_pg_xmlschema_oid, + PointerGetDatum(schema_name), + ObjectIdGetDatum(namespaceId)); + } + else + { + /* search for it in search path */ + recomputeNamespacePath(); + + foreach(l, activeSearchPath) + { + namespaceId = lfirst_oid(l); + + if (namespaceId == myTempNamespace) + continue; /* do not look in temp namespace */ + + schema_oid = GetSysCacheOid2(XMLSCHEMANAMENSP, Anum_pg_xmlschema_oid, + PointerGetDatum(schema_name), + ObjectIdGetDatum(namespaceId)); + if (OidIsValid(schema_oid)) + return schema_oid; + } + } + + /* Not found in path */ + if (!OidIsValid(schema_oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("XML schema \"%s\" does not exist", + NameListToString(schemaname)))); + return schema_oid; +} + /* * FindDefaultConversionProc - find default encoding conversion proc */ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 02af64b82c6..6306b9c8f6e 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -62,6 +62,7 @@ #include "catalog/pg_ts_template.h" #include "catalog/pg_type.h" #include "catalog/pg_user_mapping.h" +#include "catalog/pg_xmlschema.h" #include "commands/defrem.h" #include "commands/event_trigger.h" #include "commands/extension.h" @@ -187,6 +188,20 @@ static const ObjectPropertyType ObjectProperty[] = OBJECT_COLLATION, true }, + { + "xmlschema", + XmlSchemaRelationId, + XmlSchemaOidIndexId, + XMLSCHEMAOID, + XMLSCHEMANAMENSP, + Anum_pg_xmlschema_oid, + Anum_pg_xmlschema_schemaname, + Anum_pg_xmlschema_schemanamespace, + Anum_pg_xmlschema_schemaowner, + Anum_pg_xmlschema_schemaacl, + OBJECT_XMLSCHEMA, + true + }, { "constraint", ConstraintRelationId, @@ -720,6 +735,9 @@ static const struct object_type_map { "collation", OBJECT_COLLATION }, + { + "xmlschema", OBJECT_XMLSCHEMA + }, { "table constraint", OBJECT_TABCONSTRAINT }, @@ -1029,6 +1047,11 @@ get_object_address(ObjectType objtype, Node *object, address.objectId = get_collation_oid(castNode(List, object), missing_ok); address.objectSubId = 0; break; + case OBJECT_XMLSCHEMA: + address.classId = XmlSchemaRelationId; + address.objectId = get_xmlschema_oid(castNode(List, object), missing_ok); + address.objectSubId = 0; + break; case OBJECT_CONVERSION: address.classId = ConversionRelationId; address.objectId = get_conversion_oid(castNode(List, object), missing_ok); @@ -2282,6 +2305,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_COLUMN: case OBJECT_ATTRIBUTE: case OBJECT_COLLATION: + case OBJECT_XMLSCHEMA: case OBJECT_CONVERSION: case OBJECT_STATISTIC_EXT: case OBJECT_TSPARSER: @@ -2460,6 +2484,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, strVal(object)); break; case OBJECT_COLLATION: + case OBJECT_XMLSCHEMA: case OBJECT_CONVERSION: case OBJECT_OPCLASS: case OBJECT_OPFAMILY: @@ -4067,6 +4092,34 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok) break; } + case XmlSchemaRelationId: + { + HeapTuple schemaTup; + Form_pg_xmlschema schema; + char *nspname; + + schemaTup = SearchSysCache1(XMLSCHEMAOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(schemaTup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for XML schema %u", + object->objectId); + break; + } + + schema = (Form_pg_xmlschema) GETSTRUCT(schemaTup); + + /* Qualify the name if not visible in search path */ + nspname = get_namespace_name(schema->schemanamespace); + + appendStringInfo(&buffer, _("XML schema %s"), + quote_qualified_identifier(nspname, + NameStr(schema->schemaname))); + ReleaseSysCache(schemaTup); + break; + } + default: elog(ERROR, "unsupported object class: %u", object->classId); } @@ -4669,6 +4722,10 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "transform"); break; + case XmlSchemaRelationId: + appendStringInfoString(&buffer, "XML schema"); + break; + default: elog(ERROR, "unsupported object class: %u", object->classId); } @@ -6019,6 +6076,33 @@ getObjectIdentityParts(const ObjectAddress *object, } break; + case XmlSchemaRelationId: + { + HeapTuple schemaTup; + Form_pg_xmlschema schema; + char *nspname; + + schemaTup = SearchSysCache1(XMLSCHEMAOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(schemaTup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for XML schema %u", + object->objectId); + break; + } + schema = (Form_pg_xmlschema) GETSTRUCT(schemaTup); + nspname = get_namespace_name_or_temp(schema->schemanamespace); + appendStringInfoString(&buffer, + quote_qualified_identifier(nspname, + NameStr(schema->schemaname))); + if (objname) + *objname = list_make2(nspname, + pstrdup(NameStr(schema->schemaname))); + ReleaseSysCache(schemaTup); + break; + } + default: elog(ERROR, "unsupported object class: %u", object->classId); } diff --git a/src/backend/catalog/pg_xmlschema.c b/src/backend/catalog/pg_xmlschema.c new file mode 100644 index 00000000000..116bbfa71c7 --- /dev/null +++ b/src/backend/catalog/pg_xmlschema.c @@ -0,0 +1,194 @@ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_xmlschema.h" +#include "catalog/pg_namespace.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/rel.h" +#include "utils/syscache.h" +#include "utils/xml.h" + +#ifdef USE_LIBXML +#include +#endif + +/* + * XmlSchemaCreate + * + * Add a new tuple to pg_xmlschema. + * + * if_not_exists: if true, don't fail on duplicate name, just print a notice + * and return InvalidOid. + * quiet: if true, don't fail on duplicate name, just silently return + * InvalidOid (which overides if_not_exists). + */ +Oid +XmlSchemaCreate(const char *schemaname, + Oid schemanamespace, + Oid schemaowner, + xmltype *schemadata, + bool if_not_exists, + bool quiet) +{ + Relation rel; + TupleDesc tupDesc; + HeapTuple tup; + Datum values[Natts_pg_xmlschema]; + bool nulls[Natts_pg_xmlschema]; + NameData name_name; + Oid oid; + ObjectAddress myself, + referenced; + + Assert(schemaname); + Assert(schemanamespace); + Assert(schemaowner); + Assert(schemadata); + +#ifdef USE_LIBXML + /* Validate the XML Schema before storing it */ + { + xmlSchemaParserCtxtPtr parser_ctxt; + xmlSchemaPtr schema_ptr; + PgXmlErrorContext *xmlerrcxt; + char *schemastr; + + schemastr = text_to_cstring(schemadata); + xmlerrcxt = pg_xml_init(PG_XML_STRICTNESS_WELLFORMED); + + PG_TRY(); + { + parser_ctxt = xmlSchemaNewMemParserCtxt(schemastr, strlen(schemastr)); + if (parser_ctxt == NULL) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT, + "failed to create schema parser context"); + + schema_ptr = xmlSchemaParse(parser_ctxt); + if (schema_ptr == NULL) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_DOCUMENT, + "invalid XML schema definition"); + + xmlSchemaFree(schema_ptr); + xmlSchemaFreeParserCtxt(parser_ctxt); + } + PG_CATCH(); + { + pg_xml_done(xmlerrcxt, true); + PG_RE_THROW(); + } + PG_END_TRY(); + + pg_xml_done(xmlerrcxt, false); + pfree(schemastr); + } +#else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("xmlschema support requires libxml"))); +#endif + + /* + * Make sure there is no existing XML schema of same name in the + * namespace. + * + * This would be caught by the unique index anyway; we're just giving a + * friendlier error message. The unique index provides a backstop against + * race conditions. + */ + oid = GetSysCacheOid2(XMLSCHEMANAMENSP, + Anum_pg_xmlschema_oid, + PointerGetDatum(schemaname), + ObjectIdGetDatum(schemanamespace)); + if (OidIsValid(oid)) + { + if (quiet) + return InvalidOid; + else if (if_not_exists) + { + /* + * If we are in an extension script, insist that the pre-existing + * object be a member of the extension, to avoid security risks. + */ + ObjectAddressSet(myself, XmlSchemaRelationId, oid); + checkMembershipInCurrentExtension(&myself); + + /* OK to skip */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("XML schema \"%s\" already exists, skipping", + schemaname))); + return InvalidOid; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("XML schema \"%s\" already exists", + schemaname))); + } + + /* open pg_xmlschema; lock to protect against concurrent changes */ + rel = table_open(XmlSchemaRelationId, ShareRowExclusiveLock); + + tupDesc = RelationGetDescr(rel); + + /* form a tuple */ + memset(nulls, 0, sizeof(nulls)); + + namestrcpy(&name_name, schemaname); + oid = GetNewOidWithIndex(rel, XmlSchemaOidIndexId, + Anum_pg_xmlschema_oid); + values[Anum_pg_xmlschema_oid - 1] = ObjectIdGetDatum(oid); + values[Anum_pg_xmlschema_schemaname - 1] = NameGetDatum(&name_name); + values[Anum_pg_xmlschema_schemanamespace - 1] = ObjectIdGetDatum(schemanamespace); + values[Anum_pg_xmlschema_schemaowner - 1] = ObjectIdGetDatum(schemaowner); + values[Anum_pg_xmlschema_schemadata - 1] = PointerGetDatum(schemadata); + + /* Set up default ACL */ + { + Acl *schemaacl; + + schemaacl = get_user_default_acl(OBJECT_XMLSCHEMA, schemaowner, + schemanamespace); + if (schemaacl != NULL) + values[Anum_pg_xmlschema_schemaacl - 1] = PointerGetDatum(schemaacl); + else + nulls[Anum_pg_xmlschema_schemaacl - 1] = true; + } + + tup = heap_form_tuple(tupDesc, values, nulls); + + /* insert a new tuple */ + CatalogTupleInsert(rel, tup); + Assert(OidIsValid(oid)); + + /* set up dependencies for the new XML schema */ + myself.classId = XmlSchemaRelationId; + myself.objectId = oid; + myself.objectSubId = 0; + + /* create dependency on namespace */ + referenced.classId = NamespaceRelationId; + referenced.objectId = schemanamespace; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* create dependency on owner */ + recordDependencyOnOwner(XmlSchemaRelationId, oid, schemaowner); + + /* dependency on extension */ + recordDependencyOnCurrentExtension(&myself, false); + + /* Post creation hook for new XML schema */ + InvokeObjectPostCreateHook(XmlSchemaRelationId, oid, 0); + + heap_freetuple(tup); + table_close(rel, NoLock); + + return oid; +} diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 64cb6278409..07f04eafdab 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -66,6 +66,7 @@ OBJS = \ vacuumparallel.o \ variable.o \ view.o \ - wait.o + wait.o \ + xmlschemacmds.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index f7b2389b019..778f54bdae6 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -41,6 +41,7 @@ #include "catalog/pg_ts_dict.h" #include "catalog/pg_ts_parser.h" #include "catalog/pg_ts_template.h" +#include "catalog/pg_xmlschema.h" #include "commands/alter.h" #include "commands/collationcmds.h" #include "commands/dbcommands.h" @@ -140,6 +141,10 @@ report_namespace_conflict(Oid classId, const char *name, Oid nspOid) Assert(OidIsValid(nspOid)); msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\""); break; + case XmlSchemaRelationId: + Assert(OidIsValid(nspOid)); + msgfmt = gettext_noop("XML schema \"%s\" already exists in schema \"%s\""); + break; default: elog(ERROR, "unsupported object class: %u", classId); break; @@ -423,6 +428,7 @@ ExecRenameStmt(RenameStmt *stmt) case OBJECT_FDW: case OBJECT_FOREIGN_SERVER: case OBJECT_FUNCTION: + case OBJECT_XMLSCHEMA: case OBJECT_OPCLASS: case OBJECT_OPFAMILY: case OBJECT_LANGUAGE: @@ -567,6 +573,7 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt, case OBJECT_FUNCTION: case OBJECT_OPERATOR: case OBJECT_OPCLASS: + case OBJECT_XMLSCHEMA: case OBJECT_OPFAMILY: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: @@ -877,6 +884,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) case OBJECT_CONVERSION: case OBJECT_FUNCTION: case OBJECT_LANGUAGE: + case OBJECT_XMLSCHEMA: case OBJECT_LARGEOBJECT: case OBJECT_OPERATOR: case OBJECT_OPCLASS: diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index 92526012d2a..2e893968ab3 100644 --- a/src/backend/commands/dropcmds.c +++ b/src/backend/commands/dropcmds.c @@ -278,6 +278,13 @@ does_not_exist_skipping(ObjectType objtype, Node *object) name = NameListToString(castNode(List, object)); } break; + case OBJECT_XMLSCHEMA: + if (!schema_does_not_exist_skipping(castNode(List, object), &msg, &name)) + { + msg = gettext_noop("XML schema \"%s\" does not exist, skipping"); + name = NameListToString(castNode(List, object)); + } + break; case OBJECT_SCHEMA: msg = gettext_noop("schema \"%s\" does not exist, skipping"); name = strVal(object); diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 028f9e2de90..4a087935f16 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -2318,6 +2318,7 @@ stringify_grant_objtype(ObjectType objtype) case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: case OBJECT_VIEW: + case OBJECT_XMLSCHEMA: elog(ERROR, "unsupported object type: %d", (int) objtype); } @@ -2402,6 +2403,7 @@ stringify_adefprivs_objtype(ObjectType objtype) case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: case OBJECT_VIEW: + case OBJECT_XMLSCHEMA: elog(ERROR, "unsupported object type: %d", (int) objtype); } diff --git a/src/backend/commands/meson.build b/src/backend/commands/meson.build index ca3f53c6213..3363797ecee 100644 --- a/src/backend/commands/meson.build +++ b/src/backend/commands/meson.build @@ -55,4 +55,5 @@ backend_sources += files( 'variable.c', 'view.c', 'wait.c', + 'xmlschemacmds.c', ) diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index 4160f5b6855..83c6cdd9bb3 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -92,6 +92,7 @@ SecLabelSupportsObjectType(ObjectType objtype) case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: case OBJECT_USER_MAPPING: + case OBJECT_XMLSCHEMA: return false; /* diff --git a/src/backend/commands/xmlschemacmds.c b/src/backend/commands/xmlschemacmds.c new file mode 100644 index 00000000000..c400e35aefb --- /dev/null +++ b/src/backend/commands/xmlschemacmds.c @@ -0,0 +1,146 @@ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/table.h" +#include "catalog/namespace.h" +#include "catalog/objectaccess.h" +#include "catalog/pg_xmlschema.h" +#include "catalog/pg_namespace.h" +#include "commands/xmlschemacmds.h" +#include "commands/defrem.h" +#include "executor/executor.h" +#include "miscadmin.h" +#include "nodes/nodeFuncs.h" +#include "parser/parse_coerce.h" +#include "parser/parse_collate.h" +#include "parser/parse_expr.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" +#include "utils/xml.h" + + +/* + * CREATE XMLSCHEMA + */ +ObjectAddress +DefineXmlSchema(ParseState *pstate, List *names, List *parameters, bool if_not_exists) +{ + char *schemaName; + Oid schemaNamespace; + AclResult aclresult; + ListCell *pl; + DefElem *schemaDataEl = NULL; + xmltype *schemaData; + Oid newoid; + ObjectAddress address; + + schemaNamespace = QualifiedNameGetCreationNamespace(names, &schemaName); + + aclresult = object_aclcheck(NamespaceRelationId, schemaNamespace, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, OBJECT_SCHEMA, + get_namespace_name(schemaNamespace)); + + /* Parse parameters */ + foreach(pl, parameters) + { + DefElem *defel = lfirst_node(DefElem, pl); + DefElem **defelp; + + if (strcmp(defel->defname, "schema") == 0) + defelp = &schemaDataEl; + else + { + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("XML schema attribute \"%s\" not recognized", + defel->defname), + parser_errposition(pstate, defel->location))); + break; + } + if (*defelp != NULL) + errorConflictingDefElem(defel, pstate); + *defelp = defel; + } + + if (!schemaDataEl) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("parameter \"schema\" must be specified"))); + + if (IsA(schemaDataEl->arg, String)) + { + schemaData = (xmltype *) cstring_to_text(defGetString(schemaDataEl)); + } + else + { + Node *expr = schemaDataEl->arg; + EState *estate; + ExprState *exprstate; + Datum val; + bool isnull; + ExprContext *econtext; + Oid resulttype; + + expr = transformExpr(pstate, expr, EXPR_KIND_OTHER); + + resulttype = exprType(expr); + if (resulttype != XMLOID) + { + expr = coerce_to_target_type(pstate, expr, resulttype, + XMLOID, -1, + COERCION_ASSIGNMENT, + COERCE_IMPLICIT_CAST, + -1); + if (expr == NULL) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("XML schema expression must be type xml, not type %s", + format_type_be(resulttype)))); + } + + assign_expr_collations(pstate, expr); + + estate = CreateExecutorState(); + exprstate = ExecPrepareExpr((Expr *) expr, estate); + econtext = GetPerTupleExprContext(estate); + + val = ExecEvalExpr(exprstate, econtext, &isnull); + + if (isnull) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + errmsg("XML schema expression must not be null"))); + + schemaData = (xmltype *) DatumGetPointer(val); + + FreeExecutorState(estate); + } + + newoid = XmlSchemaCreate(schemaName, + schemaNamespace, + GetUserId(), + schemaData, + if_not_exists, + false); + + if (!OidIsValid(newoid)) + { + /* + * When IF NOT EXISTS was specified and the object already existed, + * XmlSchemaCreate returned InvalidOid. Report an invalid object + * address. + */ + address.classId = XmlSchemaRelationId; + address.objectId = InvalidOid; + address.objectSubId = 0; + return address; + } + + ObjectAddressSet(address, XmlSchemaRelationId, newoid); + + return address; +} diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 713ee5c10a2..cb750ede7f9 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -707,7 +707,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); */ /* ordinary key words in alphabetical order */ -%token ABORT_P ABSENT ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER +%token ABORT_P ABSENT ABSOLUTE_P ACCESS ACCORDING ACTION ADD_P ADMIN AFTER AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC ASENSITIVE ASSERTION ASSIGNMENT ASYMMETRIC ATOMIC AT ATTACH ATTRIBUTE AUTHORIZATION @@ -728,7 +728,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP - EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P ERROR_P + EACH ELSE ELEMENT EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENFORCED ENUM_P ERROR_P ESCAPE EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION EXTENSION EXTERNAL EXTRACT @@ -798,7 +798,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); WAIT WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLNAMESPACES - XMLPARSE XMLPI XMLROOT XMLSERIALIZE XMLTABLE + XMLPARSE XMLPI XMLROOT XMLSCHEMA XMLSERIALIZE XMLTABLE XMLVALIDATE YEAR_P YES_P @@ -6654,6 +6654,27 @@ DefineStmt: n->if_not_exists = true; $$ = (Node *) n; } + | CREATE XMLSCHEMA any_name AS a_expr + { + DefineStmt *n = makeNode(DefineStmt); + + n->kind = OBJECT_XMLSCHEMA; + n->args = NIL; + n->defnames = $3; + n->definition = list_make1(makeDefElem("schema", (Node *) $5, @5)); + $$ = (Node *) n; + } + | CREATE XMLSCHEMA IF_P NOT EXISTS any_name AS a_expr + { + DefineStmt *n = makeNode(DefineStmt); + + n->kind = OBJECT_XMLSCHEMA; + n->args = NIL; + n->defnames = $6; + n->definition = list_make1(makeDefElem("schema", (Node *) $8, @8)); + n->if_not_exists = true; + $$ = (Node *) n; + } ; definition: '(' def_list ')' { $$ = $2; } @@ -7193,6 +7214,7 @@ object_type_any_name: | INDEX { $$ = OBJECT_INDEX; } | FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; } | COLLATION { $$ = OBJECT_COLLATION; } + | XMLSCHEMA { $$ = OBJECT_XMLSCHEMA; } | CONVERSION_P { $$ = OBJECT_CONVERSION; } | STATISTICS { $$ = OBJECT_STATISTIC_EXT; } | TEXT_P SEARCH PARSER { $$ = OBJECT_TSPARSER; } @@ -8107,6 +8129,15 @@ privilege_target: n->objs = $2; $$ = n; } + | XMLSCHEMA any_name_list + { + PrivTarget *n = palloc_object(PrivTarget); + + n->targtype = ACL_TARGET_OBJECT; + n->objtype = OBJECT_XMLSCHEMA; + n->objs = $2; + $$ = n; + } | ALL TABLES IN_P SCHEMA name_list { PrivTarget *n = palloc_object(PrivTarget); @@ -9573,6 +9604,16 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name n->missing_ok = false; $$ = (Node *) n; } + | ALTER XMLSCHEMA any_name RENAME TO name + { + RenameStmt *n = makeNode(RenameStmt); + + n->renameType = OBJECT_XMLSCHEMA; + n->object = (Node *) $3; + n->newname = $6; + n->missing_ok = false; + $$ = (Node *) n; + } | ALTER CONVERSION_P any_name RENAME TO name { RenameStmt *n = makeNode(RenameStmt); @@ -10250,6 +10291,16 @@ AlterObjectSchemaStmt: n->missing_ok = false; $$ = (Node *) n; } + | ALTER XMLSCHEMA any_name SET SCHEMA name + { + AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); + + n->objectType = OBJECT_XMLSCHEMA; + n->object = (Node *) $3; + n->newschema = $6; + n->missing_ok = false; + $$ = (Node *) n; + } | ALTER CONVERSION_P any_name SET SCHEMA name { AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt); @@ -10583,6 +10634,15 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec n->newowner = $6; $$ = (Node *) n; } + | ALTER XMLSCHEMA any_name OWNER TO RoleSpec + { + AlterOwnerStmt *n = makeNode(AlterOwnerStmt); + + n->objectType = OBJECT_XMLSCHEMA; + n->object = (Node *) $3; + n->newowner = $6; + $$ = (Node *) n; + } | ALTER CONVERSION_P any_name OWNER TO RoleSpec { AlterOwnerStmt *n = makeNode(AlterOwnerStmt); @@ -16288,6 +16348,17 @@ func_expr_common_subexpr: n->location = @1; $$ = (Node *) n; } + | XMLVALIDATE '(' DOCUMENT_P a_expr ACCORDING TO XMLSCHEMA any_name ')' + { + XmlExpr *x = (XmlExpr *) + makeXmlExpr(IS_XMLVALIDATE, NULL, $8, + list_make1($4), + @1); + + x->xmloption = XMLOPTION_DOCUMENT; + x->location = @1; + $$ = (Node *) x; + } | JSON_OBJECT '(' func_arg_list ')' { /* Support for legacy (non-standard) json_object() */ @@ -17898,6 +17969,7 @@ unreserved_keyword: | ABSENT | ABSOLUTE_P | ACCESS + | ACCORDING | ACTION | ADD_P | ADMIN @@ -18227,6 +18299,7 @@ unreserved_keyword: | WRAPPER | WRITE | XML_P + | XMLSCHEMA | YEAR_P | YES_P | ZONE @@ -18306,6 +18379,7 @@ col_name_keyword: | XMLROOT | XMLSERIALIZE | XMLTABLE + | XMLVALIDATE ; /* Type/function identifier --- keywords that can be type or function names. @@ -18445,6 +18519,7 @@ bare_label_keyword: | ABSENT | ABSOLUTE_P | ACCESS + | ACCORDING | ACTION | ADD_P | ADMIN @@ -18896,8 +18971,10 @@ bare_label_keyword: | XMLPARSE | XMLPI | XMLROOT + | XMLSCHEMA | XMLSERIALIZE | XMLTABLE + | XMLVALIDATE | YES_P | ZONE ; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 34dd6e18df5..60e0a0f7e7c 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -57,6 +57,7 @@ #include "commands/vacuum.h" #include "commands/view.h" #include "commands/wait.h" +#include "commands/xmlschemacmds.h" #include "miscadmin.h" #include "parser/parse_utilcmd.h" #include "postmaster/bgwriter.h" @@ -1443,6 +1444,13 @@ ProcessUtilitySlow(ParseState *pstate, stmt->definition, stmt->if_not_exists); break; + case OBJECT_XMLSCHEMA: + Assert(stmt->args == NIL); + address = DefineXmlSchema(pstate, + stmt->defnames, + stmt->definition, + stmt->if_not_exists); + break; default: elog(ERROR, "unrecognized define stmt type: %d", (int) stmt->kind); @@ -2238,6 +2246,9 @@ AlterObjectTypeCommandTag(ObjectType objtype) case OBJECT_COLLATION: tag = CMDTAG_ALTER_COLLATION; break; + case OBJECT_XMLSCHEMA: + tag = CMDTAG_ALTER_XMLSCHEMA; + break; case OBJECT_COLUMN: tag = CMDTAG_ALTER_TABLE; break; @@ -2575,6 +2586,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_COLLATION: tag = CMDTAG_DROP_COLLATION; break; + case OBJECT_XMLSCHEMA: + tag = CMDTAG_DROP_XMLSCHEMA; + break; case OBJECT_CONVERSION: tag = CMDTAG_DROP_CONVERSION; break; @@ -2776,6 +2790,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_COLLATION: tag = CMDTAG_CREATE_COLLATION; break; + case OBJECT_XMLSCHEMA: + tag = CMDTAG_CREATE_XMLSCHEMA; + break; case OBJECT_ACCESS_METHOD: tag = CMDTAG_CREATE_ACCESS_METHOD; break; diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 3a6905f9546..412a0450430 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -867,6 +867,10 @@ acldefault(ObjectType objtype, Oid ownerId) world_default = ACL_NO_RIGHTS; owner_default = ACL_ALL_RIGHTS_PARAMETER_ACL; break; + case OBJECT_XMLSCHEMA: + world_default = ACL_NO_RIGHTS; + owner_default = ACL_ALL_RIGHTS_XMLSCHEMA; + break; default: elog(ERROR, "unrecognized object type: %d", (int) objtype); world_default = ACL_NO_RIGHTS; /* keep compiler quiet */ diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 033b625f3fc..1c400e8dcbd 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -10119,17 +10119,20 @@ get_rule_expr(Node *node, deparse_context *context, case IS_XMLSERIALIZE: appendStringInfoString(buf, "XMLSERIALIZE("); break; + case IS_XMLVALIDATE: + appendStringInfoString(buf, "XMLVALIDATE("); + break; case IS_DOCUMENT: break; } - if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE) + if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE || xexpr->op == IS_XMLVALIDATE) { if (xexpr->xmloption == XMLOPTION_DOCUMENT) appendStringInfoString(buf, "DOCUMENT "); else appendStringInfoString(buf, "CONTENT "); } - if (xexpr->name) + if (xexpr->name && xexpr->op != IS_XMLVALIDATE) { appendStringInfo(buf, "NAME %s", quote_identifier(map_xml_name_to_sql_identifier(xexpr->name))); @@ -10226,6 +10229,15 @@ get_rule_expr(Node *node, deparse_context *context, } } break; + case IS_XMLVALIDATE: + Assert(list_length(xexpr->args) == 2); + + get_rule_expr((Node *) linitial(xexpr->args), + context, true); + + appendStringInfoString(buf, " ACCORDING TO XMLSCHEMA "); + appendStringInfoString(buf, xexpr->name); + break; case IS_DOCUMENT: get_rule_expr_paren((Node *) xexpr->args, context, false, node); break; diff --git a/src/include/catalog/Makefile b/src/include/catalog/Makefile index c90022f7c57..dcb1d896d9f 100644 --- a/src/include/catalog/Makefile +++ b/src/include/catalog/Makefile @@ -72,6 +72,7 @@ CATALOG_HEADERS := \ pg_seclabel.h \ pg_shseclabel.h \ pg_collation.h \ + pg_xmlschema.h \ pg_parameter_acl.h \ pg_partitioned_table.h \ pg_range.h \ diff --git a/src/include/catalog/meson.build b/src/include/catalog/meson.build index b63cd584068..5846919f626 100644 --- a/src/include/catalog/meson.build +++ b/src/include/catalog/meson.build @@ -59,6 +59,7 @@ catalog_headers = [ 'pg_seclabel.h', 'pg_shseclabel.h', 'pg_collation.h', + 'pg_xmlschema.h', 'pg_parameter_acl.h', 'pg_partitioned_table.h', 'pg_range.h', diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h index 1a25973685c..a0f9585c53a 100644 --- a/src/include/catalog/namespace.h +++ b/src/include/catalog/namespace.h @@ -191,6 +191,7 @@ extern bool SearchPathMatchesCurrentEnvironment(SearchPathMatcher *path); extern Oid get_collation_oid(List *collname, bool missing_ok); extern Oid get_conversion_oid(List *conname, bool missing_ok); +extern Oid get_xmlschema_oid(List *schemaname, bool missing_ok); extern Oid FindDefaultConversionProc(int32 for_encoding, int32 to_encoding); diff --git a/src/include/catalog/pg_xmlschema.h b/src/include/catalog/pg_xmlschema.h new file mode 100644 index 00000000000..3261420f2bb --- /dev/null +++ b/src/include/catalog/pg_xmlschema.h @@ -0,0 +1,48 @@ +#ifndef PG_XMLSCHEMA_H +#define PG_XMLSCHEMA_H + +#include "catalog/genbki.h" +#include "catalog/pg_xmlschema_d.h" +#include "utils/xml.h" + +CATALOG(pg_xmlschema,6434,XmlSchemaRelationId) +{ + Oid oid; /* oid */ + NameData schemaname; /* XML schema name */ + + /* OID of namespace containing this XML schema */ + Oid schemanamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace); + + /* owner of XML schema */ + Oid schemaowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); +#ifdef CATALOG_VARLEN + /* The XSD itself */ + xml schemadata BKI_FORCE_NOT_NULL; + + /* Access privileges */ + aclitem schemaacl[1] BKI_DEFAULT(_null_); +#endif +} FormData_pg_xmlschema; + +/* ---------------- + * Form_pg_xmlschema maps to a pointer to a row with + * the format of pg_xmlschema relation. + * ---------------- + */ +typedef FormData_pg_xmlschema * Form_pg_xmlschema; + +DECLARE_TOAST(pg_xmlschema, 6435, 6436); +DECLARE_UNIQUE_INDEX(pg_xmlschema_name_nsp_index, 6437, XmlSchemaNameNspIndexId, pg_xmlschema, btree(schemaname name_ops, schemanamespace oid_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_xmlschema_oid_index, 6438, XmlSchemaOidIndexId, pg_xmlschema, btree(oid oid_ops)); + +MAKE_SYSCACHE(XMLSCHEMANAMENSP, pg_xmlschema_name_nsp_index, 8); +MAKE_SYSCACHE(XMLSCHEMAOID, pg_xmlschema_oid_index, 8); + +extern Oid XmlSchemaCreate(const char *schemaname, + Oid schemanamespace, + Oid schemaowner, + xmltype *schemadata, + bool if_not_exists, + bool quiet); + +#endif /* PG_XMLSCHEMA_H */ diff --git a/src/include/commands/xmlschemacmds.h b/src/include/commands/xmlschemacmds.h new file mode 100644 index 00000000000..302cb791f32 --- /dev/null +++ b/src/include/commands/xmlschemacmds.h @@ -0,0 +1,9 @@ +#ifndef XMLSCHEMACMDS_H +#define XMLSCHEMACMDS_H + +#include "catalog/objectaddress.h" +#include "parser/parse_node.h" + +extern ObjectAddress DefineXmlSchema(ParseState *pstate, List *names, List *parameters, bool if_not_exists); + +#endif /* XMLSCHEMACMDS_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 646d6ced763..510b79a3467 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2401,6 +2401,7 @@ typedef enum ObjectType OBJECT_TYPE, OBJECT_USER_MAPPING, OBJECT_VIEW, + OBJECT_XMLSCHEMA, } ObjectType; /* ---------------------- diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index f7753c5c8a8..4e8b5e1d7e7 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -29,6 +29,7 @@ PG_KEYWORD("abort", ABORT_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("absent", ABSENT, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("absolute", ABSOLUTE_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("access", ACCESS, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("according", ACCORDING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("action", ACTION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("add", ADD_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, BARE_LABEL) @@ -520,8 +521,10 @@ PG_KEYWORD("xmlnamespaces", XMLNAMESPACES, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlroot", XMLROOT, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlschema", XMLSCHEMA, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("xmlserialize", XMLSERIALIZE, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("xmltable", XMLTABLE, COL_NAME_KEYWORD, BARE_LABEL) +PG_KEYWORD("xmlvalidate", XMLVALIDATE, COL_NAME_KEYWORD, BARE_LABEL) PG_KEYWORD("year", YEAR_P, UNRESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("yes", YES_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("zone", ZONE, UNRESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h index 1290c9bab68..1cd35452acd 100644 --- a/src/include/tcop/cmdtaglist.h +++ b/src/include/tcop/cmdtaglist.h @@ -31,6 +31,7 @@ PG_CMDTAG(CMDTAG_ALTER_CAST, "ALTER CAST", true, false, false) PG_CMDTAG(CMDTAG_ALTER_COLLATION, "ALTER COLLATION", true, false, false) PG_CMDTAG(CMDTAG_ALTER_CONSTRAINT, "ALTER CONSTRAINT", true, false, false) PG_CMDTAG(CMDTAG_ALTER_CONVERSION, "ALTER CONVERSION", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_XMLSCHEMA, "ALTER XMLSCHEMA", true, false, false) PG_CMDTAG(CMDTAG_ALTER_DATABASE, "ALTER DATABASE", false, false, false) PG_CMDTAG(CMDTAG_ALTER_DEFAULT_PRIVILEGES, "ALTER DEFAULT PRIVILEGES", true, false, false) PG_CMDTAG(CMDTAG_ALTER_DOMAIN, "ALTER DOMAIN", true, false, false) @@ -88,6 +89,7 @@ PG_CMDTAG(CMDTAG_CREATE_CAST, "CREATE CAST", true, false, false) PG_CMDTAG(CMDTAG_CREATE_COLLATION, "CREATE COLLATION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_CONSTRAINT, "CREATE CONSTRAINT", true, false, false) PG_CMDTAG(CMDTAG_CREATE_CONVERSION, "CREATE CONVERSION", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_XMLSCHEMA, "CREATE XMLSCHEMA", true, false, false) PG_CMDTAG(CMDTAG_CREATE_DATABASE, "CREATE DATABASE", false, false, false) PG_CMDTAG(CMDTAG_CREATE_DOMAIN, "CREATE DOMAIN", true, false, false) PG_CMDTAG(CMDTAG_CREATE_EVENT_TRIGGER, "CREATE EVENT TRIGGER", false, false, false) @@ -140,6 +142,7 @@ PG_CMDTAG(CMDTAG_DROP_CAST, "DROP CAST", true, false, false) PG_CMDTAG(CMDTAG_DROP_COLLATION, "DROP COLLATION", true, false, false) PG_CMDTAG(CMDTAG_DROP_CONSTRAINT, "DROP CONSTRAINT", true, false, false) PG_CMDTAG(CMDTAG_DROP_CONVERSION, "DROP CONVERSION", true, false, false) +PG_CMDTAG(CMDTAG_DROP_XMLSCHEMA, "DROP XMLSCHEMA", true, false, false) PG_CMDTAG(CMDTAG_DROP_DATABASE, "DROP DATABASE", false, false, false) PG_CMDTAG(CMDTAG_DROP_DOMAIN, "DROP DOMAIN", true, false, false) PG_CMDTAG(CMDTAG_DROP_EVENT_TRIGGER, "DROP EVENT TRIGGER", false, false, false) diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index ec01fd581cf..e24427c9663 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -169,6 +169,7 @@ typedef struct ArrayType Acl; #define ACL_ALL_RIGHTS_SCHEMA (ACL_USAGE|ACL_CREATE) #define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE) #define ACL_ALL_RIGHTS_TYPE (ACL_USAGE) +#define ACL_ALL_RIGHTS_XMLSCHEMA (ACL_USAGE) /* operation codes for pg_*_aclmask */ typedef enum -- 2.51.2