From 31804932859aa75e050343d59628ea446e5733ea Mon Sep 17 00:00:00 2001 From: Marcos Magueta Date: Wed, 18 Feb 2026 16:13:06 -0300 Subject: [PATCH] [PATCH v6 1/2] Add CREATE XMLSCHEMA --- doc/src/sgml/datatype.sgml | 1 + doc/src/sgml/ddl.sgml | 13 +- doc/src/sgml/ref/allfiles.sgml | 3 + doc/src/sgml/ref/alter_xmlschema.sgml | 145 ++++++++++++++++++ doc/src/sgml/ref/create_xmlschema.sgml | 182 +++++++++++++++++++++++ doc/src/sgml/ref/drop_xmlschema.sgml | 120 +++++++++++++++ doc/src/sgml/ref/grant.sgml | 7 +- doc/src/sgml/ref/revoke.sgml | 7 + doc/src/sgml/reference.sgml | 3 + src/backend/catalog/Makefile | 1 + src/backend/catalog/aclchk.c | 17 +++ src/backend/catalog/dependency.c | 3 + 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 | 95 ++++++++++++ src/backend/parser/gram.y | 64 +++++++- src/backend/tcop/utility.c | 17 +++ src/backend/utils/adt/acl.c | 4 + src/bin/pg_dump/common.c | 3 + src/bin/pg_dump/pg_backup_archiver.c | 1 + src/bin/pg_dump/pg_dump.c | 128 ++++++++++++++++ src/bin/pg_dump/pg_dump.h | 8 + src/bin/pg_dump/pg_dump_sort.c | 5 + src/bin/psql/tab-complete.in.c | 22 +++ 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 | 1 + src/include/tcop/cmdtaglist.h | 3 + src/include/utils/acl.h | 1 + src/test/regress/expected/oidjoins.out | 2 + src/test/regress/expected/xml.out | 64 ++++++++ src/test/regress/expected/xml_1.out | 61 ++++++++ src/test/regress/expected/xml_2.out | 78 ++++++++++ src/test/regress/sql/xml.sql | 63 ++++++++ 46 files changed, 1536 insertions(+), 4 deletions(-) create mode 100644 doc/src/sgml/ref/alter_xmlschema.sgml create mode 100644 doc/src/sgml/ref/create_xmlschema.sgml create mode 100644 doc/src/sgml/ref/drop_xmlschema.sgml 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/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 3017c674040..f2ade57fe7d 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4649,6 +4649,7 @@ SET xmloption TO { DOCUMENT | CONTENT }; distribution. + &json; diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 9070aaa5a7c..5a2bc9ecee3 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -2486,6 +2486,9 @@ REVOKE ALL ON accounts FROM PUBLIC; dependencies on a type, which could prevent the owner from changing the type later.) + + For XML schemas, allows use of the XML schema for XML validation. + For foreign-data wrappers, allows creation of new servers using the foreign-data wrapper. @@ -2548,6 +2551,7 @@ REVOKE ALL ON accounts FROM PUBLIC; foreign data wrappers, foreign servers, large objects, + XML schemas, schemas, tablespaces, or configuration parameters. @@ -2669,7 +2673,8 @@ REVOKE ALL ON accounts FROM PUBLIC; LANGUAGE, SCHEMA, SEQUENCE, - TYPE + TYPE, + XMLSCHEMA @@ -2799,6 +2804,12 @@ REVOKE ALL ON accounts FROM PUBLIC; U \dT+ + + XMLSCHEMA + U + none + none + diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml index e167406c744..87a8e6066e4 100644 --- a/doc/src/sgml/ref/allfiles.sgml +++ b/doc/src/sgml/ref/allfiles.sgml @@ -48,6 +48,7 @@ Complete list of usable sgml source files in this directory. + @@ -100,6 +101,7 @@ Complete list of usable sgml source files in this directory. + @@ -148,6 +150,7 @@ Complete list of usable sgml source files in this directory. + diff --git a/doc/src/sgml/ref/alter_xmlschema.sgml b/doc/src/sgml/ref/alter_xmlschema.sgml new file mode 100644 index 00000000000..6a286ad00fe --- /dev/null +++ b/doc/src/sgml/ref/alter_xmlschema.sgml @@ -0,0 +1,145 @@ + + + + + ALTER XMLSCHEMA + + + + ALTER XMLSCHEMA + 7 + SQL - Language Statements + + + + ALTER XMLSCHEMA + change the definition of an XML schema + + + + +ALTER XMLSCHEMA [ IF EXISTS ] name OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER } +ALTER XMLSCHEMA [ IF EXISTS ] name RENAME TO new_name +ALTER XMLSCHEMA [ IF EXISTS ] name SET SCHEMA new_schema + + + + + Description + + + ALTER XMLSCHEMA changes the definition of an XML schema. + + + + You must own the XML schema to use ALTER XMLSCHEMA. + To change an XML schema's schema, you must also have CREATE + privilege on the new schema. + To alter the owner, you must be able to SET ROLE to the + new owning role, and that role must have CREATE + privilege on the XML schema's schema. + (These restrictions enforce that altering the owner + doesn't do anything you couldn't do by dropping and recreating the XML schema. + However, a superuser can alter ownership of any XML schema anyway.) + + + + + Parameters + + + + name + + + The name (optionally schema-qualified) of an XML schema to be altered. + + + + + + IF EXISTS + + + Do not throw an error if the XML schema does not exist. A notice is issued + in this case. + + + + + + new_owner + + + The user name of the new owner of the XML schema. + + + + + + new_name + + + The new name of the XML schema. + + + + + + new_schema + + + The new schema for the XML schema. + + + + + + + + Examples + + + To rename an XML schema: + +ALTER XMLSCHEMA person_schema RENAME TO people_schema; + + + + + To change the owner of an XML schema: + +ALTER XMLSCHEMA people_schema OWNER TO joe; + + + + + To move an XML schema to another schema: + +ALTER XMLSCHEMA people_schema SET SCHEMA myschema; + + + + + + Compatibility + + + ALTER XMLSCHEMA is a + PostgreSQL extension. + + + + + See Also + + + + + + + + diff --git a/doc/src/sgml/ref/create_xmlschema.sgml b/doc/src/sgml/ref/create_xmlschema.sgml new file mode 100644 index 00000000000..573b9b72111 --- /dev/null +++ b/doc/src/sgml/ref/create_xmlschema.sgml @@ -0,0 +1,182 @@ + + + + + CREATE XMLSCHEMA + + + + CREATE XMLSCHEMA + 7 + SQL - Language Statements + + + + CREATE XMLSCHEMA + define a new XML schema + + + + +CREATE XMLSCHEMA [ IF NOT EXISTS ] name AS schema_definition + + + + + Description + + + CREATE XMLSCHEMA defines a new XML schema in the + current database. The schema definition is an XML Schema Definition (XSD) + document that can be used to validate XML documents using the + XMLVALIDATE function. + + + + If a schema name is given then the XML schema is created in the + specified schema. Otherwise it is created in the current schema. + The XML schema name must be unique within the schema. + + + + After an XML schema is created, you use the + XMLVALIDATE function to validate XML documents + against it. + + + + + Parameters + + + + IF NOT EXISTS + + + Do not throw an error if an XML schema with the same name already exists. + A notice is issued in this case. Note that there is no guarantee that + the existing XML schema is similar to the one that would have been created. + + + + + + name + + + The name (optionally schema-qualified) of the XML schema to be created. + + + + + + schema_definition + + + An XML Schema Definition (XSD) document provided as a string literal. + The schema definition must be a valid XSD document conforming to the + W3C XML Schema standard. + + + + + + + + Notes + + + To create an XML schema, you must have CREATE privilege + on the current schema. + + + + Use DROP XMLSCHEMA to remove an XML schema. + + + + See also ALTER XMLSCHEMA + to rename an XML schema or change its owner. + + + + + Examples + + + Create an XML schema for validating person documents: + +CREATE XMLSCHEMA person_schema AS '<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="person"> + <xs:complexType> + <xs:sequence> + <xs:element name="name" type="xs:string"/> + <xs:element name="age" type="xs:integer"/> + </xs:sequence> + </xs:complexType> + </xs:element> +</xs:schema>'; + + + + + Create an XML schema with a schema-qualified name: + +CREATE SCHEMA myschema; +CREATE XMLSCHEMA myschema.product_schema AS '<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="product"> + <xs:complexType> + <xs:sequence> + <xs:element name="name" type="xs:string"/> + <xs:element name="price" type="xs:decimal"/> + </xs:sequence> + <xs:attribute name="id" type="xs:string" use="required"/> + </xs:complexType> + </xs:element> +</xs:schema>'; + + + + + Create an XML schema only if it doesn't already exist: + +CREATE XMLSCHEMA IF NOT EXISTS person_schema AS '...'; + + + + + Validate an XML document against the schema: + +SELECT XMLVALIDATE( + DOCUMENT '<person><name>John</name><age>30</age></person>' + ACCORDING TO XMLSCHEMA person_schema +); + + + + + + Compatibility + + + CREATE XMLSCHEMA is a + PostgreSQL extension. There is no + CREATE XMLSCHEMA statement in the SQL standard. + + + + + See Also + + + + + + + + diff --git a/doc/src/sgml/ref/drop_xmlschema.sgml b/doc/src/sgml/ref/drop_xmlschema.sgml new file mode 100644 index 00000000000..4204f9bc413 --- /dev/null +++ b/doc/src/sgml/ref/drop_xmlschema.sgml @@ -0,0 +1,120 @@ + + + + + DROP XMLSCHEMA + + + + DROP XMLSCHEMA + 7 + SQL - Language Statements + + + + DROP XMLSCHEMA + remove an XML schema + + + + +DROP XMLSCHEMA [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ] + + + + + Description + + + DROP XMLSCHEMA removes XML schemas from the database. + An XML schema can only be dropped by its owner or a superuser. + + + + + Parameters + + + + IF EXISTS + + + Do not throw an error if the XML schema does not exist. A notice is issued + in this case. + + + + + + name + + + The name (optionally schema-qualified) of an XML schema. + + + + + + CASCADE + + + Automatically drop objects that depend on the XML schema, + and in turn all objects that depend on those objects + (see ). + + + + + + RESTRICT + + + Refuse to drop the XML schema if any objects depend on it. This + is the default. + + + + + + + + Examples + + + To remove the XML schema person_schema: + +DROP XMLSCHEMA person_schema; + + + + + To remove an XML schema and all dependent objects: + +DROP XMLSCHEMA person_schema CASCADE; + + + + + + Compatibility + + + DROP XMLSCHEMA is a + PostgreSQL extension. There is no + DROP XMLSCHEMA statement in the SQL standard. + + + + + See Also + + + + + + + + diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index 043f5d5a40a..28345bc2215 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -97,6 +97,11 @@ GRANT { USAGE | ALL [ PRIVILEGES ] } TO role_specification [, ...] [ WITH GRANT OPTION ] [ GRANTED BY role_specification ] +GRANT { USAGE | ALL [ PRIVILEGES ] } + ON XMLSCHEMA xmlschema_name [, ...] + TO role_specification [, ...] [ WITH GRANT OPTION ] + [ GRANTED BY role_specification ] + GRANT role_name [, ...] TO role_specification [, ...] [ WITH { ADMIN | INHERIT | SET } { OPTION | TRUE | FALSE } ] [ GRANTED BY role_specification ] @@ -119,7 +124,7 @@ GRANT role_name [, ...] TO diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index 8df492281a1..3c8f81639d0 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -125,6 +125,13 @@ REVOKE [ GRANT OPTION FOR ] [ GRANTED BY role_specification ] [ CASCADE | RESTRICT ] +REVOKE [ GRANT OPTION FOR ] + { USAGE | ALL [ PRIVILEGES ] } + ON XMLSCHEMA xmlschema_name [, ...] + FROM role_specification [, ...] + [ GRANTED BY role_specification ] + [ CASCADE | RESTRICT ] + REVOKE [ { ADMIN | INHERIT | SET } OPTION FOR ] role_name [, ...] FROM role_specification [, ...] [ GRANTED BY role_specification ] diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml index 2cf02c37b17..982bbea3a27 100644 --- a/doc/src/sgml/reference.sgml +++ b/doc/src/sgml/reference.sgml @@ -76,6 +76,7 @@ &alterUser; &alterUserMapping; &alterView; + &alterXmlSchema; &analyze; &begin; &call; @@ -128,6 +129,7 @@ &createUser; &createUserMapping; &createView; + &createXmlSchema; &deallocate; &declare; &delete; @@ -176,6 +178,7 @@ &dropUser; &dropUserMapping; &dropView; + &dropXmlSchema; &end; &execute; &explain; 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 aef855abccc..fbc96176df5 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 7564965fa18..ddb60523d52 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; 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 4b0f4ba115d..00ee124cfd9 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" @@ -4144,6 +4145,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 13d73f8909c..3f4c155e93b 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" @@ -188,6 +189,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, @@ -721,6 +736,9 @@ static const struct object_type_map { "collation", OBJECT_COLLATION }, + { + "xmlschema", OBJECT_XMLSCHEMA + }, { "table constraint", OBJECT_TABCONSTRAINT }, @@ -1030,6 +1048,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); @@ -2283,6 +2306,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: @@ -2461,6 +2485,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: @@ -4068,6 +4093,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); } @@ -4670,6 +4723,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); } @@ -6020,6 +6077,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 c6f58d47be6..a451acde215 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" @@ -134,6 +135,10 @@ report_namespace_conflict(Oid classId, const char *name, Oid nspOid) case TSConfigRelationId: 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; @@ -417,6 +422,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: @@ -561,6 +567,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: @@ -871,6 +878,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 5b80396723c..54c91ecf9a8 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..43b1a56a10c --- /dev/null +++ b/src/backend/commands/xmlschemacmds.c @@ -0,0 +1,95 @@ +#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 "miscadmin.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"))); + + /* The schema definition is passed as a String node from the grammar */ + schemaData = (xmltype *) cstring_to_text(defGetString(schemaDataEl)); + + 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 c567252acc4..e56b0c0c84c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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 YEAR_P YES_P @@ -6654,6 +6654,27 @@ DefineStmt: n->if_not_exists = true; $$ = (Node *) n; } + | CREATE XMLSCHEMA any_name AS Sconst + { + DefineStmt *n = makeNode(DefineStmt); + + n->kind = OBJECT_XMLSCHEMA; + n->args = NIL; + n->defnames = $3; + n->definition = list_make1(makeDefElem("schema", (Node *) makeString($5), @5)); + $$ = (Node *) n; + } + | CREATE XMLSCHEMA IF_P NOT EXISTS any_name AS Sconst + { + DefineStmt *n = makeNode(DefineStmt); + + n->kind = OBJECT_XMLSCHEMA; + n->args = NIL; + n->defnames = $6; + n->definition = list_make1(makeDefElem("schema", (Node *) makeString($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); @@ -18245,6 +18305,7 @@ unreserved_keyword: | WRAPPER | WRITE | XML_P + | XMLSCHEMA | YEAR_P | YES_P | ZONE @@ -18914,6 +18975,7 @@ bare_label_keyword: | XMLPARSE | XMLPI | XMLROOT + | XMLSCHEMA | XMLSERIALIZE | XMLTABLE | YES_P 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 641673f0b0e..c6eb6418dbb 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -868,6 +868,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/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 349b47c8e29..651cf674365 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -182,6 +182,9 @@ getSchemaData(Archive *fout, int *numTablesPtr) pg_log_info("reading user-defined conversions"); getConversions(fout); + pg_log_info("reading XML schemas"); + getXmlSchemas(fout); + pg_log_info("reading type casts"); getCasts(fout); diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 7afcc0859c8..1ea5b365ab4 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -3812,6 +3812,7 @@ _getObjectDescription(PQExpBuffer buf, const TocEntry *te) strcmp(type, "TEXT SEARCH CONFIGURATION") == 0 || strcmp(type, "TYPE") == 0 || strcmp(type, "VIEW") == 0 || + strcmp(type, "XMLSCHEMA") == 0 || /* non-schema-specified objects */ strcmp(type, "DATABASE") == 0 || strcmp(type, "PROCEDURAL LANGUAGE") == 0 || diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 49598304335..786f7d4f33e 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -305,6 +305,7 @@ static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo); static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo); static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo); static void dumpCollation(Archive *fout, const CollInfo *collinfo); +static void dumpXmlSchema(Archive *fout, const XmlSchemaInfo * xmlschemainfo); static void dumpConversion(Archive *fout, const ConvInfo *convinfo); static void dumpRule(Archive *fout, const RuleInfo *rinfo); static void dumpAgg(Archive *fout, const AggInfo *agginfo); @@ -6551,6 +6552,62 @@ getConversions(Archive *fout) destroyPQExpBuffer(query); } +/* + * getXmlSchemas: + * get information about all XML schemas in the system catalogs + */ +void +getXmlSchemas(Archive *fout) +{ + PGresult *res; + int ntups; + int i; + PQExpBuffer query; + XmlSchemaInfo *xmlschemainfo; + int i_tableoid; + int i_oid; + int i_schemaname; + int i_schemanamespace; + int i_schemaowner; + + query = createPQExpBuffer(); + + appendPQExpBufferStr(query, "SELECT tableoid, oid, schemaname, " + "schemanamespace, " + "schemaowner " + "FROM pg_xmlschema"); + + res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + + ntups = PQntuples(res); + + xmlschemainfo = (XmlSchemaInfo *) pg_malloc(ntups * sizeof(XmlSchemaInfo)); + + i_tableoid = PQfnumber(res, "tableoid"); + i_oid = PQfnumber(res, "oid"); + i_schemaname = PQfnumber(res, "schemaname"); + i_schemanamespace = PQfnumber(res, "schemanamespace"); + i_schemaowner = PQfnumber(res, "schemaowner"); + + for (i = 0; i < ntups; i++) + { + xmlschemainfo[i].dobj.objType = DO_XMLSCHEMA; + xmlschemainfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid)); + xmlschemainfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid)); + AssignDumpId(&xmlschemainfo[i].dobj); + xmlschemainfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_schemaname)); + xmlschemainfo[i].dobj.namespace = + findNamespace(atooid(PQgetvalue(res, i, i_schemanamespace))); + xmlschemainfo[i].rolname = getRoleName(PQgetvalue(res, i, i_schemaowner)); + + selectDumpableObject(&(xmlschemainfo[i].dobj), fout); + } + + PQclear(res); + + destroyPQExpBuffer(query); +} + /* * getAccessMethods: * get information about all user-defined access methods @@ -11712,6 +11769,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj) case DO_CONVERSION: dumpConversion(fout, (const ConvInfo *) dobj); break; + case DO_XMLSCHEMA: + dumpXmlSchema(fout, (const XmlSchemaInfo *) dobj); + break; case DO_TABLE: dumpTable(fout, (const TableInfo *) dobj); break; @@ -15238,6 +15298,73 @@ dumpCollation(Archive *fout, const CollInfo *collinfo) free(qcollname); } +/* + * dumpXmlSchema + * write out a single XML schema definition + */ +static void +dumpXmlSchema(Archive *fout, const XmlSchemaInfo * xmlschemainfo) +{ + DumpOptions *dopt = fout->dopt; + PQExpBuffer query; + PQExpBuffer q; + PQExpBuffer delq; + char *qxmlschemaname; + PGresult *res; + int i_schemadata; + char *schemadata; + + if (!dopt->dumpSchema) + return; + + query = createPQExpBuffer(); + q = createPQExpBuffer(); + delq = createPQExpBuffer(); + + qxmlschemaname = pg_strdup(fmtId(xmlschemainfo->dobj.name)); + + appendPQExpBuffer(query, + "SELECT schemadata " + "FROM pg_catalog.pg_xmlschema " + "WHERE oid = '%u'::pg_catalog.oid", + xmlschemainfo->dobj.catId.oid); + + res = ExecuteSqlQueryForSingleRow(fout, query->data); + + i_schemadata = PQfnumber(res, "schemadata"); + schemadata = PQgetvalue(res, 0, i_schemadata); + + appendPQExpBuffer(delq, "DROP XMLSCHEMA %s;\n", + fmtQualifiedDumpable(xmlschemainfo)); + + appendPQExpBuffer(q, "CREATE XMLSCHEMA %s AS ", + fmtQualifiedDumpable(xmlschemainfo)); + appendStringLiteralAH(q, schemadata, fout); + appendPQExpBufferStr(q, ";\n"); + + if (xmlschemainfo->dobj.dump & DUMP_COMPONENT_DEFINITION) + ArchiveEntry(fout, xmlschemainfo->dobj.catId, xmlschemainfo->dobj.dumpId, + ARCHIVE_OPTS(.tag = xmlschemainfo->dobj.name, + .namespace = xmlschemainfo->dobj.namespace->dobj.name, + .owner = xmlschemainfo->rolname, + .description = "XMLSCHEMA", + .section = SECTION_PRE_DATA, + .createStmt = q->data, + .dropStmt = delq->data)); + + if (xmlschemainfo->dobj.dump & DUMP_COMPONENT_COMMENT) + dumpComment(fout, "XMLSCHEMA", qxmlschemaname, + xmlschemainfo->dobj.namespace->dobj.name, xmlschemainfo->rolname, + xmlschemainfo->dobj.catId, 0, xmlschemainfo->dobj.dumpId); + + PQclear(res); + + destroyPQExpBuffer(query); + destroyPQExpBuffer(q); + destroyPQExpBuffer(delq); + free(qxmlschemaname); +} + /* * dumpConversion * write out a single conversion definition @@ -20408,6 +20535,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, case DO_OPFAMILY: case DO_COLLATION: case DO_CONVERSION: + case DO_XMLSCHEMA: case DO_TABLE: case DO_TABLE_ATTACH: case DO_ATTRDEF: diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 4c4b14e5fc7..bc1cf5a00d2 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -50,6 +50,7 @@ typedef enum DO_OPFAMILY, DO_COLLATION, DO_CONVERSION, + DO_XMLSCHEMA, DO_TABLE, DO_TABLE_ATTACH, DO_ATTRDEF, @@ -299,6 +300,12 @@ typedef struct _convInfo const char *rolname; } ConvInfo; +typedef struct _xmlSchemaInfo +{ + DumpableObject dobj; + const char *rolname; +} XmlSchemaInfo; + typedef struct _tableInfo { /* @@ -797,6 +804,7 @@ extern void getOpclasses(Archive *fout); extern void getOpfamilies(Archive *fout); extern void getCollations(Archive *fout); extern void getConversions(Archive *fout); +extern void getXmlSchemas(Archive *fout); extern TableInfo *getTables(Archive *fout, int *numTables); extern void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables); extern InhInfo *getInherits(Archive *fout, int *numInherits); diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index 03e5c1c1116..0ec7dd33ac3 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -1575,6 +1575,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize) "CONVERSION %s (ID %d OID %u)", obj->name, obj->dumpId, obj->catId.oid); return; + case DO_XMLSCHEMA: + snprintf(buf, bufsize, + "XMLSCHEMA %s (ID %d OID %u)", + obj->name, obj->dumpId, obj->catId.oid); + return; case DO_TABLE: snprintf(buf, bufsize, "TABLE %s (ID %d OID %u)", diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 8b91bc00062..6c51cd6c9be 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -797,6 +797,13 @@ static const SchemaQuery Query_for_list_of_matviews = { .result = "c.relname", }; +static const SchemaQuery Query_for_list_of_xmlschemas = { + .catname = "pg_catalog.pg_xmlschema s", + .viscondition = "EXISTS (SELECT 1 FROM pg_catalog.pg_namespace n WHERE n.oid = s.schemanamespace AND n.nspname = ANY(pg_catalog.current_schemas(true)))", + .namespace = "s.schemanamespace", + .result = "s.schemaname", +}; + static const SchemaQuery Query_for_list_of_indexes = { .catname = "pg_catalog.pg_class c", .selcondition = @@ -1364,6 +1371,7 @@ static const pgsql_thing_t words_after_create[] = { {"USER", Query_for_list_of_roles, NULL, NULL, Keywords_for_user_thing}, {"USER MAPPING FOR", NULL, NULL, NULL}, {"VIEW", NULL, NULL, &Query_for_list_of_views}, + {"XMLSCHEMA", NULL, NULL, &Query_for_list_of_xmlschemas}, {NULL} /* end of list */ }; @@ -2701,6 +2709,10 @@ match_previous_words(int pattern_id, else if (Matches("ALTER", "MATERIALIZED", "VIEW", MatchAny, "SET", "ACCESS", "METHOD")) COMPLETE_WITH_QUERY(Query_for_list_of_table_access_methods); + /* ALTER XMLSCHEMA */ + else if (Matches("ALTER", "XMLSCHEMA", MatchAny)) + COMPLETE_WITH("OWNER TO", "RENAME TO", "SET SCHEMA"); + /* ALTER POLICY */ else if (Matches("ALTER", "POLICY")) COMPLETE_WITH_QUERY(Query_for_list_of_policies); @@ -4178,6 +4190,16 @@ match_previous_words(int pattern_id, Matches("CREATE", "MATERIALIZED", "VIEW", MatchAny, "USING", MatchAny, "AS")) COMPLETE_WITH("SELECT"); +/* CREATE XMLSCHEMA */ + else if (Matches("CREATE", "XMLSCHEMA", MatchAny)) + COMPLETE_WITH("AS", "IF"); + else if (Matches("CREATE", "XMLSCHEMA", "IF")) + COMPLETE_WITH("NOT"); + else if (Matches("CREATE", "XMLSCHEMA", "IF", "NOT")) + COMPLETE_WITH("EXISTS"); + else if (Matches("CREATE", "XMLSCHEMA", "IF", "NOT", "EXISTS", MatchAny)) + COMPLETE_WITH("AS"); + /* CREATE EVENT TRIGGER */ else if (Matches("CREATE", "EVENT")) COMPLETE_WITH("TRIGGER"); diff --git a/src/include/catalog/Makefile b/src/include/catalog/Makefile index 24b527230d4..7361dc6cd3f 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 433bcc908ad..1fdc6ac4e00 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 0aec49bdd22..b9f0476596e 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2403,6 +2403,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..a018c2b9e08 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -520,6 +520,7 @@ 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("year", YEAR_P, UNRESERVED_KEYWORD, AS_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 diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index 25aaae8d05a..246deabd17b 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -239,6 +239,8 @@ NOTICE: checking pg_seclabel {classoid} => pg_class {oid} NOTICE: checking pg_shseclabel {classoid} => pg_class {oid} NOTICE: checking pg_collation {collnamespace} => pg_namespace {oid} NOTICE: checking pg_collation {collowner} => pg_authid {oid} +NOTICE: checking pg_xmlschema {schemanamespace} => pg_namespace {oid} +NOTICE: checking pg_xmlschema {schemaowner} => pg_authid {oid} NOTICE: checking pg_partitioned_table {partrelid} => pg_class {oid} NOTICE: checking pg_partitioned_table {partdefid} => pg_class {oid} NOTICE: checking pg_partitioned_table {partclass} => pg_opclass {oid} diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index 103a22a3b1d..4e24657d2d3 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -1881,3 +1881,67 @@ SELECT xmltext('x'|| '

73

'::xml || .42 || true || 'j'::char); x<P>73</P>0.42truej (1 row) +CREATE XMLSCHEMA person_schema AS ' + + + + + + + + + +'; +CREATE XMLSCHEMA IF NOT EXISTS person_schema AS ' + + +'; +NOTICE: XML schema "person_schema" already exists, skipping +CREATE XMLSCHEMA person_schema AS ' + + +'; +ERROR: XML schema "person_schema" already exists +CREATE SCHEMA test_xmlschema_ns; +CREATE XMLSCHEMA test_xmlschema_ns.product_schema AS ' + + + + + + + + + + +'; +CREATE XMLSCHEMA bad_schema AS ''; +ERROR: invalid XML schema definition +DETAIL: line 1: Premature end of data in tag this-is-not-valid-xsd line 1 + + ^ +CREATE XMLSCHEMA bad_xml_schema AS 'not even xml'; +ERROR: invalid XML schema definition +DETAIL: line 1: Start tag expected, '<' not found +not even xml +^ +CREATE XMLSCHEMA book_schema AS ' + + + + + + + + + + + + + + + + + + +'; diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index 73c411118a3..aded57c78b2 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -1496,3 +1496,64 @@ ERROR: unsupported XML feature LINE 1: SELECT xmltext('x'|| '

73

'::xml || .42 || true || 'j':... ^ DETAIL: This functionality requires the server to be built with libxml support. +CREATE XMLSCHEMA person_schema AS ' + + + + + + + + + +'; +ERROR: xmlschema support requires libxml +CREATE XMLSCHEMA IF NOT EXISTS person_schema AS ' + + +'; +ERROR: xmlschema support requires libxml +CREATE XMLSCHEMA person_schema AS ' + + +'; +ERROR: xmlschema support requires libxml +CREATE SCHEMA test_xmlschema_ns; +CREATE XMLSCHEMA test_xmlschema_ns.product_schema AS ' + + + + + + + + + + +'; +ERROR: xmlschema support requires libxml +CREATE XMLSCHEMA bad_schema AS ''; +ERROR: xmlschema support requires libxml +CREATE XMLSCHEMA bad_xml_schema AS 'not even xml'; +ERROR: xmlschema support requires libxml +CREATE XMLSCHEMA book_schema AS ' + + + + + + + + + + + + + + + + + + +'; +ERROR: xmlschema support requires libxml diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out index a85d95358d9..4e24657d2d3 100644 --- a/src/test/regress/expected/xml_2.out +++ b/src/test/regress/expected/xml_2.out @@ -9,6 +9,8 @@ ERROR: invalid XML content LINE 1: INSERT INTO xmltest VALUES (3, '', NULL, ''); xmlconcat -------------- @@ -273,6 +277,8 @@ DETAIL: line 1: Entity 'idontexist' not defined &idontexist; ^ line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced +&idontexist; + ^ SELECT xmlparse(content ''); xmlparse --------------------- @@ -282,6 +288,8 @@ SELECT xmlparse(content ''); SELECT xmlparse(document ' '); ERROR: invalid XML document DETAIL: line 1: Start tag expected, '<' not found + + ^ SELECT xmlparse(document 'abc'); ERROR: invalid XML document DETAIL: line 1: Start tag expected, '<' not found @@ -299,12 +307,16 @@ DETAIL: line 1: xmlParseEntityRef: no name & ^ line 1: Opening and ending tag mismatch: invalidentity line 1 and abc +& + ^ SELECT xmlparse(document '&idontexist;'); ERROR: invalid XML document DETAIL: line 1: Entity 'idontexist' not defined &idontexist; ^ line 1: Opening and ending tag mismatch: undefinedentity line 1 and abc +&idontexist; + ^ SELECT xmlparse(document ''); xmlparse --------------------------- @@ -323,6 +335,8 @@ DETAIL: line 1: Entity 'idontexist' not defined &idontexist; ^ line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced +&idontexist; + ^ SELECT xmlparse(document ''); xmlparse --------------------- @@ -1867,3 +1881,67 @@ SELECT xmltext('x'|| '

73

'::xml || .42 || true || 'j'::char); x<P>73</P>0.42truej (1 row) +CREATE XMLSCHEMA person_schema AS ' + + + + + + + + + +'; +CREATE XMLSCHEMA IF NOT EXISTS person_schema AS ' + + +'; +NOTICE: XML schema "person_schema" already exists, skipping +CREATE XMLSCHEMA person_schema AS ' + + +'; +ERROR: XML schema "person_schema" already exists +CREATE SCHEMA test_xmlschema_ns; +CREATE XMLSCHEMA test_xmlschema_ns.product_schema AS ' + + + + + + + + + + +'; +CREATE XMLSCHEMA bad_schema AS ''; +ERROR: invalid XML schema definition +DETAIL: line 1: Premature end of data in tag this-is-not-valid-xsd line 1 + + ^ +CREATE XMLSCHEMA bad_xml_schema AS 'not even xml'; +ERROR: invalid XML schema definition +DETAIL: line 1: Start tag expected, '<' not found +not even xml +^ +CREATE XMLSCHEMA book_schema AS ' + + + + + + + + + + + + + + + + + + +'; diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 0ea4f508837..667973420fa 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -679,3 +679,66 @@ SELECT xmltext(' '); SELECT xmltext('foo `$_-+?=*^%!|/\()[]{}'); SELECT xmltext('foo & <"bar">'); SELECT xmltext('x'|| '

73

'::xml || .42 || true || 'j'::char); + +CREATE XMLSCHEMA person_schema AS ' + + + + + + + + + +'; + + +CREATE XMLSCHEMA IF NOT EXISTS person_schema AS ' + + +'; + +CREATE XMLSCHEMA person_schema AS ' + + +'; + +CREATE SCHEMA test_xmlschema_ns; + +CREATE XMLSCHEMA test_xmlschema_ns.product_schema AS ' + + + + + + + + + + +'; + +CREATE XMLSCHEMA bad_schema AS ''; + +CREATE XMLSCHEMA bad_xml_schema AS 'not even xml'; + +CREATE XMLSCHEMA book_schema AS ' + + + + + + + + + + + + + + + + + + +'; -- 2.52.0