From fb82ea3290c7707adcbb852097c999ca08780037 Mon Sep 17 00:00:00 2001 From: zhangwenchao <656540940@qq.com> Date: Mon, 20 May 2024 19:05:58 +0800 Subject: [PATCH] Implementation of tag. --- src/backend/catalog/Makefile | 2 +- src/backend/catalog/aclchk.c | 36 + src/backend/catalog/catalog.c | 14 +- src/backend/catalog/dependency.c | 36 + src/backend/catalog/objectaddress.c | 163 +- src/backend/catalog/oid_dispatch.c | 35 + src/backend/catalog/pg_shdepend.c | 30 + src/backend/catalog/system_views.sql | 61 + src/backend/commands/Makefile | 3 +- src/backend/commands/alter.c | 7 + src/backend/commands/comment.c | 1 + src/backend/commands/dbcommands.c | 55 +- src/backend/commands/event_trigger.c | 8 + src/backend/commands/exttablecmds.c | 1 + src/backend/commands/indexcmds.c | 13 + src/backend/commands/schemacmds.c | 78 + src/backend/commands/seclabel.c | 2 + src/backend/commands/sequence.c | 10 + src/backend/commands/tablecmds.c | 71 + src/backend/commands/tablespace.c | 39 + src/backend/commands/tag.c | 1157 +++++++++++++ src/backend/commands/user.c | 41 +- src/backend/commands/view.c | 12 + src/backend/nodes/copyfuncs.c | 94 ++ src/backend/nodes/equalfuncs.c | 84 + src/backend/nodes/outfast.c | 21 + src/backend/nodes/outfuncs.c | 32 + src/backend/nodes/outfuncs_common.c | 62 + src/backend/nodes/readfast.c | 47 + src/backend/nodes/readfuncs.c | 8 + src/backend/nodes/readfuncs_common.c | 60 + src/backend/parser/gram.y | 400 ++++- src/backend/tcop/utility.c | 104 ++ src/backend/utils/cache/syscache.c | 46 + src/bin/pg_dump/pg_dumpall.c | 105 ++ src/bin/psql/tab-complete.c | 28 +- src/include/catalog/dependency.h | 5 + src/include/catalog/oid_dispatch.h | 4 + src/include/catalog/pg_tag.h | 55 + src/include/catalog/pg_tag_description.h | 56 + src/include/commands/schemacmds.h | 1 + src/include/commands/tag.h | 29 + src/include/nodes/nodes.h | 5 + src/include/nodes/parsenodes.h | 71 +- src/include/parser/kwlist.h | 2 + src/include/tcop/cmdtaglist.h | 3 + src/include/utils/acl.h | 1 + src/include/utils/syscache.h | 4 + .../test_ddl_deparse/test_ddl_deparse.c | 6 + src/test/regress/expected/misc_sanity.out | 4 +- src/test/regress/expected/oidjoins.out | 4 + src/test/regress/expected/sanity_check.out | 2 + src/test/regress/greenplum_schedule | 3 + src/test/regress/input/tag.source | 623 +++++++ .../regress/output/directory_table.source | 30 +- .../output/directory_table_optimizer.source | 30 +- src/test/regress/output/tag.source | 1436 +++++++++++++++++ .../expected/misc_sanity.out | 4 +- .../singlenode_regress/expected/oidjoins.out | 4 + .../expected/sanity_check.out | 2 + src/tools/pgindent/typedefs.list | 6 + 61 files changed, 5277 insertions(+), 79 deletions(-) create mode 100644 src/backend/commands/tag.c create mode 100644 src/include/catalog/pg_tag.h create mode 100644 src/include/catalog/pg_tag_description.h create mode 100644 src/include/commands/tag.h create mode 100644 src/test/regress/input/tag.source create mode 100644 src/test/regress/output/tag.source diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index c3ccbdc18e4..2c9b02ea42f 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -94,7 +94,7 @@ CATALOG_HEADERS := \ pg_sequence.h pg_publication.h pg_publication_rel.h pg_subscription.h \ pg_subscription_rel.h gp_partition_template.h pg_task.h pg_task_run_history.h \ pg_profile.h pg_password_history.h pg_directory_table.h gp_storage_server.h \ - gp_storage_user_mapping.h + gp_storage_user_mapping.h pg_tag.h pg_tag_description.h USE_INTERNAL_FTS_FOUND := $(if $(findstring USE_INTERNAL_FTS,$(CFLAGS)),true,false) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index c579dbffc52..7e1dab6e049 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -58,6 +58,7 @@ #include "catalog/pg_statistic_ext.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" +#include "catalog/pg_tag.h" #include "catalog/pg_transform.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_dict.h" @@ -3791,6 +3792,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_EXTPROTOCOL: msg = gettext_noop("permission denied for external protocol %s"); break; + case OBJECT_TAG: + msg = gettext_noop("permission denied for tag %s"); + break; /* these currently aren't used */ case OBJECT_ACCESS_METHOD: case OBJECT_AMOP: @@ -3806,6 +3810,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_ROLE: case OBJECT_RULE: case OBJECT_TABCONSTRAINT: +// case OBJECT_TAG_DESCRIPTION: case OBJECT_TRANSFORM: case OBJECT_TRIGGER: case OBJECT_TSPARSER: @@ -3902,6 +3907,9 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_TABLE: msg = gettext_noop("must be owner of table %s"); break; + case OBJECT_TAG: + msg = gettext_noop("must be owner of tag %s"); + break; case OBJECT_TYPE: msg = gettext_noop("must be owner of type %s"); break; @@ -3953,6 +3961,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_RESGROUP: case OBJECT_RESQUEUE: case OBJECT_ROLE: +// case OBJECT_TAG_DESCRIPTION: case OBJECT_TRANSFORM: case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: @@ -5647,6 +5656,33 @@ pg_opfamily_ownercheck(Oid opf_oid, Oid roleid) return has_privs_of_role(roleid, ownerId); } +/* + * Ownership check for a tag (specified by OID). + */ +bool +pg_tag_ownercheck(Oid tag_oid, Oid roleid) +{ + HeapTuple tuple; + Oid ownerId; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(roleid)) + return true; + + tuple = SearchSysCache1(TAGOID, ObjectIdGetDatum(tag_oid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag with OID %u does not exist", + tag_oid))); + + ownerId = ((Form_pg_tag) GETSTRUCT(tuple))->tagowner; + + ReleaseSysCache(tuple); + + return has_privs_of_role(roleid, ownerId); +} + /* * Ownership check for a text search dictionary (specified by OID). */ diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 8c4c7023921..517248e694a 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -44,6 +44,8 @@ #include "catalog/pg_shseclabel.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" +#include "catalog/pg_tag.h" +#include "catalog/pg_tag_description.h" #include "catalog/pg_task.h" #include "catalog/pg_task_run_history.h" #include "catalog/pg_type.h" @@ -445,7 +447,10 @@ IsSharedRelation(Oid relationId) relationId == StorageServerRelationId || relationId == ProfileRelationId || - relationId == PasswordHistoryRelationId) + relationId == PasswordHistoryRelationId || + + relationId == TagRelationId || + relationId == TagDescriptionRelationId) return true; /* These are their indexes */ @@ -499,7 +504,12 @@ IsSharedRelation(Oid relationId) relationId == ProfileOidIndexId || relationId == ProfileVerifyFunctionIndexId || relationId == PasswordHistoryRolePasswordIndexId || - relationId == PasswordHistoryRolePasswordsetatIndexId) + relationId == PasswordHistoryRolePasswordsetatIndexId || + relationId == TagNameIndexId || + relationId == TagOidIndexId || + relationId == TagDescriptionIndexId || + relationId == TagDescriptionTagidvalueIndexId || + relationId == TagDescriptionOidIndexId) { return true; } diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 6be702e488b..4ad9c10d483 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -58,6 +58,8 @@ #include "catalog/pg_statistic_ext.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" +#include "catalog/pg_tag.h" +#include "catalog/pg_tag_description.h" #include "catalog/pg_task.h" #include "catalog/pg_transform.h" #include "catalog/pg_trigger.h" @@ -78,6 +80,7 @@ #include "commands/schemacmds.h" #include "commands/seclabel.h" #include "commands/sequence.h" +#include "commands/tag.h" #include "commands/taskcmds.h" #include "commands/trigger.h" #include "commands/typecmds.h" @@ -208,6 +211,8 @@ static const Oid object_classes[] = { DirectoryTableRelationId, /* OCLASS_DIRECTORY_TABLE */ StorageServerRelationId, /* OCLASS_STORAGE_SERVER */ StorageUserMappingRelationId, /* OCLASS_STORAGE_USER_MAPPING */ + TagRelationId, /* OCLASS_TAG */ + TagDescriptionRelationId, /* OCLASS_TAG_DESCRIPTION */ ExtprotocolRelationId, /* OCLASS_EXTPROTOCOL */ TaskRelationId /* OCLASS_TASK */ }; @@ -1472,6 +1477,13 @@ doDeletion(const ObjectAddress *object, int flags) Assert(object->objectSubId == 0); index_drop(object->objectId, concurrent, concurrent_lock_mode); + + /* + * Delete tag description. + */ + DeleteTagDescriptions(MyDatabaseId, + object->classId, + object->objectId); } else { @@ -1479,7 +1491,17 @@ doDeletion(const ObjectAddress *object, int flags) RemoveAttributeById(object->objectId, object->objectSubId); else + { heap_drop_with_catalog(object->objectId); + + /* + * Delete tag description. + */ + DeleteTagDescriptions(MyDatabaseId, + object->classId, + object->objectId); + } + } /* @@ -1549,6 +1571,12 @@ doDeletion(const ObjectAddress *object, int flags) case OCLASS_SCHEMA: RemoveSchemaById(object->objectId); + /* + * Delete tag description. + */ + DeleteTagDescriptions(MyDatabaseId, + object->classId, + object->objectId); break; case OCLASS_TASK: RemoveTaskById(object->objectId); @@ -1587,6 +1615,8 @@ doDeletion(const ObjectAddress *object, int flags) case OCLASS_PASSWORDHISTORY: case OCLASS_STORAGE_SERVER: case OCLASS_STORAGE_USER_MAPPING: + case OCLASS_TAG: + case OCLASS_TAG_DESCRIPTION: elog(ERROR, "global objects cannot be deleted by doDeletion"); break; @@ -2987,6 +3017,12 @@ getObjectClass(const ObjectAddress *object) case StorageUserMappingRelationId: return OCLASS_STORAGE_USER_MAPPING; + case TagRelationId: + return OCLASS_TAG; + + case TagDescriptionRelationId: + return OCLASS_TAG_DESCRIPTION; + default: { struct CustomObjectClass *coc; diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 852af0f6759..0c3313e0621 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -61,6 +61,8 @@ #include "catalog/pg_statistic_ext.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" +#include "catalog/pg_tag.h" +#include "catalog/pg_tag_description.h" #include "catalog/pg_task.h" #include "catalog/pg_transform.h" #include "catalog/pg_trigger.h" @@ -80,6 +82,7 @@ #include "commands/resgroupcmds.h" #include "commands/storagecmds.h" #include "commands/tablespace.h" +#include "commands/tag.h" #include "commands/trigger.h" #include "foreign/foreign.h" #include "funcapi.h" @@ -701,7 +704,37 @@ static const ObjectPropertyType ObjectProperty[] = Anum_pg_extprotocol_ptcacl, OBJECT_EXTPROTOCOL, true - } + }, + + { + "tag", + TagRelationId, + TagOidIndexId, + TAGOID, + TAGNAME, + Anum_pg_tag_oid, + Anum_pg_tag_tagname, + InvalidAttrNumber, + Anum_pg_tag_tagowner, + InvalidAttrNumber, + OBJECT_TAG, + true + }, +// +// { +// "tag description", +// TagDescriptionRelationId, +// TagDescriptionTagidIndexId, +// TAGDESCRIPTIONTAGID, +// -1, +// Anum_pg_tag_description_tagid, +// InvalidAttrNumber, +// InvalidAttrNumber, +// InvalidAttrNumber, +// InvalidAttrNumber, +// OBJECT_TAG_DESCRIPTION, +// true +// } }; /* @@ -942,6 +975,10 @@ static const struct object_type_map /* OCLASS_STORAGE_USER_MAPPING */ { "storage user mapping", OBJECT_STORAGE_USER_MAPPING + }, + /* OCLASS_TAG */ + { + "tag", OBJECT_TAG } }; @@ -1104,6 +1141,7 @@ get_object_address(ObjectType objtype, Node *object, case OBJECT_DATABASE: case OBJECT_EXTENSION: case OBJECT_TABLESPACE: + case OBJECT_TAG: case OBJECT_ROLE: case OBJECT_SCHEMA: case OBJECT_LANGUAGE: @@ -1383,6 +1421,11 @@ get_object_address_unqualified(ObjectType objtype, address.objectId = get_tablespace_oid(name, missing_ok); address.objectSubId = 0; break; + case OBJECT_TAG: + address.classId = TagRelationId; + address.objectId = get_tag_oid(name, missing_ok); + address.objectSubId = 0; + break; case OBJECT_ROLE: address.classId = AuthIdRelationId; address.objectId = get_role_oid(name, missing_ok); @@ -2425,6 +2468,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_SCHEMA: case OBJECT_SUBSCRIPTION: case OBJECT_TABLESPACE: + case OBJECT_TAG: case OBJECT_EXTPROTOCOL: case OBJECT_RESGROUP: case OBJECT_RESQUEUE: @@ -2686,6 +2730,11 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, aclcheck_error(ACLCHECK_NOT_OWNER, objtype, strVal((Value *) object)); break; + case OBJECT_TAG: + if (!pg_tag_ownercheck(address.objectId, roleid)) + aclcheck_error(ACLCHECK_NOT_OWNER, objtype, + strVal((Value *) object)); + break; case OBJECT_TSDICTIONARY: if (!pg_ts_dict_ownercheck(address.objectId, roleid)) aclcheck_error(ACLCHECK_NOT_OWNER, objtype, @@ -4194,6 +4243,55 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok) break; } + case OCLASS_TAG: + { + char *tagname = TagGetNameByOid(object->objectId, missing_ok); + + if (tagname) + appendStringInfo(&buffer, _("tag %s"), tagname); + break; + } + + case OCLASS_TAG_DESCRIPTION: + { + Relation tag_desc_rel; + ScanKeyData skey; + SysScanDesc tag_desc_scan; + HeapTuple tag_tuple; + HeapTuple tag_desc_tuple; + Form_pg_tag form_tag; + Form_pg_tag_description form_tag_desc; + char *tagname; + + ScanKeyInit(&skey, Anum_pg_tag_description_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + tag_desc_rel = table_open(TagDescriptionRelationId, AccessShareLock); + tag_desc_scan = systable_beginscan(tag_desc_rel, TagDescriptionOidIndexId, true, + NULL, 1, &skey); + + tag_desc_tuple = systable_getnext(tag_desc_scan); + if (!HeapTupleIsValid(tag_desc_tuple)) + elog(ERROR, "lookup failed for tag description %u", object->objectId); + + form_tag_desc = (Form_pg_tag_description) GETSTRUCT(tag_desc_tuple); + + tag_tuple = SearchSysCache1(TAGOID, ObjectIdGetDatum(form_tag_desc->tagid)); + if (!HeapTupleIsValid(tag_tuple)) + elog(ERROR, "cache lookup failed for tag %u", form_tag_desc->tagid); + + form_tag = (Form_pg_tag) GETSTRUCT(tag_tuple); + tagname = pstrdup(form_tag->tagname.data); + + appendStringInfo(&buffer, _("tag description with tag %s"), tagname); + + ReleaseSysCache(tag_tuple); + systable_endscan(tag_desc_scan); + table_close(tag_desc_rel, AccessShareLock); + break; + } + default: { struct CustomObjectClass *coc; @@ -4789,6 +4887,14 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "storage user mapping"); break; + case OCLASS_TAG: + appendStringInfoString(&buffer, "tag"); + break; + + case OCLASS_TAG_DESCRIPTION: + appendStringInfoString(&buffer, "tag description"); + break; + default: { struct CustomObjectClass *coc; @@ -6197,6 +6303,61 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case OCLASS_TAG: + { + char *tagname; + + tagname = TagGetNameByOid(object->objectId, missing_ok); + if (!tagname) + break; + if (objname) + *objname = list_make1(tagname); + appendStringInfoString(&buffer, + quote_identifier(tagname)); + break; + } + + case OCLASS_TAG_DESCRIPTION: + { + Relation tag_desc_rel; + ScanKeyData skey; + SysScanDesc tag_desc_scan; + HeapTuple tag_tuple; + HeapTuple tag_desc_tuple; + Form_pg_tag form_tag; + Form_pg_tag_description form_tag_desc; + char *tagname; + + ScanKeyInit(&skey, Anum_pg_tag_description_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + tag_desc_rel = table_open(TagDescriptionRelationId, AccessShareLock); + tag_desc_scan = systable_beginscan(tag_desc_rel, TagDescriptionOidIndexId, true, + NULL, 1, &skey); + + tag_desc_tuple = systable_getnext(tag_desc_scan); + if (!HeapTupleIsValid(tag_desc_tuple)) + elog(ERROR, "lookup failed for tag description %u", object->objectId); + + form_tag_desc = (Form_pg_tag_description) GETSTRUCT(tag_desc_tuple); + + tag_tuple = SearchSysCache1(TAGOID, ObjectIdGetDatum(form_tag_desc->tagid)); + if (!HeapTupleIsValid(tag_tuple)) + elog(ERROR, "cache lookup failed for tag %u", form_tag_desc->tagid); + + form_tag = (Form_pg_tag) GETSTRUCT(tag_tuple); + tagname = pstrdup(form_tag->tagname.data); + + appendStringInfo(&buffer, _("tag description with tag %s"), + quote_identifier(tagname)); + + ReleaseSysCache(tag_tuple); + systable_endscan(tag_desc_scan); + table_close(tag_desc_rel, AccessShareLock); + break; + } + default: { struct CustomObjectClass *coc; diff --git a/src/backend/catalog/oid_dispatch.c b/src/backend/catalog/oid_dispatch.c index 01c95a4644a..51a2b83bfe1 100644 --- a/src/backend/catalog/oid_dispatch.c +++ b/src/backend/catalog/oid_dispatch.c @@ -119,6 +119,8 @@ #include "catalog/pg_statistic_ext.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" +#include "catalog/pg_tag.h" +#include "catalog/pg_tag_description.h" #include "catalog/pg_transform.h" #include "catalog/pg_trigger.h" #include "catalog/pg_ts_config.h" @@ -957,6 +959,39 @@ GetNewOidForResQueue(Relation relation, Oid indexId, AttrNumber oidcolumn, return GetNewOrPreassignedOid(relation, indexId, oidcolumn, &key); } +Oid +GetNewOidForTag(Relation relation, Oid indexId, AttrNumber oidcolumn, + char *tagname) +{ + OidAssignment key; + + Assert(RelationGetRelid(relation) == TagRelationId); + Assert(indexId == TagOidIndexId); + Assert(oidcolumn == Anum_pg_tag_oid); + + memset(&key, 0, sizeof(OidAssignment)); + key.type = T_OidAssignment; + key.objname = tagname; + return GetNewOrPreassignedOid(relation, indexId, oidcolumn, &key); +} + +Oid +GetNewOidForTagDescription(Relation relation, Oid indexId, AttrNumber oidcolumn, + char *objectname, Oid tagId) +{ + OidAssignment key; + + Assert(RelationGetRelid(relation) == TagDescriptionRelationId); + Assert(indexId == TagDescriptionOidIndexId); + Assert(oidcolumn == Anum_pg_tag_description_oid); + + memset(&key, 0, sizeof(OidAssignment)); + key.type = T_OidAssignment; + key.objname = objectname; + key.keyOid1 = tagId; + return GetNewOrPreassignedOid(relation, indexId, oidcolumn, &key); +} + Oid GetNewOidForRewrite(Relation relation, Oid indexId, AttrNumber oidcolumn, Oid ev_class, char *rulename) diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index 9c101a9fdb0..46f1fc8898a 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -46,6 +46,7 @@ #include "catalog/pg_statistic_ext.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" +#include "catalog/pg_tag.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_dict.h" #include "catalog/pg_type.h" @@ -1243,6 +1244,15 @@ shdepLockAndCheckObject(Oid classId, Oid objectId) break; } + case TagRelationId: + { + if (!SearchSysCacheExists1(TAGOID, ObjectIdGetDatum(objectId))) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag %u was concurrently dropped", + objectId))); + break; + } default: elog(ERROR, "unrecognized shared classId: %u", classId); @@ -1299,6 +1309,8 @@ storeObjectDescription(StringInfo descs, appendStringInfo(descs, _("profile of %s"), objdesc); else if (deptype == SHARED_DEPENDENCY_STORAGE_SERVER) appendStringInfo(descs, _("storage server of %s"), objdesc); + else if (deptype == SHARED_DEPENDENCY_TAG) + appendStringInfo(descs, _("tag of %s"), objdesc); else elog(ERROR, "unrecognized dependency type: %d", (int) deptype); @@ -1785,4 +1797,22 @@ recordStorageServerDependency(Oid classId, Oid objectId, Oid srvId) ObjectAddressSet(referenced, StorageServerRelationId, srvId); recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_STORAGE_SERVER); +} + +/* + * recordTagDependency + * + * A convenient wrapper of recoredSharedDependencyOn -- register the specified + * tag description of attached to tag. + */ +void +recordTagDependency(Oid classId, Oid objectId, Oid tagId) +{ + ObjectAddress myself, + referenced; + + ObjectAddressSet(myself, classId, objectId); + ObjectAddressSet(referenced, TagRelationId, tagId); + + recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_TAG); } \ No newline at end of file diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index c7c46d820f3..af2b33e58f6 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1715,3 +1715,64 @@ REVOKE ALL ON pg_subscription FROM public; GRANT SELECT (oid, subdbid, subname, subowner, subenabled, subbinary, substream, subslotname, subsynccommit, subpublications) ON pg_subscription TO public; + +CREATE VIEW database_tag_descriptions AS + SELECT + databaseid, + datname, + tagname, + tagvalue + FROM pg_tag_description AS td, + pg_database AS d, + pg_tag AS t + WHERE td.tagid = t.oid and td.objid = d.oid; + +CREATE VIEW user_tag_descriptions AS + SELECT + databaseid, + rolname, + tagname, + tagvalue + FROM pg_tag_description AS td, + pg_authid AS a, + pg_tag AS t + WHERE td.tagid = t.oid and td.objid = a.oid; + +CREATE VIEW tablespace_tag_descriptions AS + SELECT + databaseid, + spcname, + tagname, + tagvalue + FROM pg_tag_description AS td, + pg_tablespace AS ts, + pg_tag AS t + WHERE td.tagid = t.oid and td.objid = ts.oid; + +CREATE VIEW schema_tag_descriptions AS + SELECT + datname, + nspname, + tagname, + tagvalue + FROM pg_tag_description AS td, + pg_namespace AS ns, + pg_database AS d, + pg_tag AS t + WHERE td.tagid = t.oid AND td.objid = ns.oid AND td.databaseid = d.oid; + +CREATE VIEW relation_tag_descriptions AS + SELECT + datname, + relname, + ns.nspname AS relnamespace, + relkind, + tagname, + tagvalue + FROM pg_tag_description AS td, + pg_class AS c, + pg_database AS d, + pg_tag AS t, + pg_namespace AS ns + WHERE td.tagid = t.oid AND td.objid = c.oid + AND td.databaseid = d.oid AND ns.oid = c.relnamespace; \ No newline at end of file diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 2fe51b415ba..4ae28e323d4 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -66,7 +66,8 @@ OBJS = \ variable.o \ view.o \ pg_profile.o \ - storagecmds.o + storagecmds.o \ + tag.o OBJS += analyzefuncs.o analyzeutils.o extprotocolcmds.o exttablecmds.o queue.o OBJS += resgroupcmds.o tablecmds_gp.o vacuum_ao.o taskcmds.o diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index df43eb8e69b..da96836f809 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -58,6 +58,7 @@ #include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" +#include "commands/tag.h" #include "commands/trigger.h" #include "commands/typecmds.h" #include "commands/user.h" @@ -359,6 +360,9 @@ ExecRenameStmt_internal(RenameStmt *stmt) case OBJECT_TABLESPACE: return RenameTableSpace(stmt->subname, stmt->newname); + case OBJECT_TAG: + return RenameTag(stmt->subname, stmt->newname); + case OBJECT_TABLE: case OBJECT_SEQUENCE: case OBJECT_VIEW: @@ -736,6 +740,8 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, case OCLASS_PASSWORDHISTORY: case OCLASS_STORAGE_SERVER: case OCLASS_STORAGE_USER_MAPPING: + case OCLASS_TAG: + case OCLASS_TAG_DESCRIPTION: /* ignore object types that don't have schema-qualified names */ break; @@ -964,6 +970,7 @@ ExecAlterOwnerStmt_internal(AlterOwnerStmt *stmt) case OBJECT_ROUTINE: case OBJECT_STATISTIC_EXT: case OBJECT_TABLESPACE: + case OBJECT_TAG: case OBJECT_TSDICTIONARY: case OBJECT_TSCONFIGURATION: { diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 906405718e2..d654a6cf25a 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -133,6 +133,7 @@ CommentObject(CommentStmt *stmt) case OBJECT_RESQUEUE: case OBJECT_RESGROUP: case OBJECT_PROFILE: + case OBJECT_TAG: CreateSharedComments(address.objectId, address.classId, stmt->comment); break; default: diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 52cef311ba3..d1146d3d4ec 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -54,6 +54,7 @@ #include "commands/defrem.h" #include "commands/seclabel.h" #include "commands/tablespace.h" +#include "commands/tag.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "pgstat.h" @@ -620,6 +621,20 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt) new_record, new_record_nulls); CatalogTupleInsert(pg_database_rel, tuple); + + CommandCounterIncrement(); + + /* + * Create tag description. + */ + if (stmt->tags) + { + AddTagDescriptions(stmt->tags, + InvalidOid, + DatabaseRelationId, + dboid, + dbname); + } if (shouldDispatch) { @@ -1067,6 +1082,13 @@ dropdb(const char *dbname, bool missing_ok, bool force) */ DeleteSharedComments(db_id, DatabaseRelationId); DeleteSharedSecurityLabel(db_id, DatabaseRelationId); + + /* + * Delete any tag description and associated dependencies. + */ + DeleteTagDescriptions(InvalidOid, + DatabaseRelationId, + db_id); /* * Remove settings associated with this database @@ -1808,7 +1830,7 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel), new_record, new_record_nulls, new_record_repl); CatalogTupleUpdate(rel, &tuple->t_self, newtuple); - + InvokeObjectPostAlterHook(DatabaseRelationId, dboid, 0); systable_endscan(scan); @@ -1823,6 +1845,37 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) /* Close pg_database, but keep lock till commit */ table_close(rel, NoLock); + if (stmt->tags) + { + if (!stmt->unsettag) + { + AlterTagDescriptions(stmt->tags, + InvalidOid, + DatabaseRelationId, + dboid, + stmt->dbname); + } + + if (stmt->unsettag) + { + UnsetTagDescriptions(stmt->tags, + InvalidOid, + DatabaseRelationId, + dboid, + stmt->dbname); + } + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_CANCEL_ON_ERROR| + DF_WITH_SNAPSHOT| + DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + } + if (Gp_role == GP_ROLE_DISPATCH) { char *cmd; diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 0b984fbb431..3392a3af4a1 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -1003,6 +1003,8 @@ EventTriggerSupportsObjectType(ObjectType obtype) return true; case OBJECT_RESQUEUE: case OBJECT_RESGROUP: + case OBJECT_TAG: +// case OBJECT_TAG_DESCRIPTION: return false; /* @@ -1030,6 +1032,8 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_PASSWORDHISTORY: case OCLASS_STORAGE_SERVER: case OCLASS_STORAGE_USER_MAPPING: + case OCLASS_TAG: + case OCLASS_TAG_DESCRIPTION: /* no support for global objects */ return false; case OCLASS_EVENT_TRIGGER: @@ -2167,6 +2171,7 @@ stringify_grant_objtype(ObjectType objtype) case OBJECT_STATISTIC_EXT: case OBJECT_SUBSCRIPTION: case OBJECT_TABCONSTRAINT: + case OBJECT_TAG: case OBJECT_TRANSFORM: case OBJECT_TRIGGER: case OBJECT_TSCONFIGURATION: @@ -2181,6 +2186,7 @@ stringify_grant_objtype(ObjectType objtype) case OBJECT_RESGROUP: case OBJECT_PROFILE: case OBJECT_DIRECTORY_TABLE: +// case OBJECT_TAG_DESCRIPTION: elog(ERROR, "unsupported object type: %d", (int) objtype); } @@ -2257,6 +2263,7 @@ stringify_adefprivs_objtype(ObjectType objtype) case OBJECT_STATISTIC_EXT: case OBJECT_SUBSCRIPTION: case OBJECT_TABCONSTRAINT: + case OBJECT_TAG: case OBJECT_TRANSFORM: case OBJECT_TRIGGER: case OBJECT_TSCONFIGURATION: @@ -2271,6 +2278,7 @@ stringify_adefprivs_objtype(ObjectType objtype) case OBJECT_RESGROUP: case OBJECT_PROFILE: case OBJECT_DIRECTORY_TABLE: +// case OBJECT_TAG_DESCRIPTION: elog(ERROR, "unsupported object type: %d", (int) objtype); } diff --git a/src/backend/commands/exttablecmds.c b/src/backend/commands/exttablecmds.c index af3a20db3a9..4acfc778fc8 100644 --- a/src/backend/commands/exttablecmds.c +++ b/src/backend/commands/exttablecmds.c @@ -118,6 +118,7 @@ DefineExternalRelation(CreateExternalStmt *createExtStmt) createStmt->tablespacename = NULL; createStmt->distributedBy = createExtStmt->distributedBy; /* policy was set in transform */ createStmt->ownerid = userid; + createStmt->tags = createExtStmt->tags; switch (exttypeDesc->exttabletype) { diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 9066ce3bb40..4580eeffe28 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -45,6 +45,7 @@ #include "commands/progress.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" +#include "commands/tag.h" #include "mb/pg_wchar.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -1574,6 +1575,18 @@ DefineIndex(Oid relationId, return address; } + /* + * Create tag description. + */ + if (stmt->tags) + { + AddTagDescriptions(stmt->tags, + MyDatabaseId, + address.classId, + address.objectId, + stmt->idxname); + } + /* * In the QD, remember the chosen index name and stash it with the * chosen OIDs, so that it's dispatched to the QE later. diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 1afbde1b754..5b720d75ff0 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -28,9 +28,11 @@ #include "catalog/oid_dispatch.h" #include "catalog/pg_authid.h" #include "catalog/pg_namespace.h" +#include "catalog/pg_tag.h" #include "commands/dbcommands.h" #include "commands/event_trigger.h" #include "commands/schemacmds.h" +#include "commands/tag.h" #include "miscadmin.h" #include "parser/parse_utilcmd.h" #include "tcop/utility.h" @@ -170,6 +172,18 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, { namespaceId = NamespaceCreate(schemaName, owner_uid, false); + /* + * Create tag description. + */ + if (stmt->tags) + { + AddTagDescriptions(stmt->tags, + MyDatabaseId, + NamespaceRelationId, + namespaceId, + stmt->schemaname); + } + if (shouldDispatch) { elog(DEBUG5, "shouldDispatch = true, namespaceOid = %d", namespaceId); @@ -198,6 +212,18 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, else { namespaceId = NamespaceCreate(schemaName, owner_uid, false); + + /* + * Create tag description. + */ + if (stmt->tags) + { + AddTagDescriptions(stmt->tags, + MyDatabaseId, + NamespaceRelationId, + namespaceId, + stmt->schemaname); + } } /* @@ -307,6 +333,58 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, return namespaceId; } +/* + * Alter Schema tag + * + * Alter a schema to change it's tag. + */ +void +AlterSchemaCommand(AlterSchemaStmt *stmt) +{ + Oid namespaceId; + HeapTuple tuple; + Form_pg_namespace namespaceform; + + tuple = SearchSysCache1(NAMESPACENAME, CStringGetDatum(stmt->schemaname)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for namespace %s", stmt->schemaname); + + namespaceform = (Form_pg_namespace) GETSTRUCT(tuple); + namespaceId = namespaceform->oid; + + if (stmt->tags) + { + if (!stmt->unsettag) + { + AlterTagDescriptions(stmt->tags, + MyDatabaseId, + NamespaceRelationId, + namespaceId, + stmt->schemaname); + } + + if (stmt->unsettag) + { + UnsetTagDescriptions(stmt->tags, + MyDatabaseId, + NamespaceRelationId, + namespaceId, + stmt->schemaname); + } + } + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_CANCEL_ON_ERROR | + DF_WITH_SNAPSHOT | + DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + ReleaseSysCache(tuple); +} + /* * Guts of schema deletion. */ diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c index a0dd92b2e04..3618821e197 100644 --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -85,6 +85,8 @@ SecLabelSupportsObjectType(ObjectType objtype) case OBJECT_RULE: case OBJECT_STATISTIC_EXT: case OBJECT_TABCONSTRAINT: + case OBJECT_TAG: +// case OBJECT_TAG_DESCRIPTION: case OBJECT_TRANSFORM: case OBJECT_TRIGGER: case OBJECT_TSCONFIGURATION: diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 87fe223d6c6..2b63b8a1e6c 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -36,6 +36,7 @@ #include "commands/defrem.h" #include "commands/sequence.h" #include "commands/tablecmds.h" +#include "commands/tag.h" #include "funcapi.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -264,6 +265,15 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) /* now initialize the sequence's data */ tuple = heap_form_tuple(tupDesc, value, null); fill_seq_with_data(rel, tuple); + + if (seq->tags) + { + AddTagDescriptions(seq->tags, + MyDatabaseId, + address.classId, + address.objectId, + seq->sequence->relname); + } /* Dispatch to segments */ if (shouldDispatch) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 982d4603aed..4bad36f0a0b 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -73,6 +73,7 @@ #include "commands/sequence.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" +#include "commands/tag.h" #include "commands/trigger.h" #include "commands/typecmds.h" #include "commands/user.h" @@ -267,6 +268,7 @@ struct DropRelationCallbackState #define ATT_FOREIGN_TABLE 0x0020 #define ATT_PARTITIONED_INDEX 0x0040 #define ATT_DIRECTORY_TABLE 0x0080 +#define ATT_SEQUENCE 0x0100 /* * ForeignTruncateInfo @@ -569,6 +571,8 @@ static List *GetParentedForeignKeyRefs(Relation partition); static void ATDetachCheckNoForeignKeyRefs(Relation partition); static char GetAttributeCompression(Oid atttypid, char *compression); +static void ATSetTags(Relation rel, List *tags, bool unset); + static RangeVar *make_temp_table_name(Relation rel, BackendId id); static bool prebuild_temp_table(Relation rel, RangeVar *tmpname, DistributedBy *distro, char *amname, List *opts, @@ -1162,6 +1166,20 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, typaddress, valid_opts); + /* + * Create tag description. + */ + if (stmt->tags && + stmt->relation->relpersistence != RELPERSISTENCE_TEMP) + { + + AddTagDescriptions(stmt->tags, + MyDatabaseId, + RelationRelationId, + relationId, + relname); + } + /* * We must bump the command counter to make the newly-created relation * tuple visible for opening. @@ -4996,6 +5014,11 @@ AlterTableGetLockLevel(List *cmds) cmd_lockmode = AccessExclusiveLock; break; + case AT_SetTags: + case AT_UnsetTags: + cmd_lockmode = ShareUpdateExclusiveLock; + break; + default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -5665,6 +5688,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, /* No command-specific prep needed */ pass = AT_PASS_MISC; break; + case AT_SetTags: + case AT_UnsetTags: + ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE | ATT_INDEX | ATT_SEQUENCE | ATT_VIEW | ATT_MATVIEW); + /* No command-specific prep needed */ + pass = AT_PASS_MISC; + break; default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -6109,6 +6138,12 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, case AT_DetachPartitionFinalize: ATExecDetachPartitionFinalize(rel, ((PartitionCmd *) cmd->def)->name); break; + case AT_SetTags: + ATSetTags(rel, cmd->tags, cmd->unsettag); + break; + case AT_UnsetTags: + ATSetTags(rel, cmd->tags, cmd->unsettag); + break; default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -7501,6 +7536,9 @@ ATSimplePermissions(Relation rel, int allowed_targets) case RELKIND_DIRECTORY_TABLE: actual_target = ATT_DIRECTORY_TABLE; break; + case RELKIND_SEQUENCE: + actual_target = ATT_SEQUENCE; + break; case RELKIND_AOSEGMENTS: case RELKIND_AOBLOCKDIR: @@ -7603,6 +7641,9 @@ ATWrongRelkindError(Relation rel, int allowed_targets) case ATT_DIRECTORY_TABLE: msg = _("\"%s\" is not a directory table"); break; + case ATT_TABLE | ATT_FOREIGN_TABLE | ATT_INDEX | ATT_SEQUENCE | ATT_VIEW | ATT_MATVIEW: + msg = _("\"%s\" is not a table, foreign table, index, sequence, view or materialized view"); + break; default: /* shouldn't get here, add all necessary cases above */ msg = _("\"%s\" is of the wrong type"); @@ -14150,6 +14191,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, case OCLASS_PASSWORDHISTORY: case OCLASS_STORAGE_SERVER: case OCLASS_STORAGE_USER_MAPPING: + case OCLASS_TAG: + case OCLASS_TAG_DESCRIPTION: /* * We don't expect any of these sorts of objects to depend on @@ -22640,3 +22683,31 @@ GetAttributeCompression(Oid atttypid, char *compression) return cmethod; } + +static void +ATSetTags(Relation rel, List *tags, bool unset) +{ + Oid relid; + + relid = RelationGetRelid(rel); + + if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP) + return; + + if (!unset) + { + AlterTagDescriptions(tags, + MyDatabaseId, + RelationRelationId, + relid, + RelationGetRelationName(rel)); + } + else + { + UnsetTagDescriptions(tags, + MyDatabaseId, + RelationRelationId, + relid, + RelationGetRelationName(rel)); + } +} diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index e5c53e7180b..e9d26b0511b 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -81,6 +81,7 @@ #include "commands/seclabel.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" +#include "commands/tag.h" #include "common/file_perm.h" #include "miscadmin.h" #include "parser/parse_func.h" @@ -461,6 +462,16 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) heap_freetuple(tuple); + /* + * Create tag description. + */ + if (stmt->tags) + AddTagDescriptions(stmt->tags, + InvalidOid, + TableSpaceRelationId, + tablespaceoid, + stmt->tablespacename); + /* Record dependency on owner */ recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId); @@ -715,6 +726,13 @@ DropTableSpace(DropTableSpaceStmt *stmt) table_endscan(scandesc); + /* + * Delete any tag description and associated dependencies. + */ + DeleteTagDescriptions(InvalidOid, + TableSpaceRelationId, + tablespaceoid); + /* * Remove any comments or security labels on this tablespace. */ @@ -1512,6 +1530,27 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) table_endscan(scandesc); table_close(rel, NoLock); + if (stmt->tags) + { + if (!stmt->unsettag) + { + AlterTagDescriptions(stmt->tags, + InvalidOid, + TableSpaceRelationId, + tablespaceoid, + stmt->tablespacename); + } + + if (stmt->unsettag) + { + UnsetTagDescriptions(stmt->tags, + InvalidOid, + TableSpaceRelationId, + tablespaceoid, + stmt->tablespacename); + } + } + if (Gp_role == GP_ROLE_DISPATCH && ENABLE_DISPATCH()) { CdbDispatchUtilityStatement((Node *) stmt, diff --git a/src/backend/commands/tag.c b/src/backend/commands/tag.c new file mode 100644 index 00000000000..25b82f62cfa --- /dev/null +++ b/src/backend/commands/tag.c @@ -0,0 +1,1157 @@ +/*------------------------------------------------------------------------- + * + * tag.c + * Commands to manipulate tag + * + * Tags in Cloudberry database are designed to make tag for a given database + * object. + * + * + * Portions Copyright (c) 2024 Hashdata Inc + * + * + * IDENTIFICATION + * src/backend/commands/tag.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/genam.h" +#include "access/relscan.h" +#include "access/skey.h" +#include "access/table.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/dependency.h" +#include "catalog/heap.h" +#include "catalog/indexing.h" +#include "catalog/objectaccess.h" +#include "catalog/oid_dispatch.h" +#include "catalog/pg_tag.h" +#include "catalog/pg_tag_description.h" +#include "catalog/pg_type.h" +#include "cdb/cdbdisp_query.h" +#include "cdb/cdbvars.h" +#include "commands/defrem.h" +#include "commands/tag.h" +#include "storage/lmgr.h" +#include "utils/acl.h" +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/rel.h" +#include "utils/relcache.h" +#include "utils/syscache.h" + +#define TAG_VALUES_ACTION_ADD 1 +#define TAG_VALUES_ACTION_DROP -1 + +#define MAX_TAG_NUMBER 50 + +static Datum transformTagValues(int action, Oid tagId, Datum oldvalues, List *allowed_values, bool unset); +static List *untransformTagValues(Datum allowed_values); +static Datum valueListToArray(List *allowed_values); +static void checkDropTagValue(Oid tagId, char *tagvalue); + +/* + * get_tag_oid - given a tag name, look up the OID + * + * If missing_ok is false, throw an error if tag name not found. If + * true, just return InvalidOid. + */ +Oid +get_tag_oid(const char *tagname, bool missing_ok) +{ + Oid oid; + + /* + * Search pg_tag syscache with name to get oid. + */ + oid = GetSysCacheOid1(TAGNAME, Anum_pg_tag_oid, CStringGetDatum(tagname)); + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag \"%s\" does not exist", tagname))); + + return oid; +} + +/* + * Create a tag + * + * We will record the create user as tag's owner, which is allowed to + * alter or drop this tag. + */ +Oid +CreateTag(CreateTagStmt *stmt) +{ + Relation rel; + Datum values[Natts_pg_tag]; + bool nulls[Natts_pg_tag]; + HeapTuple tuple; + Oid tagId; + Oid ownerId; + Datum tag_values; + + rel = table_open(TagRelationId, RowExclusiveLock); + + /* For now the owner cannot be specified on create. Use effective user ID. */ + ownerId = GetUserId(); + + tuple = SearchSysCache1(TAGNAME, CStringGetDatum(stmt->tag_name)); + if (HeapTupleIsValid(tuple)) + { + if (stmt->missing_ok) + { + ereport(NOTICE, + errmsg("tag \"%s\" already exists, skipping", + stmt->tag_name)); + ReleaseSysCache(tuple); + table_close(rel, RowExclusiveLock); + + return InvalidOid; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("tag \"%s\" already exists", stmt->tag_name))); + } + } + + /* + * Insert tuple into pg_tag. + */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + tagId = GetNewOidForTag(rel, TagOidIndexId, + Anum_pg_tag_oid, + stmt->tag_name); + values[Anum_pg_tag_oid - 1] = ObjectIdGetDatum(tagId); + values[Anum_pg_tag_tagname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(stmt->tag_name)); + values[Anum_pg_tag_tagowner - 1] = + ObjectIdGetDatum(ownerId); + + tag_values = transformTagValues(TAG_VALUES_ACTION_ADD, + tagId, + PointerGetDatum(NULL), + stmt->allowed_values, + false); + + if (PointerIsValid(DatumGetPointer(tag_values))) + values[Anum_pg_tag_allowed_values - 1] = tag_values; + else + nulls[Anum_pg_tag_allowed_values - 1] = true; + + tuple = heap_form_tuple(rel->rd_att, values, nulls); + + CatalogTupleInsert(rel, tuple); + + heap_freetuple(tuple); + + /* Post creation hook for new tag */ + InvokeObjectPostCreateHook(TagRelationId, tagId, 0); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + + table_close(rel, RowExclusiveLock); + + return tagId; +} + +/* + * Alter a tag + * + * We can alter a tag to add, drop or unset allowed_values. + */ +ObjectAddress +AlterTag(AlterTagStmt *stmt) +{ + Relation rel; + HeapTuple tuple; + Datum repl_val[Natts_pg_tag]; + bool repl_null[Natts_pg_tag]; + bool repl_repl[Natts_pg_tag]; + Oid tagId; + Datum datum = 0; + bool isnull; + Form_pg_tag tagform; + ObjectAddress address = {0}; + + rel = table_open(TagRelationId, RowExclusiveLock); + + tuple = SearchSysCacheCopy1(TAGNAME, CStringGetDatum(stmt->tag_name)); + if (!HeapTupleIsValid(tuple)) + { + if (stmt->missing_ok) + { + ereport(NOTICE, + errmsg("tag \"%s\" does not exist, skipping", + stmt->tag_name)); + table_close(rel, RowExclusiveLock); + + return InvalidObjectAddress; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag \"%s\" does not exist", + stmt->tag_name))); + } + } + + tagform = (Form_pg_tag) GETSTRUCT(tuple); + tagId = tagform->oid; + + /* + * Only owner or a superuser can ALTER a TAG. + */ + if (!pg_tag_ownercheck(tagId, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TAG, + stmt->tag_name); + + memset(repl_val, 0, sizeof(repl_val)); + memset(repl_null, false, sizeof(repl_null)); + memset(repl_repl, false, sizeof(repl_repl)); + + if (stmt->tag_values) + { + /* Extract the current allowed_values */ + datum = SysCacheGetAttr(TAGOID, + tuple, + Anum_pg_tag_allowed_values, + &isnull); + + if (isnull) + datum = PointerGetDatum(NULL); + + /* Prepare the values array */ + datum = transformTagValues(stmt->action, + tagId, + datum, + stmt->tag_values, + stmt->unset); + } + + if (PointerIsValid(DatumGetPointer(datum))) + repl_val[Anum_pg_tag_allowed_values - 1] = datum; + else + repl_null[Anum_pg_tag_allowed_values - 1] = true; + + repl_repl[Anum_pg_tag_allowed_values - 1] = true; + + /* Everything looks good - update the tuple */ + tuple = heap_modify_tuple(tuple, RelationGetDescr(rel), + repl_val, repl_null, repl_repl); + + CatalogTupleUpdate(rel, &tuple->t_self, tuple); + + InvokeObjectPostAlterHook(TagRelationId, tagId, 0); + + ObjectAddressSet(address, TagRelationId, tagId); + + heap_freetuple(tuple); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_WITH_SNAPSHOT | DF_CANCEL_ON_ERROR | DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + + table_close(rel, RowExclusiveLock); + + return address; +} + +/* + * Drop a tag + */ +void +DropTag(DropTagStmt *stmt) +{ + Relation rel; + Oid curserid; + ListCell *cell; + + curserid = GetUserId(); + + rel = table_open(TagRelationId, RowExclusiveLock); + + foreach(cell, stmt->tags) + { + HeapTuple tuple; + Form_pg_tag tagform; + char *detail; + char *detail_log; + Oid tagId; + char *tagname; + + /* + * Check that if the tag exists. Do nothing if IF NOT + * EXISTS was enforced. + */ + tagname = strVal(lfirst(cell)); + tuple = SearchSysCache1(TAGNAME, PointerGetDatum(tagname)); + if (!HeapTupleIsValid(tuple)) + { + if (!stmt->missing_ok) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag \"%s\" does not exist", tagname))); + } + if (Gp_role != GP_ROLE_EXECUTE) + { + ereport(NOTICE, + (errmsg("tag \"%s\" does not exist, skipping", tagname))); + } + + continue; + } + + tagform = (Form_pg_tag) GETSTRUCT(tuple); + tagId = tagform->oid; + + /* check permission on tag */ + if (!pg_tag_ownercheck(tagId, GetUserId())) + aclcheck_error_type(ACLCHECK_NOT_OWNER, tagId); + + /* DROP hook for the tag being removed */ + InvokeObjectDropHook(TagRelationId, tagId, 0); + + /* + * Lock the tag, so nobody can add dependencies to it while we drop + * it. We keep the lock until the end of transaction. + */ + LockSharedObject(TagRelationId, tagId, 0, AccessExclusiveLock); + + /* Check for pg_shdepend entries depending on this tag */ + if (checkSharedDependencies(TagRelationId, tagId, + &detail, &detail_log)) + ereport(ERROR, + (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), + errmsg("tag \"%s\" cannot be dropped because some objects depend on it", + tagname), + errdetail_internal("%s", detail), + errdetail_log("%s", detail_log))); + + /* + * Delete the tag from the pg_tag table + */ + CatalogTupleDelete(rel, &tuple->t_self); + + ReleaseSysCache(tuple); + + /* metadata track */ + if (Gp_role == GP_ROLE_DISPATCH) + MetaTrackDropObject(TagRelationId, tagId); + } + + /* + * Now we can clean up; but keep locks until commit. + */ + table_close(rel, NoLock); + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_CANCEL_ON_ERROR| + DF_WITH_SNAPSHOT| + DF_NEED_TWO_PHASE, + NIL, + NULL); + } +} + +/* + * Execute ALTER TAG RENAME + */ +ObjectAddress +RenameTag(const char *oldname, const char *newname) +{ + Oid tagId; + Relation rel; + HeapTuple tuple; + HeapTuple newtuple; + Form_pg_tag tagform; + ObjectAddress address; + + /* + * Look up the target tag's OID, and get exclusive lock on it. We + * need this for this same reasons as DROP TAG. + */ + rel = table_open(TagRelationId, RowExclusiveLock); + + newtuple = SearchSysCacheCopy1(TAGNAME, CStringGetDatum(oldname)); + if (!HeapTupleIsValid(newtuple)) + elog(ERROR, "cache lookup failed for tag %s", oldname); + + tagform = (Form_pg_tag) GETSTRUCT(newtuple); + tagId = tagform->oid; + + /* check permission on tag */ + if (!pg_tag_ownercheck(tagId, GetUserId())) + aclcheck_error_type(ACLCHECK_NOT_OWNER, tagId); + + tuple = SearchSysCache1(TAGNAME, CStringGetDatum(newname)); + if (HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("tag \"%s\" already exists", + newname))); + + /* OK, update the entry */ + namestrcpy(&(tagform->tagname), newname); + + CatalogTupleUpdate(rel, &newtuple->t_self, newtuple); + + /* MPP-6929: metadata tracking */ + if (Gp_role == GP_ROLE_DISPATCH) + MetaTrackUpdObject(TagRelationId, + tagId, + GetUserId(), + "ALTER", "RENAME"); + + InvokeObjectPostAlterHook(TagRelationId, tagId, 0); + + ObjectAddressSet(address, TagRelationId, tagId); + + heap_freetuple(newtuple); + table_close(rel, RowExclusiveLock); + + return address; +} + +/* + * Add tag for object + * + * Add tag for database object such as database, warehouse, table etc. + */ +void +AddTagDescriptions(List *tags, + Oid databaseid, + Oid classid, + Oid objid, + char *objname) +{ + Relation tag_rel; + Relation tag_desc_rel; + ListCell *cell; + ScanKeyData skey[3]; + SysScanDesc scan; + HeapTuple tuple_to_count; + int tags_counter = 0; + + tag_rel = table_open(TagRelationId, RowExclusiveLock); + tag_desc_rel = table_open(TagDescriptionRelationId, RowExclusiveLock); + + foreach(cell, tags) + { + Oid tag_desc_oid; + DefElem *def; + HeapTuple tuple; + HeapTuple desc_tuple; + HeapTuple new_tuple; + Form_pg_tag tagform; + Oid tagId; + char *tagname; + char *tagvalue; + Datum datum; + bool isnull; + List *allowed_values; + ListCell *value_cell; + + def = lfirst(cell); + tagname = def->defname; + tagvalue = defGetString(def); + + tuple = SearchSysCache1(TAGNAME, CStringGetDatum(tagname)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for tag %s", tagname); + + tagform = (Form_pg_tag) GETSTRUCT(tuple); + tagId = tagform->oid; + + /* Extract the current tag's allowed_values */ + datum = SysCacheGetAttr(TAGNAME, + tuple, + Anum_pg_tag_allowed_values, + &isnull); + + if (isnull) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag value \"%s\" does not exist in tag \"%s\"", + tagvalue, tagname))); + + allowed_values = untransformTagValues(datum); + + foreach(value_cell, allowed_values) + { + char *allowed_value = strVal(lfirst(value_cell)); + + if (strcmp(tagvalue, allowed_value) == 0) + { + break; + } + } + + if (value_cell) + { + desc_tuple = SearchSysCache4(TAGDESCRIPTION, + ObjectIdGetDatum(databaseid), + ObjectIdGetDatum(classid), + ObjectIdGetDatum(objid), + ObjectIdGetDatum(tagId)); + + if (!HeapTupleIsValid(desc_tuple)) + { + Datum tag_desc_values[Natts_pg_tag_description]; + bool tag_desc_nulls[Natts_pg_tag_description]; + + /* + * Insert tuple into pg_tag_description and record dependency. + */ + memset(tag_desc_values, 0, sizeof(tag_desc_values)); + memset(tag_desc_nulls, false, sizeof(tag_desc_nulls)); + + tag_desc_oid = GetNewOidForTagDescription(tag_desc_rel, + TagDescriptionOidIndexId, + Anum_pg_tag_description_oid, + objname, + tagId); + tag_desc_values[Anum_pg_tag_description_oid - 1] = ObjectIdGetDatum(tag_desc_oid); + tag_desc_values[Anum_pg_tag_description_databaseid - 1] = ObjectIdGetDatum(databaseid); + tag_desc_values[Anum_pg_tag_description_classid - 1] = ObjectIdGetDatum(classid); + tag_desc_values[Anum_pg_tag_description_objid - 1] = ObjectIdGetDatum(objid); + tag_desc_values[Anum_pg_tag_description_tagid - 1] = ObjectIdGetDatum(tagId); + +// /* Prepare the values array */ +// datum = transformTagValues(TAG_VALUES_ACTION_ADD, +// tagId, +// PointerGetDatum(NULL), +// list_make1(makeString(tagvalue)), +// false); +// if (PointerIsValid(DatumGetPointer(datum))) +// tag_desc_values[Anum_pg_tag_description_tagvalue - 1] = datum; +// else +// tag_desc_nulls[Anum_pg_tag_description_tagvalue - 1] = true; + datum = CStringGetTextDatum(tagvalue); + tag_desc_values[Anum_pg_tag_description_tagvalue - 1] = datum; + + new_tuple = heap_form_tuple(tag_desc_rel->rd_att, tag_desc_values, tag_desc_nulls); + + CatalogTupleInsert(tag_desc_rel, new_tuple); + + heap_freetuple(new_tuple); + + /* Record tag dependency */ + recordTagDependency(TagDescriptionRelationId, tag_desc_oid, tagId); + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("tag \"%s\" value has been added for object \"%s\".", + tagname, objname))); +// Datum tag_desc_repl_val[Natts_pg_tag_description]; +// bool tag_desc_repl_null[Natts_pg_tag_description]; +// bool tag_desc_repl_repl[Natts_pg_tag_description]; +// +// /* +// * Update existing tuple in pg_tag_description +// */ +// memset(tag_desc_repl_val, 0, sizeof(tag_desc_repl_val)); +// memset(tag_desc_repl_null, false, sizeof(tag_desc_repl_null)); +// memset(tag_desc_repl_repl, false, sizeof(tag_desc_repl_repl)); +// +// /* Extract the current tagvalues */ +// datum = SysCacheGetAttr(TAGDESCRIPTION, +// desc_tuple, +// Anum_pg_tag_description_tagvalues, +// &isnull); +// +// if (isnull) +// datum = PointerGetDatum(NULL); +// +// /* Prepare the values array */ +// datum = transformTagValues(TAG_VALUES_ACTION_ADD, +// datum, +// list_make1(makeString(tagvalue))); +// +// if (PointerIsValid(DatumGetPointer(datum))) +// tag_desc_repl_val[Anum_pg_tag_description_tagvalues - 1] = datum; +// else +// tag_desc_repl_null[Anum_pg_tag_description_tagvalues - 1] = true; +// +// tag_desc_repl_repl[Anum_pg_tag_description_tagvalues - 1] = true; +// +// /* Everything looks good - update the tuple */ +// new_tuple = heap_modify_tuple(desc_tuple, RelationGetDescr(tag_desc_rel), +// tag_desc_repl_val, tag_desc_repl_null, tag_desc_repl_repl); +// +// CatalogTupleUpdate(tag_desc_rel, &new_tuple->t_self, new_tuple); +// +// heap_freetuple(new_tuple); +// +// ReleaseSysCache(desc_tuple); + } + } + else + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag value \"%s\" is not in tag \"%s\" allowed values", + tagvalue, tagname))); + } + + ReleaseSysCache(tuple); + + CommandCounterIncrement(); + } + + /* + * Scan the pg_tag_description to check whether the object has been added 50 tags. + */ + ScanKeyInit(&skey[0], + Anum_pg_tag_description_databaseid, + BTEqualStrategyNumber, F_OIDEQ, + Int32GetDatum(databaseid)); + ScanKeyInit(&skey[1], + Anum_pg_tag_description_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classid)); + ScanKeyInit(&skey[2], + Anum_pg_tag_description_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objid)); + + scan = systable_beginscan(tag_desc_rel, TagDescriptionIndexId, true, + NULL, 3, skey); + + while ((tuple_to_count = systable_getnext(scan)) != NULL) + tags_counter += 1; + + if (tags_counter > MAX_TAG_NUMBER) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("Object \"%s\" added tags have exceeded the max number %d", + objname, MAX_TAG_NUMBER))); + + systable_endscan(scan); + + table_close(tag_desc_rel, RowExclusiveLock); + table_close(tag_rel, NoLock); + + return; +} + +/* + * Alter tag for object + * + * Alter tag for database object such as database, warehouse, table etc. + */ +void +AlterTagDescriptions(List *tags, + Oid databaseid, + Oid classid, + Oid objid, + char *objname) +{ + Relation tag_rel; + Relation tag_desc_rel; + ListCell *cell; + + tag_rel = table_open(TagRelationId, RowExclusiveLock); + tag_desc_rel = table_open(TagDescriptionRelationId, RowExclusiveLock); + + foreach(cell, tags) + { + HeapTuple tuple; + HeapTuple desc_tuple; + HeapTuple new_tuple; + Form_pg_tag tagform; + Oid tagId; + char *tagname = NULL; + char *tagvalue = NULL; + Datum datum; + bool isnull; + List *allowed_values; + ListCell *value_cell; + + DefElem *def = lfirst(cell); + tagname = def->defname; + tagvalue = defGetString(def); + + tuple = SearchSysCache1(TAGNAME, CStringGetDatum(tagname)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for tag %s", tagname); + + /* Extract the current tag's allowed_values */ + datum = SysCacheGetAttr(TAGNAME, + tuple, + Anum_pg_tag_allowed_values, + &isnull); + + if (isnull) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag value \"%s\" does not exist in tag \"%s\"", + tagvalue, tagname))); + + allowed_values = untransformTagValues(datum); + + foreach(value_cell, allowed_values) + { + char *allowed_value = strVal(lfirst(value_cell)); + + if (strcmp(tagvalue, allowed_value) == 0) + { + break; + } + } + + if (!value_cell) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tag value \"%s\" is not in tag \"%s\" allowed values", + tagvalue, tagname))); + } + + tagform = (Form_pg_tag) GETSTRUCT(tuple); + tagId = tagform->oid; + + desc_tuple = SearchSysCache4(TAGDESCRIPTION, + ObjectIdGetDatum(databaseid), + ObjectIdGetDatum(classid), + ObjectIdGetDatum(objid), + ObjectIdGetDatum(tagId)); + + if (!HeapTupleIsValid(desc_tuple)) + { + if (Gp_role == GP_ROLE_DISPATCH) + ereport(WARNING, + errmsg("object \"%s\" does not have tag \"%s\", creating", + objname, tagname)); + + AddTagDescriptions(list_make1(def), + databaseid, classid, + objid, objname); + } + else + { + Datum tag_desc_repl_val[Natts_pg_tag_description]; + bool tag_desc_repl_null[Natts_pg_tag_description]; + bool tag_desc_repl_repl[Natts_pg_tag_description]; + + /* + * Update existing tuple in pg_tag_description + */ + memset(tag_desc_repl_val, 0, sizeof(tag_desc_repl_val)); + memset(tag_desc_repl_null, false, sizeof(tag_desc_repl_null)); + memset(tag_desc_repl_repl, false, sizeof(tag_desc_repl_repl)); + +// /* Extract the current tagvalue */ +// datum = SysCacheGetAttr(TAGDESCRIPTION, +// desc_tuple, +// Anum_pg_tag_description_tagvalue, +// &isnull); +// +// if (isnull) +// datum = PointerGetDatum(NULL); + + /* Prepare the values array */ +// datum = transformTagValues(TAG_VALUES_ACTION_ADD, +// tagId, +// PointerGetDatum(NULL), +// list_make1(makeString(tagvalue)), +// false); +// +// if (PointerIsValid(DatumGetPointer(datum))) +// tag_desc_repl_val[Anum_pg_tag_description_tagvalue - 1] = datum; +// else +// tag_desc_repl_null[Anum_pg_tag_description_tagvalue - 1] = true; + datum = CStringGetTextDatum(tagvalue); + tag_desc_repl_val[Anum_pg_tag_description_tagvalue - 1] = datum; + + tag_desc_repl_repl[Anum_pg_tag_description_tagvalue - 1] = true; + + /* Everything looks good - update the tuple */ + new_tuple = heap_modify_tuple(desc_tuple, RelationGetDescr(tag_desc_rel), + tag_desc_repl_val, tag_desc_repl_null, tag_desc_repl_repl); + + CatalogTupleUpdate(tag_desc_rel, &new_tuple->t_self, new_tuple); + + heap_freetuple(new_tuple); + + ReleaseSysCache(desc_tuple); + } + + ReleaseSysCache(tuple); + + CommandCounterIncrement(); + } + + table_close(tag_desc_rel, RowExclusiveLock); + table_close(tag_rel, NoLock); + + return; +} + + +/* + * Unset tags for object + * + * Unset tag description value for object. + */ +void +UnsetTagDescriptions(List *tags, + Oid databaseid, + Oid classid, + Oid objid, + char *objname) +{ + Relation tag_rel; + Relation tag_desc_rel; + ListCell *cell; + + tag_rel = table_open(TagRelationId, RowExclusiveLock); + tag_desc_rel = table_open(TagDescriptionRelationId, RowExclusiveLock); + + foreach(cell, tags) + { + HeapTuple tuple; + HeapTuple desc_tuple; + HeapTuple new_tuple; + Form_pg_tag tagform; + Oid tagId; + char *tagname = NULL; + Datum tag_desc_repl_val[Natts_pg_tag_description]; + bool tag_desc_repl_null[Natts_pg_tag_description]; + bool tag_desc_repl_repl[Natts_pg_tag_description]; + + tagname = strVal(lfirst(cell)); + + tuple = SearchSysCache1(TAGNAME, CStringGetDatum(tagname)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for tag %s", tagname); + + tagform = (Form_pg_tag) GETSTRUCT(tuple); + tagId = tagform->oid; + + desc_tuple = SearchSysCache4(TAGDESCRIPTION, + ObjectIdGetDatum(databaseid), + ObjectIdGetDatum(classid), + ObjectIdGetDatum(objid), + ObjectIdGetDatum(tagId)); + + if (!HeapTupleIsValid(desc_tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("object \"%s\" does not have tag \"%s\"", + objname, tagname))); + + /* + * Unset existing tag value in pg_tag_description + */ + memset(tag_desc_repl_val, 0, sizeof(tag_desc_repl_val)); + memset(tag_desc_repl_null, false, sizeof(tag_desc_repl_null)); + memset(tag_desc_repl_repl, false, sizeof(tag_desc_repl_repl)); + + tag_desc_repl_null[Anum_pg_tag_description_tagvalue - 1] = true; + tag_desc_repl_repl[Anum_pg_tag_description_tagvalue - 1] = true; + + /* Everything looks good - update the tuple */ + new_tuple = heap_modify_tuple(desc_tuple, RelationGetDescr(tag_desc_rel), + tag_desc_repl_val, tag_desc_repl_null, tag_desc_repl_repl); + + CatalogTupleUpdate(tag_desc_rel, &new_tuple->t_self, new_tuple); + + heap_freetuple(new_tuple); + + ReleaseSysCache(desc_tuple); + ReleaseSysCache(tuple); + + CommandCounterIncrement(); + } + + table_close(tag_desc_rel, RowExclusiveLock); + table_close(tag_rel, NoLock); + + return; +} + +/* + * Remove tag for object + * + * Remove tag for database object such as database, warehouse, table etc. + */ +void +DeleteTagDescriptions(Oid databaseid, + Oid classid, + Oid objid) +{ + Oid tagdescId; + HeapTuple desc_tuple; + Relation rel; + ScanKeyData skey[3]; + SysScanDesc scan; + Form_pg_tag tagform; + + ScanKeyInit(&skey[0], + Anum_pg_tag_description_databaseid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(databaseid)); + ScanKeyInit(&skey[1], + Anum_pg_tag_description_classid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classid)); + ScanKeyInit(&skey[2], + Anum_pg_tag_description_objid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objid)); + + rel = table_open(TagDescriptionRelationId, RowExclusiveLock); + + scan = systable_beginscan(rel, TagDescriptionIndexId, true, + NULL, 3, skey); + + while ((desc_tuple = systable_getnext(scan)) != NULL) + { + tagform = (Form_pg_tag) GETSTRUCT(desc_tuple); + tagdescId = tagform->oid; + + CatalogTupleDelete(rel, &desc_tuple->t_self); + + /* + * Delete shared dependency references related to this tag description object. + */ + deleteSharedDependencyRecordsFor(TagDescriptionRelationId, tagdescId, 0); + } + + systable_endscan(scan); + + /* Hold lock until transaction commit */ + table_close(rel, NoLock); +} + + +/* + * Transform tag values to datum. + */ +static Datum +transformTagValues(int action, Oid tagId, Datum oldvalues, + List *allowed_values, bool unset) +{ + List *resultValues = untransformTagValues(oldvalues); + ListCell *value_cell; + Datum result; + + Assert(!(resultValues && unset)); + + foreach(value_cell, allowed_values) + { + char *value = strVal(lfirst(value_cell)); + ListCell *cell; + + foreach(cell, resultValues) + { + char *oldvalue = strVal(lfirst(cell)); + + if (strcmp(value, oldvalue) == 0 || unset) + break; + } + + if (action > 0) + { + if (cell) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("allowed value \"%s\" has been added", + strVal(lfirst(value_cell))))); + + /* Max allowed value length is 256. */ + if (strlen(value) > 256) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("added allowed value \"%s\" has exceeded max 256 length", + strVal(lfirst(value_cell))))); + + resultValues = lappend(resultValues, lfirst(value_cell)); + } + else + { + if (!cell) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("allowed value \"%s\" not found", + strVal(lfirst(value_cell))))); + + checkDropTagValue(tagId, strVal(lfirst(cell))); + + resultValues = list_delete_cell(resultValues, cell); + } + } + + /* Max allowed_values number is 300. */ + if (list_length(resultValues) > 300) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("Allowed_values only allow 300 values."))); + + result = valueListToArray(resultValues); + + return result; +} + +/* + * Untranform tag values from datum to list. + */ +static List * +untransformTagValues(Datum allowed_values) +{ + List *result = NIL; + ArrayType *array; + Datum *valuedatums; + int nvalues; + int i; + + /* Nothing to do if no allowed_values */ + if (!PointerIsValid(DatumGetPointer(allowed_values))) + return result; + + array = DatumGetArrayTypeP(allowed_values); + + deconstruct_array(array, TEXTOID, -1, false, TYPALIGN_INT, + &valuedatums, NULL, &nvalues); + + for (i = 0; i < nvalues; i ++) + { + char *s; + Node *val = NULL; + + s = TextDatumGetCString(valuedatums[i]); + val = (Node *) makeString(pstrdup(s)); + + result = lappend(result, val); + } + + return result; +} + +/* + * Get array datum from allowed_values list. + */ +static Datum +valueListToArray(List *allowed_values) +{ + ArrayBuildState *astate = NULL; + ListCell *cell; + + foreach(cell, allowed_values) + { + char *value = strVal(lfirst(cell)); + Size len; + text *t; + + len = VARHDRSZ + strlen(value); + t = palloc(len + 1); + SET_VARSIZE(t, len); + sprintf(VARDATA(t), "%s", value); + + astate = accumArrayResult(astate, PointerGetDatum(t), + false, TEXTOID, + CurrentMemoryContext); + } + + if (astate) + return makeArrayResult(astate, CurrentMemoryContext); + + return PointerGetDatum(NULL); +} + +/* + * Check whether the tag value has been used on object. + * + * When we alter tag to drop allowed_values, only when the tag + * value has not been used on object we can do it. Otherwise, + * we will report error. Here, we do this check. + */ +static +void checkDropTagValue(Oid tagId, char *tagvalue) +{ + Relation tag_desc_rel; + ScanKeyData skey[2]; + SysScanDesc scan; + HeapTuple tuple; + char *tagname; + + ScanKeyInit(&skey[0], Anum_pg_tag_description_tagid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(tagId)); + ScanKeyInit(&skey[1], Anum_pg_tag_description_tagvalue, + BTEqualStrategyNumber, F_TEXTEQ, + CStringGetTextDatum(tagvalue)); + + tag_desc_rel = table_open(TagDescriptionRelationId, AccessShareLock); + + scan = systable_beginscan(tag_desc_rel, TagDescriptionTagidvalueIndexId, true, + NULL, 2, skey); + + tuple = systable_getnext(scan); + if (HeapTupleIsValid(tuple)) + { + tagname = TagGetNameByOid(tagId, false); + + ereport(ERROR, + (errcode(ERRCODE_CHECK_VIOLATION), + errmsg("Can't drop tag \"%s\" value \"%s\", which is using.", + tagname, tagvalue))); + } + + systable_endscan(scan); + table_close(tag_desc_rel, AccessShareLock); +} + +/* + * TagGetNameByOid + * + * Get tag name by tag oid. + */ +char * +TagGetNameByOid(Oid tagid, bool missing_ok) +{ + char *tagname; + HeapTuple tuple; + Form_pg_tag tagform; + + tuple = SearchSysCache1(TAGOID, ObjectIdGetDatum(tagid)); + if (!HeapTupleIsValid(tuple)) + { + if (!missing_ok) + elog(ERROR, "tag %u could not be found", tagid); + + tagname = NULL; + } + else + { + tagform = (Form_pg_tag) GETSTRUCT(tuple); + + tagname = pstrdup(tagform->tagname.data); + } + ReleaseSysCache(tuple); + + return tagname; +} diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 8ff1782d776..ecb74df291e 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -34,6 +34,7 @@ #include "commands/comment.h" #include "commands/dbcommands.h" #include "commands/seclabel.h" +#include "commands/tag.h" #include "commands/user.h" #include "libpq/crypt.h" #include "miscadmin.h" @@ -857,6 +858,16 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) AddRoleDenials(stmt->role, roleid, addintervals); } + /* + * Create tag description. + */ + if (stmt->tags) + AddTagDescriptions(stmt->tags, + InvalidOid, + AuthIdRelationId, + roleid, + stmt->role); + /* * Close pg_authid, but keep lock till commit. */ @@ -1774,6 +1785,27 @@ AlterRole(AlterRoleStmt *stmt) ReleaseSysCache(tuple); heap_freetuple(new_tuple); + if (stmt->tags) + { + if (!stmt->unsettag) + { + AlterTagDescriptions(stmt->tags, + InvalidOid, + AuthIdRelationId, + roleid, + rolename); + } + + if (stmt->unsettag) + { + UnsetTagDescriptions(stmt->tags, + InvalidOid, + AuthIdRelationId, + roleid, + rolename); + } + } + /* * Advance command counter so we can see new record; else tests in * AddRoleMems may fail. @@ -1859,7 +1891,7 @@ AlterRole(AlterRoleStmt *stmt) DF_CANCEL_ON_ERROR| DF_WITH_SNAPSHOT| DF_NEED_TWO_PHASE, - NIL, + GetAssignedOidsForDispatch(), NULL); } @@ -2131,6 +2163,13 @@ DropRole(DropRoleStmt *stmt) */ DeleteSharedComments(roleid, AuthIdRelationId); DeleteSharedSecurityLabel(roleid, AuthIdRelationId); + + /* + * Delete any tag description and associated dependencies. + */ + DeleteTagDescriptions(InvalidOid, + AuthIdRelationId, + roleid); /* MPP-6929: metadata tracking */ if (Gp_role == GP_ROLE_DISPATCH) diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 52edda2ed02..0b070e3c69d 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -23,6 +23,7 @@ #include "catalog/pg_depend.h" #include "commands/defrem.h" #include "commands/tablecmds.h" +#include "commands/tag.h" #include "commands/view.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -587,6 +588,17 @@ DefineView(ViewStmt *stmt, const char *queryString, address = DefineVirtualRelation(view, viewParse->targetList, stmt->replace, stmt->options, viewParse); + /* + * Create tag description. + */ + if (stmt->tags) + AddTagDescriptions(stmt->tags, + MyDatabaseId, + address.classId, + address.objectId, + stmt->view->relname); + + if (Gp_role == GP_ROLE_DISPATCH) { ViewStmt *dispatchStmt = (ViewStmt *) copyObject(stmt); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 7fe3e7d0836..b0e2fc50f27 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3923,6 +3923,8 @@ _copyAlterTableCmd(const AlterTableCmd *from) COPY_NODE_FIELD(def); COPY_SCALAR_FIELD(behavior); COPY_SCALAR_FIELD(missing_ok); + COPY_NODE_FIELD(tags); + COPY_SCALAR_FIELD(unsettag); return newnode; } @@ -4130,6 +4132,7 @@ CopyCreateStmtFields(const CreateStmt *from, CreateStmt *newnode) COPY_NODE_FIELD(part_idx_oids); COPY_NODE_FIELD(part_idx_names); + COPY_NODE_FIELD(tags); } static CreateStmt * @@ -4183,6 +4186,7 @@ _copyCreateExternalStmt(const CreateExternalStmt *from) COPY_NODE_FIELD(extOptions); COPY_NODE_FIELD(encoding); COPY_NODE_FIELD(distributedBy); + COPY_NODE_FIELD(tags); return newnode; } @@ -4310,6 +4314,7 @@ _copyIndexStmt(const IndexStmt *from) COPY_SCALAR_FIELD(reset_default_tblspc); COPY_SCALAR_FIELD(concurrentlyPhase); COPY_SCALAR_FIELD(indexRelationOid); + COPY_NODE_FIELD(tags); return newnode; } @@ -4594,6 +4599,7 @@ _copyViewStmt(const ViewStmt *from) COPY_SCALAR_FIELD(replace); COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(withCheckOption); + COPY_NODE_FIELD(tags); return newnode; } @@ -4682,6 +4688,7 @@ _copyCreatedbStmt(const CreatedbStmt *from) COPY_STRING_FIELD(dbname); COPY_NODE_FIELD(options); + COPY_NODE_FIELD(tags); return newnode; } @@ -4693,6 +4700,8 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from) COPY_STRING_FIELD(dbname); COPY_NODE_FIELD(options); + COPY_NODE_FIELD(tags); + COPY_SCALAR_FIELD(unsettag); return newnode; } @@ -4812,6 +4821,7 @@ _copyCreateSeqStmt(const CreateSeqStmt *from) COPY_SCALAR_FIELD(ownerId); COPY_SCALAR_FIELD(for_identity); COPY_SCALAR_FIELD(if_not_exists); + COPY_NODE_FIELD(tags); return newnode; } @@ -4872,6 +4882,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from) COPY_STRING_FIELD(location); COPY_NODE_FIELD(options); COPY_STRING_FIELD(filehandler); + COPY_NODE_FIELD(tags); return newnode; } @@ -4895,6 +4906,8 @@ _copyAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *from) COPY_STRING_FIELD(tablespacename); COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(isReset); + COPY_NODE_FIELD(tags); + COPY_SCALAR_FIELD(unsettag); return newnode; } @@ -5238,6 +5251,7 @@ _copyCreateRoleStmt(const CreateRoleStmt *from) COPY_SCALAR_FIELD(stmt_type); COPY_STRING_FIELD(role); COPY_NODE_FIELD(options); + COPY_NODE_FIELD(tags); return newnode; } @@ -5283,6 +5297,8 @@ _copyAlterRoleStmt(const AlterRoleStmt *from) COPY_NODE_FIELD(role); COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(action); + COPY_NODE_FIELD(tags); + COPY_SCALAR_FIELD(unsettag); return newnode; } @@ -5398,10 +5414,60 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from) COPY_SCALAR_FIELD(if_not_exists); COPY_SCALAR_FIELD(istemp); COPY_SCALAR_FIELD(pop_search_path); + COPY_NODE_FIELD(tags); return newnode; } +static AlterSchemaStmt * +_copyAlterSchemaStmt(const AlterSchemaStmt *from) +{ + AlterSchemaStmt *newnode = makeNode(AlterSchemaStmt); + + COPY_STRING_FIELD(schemaname); + COPY_NODE_FIELD(tags); + COPY_SCALAR_FIELD(unsettag); + + return newnode; +} + +static CreateTagStmt * +_copyCreateTagStmt(const CreateTagStmt *from) +{ + CreateTagStmt *newnode = makeNode(CreateTagStmt); + + COPY_STRING_FIELD(tag_name); + COPY_SCALAR_FIELD(missing_ok); + COPY_NODE_FIELD(allowed_values); + + return newnode; +} + +static AlterTagStmt * +_copyAlterTagStmt(const AlterTagStmt *from) +{ + AlterTagStmt *newnode = makeNode(AlterTagStmt); + + COPY_STRING_FIELD(tag_name); + COPY_SCALAR_FIELD(action); + COPY_NODE_FIELD(tag_values); + COPY_SCALAR_FIELD(missing_ok); + COPY_SCALAR_FIELD(unset); + + return newnode; +} + +static DropTagStmt * +_copyDropTagStmt(const DropTagStmt *from) +{ + DropTagStmt *newnode = makeNode(DropTagStmt); + + COPY_NODE_FIELD(tags); + COPY_SCALAR_FIELD(missing_ok); + + return newnode; +} + static CreateConversionStmt * _copyCreateConversionStmt(const CreateConversionStmt *from) { @@ -6112,6 +6178,18 @@ _copyCreateDirectoryTableStmt(const CreateDirectoryTableStmt *from) return newnode; } +static AlterDirectoryTableStmt * +_copyAlterDirectoryTableStmt(const AlterDirectoryTableStmt *from) +{ + AlterDirectoryTableStmt *newnode = makeNode(AlterDirectoryTableStmt); + + COPY_NODE_FIELD(relation); + COPY_NODE_FIELD(tags); + COPY_SCALAR_FIELD(unsettag); + + return newnode; +} + static EphemeralNamedRelationInfo* _copyEphemeralNamedRelationInfo(const EphemeralNamedRelationInfo *from) { @@ -6946,6 +7024,18 @@ copyObjectImpl(const void *from) case T_CreateSchemaStmt: retval = _copyCreateSchemaStmt(from); break; + case T_AlterSchemaStmt: + retval = _copyAlterSchemaStmt(from); + break; + case T_CreateTagStmt: + retval = _copyCreateTagStmt(from); + break; + case T_AlterTagStmt: + retval = _copyAlterTagStmt(from); + break; + case T_DropTagStmt: + retval = _copyDropTagStmt(from); + break; case T_CreateConversionStmt: retval = _copyCreateConversionStmt(from); break; @@ -7257,6 +7347,10 @@ copyObjectImpl(const void *from) retval = _copyCreateDirectoryTableStmt(from); break; + case T_AlterDirectoryTableStmt: + retval = _copyAlterDirectoryTableStmt(from); + break; + case T_EphemeralNamedRelationInfo: retval = _copyEphemeralNamedRelationInfo(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 283a5c5d552..b222609948f 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1219,6 +1219,8 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b) COMPARE_NODE_FIELD(def); COMPARE_SCALAR_FIELD(behavior); COMPARE_SCALAR_FIELD(missing_ok); + COMPARE_NODE_FIELD(tags); + COMPARE_SCALAR_FIELD(unsettag); return true; } @@ -1389,6 +1391,7 @@ _equalCreateStmt(const CreateStmt *a, const CreateStmt *b) COMPARE_SCALAR_FIELD(buildAoBlkdir); COMPARE_NODE_FIELD(attr_encodings); COMPARE_SCALAR_FIELD(isCtas); + COMPARE_NODE_FIELD(tags); return true; } @@ -1439,6 +1442,7 @@ _equalCreateExternalStmt(const CreateExternalStmt *a, const CreateExternalStmt * COMPARE_NODE_FIELD(extOptions); COMPARE_NODE_FIELD(encoding); COMPARE_NODE_FIELD(distributedBy); + COMPARE_NODE_FIELD(tags); return true; } @@ -1560,6 +1564,7 @@ _equalIndexStmt(const IndexStmt *a, const IndexStmt *b) COMPARE_SCALAR_FIELD(reset_default_tblspc); COMPARE_SCALAR_FIELD(concurrentlyPhase); COMPARE_SCALAR_FIELD(indexRelationOid); + COMPARE_NODE_FIELD(tags); return true; } @@ -1800,6 +1805,7 @@ _equalViewStmt(const ViewStmt *a, const ViewStmt *b) COMPARE_SCALAR_FIELD(replace); COMPARE_NODE_FIELD(options); COMPARE_SCALAR_FIELD(withCheckOption); + COMPARE_NODE_FIELD(tags); return true; } @@ -1874,6 +1880,7 @@ _equalCreatedbStmt(const CreatedbStmt *a, const CreatedbStmt *b) { COMPARE_STRING_FIELD(dbname); COMPARE_NODE_FIELD(options); + COMPARE_NODE_FIELD(tags); return true; } @@ -1882,6 +1889,8 @@ _equalAlterDatabaseStmt(const AlterDatabaseStmt *a, const AlterDatabaseStmt *b) { COMPARE_STRING_FIELD(dbname); COMPARE_NODE_FIELD(options); + COMPARE_NODE_FIELD(tags); + COMPARE_SCALAR_FIELD(unsettag); return true; } @@ -1983,6 +1992,7 @@ _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b) COMPARE_SCALAR_FIELD(ownerId); COMPARE_SCALAR_FIELD(for_identity); COMPARE_SCALAR_FIELD(if_not_exists); + COMPARE_NODE_FIELD(tags); return true; } @@ -2033,6 +2043,7 @@ _equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpace COMPARE_STRING_FIELD(location); COMPARE_NODE_FIELD(options); COMPARE_STRING_FIELD(filehandler); + COMPARE_NODE_FIELD(tags); return true; } @@ -2053,6 +2064,8 @@ _equalAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *a, COMPARE_STRING_FIELD(tablespacename); COMPARE_NODE_FIELD(options); COMPARE_SCALAR_FIELD(isReset); + COMPARE_NODE_FIELD(tags); + COMPARE_SCALAR_FIELD(unsettag); return true; } @@ -2346,6 +2359,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b) COMPARE_SCALAR_FIELD(stmt_type); COMPARE_STRING_FIELD(role); COMPARE_NODE_FIELD(options); + COMPARE_NODE_FIELD(tags); return true; } @@ -2383,6 +2397,8 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b) COMPARE_NODE_FIELD(role); COMPARE_NODE_FIELD(options); COMPARE_SCALAR_FIELD(action); + COMPARE_NODE_FIELD(tags); + COMPARE_SCALAR_FIELD(unsettag); return true; } @@ -2480,10 +2496,52 @@ _equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b) COMPARE_SCALAR_FIELD(if_not_exists); COMPARE_SCALAR_FIELD(istemp); COMPARE_SCALAR_FIELD(pop_search_path); + COMPARE_NODE_FIELD(tags); return true; } +static bool +_equalAlterSchemaStmt(const AlterSchemaStmt *a, const AlterSchemaStmt *b) +{ + COMPARE_STRING_FIELD(schemaname); + COMPARE_NODE_FIELD(tags); + COMPARE_SCALAR_FIELD(unsettag); + + return true; +} + +static bool +_equalCreateTagStmt(const CreateTagStmt *a, const CreateTagStmt *b) +{ + COMPARE_STRING_FIELD(tag_name); + COMPARE_SCALAR_FIELD(missing_ok); + COMPARE_NODE_FIELD(allowed_values); + + return true; +} + +static bool +_equalAlterTagStmt(const AlterTagStmt *a, const AlterTagStmt *b) +{ + COMPARE_STRING_FIELD(tag_name); + COMPARE_SCALAR_FIELD(action); + COMPARE_NODE_FIELD(tag_values); + COMPARE_SCALAR_FIELD(missing_ok); + COMPARE_SCALAR_FIELD(unset); + + return true; +} + +static bool +_equalDropTagStmt(const DropTagStmt *a, const DropTagStmt *b) +{ + COMPARE_NODE_FIELD(tags); + COMPARE_SCALAR_FIELD(missing_ok); + + return true; +} + static bool _equalCreateConversionStmt(const CreateConversionStmt *a, const CreateConversionStmt *b) { @@ -3406,6 +3464,16 @@ _equalCreateDirectoryTableStmt(const CreateDirectoryTableStmt *a, const CreateDi return true; } +static bool +_equalAlterDirectoryTableStmt(const AlterDirectoryTableStmt *a, const AlterDirectoryTableStmt *b) +{ + COMPARE_NODE_FIELD(relation); + COMPARE_NODE_FIELD(tags); + COMPARE_SCALAR_FIELD(unsettag); + + return true; +} + /* * Stuff from pg_list.h */ @@ -4096,6 +4164,18 @@ equal(const void *a, const void *b) case T_CreateSchemaStmt: retval = _equalCreateSchemaStmt(a, b); break; + case T_AlterSchemaStmt: + retval = _equalAlterSchemaStmt(a, b); + break; + case T_CreateTagStmt: + retval = _equalCreateTagStmt(a, b); + break; + case T_AlterTagStmt: + retval = _equalAlterTagStmt(a, b); + break; + case T_DropTagStmt: + retval = _equalDropTagStmt(a, b); + break; case T_CreateConversionStmt: retval = _equalCreateConversionStmt(a, b); break; @@ -4343,6 +4423,10 @@ equal(const void *a, const void *b) retval = _equalCreateDirectoryTableStmt(a, b); break; + case T_AlterDirectoryTableStmt: + retval = _equalAlterDirectoryTableStmt(a, b); + break; + default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(a)); diff --git a/src/backend/nodes/outfast.c b/src/backend/nodes/outfast.c index 043a2b8af6c..d2ef98d93ed 100644 --- a/src/backend/nodes/outfast.c +++ b/src/backend/nodes/outfast.c @@ -806,6 +806,8 @@ _outAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *node) WRITE_STRING_FIELD(tablespacename); WRITE_NODE_FIELD(options); WRITE_BOOL_FIELD(isReset); + WRITE_NODE_FIELD(tags); + WRITE_BOOL_FIELD(unsettag); } static void @@ -1624,6 +1626,19 @@ _outNode(StringInfo str, void *obj) case T_CreateSchemaStmt: _outCreateSchemaStmt(str, obj); break; + case T_AlterSchemaStmt: + _outAlterSchemaStmt(str, obj); + break; + + case T_CreateTagStmt: + _outCreateTagStmt(str, obj); + break; + case T_AlterTagStmt: + _outAlterTagStmt(str, obj); + break; + case T_DropTagStmt: + _outDropTagStmt(str, obj); + break; case T_CreatePLangStmt: _outCreatePLangStmt(str, obj); break; @@ -1863,9 +1878,15 @@ _outNode(StringInfo str, void *obj) case T_CreateDirectoryTableStmt: _outCreateDirectoryTableStmt(str, obj); break; + case T_AlterDirectoryTableStmt: + _outAlterDirectoryTableStmt(str, obj); + break; case T_EphemeralNamedRelationInfo: _outEphemeralNamedRelationInfo(str, obj); break; + case T_AlterDatabaseStmt: + _outAlterDatabaseStmt(str, obj); + break; default: elog(ERROR, "could not serialize unrecognized node type: %d", (int) nodeTag(obj)); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 4d0dee54f2c..0b53a1a3c4d 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2901,6 +2901,7 @@ _outCreateStmtInfo(StringInfo str, const CreateStmt *node) WRITE_NODE_FIELD(part_idx_oids); WRITE_NODE_FIELD(part_idx_names); + WRITE_NODE_FIELD(tags); /* * Some extra checks to make sure we didn't get lost @@ -2974,6 +2975,7 @@ _outIndexStmt(StringInfo str, const IndexStmt *node) WRITE_BOOL_FIELD(reset_default_tblspc); WRITE_ENUM_FIELD(concurrentlyPhase, IndexConcurrentlyPhase); WRITE_OID_FIELD(indexRelationOid); + WRITE_NODE_FIELD(tags); } static void @@ -3285,6 +3287,7 @@ _outQuery(StringInfo str, const Query *node) case T_DropProfileStmt: case T_CreateSchemaStmt: + case T_AlterSchemaStmt: case T_CreatePLangStmt: case T_AlterOwnerStmt: case T_AlterObjectSchemaStmt: @@ -4031,6 +4034,16 @@ _outCreateDirectoryTableStmt(StringInfo str, const CreateDirectoryTableStmt *nod WRITE_STRING_FIELD(tablespacename); } +static void +_outAlterDirectoryTableStmt(StringInfo str, const AlterDirectoryTableStmt *node) +{ + WRITE_NODE_TYPE("ALTERDIRECTORYTABLESTMT"); + + WRITE_NODE_FIELD(relation); + WRITE_NODE_FIELD(tags); + WRITE_BOOL_FIELD(unsettag); +} + #include "outfuncs_common.c" #ifndef COMPILING_BINARY_FUNCS /* @@ -5031,6 +5044,19 @@ outNode(StringInfo str, const void *obj) case T_CreateSchemaStmt: _outCreateSchemaStmt(str, obj); break; + case T_AlterSchemaStmt: + _outAlterSchemaStmt(str, obj); + break; + + case T_CreateTagStmt: + _outCreateTagStmt(str, obj); + break; + case T_AlterTagStmt: + _outAlterTagStmt(str, obj); + break; + case T_DropTagStmt: + _outDropTagStmt(str, obj); + break; case T_CreatePLangStmt: _outCreatePLangStmt(str, obj); break; @@ -5166,9 +5192,15 @@ outNode(StringInfo str, const void *obj) case T_EphemeralNamedRelationInfo: _outEphemeralNamedRelationInfo(str, obj); break; + case T_AlterDatabaseStmt: + _outAlterDatabaseStmt(str, obj); + break; case T_CreateDirectoryTableStmt: _outCreateDirectoryTableStmt(str, obj); break; + case T_AlterDirectoryTableStmt: + _outAlterDirectoryTableStmt(str, obj); + break; default: /* diff --git a/src/backend/nodes/outfuncs_common.c b/src/backend/nodes/outfuncs_common.c index 76e766e55d2..4cf0c1b8287 100644 --- a/src/backend/nodes/outfuncs_common.c +++ b/src/backend/nodes/outfuncs_common.c @@ -568,6 +568,7 @@ _outCreateExternalStmt(StringInfo str, const CreateExternalStmt *node) WRITE_NODE_FIELD(extOptions); WRITE_NODE_FIELD(encoding); WRITE_NODE_FIELD(distributedBy); + WRITE_NODE_FIELD(tags); } static void @@ -619,6 +620,7 @@ _outViewStmt(StringInfo str, const ViewStmt *node) WRITE_NODE_FIELD(query); WRITE_BOOL_FIELD(replace); WRITE_NODE_FIELD(options); + WRITE_NODE_FIELD(tags); } static void @@ -712,6 +714,8 @@ _outAlterTableCmd(StringInfo str, const AlterTableCmd *node) WRITE_INT_FIELD(backendId); WRITE_NODE_FIELD(policy); + WRITE_NODE_FIELD(tags); + WRITE_BOOL_FIELD(unsettag); } static void @@ -840,6 +844,7 @@ _outCreateRoleStmt(StringInfo str, const CreateRoleStmt *node) WRITE_ENUM_FIELD(stmt_type, RoleStmtType); WRITE_STRING_FIELD(role); WRITE_NODE_FIELD(options); + WRITE_NODE_FIELD(tags); } static void @@ -927,6 +932,8 @@ _outAlterRoleStmt(StringInfo str, const AlterRoleStmt *node) WRITE_NODE_FIELD(role); WRITE_NODE_FIELD(options); WRITE_INT_FIELD(action); + WRITE_NODE_FIELD(tags); + WRITE_BOOL_FIELD(unsettag); } static void @@ -973,6 +980,7 @@ _outCreateSeqStmt(StringInfo str, const CreateSeqStmt *node) WRITE_OID_FIELD(ownerId); WRITE_BOOL_FIELD(for_identity); WRITE_BOOL_FIELD(if_not_exists); + WRITE_NODE_FIELD(tags); } static void @@ -1000,6 +1008,7 @@ _outCreatedbStmt(StringInfo str, const CreatedbStmt *node) WRITE_NODE_TYPE("CREATEDBSTMT"); WRITE_STRING_FIELD(dbname); WRITE_NODE_FIELD(options); + WRITE_NODE_FIELD(tags); } static void @@ -1366,6 +1375,48 @@ _outCreateSchemaStmt(StringInfo str, const CreateSchemaStmt *node) WRITE_NODE_FIELD(authrole); WRITE_BOOL_FIELD(istemp); WRITE_BOOL_FIELD(pop_search_path); + WRITE_NODE_FIELD(tags); +} + +static void +_outAlterSchemaStmt(StringInfo str, const AlterSchemaStmt *node) +{ + WRITE_NODE_TYPE("ALTERSCHEMASTMT"); + + WRITE_STRING_FIELD(schemaname); + WRITE_NODE_FIELD(tags); + WRITE_BOOL_FIELD(unsettag); +} + +static void +_outCreateTagStmt(StringInfo str, const CreateTagStmt *node) +{ + WRITE_NODE_TYPE("CREATETAGSTMT"); + + WRITE_STRING_FIELD(tag_name); + WRITE_BOOL_FIELD(missing_ok); + WRITE_NODE_FIELD(allowed_values); +} + +static void +_outAlterTagStmt(StringInfo str, const AlterTagStmt *node) +{ + WRITE_NODE_TYPE("ALTERTAGSTMT"); + + WRITE_STRING_FIELD(tag_name); + WRITE_INT_FIELD(action); + WRITE_NODE_FIELD(tag_values); + WRITE_BOOL_FIELD(missing_ok); + WRITE_BOOL_FIELD(unset); +} + +static void +_outDropTagStmt(StringInfo str, const DropTagStmt *node) +{ + WRITE_NODE_TYPE("DROPTAGSTMT"); + + WRITE_NODE_FIELD(tags); + WRITE_BOOL_FIELD(missing_ok); } static void @@ -1485,6 +1536,7 @@ _outCreateTableSpaceStmt(StringInfo str, const CreateTableSpaceStmt *node) WRITE_STRING_FIELD(location); WRITE_NODE_FIELD(options); WRITE_STRING_FIELD(filehandler); + WRITE_NODE_FIELD(tags); } static void @@ -1714,3 +1766,13 @@ _outEphemeralNamedRelationInfo(StringInfo str, const EphemeralNamedRelationInfo WRITE_ENUM_FIELD(enrtype, EphemeralNameRelationType); WRITE_FLOAT_FIELD(enrtuples, "%.0f"); } + +static void +_outAlterDatabaseStmt(StringInfo str, const AlterDatabaseStmt *node) +{ + WRITE_NODE_TYPE("AlterDatabaseStmt"); + WRITE_STRING_FIELD(dbname); + WRITE_NODE_FIELD(options); + WRITE_NODE_FIELD(tags); + WRITE_BOOL_FIELD(unsettag); +} \ No newline at end of file diff --git a/src/backend/nodes/readfast.c b/src/backend/nodes/readfast.c index 96e42bff0cd..351c8eae1d5 100644 --- a/src/backend/nodes/readfast.c +++ b/src/backend/nodes/readfast.c @@ -744,6 +744,7 @@ _readCreateStmt_common(CreateStmt *local_node) READ_NODE_FIELD(part_idx_oids); READ_NODE_FIELD(part_idx_names); + READ_NODE_FIELD(tags); /* * Some extra checks to make sure we didn't get lost @@ -1132,6 +1133,7 @@ _readCreateTableSpaceStmt(void) READ_STRING_FIELD(location); READ_NODE_FIELD(options); READ_STRING_FIELD(filehandler); + READ_NODE_FIELD(tags); READ_DONE(); } @@ -1170,6 +1172,8 @@ _readAlterTableSpaceOptionsStmt(void) READ_STRING_FIELD(tablespacename); READ_NODE_FIELD(options); READ_BOOL_FIELD(isReset); + READ_NODE_FIELD(tags); + READ_BOOL_FIELD(unsettag); READ_DONE(); } @@ -1726,6 +1730,18 @@ _readCreateDirectoryTableStmt(void) READ_DONE(); } +static AlterDirectoryTableStmt * +_readAlterDirectoryTableStmt(void) +{ + READ_LOCALS(AlterDirectoryTableStmt); + + READ_NODE_FIELD(relation); + READ_NODE_FIELD(tags); + READ_BOOL_FIELD(unsettag); + + READ_DONE(); +} + static EphemeralNamedRelationInfo * _readEphemeralNamedRelationInfo(void) { @@ -1758,6 +1774,19 @@ _readEphemeralNamedRelationInfo(void) READ_DONE(); } +static void * +_readAlterDatabaseStmt(void) +{ + READ_LOCALS(AlterDatabaseStmt); + + READ_STRING_FIELD(dbname); + READ_NODE_FIELD(options); + READ_NODE_FIELD(tags); + READ_BOOL_FIELD(unsettag); + + READ_DONE(); +} + static void * readNodeBinary(void) { @@ -2548,6 +2577,18 @@ readNodeBinary(void) case T_CreateSchemaStmt: return_value = _readCreateSchemaStmt(); break; + case T_AlterSchemaStmt: + return_value = _readAlterSchemaStmt(); + break; + case T_CreateTagStmt: + return_value = _readCreateTagStmt(); + break; + case T_AlterTagStmt: + return_value = _readAlterTagStmt(); + break; + case T_DropTagStmt: + return_value = _readDropTagStmt(); + break; case T_CreatePLangStmt: return_value = _readCreatePLangStmt(); break; @@ -2773,9 +2814,15 @@ readNodeBinary(void) case T_EphemeralNamedRelationInfo: return_value = _readEphemeralNamedRelationInfo(); break; + case T_AlterDatabaseStmt: + return_value = _readAlterDatabaseStmt(); + break; case T_CreateDirectoryTableStmt: return_value = _readCreateDirectoryTableStmt(); break; + case T_AlterDirectoryTableStmt: + return_value = _readAlterDirectoryTableStmt(); + break; default: return_value = NULL; /* keep the compiler silent */ elog(ERROR, "could not deserialize unrecognized node type: %d", diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index d82095aa802..5bdddc09ea6 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -3203,6 +3203,14 @@ parseNodeString(void) return_value = _readCreateProfileStmt(); else if (MATCHX("CREATESCHEMASTMT")) return_value = _readCreateSchemaStmt(); + else if (MATCHX("ALTERSCHEMASTMT")) + return_value = _readAlterSchemaStmt(); + else if (MATCHX("CREATETAGSTMT")) + return_value = _readCreateTagStmt(); + else if (MATCHX("ALTERTAGSTMT")) + return_value = _readAlterTagStmt(); + else if (MATCHX("DROPTAGSTMT")) + return_value = _readDropTagStmt(); else if (MATCHX("CREATESEQSTMT")) return_value = _readCreateSeqStmt(); else if (MATCHX("CREATETRANSFORMSTMT")) diff --git a/src/backend/nodes/readfuncs_common.c b/src/backend/nodes/readfuncs_common.c index f23687143e3..96b8c9f8690 100644 --- a/src/backend/nodes/readfuncs_common.c +++ b/src/backend/nodes/readfuncs_common.c @@ -385,6 +385,8 @@ _readAlterRoleStmt(void) READ_NODE_FIELD(role); READ_NODE_FIELD(options); READ_INT_FIELD(action); + READ_NODE_FIELD(tags); + READ_BOOL_FIELD(unsettag); READ_DONE(); } @@ -453,6 +455,8 @@ _readAlterTableCmd(void) READ_INT_FIELD(backendId); READ_NODE_FIELD(policy); + READ_NODE_FIELD(tags); + READ_BOOL_FIELD(unsettag); READ_DONE(); } @@ -765,6 +769,7 @@ _readCreateExternalStmt(void) READ_NODE_FIELD(extOptions); READ_NODE_FIELD(encoding); READ_NODE_FIELD(distributedBy); + READ_NODE_FIELD(tags); READ_DONE(); } @@ -877,6 +882,7 @@ _readCreateRoleStmt(void) READ_ENUM_FIELD(stmt_type, RoleStmtType); READ_STRING_FIELD(role); READ_NODE_FIELD(options); + READ_NODE_FIELD(tags); READ_DONE(); } @@ -902,10 +908,60 @@ _readCreateSchemaStmt(void) local_node->schemaElts = 0; READ_BOOL_FIELD(istemp); READ_BOOL_FIELD(pop_search_path); + READ_NODE_FIELD(tags); READ_DONE(); } +static AlterSchemaStmt * +_readAlterSchemaStmt(void) +{ + READ_LOCALS(AlterSchemaStmt); + + READ_STRING_FIELD(schemaname); + READ_NODE_FIELD(tags); + READ_BOOL_FIELD(unsettag); + + READ_DONE(); +} + +static CreateTagStmt * +_readCreateTagStmt(void) +{ + READ_LOCALS(CreateTagStmt); + + READ_STRING_FIELD(tag_name); + READ_BOOL_FIELD(missing_ok); + READ_NODE_FIELD(allowed_values); + + READ_DONE(); +} + +static AlterTagStmt * +_readAlterTagStmt(void) +{ + READ_LOCALS(AlterTagStmt); + + READ_STRING_FIELD(tag_name); + READ_INT_FIELD(action); + READ_NODE_FIELD(tag_values); + READ_BOOL_FIELD(missing_ok); + READ_BOOL_FIELD(unset); + + READ_DONE(); +} + +static DropTagStmt * +_readDropTagStmt(void) +{ + READ_LOCALS(DropTagStmt); + + READ_NODE_FIELD(tags); + READ_BOOL_FIELD(missing_ok); + + READ_DONE(); +} + static CreateSeqStmt * _readCreateSeqStmt(void) { @@ -915,6 +971,7 @@ _readCreateSeqStmt(void) READ_OID_FIELD(ownerId); READ_BOOL_FIELD(for_identity); READ_BOOL_FIELD(if_not_exists); + READ_NODE_FIELD(tags); READ_DONE(); } @@ -961,6 +1018,7 @@ _readCreatedbStmt(void) READ_STRING_FIELD(dbname); READ_NODE_FIELD(options); + READ_NODE_FIELD(tags); READ_DONE(); } @@ -1266,6 +1324,7 @@ _readIndexStmt(void) READ_BOOL_FIELD(reset_default_tblspc); READ_ENUM_FIELD(concurrentlyPhase,IndexConcurrentlyPhase); READ_OID_FIELD(indexRelationOid); + READ_NODE_FIELD(tags); READ_DONE(); } @@ -1713,6 +1772,7 @@ _readViewStmt(void) READ_NODE_FIELD(query); READ_BOOL_FIELD(replace); READ_NODE_FIELD(options); + READ_NODE_FIELD(tags); READ_DONE(); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0f9f3fac527..9174cf59f76 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -280,7 +280,7 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ %type stmt toplevel_stmt schema_stmt routine_body_stmt AlterEventTrigStmt AlterCollationStmt - AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt + AlterDatabaseStmt AlterDatabaseSetStmt AlterDirectoryTableStmt AlterDomainStmt AlterEnumStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt AlterOperatorStmt AlterTypeStmt AlterSeqStmt AlterStorageServerStmt AlterSystemStmt AlterTableStmt @@ -321,10 +321,10 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ RetrieveStmt CreateTaskStmt AlterTaskStmt DropTaskStmt /* GPDB-specific commands */ -%type AlterProfileStmt AlterQueueStmt AlterResourceGroupStmt +%type AlterProfileStmt AlterQueueStmt AlterResourceGroupStmt AlterSchemaStmt AlterTagStmt CreateExternalStmt - CreateProfileStmt CreateQueueStmt CreateResourceGroupStmt - DropProfileStmt DropQueueStmt DropResourceGroupStmt + CreateProfileStmt CreateQueueStmt CreateResourceGroupStmt CreateTagStmt + DropProfileStmt DropQueueStmt DropResourceGroupStmt DropTagStmt ExtTypedesc OptSingleRowErrorHandling ExtSingleRowErrorHandling %type deny_login_role deny_interval deny_point deny_day_specifier @@ -377,6 +377,8 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ %type OptRoleList AlterOptRoleList %type OptProfileList +%type OptTagValuesList OptTagOptList TagOptList +%type TagOptElem %type CreateOptRoleElem AlterOptRoleElem %type AlterOnlyOptRoleElem %type OptProfileElem @@ -840,7 +842,7 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ /* GPDB-added keywords, in alphabetical order */ %token - ACCOUNT ACTIVE + ACCOUNT ACTIVE ALLOWED_VALUES CONTAINS COORDINATOR CPUSET CPU_RATE_LIMIT @@ -884,6 +886,8 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ THRESHOLD UNLOCK_P + + UNSET_P VALIDATION @@ -1190,6 +1194,7 @@ static void check_expressions_in_partition_key(PartitionSpec *spec, core_yyscan_ %nonassoc SYSTEM_P %nonassoc STRICT_P %nonassoc TABLESPACE + %nonassoc TAG %nonassoc TASK %nonassoc TEMP %nonassoc TEMPLATE @@ -1385,6 +1390,7 @@ stmt: | AlterDatabaseStmt | AlterDatabaseSetStmt | AlterDefaultPrivilegesStmt + | AlterDirectoryTableStmt | AlterDomainStmt | AlterEnumStmt | AlterExtensionStmt @@ -1403,10 +1409,12 @@ stmt: | AlterProfileStmt | AlterQueueStmt | AlterResourceGroupStmt + | AlterSchemaStmt | AlterSeqStmt | AlterStorageServerStmt | AlterSystemStmt | AlterTableStmt + | AlterTagStmt | AlterTblSpcStmt | AlterCompositeTypeStmt | AlterPublicationStmt @@ -1459,6 +1467,7 @@ stmt: | CreateStorageServerStmt | CreateStorageUserMappingStmt | CreateTableSpaceStmt + | CreateTagStmt | CreateTaskStmt | CreateTransformStmt | CreateTrigStmt @@ -1483,6 +1492,7 @@ stmt: | DropStmt | DropSubscriptionStmt | DropTableSpaceStmt + | DropTagStmt | DropTaskStmt | DropTransformStmt | DropRoleStmt @@ -2024,12 +2034,13 @@ keyvalue_pair: *****************************************************************************/ CreateUserStmt: - CREATE USER RoleId opt_with OptRoleList + CREATE USER RoleId opt_with OptRoleList OptTagOptList { CreateRoleStmt *n = makeNode(CreateRoleStmt); n->stmt_type = ROLESTMT_USER; n->role = $3; n->options = $5; + n->tags = $6; $$ = (Node *)n; } ; @@ -2058,6 +2069,21 @@ AlterRoleStmt: n->options = $5; $$ = (Node *)n; } + | ALTER USER RoleSpec TAG '(' TagOptList ')' + { + AlterRoleStmt *n = makeNode(AlterRoleStmt); + n->role = $3; + n->tags = $6; + $$ = (Node *)n; + } + | ALTER USER RoleSpec UNSET_P TAG '(' name_list ')' + { + AlterRoleStmt *n = makeNode(AlterRoleStmt); + n->role = $3; + n->tags = $7; + n->unsettag = true; + $$ = (Node *)n; + } ; opt_in_database: @@ -2347,8 +2373,40 @@ CreateSchemaStmt: n->if_not_exists = true; $$ = (Node *)n; } + | CREATE SCHEMA ColId WITH TAG '(' TagOptList ')' + { + CreateSchemaStmt *n = makeNode(CreateSchemaStmt); + n->schemaname = $3; + n->if_not_exists = false; + n->tags = $7; + $$ = (Node *)n; + } ; +/***************************************************************************** + * + * Alter a schema to add a tag + * + *****************************************************************************/ + +AlterSchemaStmt: + ALTER SCHEMA name TAG '(' TagOptList ')' + { + AlterSchemaStmt *n = makeNode(AlterSchemaStmt); + n->schemaname = $3; + n->tags = $6; + $$ = (Node *)n; + } + | ALTER SCHEMA name UNSET_P TAG '(' name_list ')' + { + AlterSchemaStmt *n = makeNode(AlterSchemaStmt); + n->schemaname = $3; + n->tags = $7; + n->unsettag = true; + $$ = (Node *)n; + } + ; + OptSchemaName: ColId { $$ = $1; } | /* EMPTY */ { $$ = NULL; } @@ -2379,6 +2437,136 @@ schema_stmt: ; +/***************************************************************************** + * + * Create a new Postgres DBMS Tag + * + *****************************************************************************/ + +CreateTagStmt: + CREATE TAG name + { + CreateTagStmt *n = makeNode(CreateTagStmt); + n->tag_name = $3; + n->missing_ok = false; + n->allowed_values = NIL; + $$ = (Node *)n; + } + | CREATE TAG IF_P NOT EXISTS name + { + CreateTagStmt *n = makeNode(CreateTagStmt); + n->tag_name = $6; + n->missing_ok = true; + n->allowed_values = NIL; + $$ = (Node *)n; + } + | CREATE TAG name ALLOWED_VALUES OptTagValuesList + { + CreateTagStmt *n = makeNode(CreateTagStmt); + n->tag_name = $3; + n->missing_ok = false; + n->allowed_values = $5; + $$ = (Node *)n; + } + | CREATE TAG IF_P NOT EXISTS name ALLOWED_VALUES OptTagValuesList + { + CreateTagStmt *n = makeNode(CreateTagStmt); + n->tag_name = $6; + n->missing_ok = true; + n->allowed_values = $8; + $$ = (Node *)n; + } + ; + + +/***************************************************************************** + * + * Alter a postgresql DBMS Tag + * + *****************************************************************************/ + +AlterTagStmt: + ALTER TAG name add_drop ALLOWED_VALUES OptTagValuesList + { + AlterTagStmt *n = makeNode(AlterTagStmt); + n->missing_ok = false; + n->tag_name = $3; + n->action = $4; + n->tag_values = $6; + n->unset = false; + $$ = (Node *)n; + } + | ALTER TAG IF_P EXISTS name add_drop ALLOWED_VALUES OptTagValuesList + { + AlterTagStmt *n = makeNode(AlterTagStmt); + n->missing_ok = true; + n->tag_name = $5; + n->action = $6; + n->tag_values = $8; + n->unset = false; + $$ = (Node *)n; + } + | ALTER TAG name UNSET_P ALLOWED_VALUES + { + AlterTagStmt *n = makeNode(AlterTagStmt); + n->tag_name = $3; + n->unset = true; + $$ = (Node *)n; + } + ; + + +/***************************************************************************** + * + * Drop a postgresql DBMS Tag + * + * XXX Ideally this would have CASCADE/RESTRICT options, but a profile + * might be attached by users in multiple databases, using CASCADE will drop + * users meanwhile which is unreasonable. So we always behave as RESTRICT. + *****************************************************************************/ + +DropTagStmt: + DROP TAG name_list + { + DropTagStmt *n = makeNode(DropTagStmt); + n->tags = $3; + n->missing_ok = false; + $$ = (Node *)n; + } + | DROP TAG IF_P EXISTS name_list + { + DropTagStmt *n = makeNode(DropTagStmt); + n->tags = $5; + n->missing_ok = true; + $$ = (Node *)n; + } + ; + +/* + * List of allowed values for Tag. + */ +OptTagValuesList: + OptTagValuesList ',' Sconst { $$ = lappend($1, makeString($3)); } + | Sconst { $$ = list_make1(makeString($1)); } + ; + +OptTagOptList: + TAG '(' TagOptList ')' { $$ = $3; } + | /*EMPTY*/ { $$ = NIL; } + ; + +TagOptList: + TagOptElem { $$ = list_make1($1); } + | TagOptList ',' TagOptElem { $$ = lappend($1, $3); } + ; + +TagOptElem: + ColLabel '=' Sconst + { + $$ = makeDefElem($1, (Node *) makeString($3), @1); + } + ; + /***************************************************************************** * * Set PG internal variable @@ -3662,6 +3850,21 @@ alter_table_cmd: n->def = (Node *)$1; $$ = (Node *) n; } + | TAG '(' TagOptList ')' + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetTags; + n->tags = $3; + $$ = (Node *) n; + } + | UNSET_P TAG '(' name_list ')' + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_UnsetTags; + n->tags = $4; + n->unsettag = true; + $$ = (Node *) n; + } ; alter_column_default: @@ -4768,7 +4971,7 @@ copy_generic_opt_arg_list_item: CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' OptInherit OptFirstPartitionSpec table_access_method_clause OptWith OnCommitOption OptTableSpace - OptDistributedBy OptSecondPartitionSpec + OptDistributedBy OptSecondPartitionSpec OptTagOptList { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; @@ -4789,6 +4992,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tablespacename = $13; n->if_not_exists = false; n->distributedBy = (DistributedBy *) $14; + n->tags = $16; n->relKind = RELKIND_RELATION; n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); @@ -4798,7 +5002,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '(' OptTableElementList ')' OptInherit OptFirstPartitionSpec table_access_method_clause OptWith OnCommitOption OptTableSpace - OptDistributedBy OptSecondPartitionSpec + OptDistributedBy OptSecondPartitionSpec OptTagOptList { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; @@ -4819,6 +5023,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tablespacename = $16; n->if_not_exists = true; n->distributedBy = (DistributedBy *) $17; + n->tags = $19; n->relKind = RELKIND_RELATION; n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); @@ -4828,7 +5033,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' | CREATE OptTemp TABLE qualified_name OF any_name OptTypedTableElementList OptFirstPartitionSpec table_access_method_clause OptWith OnCommitOption OptTableSpace - OptDistributedBy OptSecondPartitionSpec + OptDistributedBy OptSecondPartitionSpec OptTagOptList { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; @@ -4850,6 +5055,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tablespacename = $12; n->if_not_exists = false; n->distributedBy = (DistributedBy *) $13; + n->tags = $15; n->relKind = RELKIND_RELATION; n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); @@ -4859,7 +5065,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name OptTypedTableElementList OptFirstPartitionSpec table_access_method_clause OptWith OnCommitOption OptTableSpace - OptDistributedBy OptSecondPartitionSpec + OptDistributedBy OptSecondPartitionSpec OptTagOptList { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; @@ -4881,6 +5087,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tablespacename = $15; n->if_not_exists = true; n->distributedBy = (DistributedBy *) $16; + n->tags = $18; n->relKind = RELKIND_RELATION; n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); @@ -4890,7 +5097,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' | CREATE OptTemp TABLE qualified_name PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec OptFirstPartitionSpec table_access_method_clause OptWith OnCommitOption OptTableSpace - OptSecondPartitionSpec + OptSecondPartitionSpec OptTagOptList { CreateStmt *n = makeNode(CreateStmt); $4->relpersistence = $2; @@ -4912,6 +5119,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tablespacename = $14; n->if_not_exists = false; n->distributedBy = NULL; + n->tags = $16; n->relKind = RELKIND_RELATION; n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); @@ -4921,7 +5129,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec OptFirstPartitionSpec table_access_method_clause OptWith OnCommitOption OptTableSpace - OptSecondPartitionSpec + OptSecondPartitionSpec OptTagOptList { CreateStmt *n = makeNode(CreateStmt); $7->relpersistence = $2; @@ -4943,6 +5151,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tablespacename = $17; n->if_not_exists = true; n->distributedBy = NULL; + n->tags = $19; n->relKind = RELKIND_RELATION; n->accessMethod = greenplumLegacyAOoptions(n->accessMethod, &n->options); @@ -6488,7 +6697,7 @@ opt_with_data: *****************************************************************************/ CreateExternalStmt: CREATE OptWritable EXTERNAL OptWeb OptTemp TABLE qualified_name '(' OptExtTableElementList ')' - ExtTypedesc FORMAT Sconst format_opt ext_options_opt ext_opt_encoding_list ExtSingleRowErrorHandling OptDistributedBy + ExtTypedesc FORMAT Sconst format_opt ext_options_opt ext_opt_encoding_list ExtSingleRowErrorHandling OptDistributedBy OptTagOptList { CreateExternalStmt *n = makeNode(CreateExternalStmt); n->iswritable = $2; @@ -6503,6 +6712,7 @@ CreateExternalStmt: CREATE OptWritable EXTERNAL OptWeb OptTemp TABLE qualified_n n->encoding = $16; n->sreh = $17; n->distributedBy = (DistributedBy *) $18; + n->tags = $19; /* various syntax checks for EXECUTE external table */ if(((ExtTableTypeDesc *) n->exttypedesc)->exttabletype == EXTTBL_TYPE_EXECUTE) @@ -6959,7 +7169,7 @@ RefreshMatViewStmt: *****************************************************************************/ CreateSeqStmt: - CREATE OptTemp SEQUENCE qualified_name OptSeqOptList + CREATE OptTemp SEQUENCE qualified_name OptSeqOptList OptTagOptList { CreateSeqStmt *n = makeNode(CreateSeqStmt); $4->relpersistence = $2; @@ -6967,9 +7177,10 @@ CreateSeqStmt: n->options = $5; n->ownerId = InvalidOid; n->if_not_exists = false; + n->tags = $6; $$ = (Node *)n; } - | CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList + | CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList OptTagOptList { CreateSeqStmt *n = makeNode(CreateSeqStmt); $7->relpersistence = $2; @@ -6977,6 +7188,7 @@ CreateSeqStmt: n->options = $8; n->ownerId = InvalidOid; n->if_not_exists = true; + n->tags = $9; $$ = (Node *)n; } ; @@ -7170,7 +7382,7 @@ opt_procedural: * *****************************************************************************/ -CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions OptServer OptFileHandler +CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst opt_reloptions OptServer OptFileHandler OptTagOptList { CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt); List *fileHandler_list; @@ -7201,6 +7413,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst errmsg("invalid list syntax for \"handler\""), parser_errposition(@9))); } + n->tags = $10; $$ = (Node *) n; } @@ -7887,7 +8100,7 @@ DropStorageServerStmt: CreateForeignTableStmt: CREATE FOREIGN TABLE qualified_name '(' OptTableElementList ')' - OptInherit SERVER name create_generic_options OptDistributedBy + OptInherit SERVER name create_generic_options OptDistributedBy OptTagOptList { CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); $4->relpersistence = RELPERSISTENCE_PERMANENT; @@ -7904,6 +8117,7 @@ CreateForeignTableStmt: n->servername = $10; n->options = $11; n->distributedBy = (DistributedBy *) $12; + n->base.tags = $13; if (strcmp(n->servername, GP_EXTTABLE_SERVER_NAME) != 0 && n->distributedBy) { ereport(ERROR, @@ -7914,7 +8128,7 @@ CreateForeignTableStmt: } | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name '(' OptTableElementList ')' - OptInherit SERVER name create_generic_options + OptInherit SERVER name create_generic_options OptTagOptList { CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); $7->relpersistence = RELPERSISTENCE_PERMANENT; @@ -7930,11 +8144,12 @@ CreateForeignTableStmt: /* FDW-specific data */ n->servername = $13; n->options = $14; + n->base.tags = $15; $$ = (Node *) n; } | CREATE FOREIGN TABLE qualified_name PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec - SERVER name create_generic_options + SERVER name create_generic_options OptTagOptList { CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); $4->relpersistence = RELPERSISTENCE_PERMANENT; @@ -7951,11 +8166,12 @@ CreateForeignTableStmt: /* FDW-specific data */ n->servername = $11; n->options = $12; + n->base.tags = $13; $$ = (Node *) n; } | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec - SERVER name create_generic_options + SERVER name create_generic_options OptTagOptList { CreateForeignTableStmt *n = makeNode(CreateForeignTableStmt); $7->relpersistence = RELPERSISTENCE_PERMANENT; @@ -7972,6 +8188,7 @@ CreateForeignTableStmt: /* FDW-specific data */ n->servername = $14; n->options = $15; + n->base.tags = $16; $$ = (Node *) n; } ; @@ -8182,7 +8399,7 @@ AlterStorageUserMappingStmt: CreateDirectoryTableStmt: CREATE DIRECTORY TABLE qualified_name - table_access_method_clause OptTableSpace OptDistributedBy + table_access_method_clause OptTableSpace OptDistributedBy OptTagOptList { CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); $4->relpersistence = RELPERSISTENCE_PERMANENT; @@ -8202,12 +8419,13 @@ CreateDirectoryTableStmt: errmsg("Create directory table is not allowed to set distributed by."), parser_errposition(@7))); n->base.relKind = RELKIND_DIRECTORY_TABLE; + n->base.tags = $8; n->tablespacename = $6; $$ = (Node *) n; } | CREATE DIRECTORY TABLE IF_P NOT EXISTS qualified_name - table_access_method_clause OptTableSpace OptDistributedBy + table_access_method_clause OptTableSpace OptDistributedBy OptTagOptList { CreateDirectoryTableStmt *n = makeNode(CreateDirectoryTableStmt); $7->relpersistence = RELPERSISTENCE_PERMANENT; @@ -8227,12 +8445,42 @@ CreateDirectoryTableStmt: errmsg("Create directory table is not allowed to set distributed by."), parser_errposition(@10))); n->base.relKind = RELKIND_DIRECTORY_TABLE; + n->base.tags = $11; n->tablespacename = $9; $$ = (Node *) n; } ; +/***************************************************************************** + * + * QUERY: + * ALTER DIRECTORY TABLE relname TAG (tagname = tagvalue, ...) + * ALTER DIRECTORY TABLE relname UNSET TAG (tagname_list) + * + *****************************************************************************/ + +AlterDirectoryTableStmt: + ALTER DIRECTORY TABLE qualified_name TAG '(' TagOptList ')' + { + AlterDirectoryTableStmt *n = makeNode(AlterDirectoryTableStmt); + n->relation = $4; + n->tags = $7; + + $$ = (Node *)n; + } + | ALTER DIRECTORY TABLE qualified_name UNSET_P TAG '(' name_list ')' + { + AlterDirectoryTableStmt *n = makeNode(AlterDirectoryTableStmt); + n->relation = $4; + n->tags = $8; + n->unsettag = true; + + $$ = (Node *)n; + } + ; + + /***************************************************************************** * * QUERIES: @@ -9611,6 +9859,14 @@ CommentStmt: n->comment = $10; $$ = (Node *) n; } + | COMMENT ON TAG name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_TAG; + n->object = (Node *) makeString($4); + n->comment = $6; + $$ = (Node *) n; + } ; comment_text: @@ -10366,7 +10622,7 @@ defacl_privilege_target: IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name ON relation_expr access_method_clause '(' index_params ')' - opt_include opt_reloptions OptTableSpace where_clause + opt_include opt_reloptions OptTableSpace where_clause OptTagOptList { IndexStmt *n = makeNode(IndexStmt); n->unique = $2; @@ -10392,12 +10648,13 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name n->transformed = false; n->if_not_exists = false; n->reset_default_tblspc = false; + n->tags = $16; $$ = (Node *)n; } | CREATE opt_unique INDEX opt_concurrently IF_P NOT EXISTS name ON relation_expr access_method_clause '(' index_params ')' - opt_include opt_reloptions OptTableSpace where_clause + opt_include opt_reloptions OptTableSpace where_clause OptTagOptList { IndexStmt *n = makeNode(IndexStmt); n->unique = $2; @@ -10423,6 +10680,7 @@ IndexStmt: CREATE opt_unique INDEX opt_concurrently opt_index_name n->transformed = false; n->if_not_exists = true; n->reset_default_tblspc = false; + n->tags = $19; $$ = (Node *)n; } @@ -11567,6 +11825,21 @@ AlterTblSpcStmt: n->isReset = true; $$ = (Node *)n; } + | ALTER TABLESPACE name TAG '(' TagOptList ')' + { + AlterTableSpaceOptionsStmt *n = makeNode(AlterTableSpaceOptionsStmt); + n->tablespacename = $3; + n->tags = $6; + $$ = (Node *)n; + } + | ALTER TABLESPACE name UNSET_P TAG '(' name_list ')' + { + AlterTableSpaceOptionsStmt *n = makeNode(AlterTableSpaceOptionsStmt); + n->tablespacename = $3; + n->tags = $7; + n->unsettag = true; + $$ = (Node *)n; + } ; /***************************************************************************** @@ -12124,6 +12397,24 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name n->missing_ok = false; $$ = (Node *)n; } + | ALTER TAG name RENAME TO name + { + RenameStmt *n = makeNode(RenameStmt); + n->renameType = OBJECT_TAG; + n->subname = $3; + n->newname = $6; + n->missing_ok = false; + $$ = (Node *)n; + } + | ALTER TAG IF_P EXISTS name RENAME TO name + { + RenameStmt *n = makeNode(RenameStmt); + n->renameType = OBJECT_TAG; + n->subname = $5; + n->newname = $8; + n->missing_ok = true; + $$ = (Node *)n; + } ; opt_column: COLUMN @@ -12722,6 +13013,14 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec n->newowner = $6; $$ = (Node *)n; } + | ALTER TAG name OWNER TO RoleSpec + { + AlterOwnerStmt *n = makeNode(AlterOwnerStmt); + n->objectType = OBJECT_TAG; + n->object = (Node *) makeString($3); + n->newowner = $6; + $$ = (Node *)n; + } ; @@ -12775,11 +13074,12 @@ publication_for_tables: * *****************************************************************************/ -CreateWarehouseStmt: CREATE WAREHOUSE name OptWarehouseOptList +CreateWarehouseStmt: CREATE WAREHOUSE name OptWarehouseOptList OptTagOptList { CreateWarehouseStmt *n = makeNode(CreateWarehouseStmt); n->whname = $3; n->options = $4; + n->tags = $5; $$ = (Node *) n; } ; @@ -13271,43 +13571,46 @@ opt_transaction_chain: * *****************************************************************************/ -ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list opt_reloptions +ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list opt_reloptions OptTagOptList AS SelectStmt opt_check_option { ViewStmt *n = makeNode(ViewStmt); n->view = $4; n->view->relpersistence = $2; n->aliases = $5; - n->query = $8; + n->query = $9; n->replace = false; n->options = $6; - n->withCheckOption = $9; + n->withCheckOption = $10; + n->tags = $7; $$ = (Node *) n; } - | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list opt_reloptions + | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list opt_reloptions OptTagOptList AS SelectStmt opt_check_option { ViewStmt *n = makeNode(ViewStmt); n->view = $6; n->view->relpersistence = $4; n->aliases = $7; - n->query = $10; + n->query = $11; n->replace = true; n->options = $8; - n->withCheckOption = $11; + n->withCheckOption = $12; + n->tags = $9; $$ = (Node *) n; } - | CREATE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions + | CREATE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions OptTagOptList AS SelectStmt opt_check_option { ViewStmt *n = makeNode(ViewStmt); n->view = $5; n->view->relpersistence = $2; n->aliases = $7; - n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $11); + n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $12); n->replace = false; n->options = $9; - n->withCheckOption = $12; + n->withCheckOption = $13; + n->tags = $10; if (n->withCheckOption != NO_CHECK_OPTION) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -13315,17 +13618,18 @@ ViewStmt: CREATE OptTemp VIEW qualified_name opt_column_list opt_reloptions parser_errposition(@12))); $$ = (Node *) n; } - | CREATE OR REPLACE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions + | CREATE OR REPLACE OptTemp RECURSIVE VIEW qualified_name '(' columnList ')' opt_reloptions OptTagOptList AS SelectStmt opt_check_option { ViewStmt *n = makeNode(ViewStmt); n->view = $7; n->view->relpersistence = $4; n->aliases = $9; - n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $13); + n->query = makeRecursiveViewSelect(n->view->relname, n->aliases, $14); n->replace = true; n->options = $11; - n->withCheckOption = $14; + n->withCheckOption = $15; + n->tags = $12; if (n->withCheckOption != NO_CHECK_OPTION) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -13365,11 +13669,12 @@ LoadStmt: LOAD file_name *****************************************************************************/ CreatedbStmt: - CREATE DATABASE name opt_with createdb_opt_list + CREATE DATABASE name opt_with createdb_opt_list OptTagOptList { CreatedbStmt *n = makeNode(CreatedbStmt); n->dbname = $3; n->options = $5; + n->tags = $6; $$ = (Node *)n; } ; @@ -13458,6 +13763,21 @@ AlterDatabaseStmt: (Node *)makeString($6), @6)); $$ = (Node *)n; } + | ALTER DATABASE name TAG '(' TagOptList ')' + { + AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); + n->dbname = $3; + n->tags = $6; + $$ = (Node *)n; + } + | ALTER DATABASE name UNSET_P TAG '(' name_list ')' + { + AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); + n->dbname = $3; + n->tags = $7; + n->unsettag = true; + $$ = (Node *)n; + } ; AlterDatabaseSetStmt: @@ -18946,6 +19266,7 @@ unreserved_keyword: | ADMIN | AFTER | AGGREGATE + | ALLOWED_VALUES | ALSO | ALTER | ALWAYS @@ -19280,6 +19601,7 @@ unreserved_keyword: | UNLISTEN | UNLOCK_P | UNLOGGED + | UNSET_P | UNTIL | UPDATE | VACUUM @@ -19835,6 +20157,7 @@ bare_label_keyword: | AFTER | AGGREGATE | ALL + | ALLOWED_VALUES | ALSO | ALTER | ALWAYS @@ -20276,6 +20599,7 @@ bare_label_keyword: | UNLISTEN | UNLOCK_P | UNLOGGED + | UNSET_P | UNTIL | UPDATE | USER diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 55105efebd0..0fcb3624846 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -59,6 +59,7 @@ #include "commands/subscriptioncmds.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" +#include "commands/tag.h" #include "commands/taskcmds.h" #include "commands/trigger.h" #include "commands/typecmds.h" @@ -173,6 +174,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_AlterPublicationStmt: case T_AlterRoleSetStmt: case T_AlterRoleStmt: + case T_AlterSchemaStmt: case T_AlterSeqStmt: case T_AlterStatsStmt: case T_AlterSubscriptionStmt: @@ -244,16 +246,20 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_AlterProfileStmt: case T_AlterQueueStmt: case T_AlterResourceGroupStmt: + case T_AlterTagStmt: case T_CreateDirectoryTableStmt: + case T_AlterDirectoryTableStmt: case T_CreateProfileStmt: case T_CreateQueueStmt: case T_CreateResourceGroupStmt: case T_CreateTaskStmt: + case T_CreateTagStmt: case T_AlterTaskStmt: case T_DropTaskStmt: case T_DropProfileStmt: case T_DropQueueStmt: case T_DropResourceGroupStmt: + case T_DropTagStmt: case T_DropWarehouseStmt: case T_CreateExternalStmt: case T_RetrieveStmt: @@ -1010,10 +1016,23 @@ standard_ProcessUtility(PlannedStmt *pstmt, } break; + case T_CreateTagStmt: + CreateTag((CreateTagStmt *) parsetree); + break; + + case T_AlterTagStmt: + AlterTag((AlterTagStmt *) parsetree); + break; + + case T_DropTagStmt: + DropTag((DropTagStmt *) parsetree); + break; + case T_ExplainStmt: ExplainQuery(pstate, (ExplainStmt *) parsetree, params, dest); break; + case T_AlterSystemStmt: PreventInTransactionBlock(isTopLevel, "ALTER SYSTEM"); AlterSystemSetConfigFile((AlterSystemStmt *) parsetree); @@ -1365,6 +1384,15 @@ ProcessUtilitySlow(ParseState *pstate, commandCollected = true; break; + case T_AlterSchemaStmt: + AlterSchemaCommand((AlterSchemaStmt *) parsetree); + /* + * EventTriggerCollectSimpleCommand called by + * CreateSchemaCommand + */ + commandCollected = true; + break; + case T_CreateStmt: case T_CreateForeignTableStmt: case T_CreateDirectoryTableStmt: @@ -1699,6 +1727,54 @@ ProcessUtilitySlow(ParseState *pstate, commandCollected = true; break; + case T_AlterDirectoryTableStmt: + { + AlterDirectoryTableStmt *stmt = (AlterDirectoryTableStmt *) parsetree; + Oid relid; + + /* + * Get relid of the directory table. + */ + relid = RangeVarGetRelidExtended(stmt->relation, + ShareUpdateExclusiveLock, + 0, + NULL, + NULL); + + if (stmt->tags) + { + if (!stmt->unsettag) + { + AlterTagDescriptions(stmt->tags, + MyDatabaseId, + RelationRelationId, + relid, + stmt->relation->relname); + } + + if (stmt->unsettag) + { + UnsetTagDescriptions(stmt->tags, + MyDatabaseId, + RelationRelationId, + relid, + stmt->relation->relname); + } + + } + + if (Gp_role == GP_ROLE_DISPATCH) + { + CdbDispatchUtilityStatement((Node *) stmt, + DF_CANCEL_ON_ERROR | + DF_WITH_SNAPSHOT | + DF_NEED_TWO_PHASE, + GetAssignedOidsForDispatch(), + NULL); + } + } + break; + case T_AlterDomainStmt: { AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree; @@ -2859,6 +2935,9 @@ AlterObjectTypeCommandTag(ObjectType objtype) case OBJECT_TABLESPACE: tag = CMDTAG_ALTER_TABLESPACE; break; + case OBJECT_TAG: + tag = CMDTAG_ALTER_TAG; + break; case OBJECT_TRIGGER: tag = CMDTAG_ALTER_TRIGGER; break; @@ -3037,6 +3116,10 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_CREATE_SCHEMA; break; + case T_AlterSchemaStmt: + tag = CMDTAG_ALTER_SCHEMA; + break; + case T_CreateStmt: tag = CMDTAG_CREATE_TABLE; break; @@ -3057,6 +3140,18 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_ALTER_TABLESPACE; break; + case T_CreateTagStmt: + tag = CMDTAG_CREATE_TAG; + break; + + case T_AlterTagStmt: + tag = CMDTAG_ALTER_TAG; + break; + + case T_DropTagStmt: + tag = CMDTAG_DROP_TAG; + break; + case T_CreateExtensionStmt: tag = CMDTAG_CREATE_EXTENSION; break; @@ -3133,6 +3228,10 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_CREATE_DIRECTORY_TABLE; break; + case T_AlterDirectoryTableStmt: + tag = CMDTAG_ALTER_DIRECTORY_TABLE; + break; + case T_DropStmt: switch (((DropStmt *) parsetree)->removeType) { @@ -3169,6 +3268,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_TABLESPACE: tag = CMDTAG_DROP_TABLESPACE; break; + case OBJECT_TAG: + tag = CMDTAG_DROP_TAG; + break; case OBJECT_EXTPROTOCOL: tag = CMDTAG_DROP_PROTOCOL; break; @@ -3956,6 +4058,7 @@ GetCommandLogLevel(Node *parsetree) break; case T_CreateSchemaStmt: + case T_AlterSchemaStmt: lev = LOGSTMT_DDL; break; @@ -3995,6 +4098,7 @@ GetCommandLogLevel(Node *parsetree) case T_DropStorageUserMappingStmt: case T_ImportForeignSchemaStmt: case T_CreateDirectoryTableStmt: + case T_AlterDirectoryTableStmt: lev = LOGSTMT_DDL; break; diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index f81c922e3fc..1a88505a53b 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -71,6 +71,8 @@ #include "catalog/pg_subscription.h" #include "catalog/pg_subscription_rel.h" #include "catalog/pg_tablespace.h" +#include "catalog/pg_tag.h" +#include "catalog/pg_tag_description.h" #include "catalog/pg_transform.h" #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_config_map.h" @@ -952,6 +954,50 @@ static const struct cachedesc cacheinfo[] = { }, 4 }, + {TagRelationId, /* TAGNAME */ + TagNameIndexId, + 1, + { + Anum_pg_tag_tagname, + 0, + 0, + 0, + }, + 16 + }, + {TagRelationId, /* TAGOID */ + TagOidIndexId, + 1, + { + Anum_pg_tag_oid, + 0, + 0, + 0, + }, + 16 + }, + {TagDescriptionRelationId, /* TAGDESCRIPTION */ + TagDescriptionIndexId, + 4, + { + Anum_pg_tag_description_databaseid, + Anum_pg_tag_description_classid, + Anum_pg_tag_description_objid, + Anum_pg_tag_description_tagid, + }, + 16 + }, +// {TagDescriptionRelationId, /* TAGDESCRIPTIONTAGID */ +// TagDescriptionTagidIndexId, +// 1, +// { +// Anum_pg_tag_description_tagid, +// 0, +// 0, +// 0, +// }, +// 16 +// }, {TransformRelationId, /* TRFOID */ TransformOidIndexId, 1, diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 1b2ba109c8e..ca8e8d47e4a 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -47,6 +47,8 @@ static void dumpProfiles(PGconn *conn); static void dumpPasswordHistory(PGconn *conn); static void dropTablespaces(PGconn *conn); static void dumpTablespaces(PGconn *conn); +static void dumpTags(PGconn *conn); +//static void dumpTagDescriptions(PGconn *conn); static void dropDBs(PGconn *conn); static void dumpUserConfig(PGconn *conn, const char *username); static void dumpDatabases(PGconn *conn); @@ -664,6 +666,9 @@ main(int argc, char *argv[]) /* Dump role profile */ dumpProfiles(conn); + /* Dump tags */ + dumpTags(conn); + /* Dump roles (users) */ dumpRoles(conn); @@ -1927,6 +1932,106 @@ dumpTablespaces(PGconn *conn) fprintf(OPF, "\n\n"); } +/* + * Dump tags. + */ +static void +dumpTags(PGconn *conn) +{ + PGresult *res; + int i; + + if (server_version < 140000) + return; + + res = executeQuery(conn, "SELECT oid, tagname, " + "pg_catalog.pg_get_userbyid(tagowner) AS tagowner, " + "array_to_string(allowed_values, ', '), " + "pg_catalog.shobj_description(oid, 'pg_tag') " + "FROM pg_catalog.pg_tag " + "ORDER BY 1"); + + if (PQntuples(res) > 0) + fprintf(OPF, "--\n-- Tags\n--\n\n"); + + for (i = 0; i < PQntuples(res); i++) + { + PQExpBuffer buf = createPQExpBuffer(); + Oid tagid = atooid(PQgetvalue(res, i, 0)); + char *tagname = PQgetvalue(res, i, 1); + char *tagowner = PQgetvalue(res, i, 2); + char *allowed_values = PQgetvalue(res, i, 3); + char *tagcomment = PQgetvalue(res, i, 4); + + appendPQExpBuffer(buf, "CREATE TAG %s", tagname); + + if (allowed_values && allowed_values[0] != '\0') + appendPQExpBuffer(buf, " ALLOWED_VALUES %s;\n ", allowed_values); + + appendPQExpBuffer(buf, "ALTER TAG %s OWNER TO %s;\n", + tagname, tagowner); + + if (!no_comments && tagcomment && tagcomment[0] != '\0') + { + appendPQExpBuffer(buf, "COMMENT ON TAG %s IS ", tagname); + appendStringLiteralConn(buf, tagcomment, conn); + appendPQExpBufferStr(buf, ";\n"); + } + + if (!no_security_labels && server_version >= 140000) + buildShSecLabels(conn, "pg_tag", tagid, + "TAG", tagname, + buf); + + fprintf(OPF, "%s", buf->data); + + destroyPQExpBuffer(buf); + } + + PQclear(res); + fprintf(OPF, "\n\n"); +} + +/* + * Dump pg_tag_description. + */ +//static void +//dumpTagDescriptions(PGconn *conn) +//{ +// PQExpBuffer buf = createPQExpBuffer(); +// PGresult *res; +// int i; +// +// if (server_version < 140000) +// return; +// +// res = executeQuery(conn, "SELECT oid, " +// "(SELECT datname FROM pg_database WHERE oid = databaseid) AS databasename, " +// "(SELECT relname FROM pg_class WHERE oid = classid) AS relname, " +// "(SELECT pg_catalog.get_object_name(databaseid, classid, objid)) AS objname, " +// "(SELECT tagname FROM pg_tag WHERE oid = tagid) AS tagname, " +// "tagvalue FROM pg_tag_description " +// "ORDER BY databasename"); +// +// if (PQntuples(res) > 0) +// fprintf(OPF, "--\n-- Tag Descriptions\n--\n\n"); +// +// for (i = 0; i < PQntuples(res); i++) +// { +// PQExpBuffer buf = createPQExpBuffer(); +// Oid oid = atooid(PQgetvalue(res, i, 0)); +// char *datname = PQgetvalue(res, i, 1); +// char *relname = PQgetvalue(res, i, 2); +// char *objname = PQgetvalue(res, i, 3); +// char *tagname = PQgetvalue(res, i, 4); +// char *tagvalue = PQgetvalue(res, i, 5); +// +// +// +// +// PQfinish(conn); +// } +//} /* * Dump commands to drop each database. diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 20a59a6ee6f..bc81c031e2c 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -761,6 +761,10 @@ static const SchemaQuery Query_for_list_of_collations = { "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\ " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'" +#define Query_for_list_of_tags \ +"SELECT pg_catalog.quote_ident(tagname) FROM pg_catalog.pg_tag " \ +" WHERE substring(pg_catalog.quote_ident(tagname),1,%d)='%s'" + #define Query_for_list_of_encodings \ " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\ " FROM pg_catalog.pg_conversion "\ @@ -1150,6 +1154,7 @@ static const pgsql_thing_t words_after_create[] = { {"SYSTEM", NULL, NULL, NULL, THING_NO_CREATE | THING_NO_DROP}, {"TABLE", NULL, NULL, &Query_for_list_of_tables}, {"TABLESPACE", Query_for_list_of_tablespaces}, + {"TAG", Query_for_list_of_tags}, {"TASK", Query_for_list_of_tasks}, {"TEMP", NULL, NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE TEMP TABLE * ... */ @@ -1709,6 +1714,19 @@ psql_completion(const char *text, int start, int end) else COMPLETE_WITH_FUNCTION_ARG(prev2_wd); } + /* ALTER TAG (...) */ + else if (Matches("ALTER", "TAG")) + { + COMPLETE_WITH("IF EXISTS"); + } + else if (Matches("ALTER", "TAG", "IF EXISTS", MatchAny)) + { + COMPLETE_WITH("OWNER TO", "RENAME TO", "UNSET ALLOWED_VALUES", "ADD ALLOWED_VLAUES", "DROP ALLOWED_VLAUES"); + } + else if (Matches("ALTER", "TAG", MatchAny)) + { + COMPLETE_WITH("OWNER TO", "RENAME TO", "UNSET ALLOWED_VALUES", "ADD ALLOWED_VLAUES", "DROP ALLOWED_VLAUES"); + } /* ALTER FUNCTION,PROCEDURE,ROUTINE (...) */ else if (Matches("ALTER", "FUNCTION|PROCEDURE|ROUTINE", MatchAny, MatchAny)) { @@ -2457,7 +2475,7 @@ psql_completion(const char *text, int start, int end) "COLUMN", "AGGREGATE", "FUNCTION", "STORAGE SERVER", "PROCEDURE", "PROFILE", "ROUTINE", "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", - "LARGE OBJECT", "TABLESPACE", "TEXT SEARCH", "ROLE"); + "LARGE OBJECT", "TABLESPACE", "TAG", "TEXT SEARCH", "ROLE"); else if (Matches("COMMENT", "ON", "ACCESS", "METHOD")) COMPLETE_WITH_QUERY(Query_for_list_of_access_methods); else if (Matches("COMMENT", "ON", "FOREIGN")) @@ -2866,6 +2884,14 @@ psql_completion(const char *text, int start, int end) else if (Matches("CREATE", "TABLESPACE", MatchAny, "OWNER", MatchAny)) COMPLETE_WITH("LOCATION"); +/* CREATE TAG */ + else if (Matches("CREATE", "TAG")) + COMPLETE_WITH("IF NOT EXISTS"); + else if (Matches("CREATE", "TAG", MatchAny)) + COMPLETE_WITH("ALLOWED_VALUES"); + else if (Matches("CREATE", "TAG", "IF NOT EXISTS", MatchAny)) + COMPLETE_WITH("ALLOWED_VALUES"); + /* CREATE TEXT SEARCH */ else if (Matches("CREATE", "TEXT", "SEARCH")) COMPLETE_WITH("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index c39c0edfa58..dd0b9330656 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -94,6 +94,7 @@ typedef enum SharedDependencyType SHARED_DEPENDENCY_TABLESPACE = 't', SHARED_DEPENDENCY_PROFILE = 'f', SHARED_DEPENDENCY_STORAGE_SERVER = 's', + SHARED_DEPENDENCY_TAG = 'g', SHARED_DEPENDENCY_INVALID = 0 } SharedDependencyType; @@ -151,6 +152,8 @@ typedef enum ObjectClass OCLASS_DIRTABLE, /* pg_directory_table */ OCLASS_STORAGE_SERVER, /* gp_storage_server */ OCLASS_STORAGE_USER_MAPPING, /* gp_storage_user_mapping */ + OCLASS_TAG, /* pg_tag */ + OCLASS_TAG_DESCRIPTION, /* pg_tag_description */ OCLASS_EXTPROTOCOL, /* pg_extprotocol */ OCLASS_TASK, /* pg_task */ } ObjectClass; @@ -300,6 +303,8 @@ extern void changeProfileDependency(Oid roleId, Oid profileId); extern void recordStorageServerDependency(Oid classId, Oid objectId, Oid srvId); +extern void recordTagDependency(Oid classId, Oid objectId, Oid tagId); + /* Custom object class */ struct StringInfoData; struct CustomObjectClass { diff --git a/src/include/catalog/oid_dispatch.h b/src/include/catalog/oid_dispatch.h index 90cc813c6a5..0dbb8532511 100644 --- a/src/include/catalog/oid_dispatch.h +++ b/src/include/catalog/oid_dispatch.h @@ -83,6 +83,10 @@ extern Oid GetNewOidForRelation(Relation relation, Oid indexId, AttrNumber oidco char *relname, Oid relnamespace); extern Oid GetNewOidForResQueue(Relation relation, Oid indexId, AttrNumber oidcolumn, char *rsqname); +extern Oid GetNewOidForTag(Relation relation, Oid indexId, AttrNumber oidcolumn, + char *tagname); +extern Oid GetNewOidForTagDescription(Relation relation, Oid indexId, AttrNumber oidcolumn, + char *objectname, Oid tagId); extern Oid GetNewOidForRewrite(Relation relation, Oid indexId, AttrNumber oidcolumn, Oid ev_class, char *rulename); extern Oid GetNewOidForStatisticExt(Relation relation, Oid indexId, AttrNumber oidcolumn, diff --git a/src/include/catalog/pg_tag.h b/src/include/catalog/pg_tag.h new file mode 100644 index 00000000000..f4a8a1e47b6 --- /dev/null +++ b/src/include/catalog/pg_tag.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------- + * + * pg_tag.h + * definition of the "tag" system catalog (pg_tag) + * + * + * Portions Copyright (c) 2024, Hashdata Inc. + * + * src/include/catalog/pg_tag.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_TAG_H +#define PG_TAG_H + +#include "catalog/genbki.h" +#include "catalog/pg_tag_d.h" +#include "parser/parse_node.h" + +/* ---------------- + * pg_tag definition. cpp turns this into + * typedef struct FormData_pg_tag + * + * If you change the following, make sure you change the structs for + * system attributes in catalog/heap.c also. + * You may need to change catalog/genbki.pl as well. + */ +CATALOG(pg_tag,6461,TagRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6462,TagRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid oid BKI_FORCE_NOT_NULL; /* oid */ + NameData tagname BKI_FORCE_NOT_NULL; /* name of tag */ + Oid tagowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid); /* owner of tag */ +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text allowed_values[1]; /* per tag allowed values */ +#endif +} FormData_pg_tag; + +/* ---------------- + * Form_pg_tag corresponds to a pointer to a tuple with + * the format of pg_tag relation. + * ---------------- + */ +typedef FormData_pg_tag *Form_pg_tag; + +DECLARE_UNIQUE_INDEX_PKEY(pg_tag_tagname_index, 6463, on pg_tag using btree(tagname name_ops)); +#define TagNameIndexId 6463 +DECLARE_UNIQUE_INDEX(pg_tag_oid_index, 6464, on pg_tag using btree(oid oid_ops)); +#define TagOidIndexId 6464 + +#endif /* PG_TAG_H */ \ No newline at end of file diff --git a/src/include/catalog/pg_tag_description.h b/src/include/catalog/pg_tag_description.h new file mode 100644 index 00000000000..33f79c28f5f --- /dev/null +++ b/src/include/catalog/pg_tag_description.h @@ -0,0 +1,56 @@ +/*------------------------------------------------------------------------- + * + * pg_tag_description.h + * definition of the "tag description" system catalog (pg_tag_description) + * + * + * Portions Copyright (c) 2024, Hashdata Inc. + * + * src/include/catalog/pg_tag_description.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_TAG_DESCRIPTION_H +#define PG_TAG_DESCRIPTION_H + +#include "catalog/genbki.h" +#include "catalog/pg_tag_description_d.h" +#include "parser/parse_node.h" + +/* ---------------- + * pg_tag_description definition. cpp turns this into + * typedef struct FormData_pg_tag_description + * ---------------- + */ +CATALOG(pg_tag_description,6485,TagDescriptionRelationId) BKI_SHARED_RELATION BKI_ROWTYPE_OID(6486,TagDescriptionRelation_Rowtype_Id) BKI_SCHEMA_MACRO +{ + Oid oid BKI_FORCE_NOT_NULL; /* OID of this tag description */ + Oid databaseid BKI_LOOKUP_OPT(pg_database); /* OID of database containing object */ + Oid classid BKI_LOOKUP_OPT(pg_class); /* OID of table containing object */ + Oid objid; /* OID of object itself */ + Oid tagid BKI_LOOKUP_OPT(pg_tag); /* Oid of tag */ +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + text tagvalue; /* tag value for this object */ +#endif +} FormData_pg_tag_description; + +/* ---------------- + * Form_pg_tag_description corresponds to a pointer to a tuple with + * the format of pg_tag_description relation. + * ---------------- + */ +typedef FormData_pg_tag_description *Form_pg_tag_description; + +DECLARE_UNIQUE_INDEX_PKEY(pg_tag_description_d_c_o_t_index, 6487, on pg_tag_description using btree(databaseid oid_ops, classid oid_ops, objid oid_ops, tagid oid_ops)); +#define TagDescriptionIndexId 6487 +DECLARE_UNIQUE_INDEX(pg_tag_description_oid_index, 6488, on pg_tag_description using btree(oid oid_ops)); +#define TagDescriptionOidIndexId 6488 +DECLARE_INDEX(pg_tag_description_tagidvalue_index, 6489, on pg_tag_description using btree(tagid oid_ops, tagvalue text_ops)); +#define TagDescriptionTagidvalueIndexId 6489 + +#endif /* PG_TAG_DESCRIPTION_H */ \ No newline at end of file diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h index 90aea55605b..297f8431203 100644 --- a/src/include/commands/schemacmds.h +++ b/src/include/commands/schemacmds.h @@ -21,6 +21,7 @@ extern Oid CreateSchemaCommand(CreateSchemaStmt *parsetree, const char *queryString, int stmt_location, int stmt_len); +extern void AlterSchemaCommand(AlterSchemaStmt *stmt); extern void RemoveSchemaById(Oid schemaOid); diff --git a/src/include/commands/tag.h b/src/include/commands/tag.h new file mode 100644 index 00000000000..2e6022d228a --- /dev/null +++ b/src/include/commands/tag.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * tag.h + * Tag management commands (create/drop/alter tag). + * + * + * Portions Copyright (c) 2024 Hashdata Inc + * + * src/include/commands/tag.h + * + *------------------------------------------------------------------------- + */ + +#ifndef TAG_H +#define TAG_H +#include "catalog/objectaddress.h" + +extern Oid CreateTag(CreateTagStmt *stmt); +extern ObjectAddress AlterTag(AlterTagStmt *stmt); +extern void DropTag(DropTagStmt *stmt); +extern void AddTagDescriptions(List *tags, Oid databaseid, Oid classid, Oid objid, char *objname); +extern void AlterTagDescriptions(List *tags, Oid databaseid, Oid classid, Oid objid, char *objname); +extern void UnsetTagDescriptions(List *tags, Oid databaseid, Oid classid, Oid objid, char *objname); +extern void DeleteTagDescriptions(Oid databaseid, Oid classid, Oid objid); +extern Oid get_tag_oid(const char *tagname, bool missing_ok); +extern ObjectAddress RenameTag(const char *oldname, const char *newname); +extern char *TagGetNameByOid(Oid tagid, bool missing_ok); + +#endif /* TAG_H */ \ No newline at end of file diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 8496472faa8..65af47ad2af 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -459,6 +459,10 @@ typedef enum NodeTag T_ReindexStmt, T_CheckPointStmt, T_CreateSchemaStmt, + T_AlterSchemaStmt, + T_CreateTagStmt, + T_AlterTagStmt, + T_DropTagStmt, T_AlterDatabaseStmt, T_AlterDatabaseSetStmt, T_AlterRoleSetStmt, @@ -534,6 +538,7 @@ typedef enum NodeTag T_PartitionRangeItem, T_PartitionValuesSpec, T_CreateDirectoryTableStmt, + T_AlterDirectoryTableStmt, T_CreateFileSpaceStmt, T_FileSpaceEntry, T_DropFileSpaceStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 29a2782a662..a988ce8385d 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1947,6 +1947,8 @@ typedef enum ObjectType OBJECT_TABLE, OBJECT_EXTPROTOCOL, OBJECT_TABLESPACE, + OBJECT_TAG, +// OBJECT_TAG_DESCRIPTION, OBJECT_TRANSFORM, OBJECT_TRIGGER, OBJECT_TSCONFIGURATION, @@ -1993,8 +1995,31 @@ typedef struct CreateSchemaStmt */ bool istemp; /* true for temp schemas (internal only) */ bool pop_search_path; /* true for pop search path only (internal only) */ + List *tags; /* List of tags DefElem nodes */ } CreateSchemaStmt; +typedef struct AlterSchemaStmt +{ + NodeTag type; + char *schemaname; /* the name of the schema to create */ + List *tags; /* List of tags, DelElem or String nodes */ + bool unsettag; /* Whether unset tag */ +} AlterSchemaStmt; + +/* ---------------------- + * Create Tag Statement + * + * NOTE: the allowed_values list contains all the allowed values for this tag. + * ---------------------- + */ +typedef struct CreateTagStmt +{ + NodeTag type; + char *tag_name; /* the name of the tag to create */ + bool missing_ok; /* skip error if table missing */ + List *allowed_values; /* allowed values list for this tag */ +} CreateTagStmt; + typedef enum DropBehavior { DROP_RESTRICT, /* drop fails if any dependent objects */ @@ -2032,6 +2057,16 @@ typedef struct AlterTableStmt bool is_internal; /* GPDB: set for internal generated alter table stmt */ } AlterTableStmt; +typedef struct AlterTagStmt +{ + NodeTag type; + char *tag_name; + int action; + List *tag_values; + bool missing_ok; + bool unset; +} AlterTagStmt; + typedef enum AlterTableType { AT_AddColumn, /* add column */ @@ -2110,6 +2145,8 @@ typedef enum AlterTableType AT_ExpandTable, /* EXPAND DISTRIBUTED */ AT_ExpandPartitionTablePrepare, /* EXPAND PARTITION PREPARE */ AT_ShrinkTable, /* SHRINK DISTRIBUTED */ + AT_SetTags, /* Set tags */ + AT_UnsetTags, /* Unset tags */ /* GPDB: Legacy commands to manipulate partitions */ AT_PartAdd, /* Add */ @@ -2154,6 +2191,9 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ const char *queryString; GpPolicy *policy; + + List *tags; /* List of tags, DefElem or String nodes */ + bool unsettag; /* Whether unset tag */ } AlterTableCmd; @@ -2474,6 +2514,7 @@ typedef struct CreateStmt /* names chosen for partition indexes */ List *part_idx_oids; List *part_idx_names; + List *tags; /* List of tags DefElem nodes */ } CreateStmt; /* ---------------------- @@ -2510,7 +2551,7 @@ typedef struct CreateExternalStmt List *encoding; /* List (size 1 max) of DefElem nodes for data encoding */ DistributedBy *distributedBy; /* what columns we distribute the data by */ - + List *tags; /* List of tags DefElem nodes */ } CreateExternalStmt; /* ---------------------- @@ -2718,6 +2759,7 @@ typedef struct CreateTableSpaceStmt char *location; List *options; char *filehandler; + List *tags; /* List of tags DefElem nodes */ } CreateTableSpaceStmt; typedef struct DropTableSpaceStmt @@ -2733,6 +2775,8 @@ typedef struct AlterTableSpaceOptionsStmt char *tablespacename; List *options; bool isReset; + List *tags; /* List of tags, DefElem or String nodes */ + bool unsettag; /* Whether unset tag */ } AlterTableSpaceOptionsStmt; typedef struct AlterTableMoveAllStmt @@ -2745,6 +2789,13 @@ typedef struct AlterTableMoveAllStmt bool nowait; } AlterTableMoveAllStmt; +typedef struct DropTagStmt +{ + NodeTag type; + List *tags; + bool missing_ok; +} DropTagStmt; + /* ---------------------- * Create/Alter/Drop Task Statements * ---------------------- @@ -3170,6 +3221,7 @@ typedef struct CreateRoleStmt RoleStmtType stmt_type; /* ROLE/USER/GROUP */ char *role; /* role name */ List *options; /* List of DefElem nodes */ + List *tags; /* List of DefElem tag nodes */ } CreateRoleStmt; typedef struct AlterRoleStmt @@ -3178,6 +3230,8 @@ typedef struct AlterRoleStmt RoleSpec *role; /* role */ List *options; /* List of DefElem nodes */ int action; /* +1 = add members, -1 = drop members */ + List *tags; /* List of DefElem tag nodes */ + bool unsettag; } AlterRoleStmt; typedef struct AlterRoleSetStmt @@ -3244,6 +3298,7 @@ typedef struct CreateSeqStmt Oid ownerId; /* ID of owner, or InvalidOid for default */ bool for_identity; bool if_not_exists; /* just do nothing if it already exists? */ + List *tags; /* List of tags DefElem nodes */ } CreateSeqStmt; typedef struct AlterSeqStmt @@ -3352,6 +3407,14 @@ typedef struct CreateDirectoryTableStmt char *tablespacename; } CreateDirectoryTableStmt; +typedef struct AlterDirectoryTableStmt +{ + NodeTag type; + RangeVar *relation; /* directory table to alter */ + List *tags; /* List of tags, DefElem or String nodes */ + bool unsettag; /* Whether unset tag */ +} AlterDirectoryTableStmt; + /* ---------------------- * DROP Statement, applies to: @@ -3532,6 +3595,7 @@ typedef struct IndexStmt * concurrently build */ Oid indexRelationOid; /* relationOid of index, dispatch to QEs when * concurrently build */ + List *tags; /* List of tags DefElem nodes */ } IndexStmt; /* ---------------------- @@ -3892,6 +3956,7 @@ typedef struct ViewStmt bool replace; /* replace an existing view? */ List *options; /* options from WITH clause */ ViewCheckOption withCheckOption; /* WITH CHECK OPTION */ + List *tags; /* List of tags DefElem nodes */ } ViewStmt; /* ---------------------- @@ -3913,6 +3978,7 @@ typedef struct CreatedbStmt NodeTag type; char *dbname; /* name of database to create */ List *options; /* List of DefElem nodes */ + List *tags; /* List of tags DefElem nodes */ } CreatedbStmt; /* ---------------------- @@ -3924,6 +3990,8 @@ typedef struct AlterDatabaseStmt NodeTag type; char *dbname; /* name of database to alter */ List *options; /* List of DefElem nodes */ + List *tags; /* List of tags, DefElem or String nodes */ + bool unsettag; /* Whether unset tag */ } AlterDatabaseStmt; typedef struct AlterDatabaseSetStmt @@ -4364,6 +4432,7 @@ typedef struct CreateWarehouseStmt NodeTag type; char *whname; List *options; /* List of DefElem nodes */ + List *tags; /* List of tag DefElem nodes */ } CreateWarehouseStmt; typedef struct DropWarehouseStmt diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 60d7e4d7cee..edfc3435d6a 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -37,6 +37,7 @@ PG_KEYWORD("admin", ADMIN, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("after", AFTER, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("aggregate", AGGREGATE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("all", ALL, RESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("allowed_values", ALLOWED_VALUES, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("also", ALSO, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("alter", ALTER, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("always", ALWAYS, UNRESERVED_KEYWORD, BARE_LABEL) @@ -511,6 +512,7 @@ PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("unlock", UNLOCK_P, UNRESERVED_KEYWORD, BARE_LABEL) /* GPDB */ PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("unset", UNSET_P, UNRESERVED_KEYWORD, BARE_LABEL) /* GPDB */ PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("user", USER, RESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h index c97011262df..dd63c7659e4 100644 --- a/src/include/tcop/cmdtaglist.h +++ b/src/include/tcop/cmdtaglist.h @@ -68,6 +68,7 @@ PG_CMDTAG(CMDTAG_ALTER_SUBSCRIPTION, "ALTER SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_ALTER_SYSTEM, "ALTER SYSTEM", false, false, false) PG_CMDTAG(CMDTAG_ALTER_TABLE, "ALTER TABLE", true, true, false) PG_CMDTAG(CMDTAG_ALTER_TABLESPACE, "ALTER TABLESPACE", false, false, false) +PG_CMDTAG(CMDTAG_ALTER_TAG, "ALTER TAG", true, false, false) PG_CMDTAG(CMDTAG_ALTER_TASK, "ALTER TASK", true, false, false) PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION, "ALTER TEXT SEARCH CONFIGURATION", true, false, false) PG_CMDTAG(CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY, "ALTER TEXT SEARCH DICTIONARY", true, false, false) @@ -133,6 +134,7 @@ PG_CMDTAG(CMDTAG_CREATE_SUBSCRIPTION, "CREATE SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TABLE, "CREATE TABLE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TABLE_AS, "CREATE TABLE AS", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TABLESPACE, "CREATE TABLESPACE", false, false, false) +PG_CMDTAG(CMDTAG_CREATE_TAG, "CREATE TAG", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_CONFIGURATION, "CREATE TEXT SEARCH CONFIGURATION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_DICTIONARY, "CREATE TEXT SEARCH DICTIONARY", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TEXT_SEARCH_PARSER, "CREATE TEXT SEARCH PARSER", true, false, false) @@ -204,6 +206,7 @@ PG_CMDTAG(CMDTAG_DROP_STORAGE_USER_MAPPING, "DROP STORAGE USER MAPPING", true, f PG_CMDTAG(CMDTAG_DROP_SUBSCRIPTION, "DROP SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_DROP_TABLE, "DROP TABLE", true, false, false) PG_CMDTAG(CMDTAG_DROP_TABLESPACE, "DROP TABLESPACE", false, false, false) +PG_CMDTAG(CMDTAG_DROP_TAG, "DROP TAG", true, false, false) PG_CMDTAG(CMDTAG_DROP_TASK, "DROP TASK", true, false, false) PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_CONFIGURATION, "DROP TEXT SEARCH CONFIGURATION", true, false, false) PG_CMDTAG(CMDTAG_DROP_TEXT_SEARCH_DICTIONARY, "DROP TEXT SEARCH DICTIONARY", true, false, false) diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index bf47cd0a592..223175099bd 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -318,6 +318,7 @@ extern bool pg_opfamily_ownercheck(Oid opf_oid, Oid roleid); extern bool pg_database_ownercheck(Oid db_oid, Oid roleid); extern bool pg_collation_ownercheck(Oid coll_oid, Oid roleid); extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid); +extern bool pg_tag_ownercheck(Oid tag_oid, Oid roleid); extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid); extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid); extern bool pg_foreign_data_wrapper_ownercheck(Oid srv_oid, Oid roleid); diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 62f6b2a46e2..a1f8c73651e 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -106,6 +106,10 @@ enum SysCacheIdentifier SUBSCRIPTIONOID, SUBSCRIPTIONRELMAP, TABLESPACEOID, + TAGNAME, + TAGOID, + TAGDESCRIPTION, +// TAGDESCRIPTIONTAGID, TRFOID, TRFTYPELANG, TSCONFIGMAP, diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c index 1bae1e54380..849bf7898b5 100644 --- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c +++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c @@ -279,6 +279,12 @@ get_altertable_subcmdtypes(PG_FUNCTION_ARGS) case AT_GenericOptions: strtype = "SET OPTIONS"; break; + case AT_SetTags: + strtype = "SET TAGS"; + break; + case AT_UnsetTags: + strtype = "UNSET TAGS"; + break; default: strtype = "unrecognized"; break; diff --git a/src/test/regress/expected/misc_sanity.out b/src/test/regress/expected/misc_sanity.out index 7e1df68863b..0dff5fe6374 100644 --- a/src/test/regress/expected/misc_sanity.out +++ b/src/test/regress/expected/misc_sanity.out @@ -123,6 +123,8 @@ ORDER BY 1, 2; pg_resqueuecapability | ressetting | text pg_stat_last_operation | stasubtype | text pg_stat_last_shoperation | stasubtype | text + pg_tag | allowed_values | text[] + pg_tag_description | tagvalue | text pg_task | command | text pg_task | database | text pg_task | jobname | text @@ -134,7 +136,7 @@ ORDER BY 1, 2; pg_task_run_history | return_message | text pg_task_run_history | status | text pg_task_run_history | username | text -(31 rows) +(33 rows) -- system catalogs without primary keys -- diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index 4d6ad39fbb8..a8a81903797 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -202,6 +202,10 @@ NOTICE: checking pg_tablespace {spcowner} => pg_authid {oid} NOTICE: checking pg_auth_members {roleid} => pg_authid {oid} NOTICE: checking pg_auth_members {member} => pg_authid {oid} NOTICE: checking pg_auth_members {grantor} => pg_authid {oid} +NOTICE: checking pg_tag {tagowner} => pg_authid {oid} +NOTICE: checking pg_tag_description {classid} => pg_class {oid} +NOTICE: checking pg_tag_description {databaseid} => pg_database {oid} +NOTICE: checking pg_tag_description {tagid} => pg_tag {oid} NOTICE: checking pg_shdepend {dbid} => pg_database {oid} NOTICE: checking pg_shdepend {classid} => pg_class {oid} NOTICE: checking pg_shdepend {refclassid} => pg_class {oid} diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index ca4b1db5320..2c8d696a0b1 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -174,6 +174,8 @@ pg_statistic_ext_data|t pg_subscription|t pg_subscription_rel|t pg_tablespace|t +pg_tag|t +pg_tag_description|t pg_task|t pg_task_run_history|t pg_transform|t diff --git a/src/test/regress/greenplum_schedule b/src/test/regress/greenplum_schedule index 66c5129c356..6b93b88f59a 100755 --- a/src/test/regress/greenplum_schedule +++ b/src/test/regress/greenplum_schedule @@ -321,4 +321,7 @@ test: am_encoding # tests of directory table test: directory_table +# test of tag +test: tag + # end of tests diff --git a/src/test/regress/input/tag.source b/src/test/regress/input/tag.source new file mode 100644 index 00000000000..2eae5f315a6 --- /dev/null +++ b/src/test/regress/input/tag.source @@ -0,0 +1,623 @@ +-- Test tag manipulation +\d+ pg_tag; +\d+ pg_tag_description; +SELECT * FROM pg_tag; +SELECT * FROM pg_tag_description; +CREATE DATABASE other_db; + +-- Test create tag +CREATE TAG tag1; +CREATE TAG IF NOT EXISTS tag1; +CREATE TAG IF NOT EXISTS tag2; +CREATE TAG tag2; -- error +CREATE TAG tag3 ALLOWED_VALUES '123'; +CREATE TAG tag3; -- error +CREATE TAG tag4 ALLOWED_VALUES '123', '456', ' '; +CREATE TAG IF NOT EXISTS tag5 ALLOWED_VALUES '123', 'val1'; +CREATE TAG tag6 ALLOWED_VALUES 'nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqwef' +'fjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwef' +'qifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdas' +'iqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho'; -- error +CREATE TAG tag7 ALLOWED_VALUES 'val1', '123', 'val1'; -- error +CREATE TAG tag8 ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +CREATE TAG tag9 ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300', '301'; + +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c postgres + +-- Test Drop tag +DROP TAG tag5; +DROP TAG IF EXISTS tag5; +DROP TAG IF EXISTS tag8; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c postgres + +-- Test Alter tag +-- Rename +ALTER TAG tag3 RENAME TO tag3_new; +ALTER TAG IF EXISTS tag4 RENAME TO tag4_new; +ALTER TAG tag3_new RENAME TO tag3; +ALTER TAG tag4_new RENAME TO tag4; + +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c postgres + +-- OWNER TO +CREATE USER tag_user; +ALTER TAG tag1 OWNER TO tag_user; +SELECT tagname, rolname AS tagowner, allowed_values FROM pg_tag, pg_authid +WHERE pg_tag.tagowner = pg_authid.oid +ORDER BY 1; +ALTER TAG tag1 OWNER TO gpadmin; +SELECT tagname, rolname AS tagowner, allowed_values FROM pg_tag, pg_authid +WHERE pg_tag.tagowner = pg_authid.oid +ORDER BY 1; +\c other_db +SELECT tagname, rolname AS tagowner, allowed_values FROM pg_tag, pg_authid +WHERE pg_tag.tagowner = pg_authid.oid +ORDER BY 1; +\c postgres + +-- Unset allowed_values +ALTER TAG tag1 UNSET ALLOWED_VALUES; +ALTER TAG tag2 UNSET ALLOWED_VALUES; +ALTER TAG tag3 UNSET ALLOWED_VALUES; + +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c postgres + +-- ADD allowed_values +ALTER TAG tag1 ADD ALLOWED_VALUES 'val1'; +ALTER TAG tag1 ADD ALLOWED_VALUES 'val1'; -- error +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES 'val1'; -- error +ALTER TAG tag1 ADD ALLOWED_VALUES 'val2', 'val2'; -- error +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES 'val2', 'val2'; -- error +ALTER TAG tag1 ADD ALLOWED_VALUES 'val2', 'val3'; +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES 'val4', 'val5'; +ALTER TAG tag1 ADD ALLOWED_VALUES '', ''; -- error +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES '', ''; --error +ALTER TAG tag1 ADD ALLOWED_VALUES ' ', ' '; -- error +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES ' '; + +ALTER TAG tag1 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c postgres + +ALTER TAG tag2 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ALTER TAG IF EXISTS tag2 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; + +ALTER TAG tag3 ADD ALLOWED_VALUES 'nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqwef' +'fjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwef' +'qifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdas' +'iqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho'; -- error +ALTER TAG IF EXISTS tag3 ADD ALLOWED_VALUES 'nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqwef' +'fjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwef' +'qifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdas' +'iqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho'; -- error +ALTER TAG tag3 ADD ALLOWED_VALUES 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'; + +ALTER TAG tag4 ADD ALLOWED_VALUES ' '; -- error +ALTER TAG IF EXISTS tag4 ADD ALLOWED_VALUES ' '; -- error +ALTER TAG tag4 ADD ALLOWED_VALUES ''; +ALTER TAG tag4 ADD ALLOWED_VALUES ''; -- error + +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c postgres + +-- DROP allowed_values +ALTER TAG tag1 DROP ALLOWED_VALUES 'unknown'; -- error; +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES 'unknown'; -- error; +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ALTER TAG tag1 DROP ALLOWED_VALUES '1'; -- error +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES '1'; -- error +ALTER TAG tag1 DROP ALLOWED_VALUES ''; -- error +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES ''; -- error +ALTER TAG tag1 UNSET ALLOWED_VALUES; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + +ALTER TAG tag1 ADD ALLOWED_VALUES 'val1', 'val2', 'val3'; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; +SELECT count(*) FROM pg_tag_description; +\c postgres + +-- Cleanup +DROP USER tag_user; + +-- Test database with tag +-- Create database +CREATE DATABASE tag_db1 TAG (tag1 = 'novalue'); -- error +CREATE DATABASE tag_db1 TAG (tag1 = 'val1'); +CREATE DATABASE tag_db2 TAG; -- error +CREATE DATABASE tag_db2 TAG (); -- error +CREATE DATABASE tag_db2 TAG (tag1 = ''); -- error +CREATE DATABASE tag_db2 TAG (tag1 = 'val1', tag2 = '10'); +CREATE DATABASE tag_db3 TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +CREATE DATABASE tag_db3 TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +CREATE DATABASE tag_db3 TAG (tag1 = 'val1', tag2 = '1'); +CREATE DATABASE tag_db4 TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +CREATE DATABASE tag_db5 TAG (tag2 = '300', tag4 = ' '); +CREATE DATABASE tag_db6 TAG (tag4 = '', tag4 = ' '); -- error +CREATE DATABASE tag_db6 TAG (tag4 = '', tag4 = ''); -- error +CREATE DATABASE tag_db6 TAG (tag4 = ' ', tag4 = ' '); -- error +CREATE DATABASE tag_db6 TAG (tag4 = ''); +CREATE DATABASE tag_db7 TAG (tag4 = ' '); +CREATE DATABASE tag_db8 TAG (tag3 = ''); -- error +CREATE DATABASE tag_db8 WITH TEMPLATE = template0 ENCODING='UTF-8' LC_COLLATE='C' LC_CTYPE='C' TAG (tag1 = 'novalue'); -- error +CREATE DATABASE tag_db8 WITH TEMPLATE = template0 ENCODING='UTF-8' LC_COLLATE='C' LC_CTYPE='C' TAG (tag1 = 'val1'); +CREATE DATABASE tag_db9 WITH TEMPLATE = template0 ENCODING='UTF-8' LC_COLLATE='C' LC_CTYPE='C'; +CREATE DATABASE tag_db10 WITH TEMPLATE = template0 TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); + +SELECT * FROM database_tag_descriptions +ORDER BY 1, 2, 3, 4; + +SELECT datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit +FROM pg_database ORDER BY 1; + +DROP TAG tag1; -- error +DROP TAG tag2; -- error +DROP TAG tag3; -- error +DROP TAG tag4; -- error +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + +-- Alter Database +ALTER DATABASE tag_db1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER DATABASE tag_db2 TAG (tag2 = '10'); +ALTER DATABASE tag_db3 TAG (tag3 = ''); -- error +ALTER DATABASE tag_db4 UNSET TAG (tag1, tag2); +ALTER DATABASE tag_db4 TAG (tag1 = 'val3', tag4 = ''); +ALTER DATABASE tag_db5 TAG (tag4 = '', tag4 = ' '); +ALTER DATABASE tag_db6 TAG (tag4 = ' '); +ALTER DATABASE tag_db7 TAG (tag1 = 'val2', tag2 = '3'); +ALTER DATABASE tag_db7 UNSET TAG (tag1); +ALTER DATABASE tag_db8 TAG (tag4 = '123', tag4 = '123'); +ALTER DATABASE tag_db9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +ALTER DATABASE tag_db9 TAG (tag4 = '123'); + +SELECT * FROM database_tag_descriptions +ORDER BY 1, 2, 3, 4; + +SELECT datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit +FROM pg_database ORDER BY 1; + +-- Drop Database +DROP DATABASE tag_db1; +DROP DATABASE tag_db2; +DROP DATABASE tag_db3; +DROP DATABASE tag_db4; +DROP DATABASE tag_db5; +DROP DATABASE tag_db6; +DROP DATABASE tag_db7; +DROP DATABASE tag_db8; +DROP DATABASE tag_db9; +DROP DATABASE tag_db10; + +SELECT * FROM database_tag_descriptions +ORDER BY 1, 2, 3, 4; + +SELECT datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit +FROM pg_database ORDER BY 1; + + +-- Test user with tag +-- Create User +CREATE USER tag_user1 TAG (tag1 = 'novalue'); -- error +CREATE USER tag_user1 TAG (tag1 = 'val1'); +CREATE USER tag_user2 TAG; -- error +CREATE USER tag_user2 TAG (); -- error +CREATE USER tag_user2 TAG (tag1 = ''); -- error +CREATE USER tag_user2 TAG (tag1 = 'val1', tag2 = '10'); +CREATE USER tag_user3 TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +CREATE USER tag_user3 TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +CREATE USER tag_user3 TAG (tag1 = 'val1', tag2 = '1'); +CREATE USER tag_user4 TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +CREATE USER tag_user5 TAG (tag2 = '300', tag4 = ' '); +CREATE USER tag_user6 TAG (tag4 = '', tag4 = ''); -- error +CREATE USER tag_user6 TAG (tag4 = ' ', tag4 = ' '); -- error +CREATE USER tag_user6 TAG (tag4 = ''); +CREATE USER tag_user7 CONNECTION LIMIT 10 TAG (tag4 = ' '); +CREATE USER tag_user8 TAG (tag3 = ''); -- error +CREATE USER tag_user8 superuser TAG (tag1 = 'novalue'); -- error +CREATE USER tag_user8 superuser TAG (tag1 = 'val1'); +CREATE USER tag_user9 superuser; +CREATE USER tag_user10 superuser TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); + +SELECT * FROM user_tag_descriptions +WHERE rolname like '%tag_user%' +ORDER BY 1, 2, 3, 4; + +SELECT rolname, rolsuper, rolconnlimit FROM pg_authid +WHERE rolname like '%tag_user%' +ORDER BY 1; + +DROP TAG tag1; -- error +DROP TAG tag2; -- error +DROP TAG tag3; -- error +DROP TAG tag4; -- error +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + +-- Alter User +ALTER USER tag_user1 CONNECTION LIMIT 3 TAG (tag1 = 'val1', tag1 = 'val1'); -- error +ALTER USER tag_user1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER USER tag_user2 TAG (tag2 = '10'); +ALTER USER tag_user3 TAG (tag3 = ''); -- error +ALTER USER tag_user4 UNSET TAG (tag1, tag2); +ALTER USER tag_user4 TAG (tag1 = 'val3', tag4 = ''); +ALTER USER tag_user5 TAG (tag4 = '', tag4 = ' '); +ALTER USER tag_user6 TAG (tag4 = ' '); +ALTER USER tag_user7 TAG (tag1 = 'val2', tag2 = '3'); +ALTER USER tag_user7 UNSET TAG (tag1); +ALTER USER tag_user8 TAG (tag4 = '123', tag4 = '123'); +ALTER USER tag_user9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +ALTER USER tag_user9 TAG (tag4 = '123'); + +SELECT * FROM user_tag_descriptions +WHERE rolname like '%tag_user%' +ORDER BY 1, 2, 3, 4; + +SELECT rolname, rolsuper, rolconnlimit FROM pg_authid +WHERE rolname like '%tag_user%' +ORDER BY 1; + +-- Drop User +DROP USER tag_user1; +DROP USER tag_user2; +DROP USER tag_user3; +DROP USER tag_user4; +DROP USER tag_user5; +DROP USER tag_user6; +DROP USER tag_user7; +DROP USER tag_user8; +DROP USER tag_user9; +DROP USER tag_user10; + +SELECT * FROM user_tag_descriptions +WHERE rolname like '%tag_user%' +ORDER BY 1, 2, 3, 4; + +SELECT rolname, rolsuper, rolconnlimit FROM pg_authid +WHERE rolname like '%tag_user%' +ORDER BY 1; + + +-- Test tablespace with tag +-- Create tablespace +CREATE TABLESPACE tag_tablespace LOCATION '@testtablespace@' WITH (random_page_cost = 3.0) TAG (tag1 = 'test'); -- error +CREATE TABLESPACE tag_tablespace LOCATION '@testtablespace@' WITH (random_page_cost = 3.0) TAG (tag1 = 'val1', tag2 = '301'); -- error +CREATE TABLESPACE tag_tablespace LOCATION '@testtablespace@' WITH (random_page_cost = 3.0) TAG (tag1 = 'val1', tag2 = '2'); + +SELECT * FROM tablespace_tag_descriptions +ORDER BY 1, 2, 3, 4; + +SELECT spcname FROM pg_tablespace +ORDER BY 1; + +-- Alter tablespace +ALTER TABLESPACE tag_tablespace SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag2 = '10'); -- error +ALTER TABLESPACE tag_tablespace SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag3 = ''); -- error +ALTER TABLESPACE tag_tablespace SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag4 = '', tag1 = 'val1'); -- error +ALTER TABLESPACE tag_tablespace TAG (tag4 = '', tag1 = 'val1'); +ALTER TABLESPACE tag_tablespace UNSET TAG (tag1, tag2); +ALTER TABLESPACE tag_tablespace UNSET TAG (tag2); +ALTER TABLESPACE tag_tablespace TAG (tag1 = 'val2', tag1 = 'val3'); + +SELECT * FROM tablespace_tag_descriptions +ORDER BY 1, 2, 3, 4; + +SELECT spcname FROM pg_tablespace +ORDER BY 1; + +DROP TAG tag1; -- error +DROP TAG tag2; -- error +DROP TAG tag4; -- error +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + +-- Drop tablespace +DROP TABLESPACE tag_tablespace; + +SELECT * FROM tablespace_tag_descriptions +ORDER BY 1, 2, 3, 4; + +SELECT spcname FROM pg_tablespace +ORDER BY 1; + + +-- Test Schema with Tag +-- Create Schema +CREATE SCHEMA tag_schema1 TAG (tag1 = 'val1'); -- error +CREATE SCHEMA tag_schema1 WITH TAG (tag1 = 'novalue'); -- error +CREATE SCHEMA tag_schema1 WITH TAG (tag1 = 'val1'); +CREATE SCHEMA tag_schema2 WITH TAG; -- error +CREATE SCHEMA tag_schema2 WITH TAG (); -- error +CREATE SCHEMA tag_schema2 WITH TAG (tag1 = ''); -- error +CREATE SCHEMA tag_schema2 WITH TAG (tag1 = 'val1', tag2 = '10'); +CREATE SCHEMA tag_schema3 WITH TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +CREATE SCHEMA tag_schema3 WITH TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +CREATE SCHEMA tag_schema3 WITH TAG (tag1 = 'val1', tag2 = '1'); +CREATE SCHEMA tag_schema4 WITH TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +CREATE SCHEMA tag_schema5 WITH TAG (tag2 = '300', tag4 = ' '); +CREATE SCHEMA tag_schema6 WITH TAG (tag4 = '', tag4 = ''); -- error +CREATE SCHEMA tag_schema6 WITH TAG (tag4 = ' ', tag4 = ' '); -- error +CREATE SCHEMA tag_schema6 WITH TAG (tag4 = ''); +CREATE SCHEMA tag_schema7 WITH TAG (tag4 = ' '); +CREATE SCHEMA tag_schema8 WITH TAG (tag3 = ''); -- error +CREATE SCHEMA tag_schema8 WITH TAG (tag1 = 'novalue'); -- error +CREATE SCHEMA tag_schema8 WITH TAG (tag1 = 'val1'); +CREATE SCHEMA tag_schema9; +CREATE SCHEMA tag_schema10 WITH TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); + +SELECT * FROM schema_tag_descriptions +WHERE nspname like '%tag_schema%' +ORDER BY 1, 2, 3, 4; + +SELECT nspname, nspowner FROM pg_namespace +WHERE nspname like '%tag_schema%' +ORDER BY 1; + +DROP TAG tag1; -- error +DROP TAG tag2; -- error +DROP TAG tag3; -- error +DROP TAG tag4; -- error +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + +-- Alter Schema +ALTER SCHEMA tag_schema1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER SCHEMA tag_schema2 TAG (tag2 = '10'); +ALTER SCHEMA tag_schema3 TAG (tag3 = ''); -- error +ALTER SCHEMA tag_schema4 UNSET TAG (tag1, tag2); +ALTER SCHEMA tag_schema4 TAG (tag1 = 'val3', tag4 = ''); +ALTER SCHEMA tag_schema5 TAG (tag4 = '', tag4 = ' '); +ALTER SCHEMA tag_schema6 TAG (tag4 = ' '); +ALTER SCHEMA tag_schema7 TAG (tag1 = 'val2', tag2 = '3'); +ALTER SCHEMA tag_schema7 UNSET TAG (tag1); +ALTER SCHEMA tag_schema8 TAG (tag4 = '123', tag4 = '123'); +ALTER SCHEMA tag_schema9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +ALTER SCHEMA tag_schema9 TAG (tag4 = '123'); + +SELECT * FROM schema_tag_descriptions +WHERE nspname like '%tag_schema%' +ORDER BY 1, 2, 3, 4; + +SELECT nspname, nspowner FROM pg_namespace +WHERE nspname like '%tag_schema%' +ORDER BY 1; + +-- Drop Schema +DROP SCHEMA tag_schema1; +DROP SCHEMA tag_schema2; +DROP SCHEMA tag_schema3; +DROP SCHEMA tag_schema4; +DROP SCHEMA tag_schema5; +DROP SCHEMA tag_schema6; +DROP SCHEMA tag_schema7; +DROP SCHEMA tag_schema8; +DROP SCHEMA tag_schema9; +DROP SCHEMA tag_schema10; + +SELECT * FROM schema_tag_descriptions +WHERE nspname like '%tag_schema%' +ORDER BY 1, 2, 3, 4; + +SELECT nspname, nspowner FROM pg_namespace +WHERE nspname like '%tag_schema%' +ORDER BY 1; + + +-- Test Table with Tag +-- Create Table +CREATE TABLE tag_table1(a int, b varchar) TAG (tag1 = 'novalue'); -- error +CREATE TEMP TABLE tag_table1(a int, b varchar) TAG (tag1 = 'val1'); +CREATE TEMP TABLE tag_table2(a int, b varchar) TAG; -- error +CREATE TEMP TABLE tag_table2(a int, b varchar) TAG (); -- error +CREATE TABLE tag_table2(a int, b varchar) TAG (tag1 = ''); -- error +CREATE TEMP TABLE tag_table2(a int, b varchar) TAG (tag1 = 'val1', tag2 = '10'); +CREATE TABLE tag_table3(a int, b varchar) TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +CREATE TABLE tag_table3(a int, b varchar) TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +CREATE TEMP TABLE tag_table3(a int, b varchar) TAG (tag1 = 'val1', tag2 = '1'); +CREATE TABLE tag_table4(a int, b varchar) TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +CREATE TABLE tag_table5(a int, b varchar) TAG (tag2 = '300', tag4 = ' '); +CREATE TABLE tag_table6(a int, b varchar) TAG (tag4 = '', tag4 = ''); -- error +CREATE TABLE tag_table6(a int, b varchar) TAG (tag4 = ' ', tag4 = ' '); -- error +CREATE TABLE tag_table6(a int, b varchar) TAG (tag4 = ''); +CREATE TABLE tag_table7(a int, b varchar) TAG (tag4 = ' '); +CREATE TABLE tag_table8(a int, b varchar) TAG (tag3 = ''); -- error +CREATE TABLE tag_table8(a int, b varchar) TAG (tag1 = 'novalue'); -- error +CREATE TABLE tag_table8(a int, b varchar) TAG (tag1 = 'val1'); +CREATE TABLE tag_table9(a int, b varchar); +CREATE TABLE tag_table10(a int, b varchar) TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); + +SELECT * FROM relation_tag_descriptions +WHERE relname like '%tag_table%' +ORDER BY 1, 2, 3, 4, 5, 6; + +SELECT relname, relpersistence FROM pg_class +WHERE relname like '%tag_table%' +ORDER BY 1; + +DROP TAG tag1; -- error +DROP TAG tag2; -- error +DROP TAG tag3; -- error +DROP TAG tag4; -- error +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + +-- Alter Table +ALTER TABLE tag_table1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER TABLE tag_table2 TAG (tag2 = '10'); +ALTER TABLE tag_table3 TAG (tag3 = ''); +ALTER TABLE tag_table4 UNSET TAG (tag1, tag2); +ALTER TABLE tag_table4 TAG (tag1 = 'val3', tag4 = ''); +ALTER TABLE tag_table5 TAG (tag4 = '', tag4 = ' '); +ALTER TABLE tag_table6 TAG (tag4 = ' '); +ALTER TABLE tag_table7 TAG (tag1 = 'val2', tag2 = '3'); +ALTER TABLE tag_table7 UNSET TAG (tag1); +ALTER TABLE tag_table8 TAG (tag4 = '123', tag4 = '123'); +ALTER TABLE tag_table9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +ALTER TABLE tag_table9 TAG (tag4 = '123'); + +SELECT * FROM relation_tag_descriptions +WHERE relname like '%tag_table%' +ORDER BY 1, 2, 3, 4, 5, 6; + +SELECT relname, relpersistence FROM pg_class +WHERE relname like '%tag_table%' +ORDER BY 1; + +-- Drop Table +DROP TABLE tag_table1; +DROP TABLE tag_table2; +DROP TABLE tag_table3; +DROP TABLE tag_table4; +DROP TABLE tag_table5; +DROP TABLE tag_table6; +DROP TABLE tag_table7; +DROP TABLE tag_table8; +DROP TABLE tag_table9; +DROP TABLE tag_table10; + +SELECT * FROM relation_tag_descriptions +WHERE relname like '%tag_table%' +ORDER BY 1, 2, 3, 4, 5, 6; + +SELECT relname, relpersistence FROM pg_class +WHERE relname like '%tag_table%' +ORDER BY 1; + + +-- Cleanup +DROP TAG tag1; +DROP TAG tag2; +DROP TAG tag3; +DROP TAG tag4; +DROP DATABASE other_db; diff --git a/src/test/regress/output/directory_table.source b/src/test/regress/output/directory_table.source index 1fb529faae6..69a7685347b 100644 --- a/src/test/regress/output/directory_table.source +++ b/src/test/regress/output/directory_table.source @@ -694,15 +694,15 @@ SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname -- Test CREATE/DROP/REINDEX on DIRECTORY SCHEMA TABLE -- Test CREATE INDEX on DIRECTORY SCHEMA TABLE CREATE INDEX dirtable1_relative_path_idx on dir_table1(relative_path); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_size_idx on dir_table1(size); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_last_modified_idx on dir_table1(last_modified); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_md5_idx on dir_table1(md5); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_tag_idx on dir_table1(tag); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) \d+ dir_table1; Directory able "public.dir_table1" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description @@ -1287,35 +1287,35 @@ SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; ALTER TABLE dir_table1 ADD COLUMN a int; -- fail ERROR: "dir_table1" is not a table, composite type, or foreign table ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "ADD" LINE 1: ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; - ^ + ^ ALTER TABLE dir_table2 DROP COLUMN relative_path; -- fail ERROR: "dir_table2" is not a table, composite type, or foreign table ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "DROP" LINE 1: ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; - ^ + ^ ALTER TABLE dir_table1 RENAME TO dir_table_new; -- fail ERROR: Rename directory table is not allowed. ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "RENAME" LINE 1: ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; - ^ + ^ ALTER TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail ERROR: "dir_table2" is not a table or foreign table ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "ADD" LINE 1: ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_con... - ^ + ^ ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail ERROR: syntax error at or near "CONSTRAINT" LINE 1: ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_... ^ ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "DROP" LINE 1: ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTR... - ^ + ^ -- Test remove_table SELECT remove_file('dir_table1', 'nation5'); -- fail remove_file diff --git a/src/test/regress/output/directory_table_optimizer.source b/src/test/regress/output/directory_table_optimizer.source index c1594f80cb9..c92ca71cc00 100644 --- a/src/test/regress/output/directory_table_optimizer.source +++ b/src/test/regress/output/directory_table_optimizer.source @@ -694,15 +694,15 @@ SELECT relname, relisshared, relpersistence, relkind FROM pg_class WHERE relname -- Test CREATE/DROP/REINDEX on DIRECTORY SCHEMA TABLE -- Test CREATE INDEX on DIRECTORY SCHEMA TABLE CREATE INDEX dirtable1_relative_path_idx on dir_table1(relative_path); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_size_idx on dir_table1(size); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_last_modified_idx on dir_table1(last_modified); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_md5_idx on dir_table1(md5); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) CREATE INDEX dirtable1_tag_idx on dir_table1(tag); -- fail -ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:709) +ERROR: Disallowed to create index on directory table "dir_table1". (indexcmds.c:710) \d+ dir_table1; Directory able "public.dir_table1" Column | Type | Collation | Nullable | Default | Storage | Stats target | Description @@ -1282,35 +1282,35 @@ SELECT relative_path, size, tag FROM dir_table2 ORDER BY 1; ALTER TABLE dir_table1 ADD COLUMN a int; -- fail ERROR: "dir_table1" is not a table, composite type, or foreign table ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "ADD" LINE 1: ALTER DIRECTORY TABLE dir_table1 ADD COLUMN a int; - ^ + ^ ALTER TABLE dir_table2 DROP COLUMN relative_path; -- fail ERROR: "dir_table2" is not a table, composite type, or foreign table ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "DROP" LINE 1: ALTER DIRECTORY TABLE dir_table2 DROP COLUMN relative_path; - ^ + ^ ALTER TABLE dir_table1 RENAME TO dir_table_new; -- fail ERROR: Rename directory table is not allowed. ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "RENAME" LINE 1: ALTER DIRECTORY TABLE dir_table1 RENAME TO dir_table_new; - ^ + ^ ALTER TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail ERROR: "dir_table2" is not a table or foreign table ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_constraint UNIQUE (tag); -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "ADD" LINE 1: ALTER DIRECTORY TABLE dir_table2 ADD CONSTRAINT dirtable_con... - ^ + ^ ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail ERROR: syntax error at or near "CONSTRAINT" LINE 1: ALTER TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_... ^ ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTRAINT test_pkey; -- fail -ERROR: syntax error at or near "DIRECTORY" +ERROR: syntax error at or near "DROP" LINE 1: ALTER DIRECTORY TABLE dir_table1 DROP CONSTRAINT DROP CONSTR... - ^ + ^ -- Test remove_table SELECT remove_file('dir_table1', 'nation5'); -- fail remove_file diff --git a/src/test/regress/output/tag.source b/src/test/regress/output/tag.source new file mode 100644 index 00000000000..9f8eebfcaab --- /dev/null +++ b/src/test/regress/output/tag.source @@ -0,0 +1,1436 @@ +-- Test tag manipulation +\d+ pg_tag; + Table "pg_catalog.pg_tag" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------------+--------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + tagname | name | | not null | | plain | | + tagowner | oid | | not null | | plain | | + allowed_values | text[] | C | | | extended | | +Indexes: + "pg_tag_tagname_index" PRIMARY KEY, btree (tagname), tablespace "pg_global" + "pg_tag_oid_index" UNIQUE CONSTRAINT, btree (oid), tablespace "pg_global" +Tablespace: "pg_global" + +\d+ pg_tag_description; + Table "pg_catalog.pg_tag_description" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +------------+------+-----------+----------+---------+----------+--------------+------------- + oid | oid | | not null | | plain | | + databaseid | oid | | not null | | plain | | + classid | oid | | not null | | plain | | + objid | oid | | not null | | plain | | + tagid | oid | | not null | | plain | | + tagvalue | text | C | | | extended | | +Indexes: + "pg_tag_description_d_c_o_t_index" PRIMARY KEY, btree (databaseid, classid, objid, tagid), tablespace "pg_global" + "pg_tag_description_oid_index" UNIQUE CONSTRAINT, btree (oid), tablespace "pg_global" + "pg_tag_description_tagidvalue_index" btree (tagid, tagvalue), tablespace "pg_global" +Tablespace: "pg_global" + +SELECT * FROM pg_tag; + oid | tagname | tagowner | allowed_values +-----+---------+----------+---------------- +(0 rows) + +SELECT * FROM pg_tag_description; + oid | databaseid | classid | objid | tagid | tagvalue +-----+------------+---------+-------+-------+---------- +(0 rows) + +CREATE DATABASE other_db; +-- Test create tag +CREATE TAG tag1; +CREATE TAG IF NOT EXISTS tag1; +NOTICE: tag "tag1" already exists, skipping +CREATE TAG IF NOT EXISTS tag2; +CREATE TAG tag2; -- error +ERROR: tag "tag2" already exists +CREATE TAG tag3 ALLOWED_VALUES '123'; +CREATE TAG tag3; -- error +ERROR: tag "tag3" already exists +CREATE TAG tag4 ALLOWED_VALUES '123', '456', ' '; +CREATE TAG IF NOT EXISTS tag5 ALLOWED_VALUES '123', 'val1'; +CREATE TAG tag6 ALLOWED_VALUES 'nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqwef' +'fjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwef' +'qifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdas' +'iqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho'; -- error +ERROR: added allowed value "nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqweffjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwefqifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdasiqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho" has exceeded max 256 length +CREATE TAG tag7 ALLOWED_VALUES 'val1', '123', 'val1'; -- error +ERROR: allowed value "val1" has been added +CREATE TAG tag8 ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +CREATE TAG tag9 ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300', '301'; +ERROR: Allowed_values only allow 300 values. +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | {123} + tag4 | 10 | {123,456," "} + tag5 | 10 | {123,val1} + tag8 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} +(6 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | {123} + tag4 | 10 | {123,456," "} + tag5 | 10 | {123,val1} + tag8 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} +(6 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c postgres +-- Test Drop tag +DROP TAG tag5; +DROP TAG IF EXISTS tag5; +NOTICE: tag "tag5" does not exist, skipping +DROP TAG IF EXISTS tag8; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | {123} + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | {123} + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c postgres +-- Test Alter tag +-- Rename +ALTER TAG tag3 RENAME TO tag3_new; +ALTER TAG IF EXISTS tag4 RENAME TO tag4_new; +ALTER TAG tag3_new RENAME TO tag3; +ALTER TAG tag4_new RENAME TO tag4; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | {123} + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | {123} + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c postgres +-- OWNER TO +CREATE USER tag_user; +NOTICE: resource queue required -- using default resource queue "pg_default" +ALTER TAG tag1 OWNER TO tag_user; +SELECT tagname, rolname AS tagowner, allowed_values FROM pg_tag, pg_authid +WHERE pg_tag.tagowner = pg_authid.oid +ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | tag_user | + tag2 | gpadmin | + tag3 | gpadmin | {123} + tag4 | gpadmin | {123,456," "} +(4 rows) + +ALTER TAG tag1 OWNER TO gpadmin; +SELECT tagname, rolname AS tagowner, allowed_values FROM pg_tag, pg_authid +WHERE pg_tag.tagowner = pg_authid.oid +ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | gpadmin | + tag2 | gpadmin | + tag3 | gpadmin | {123} + tag4 | gpadmin | {123,456," "} +(4 rows) + +\c other_db +SELECT tagname, rolname AS tagowner, allowed_values FROM pg_tag, pg_authid +WHERE pg_tag.tagowner = pg_authid.oid +ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | gpadmin | + tag2 | gpadmin | + tag3 | gpadmin | {123} + tag4 | gpadmin | {123,456," "} +(4 rows) + +\c postgres +-- Unset allowed_values +ALTER TAG tag1 UNSET ALLOWED_VALUES; +ALTER TAG tag2 UNSET ALLOWED_VALUES; +ALTER TAG tag3 UNSET ALLOWED_VALUES; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+---------------- + tag1 | 10 | + tag2 | 10 | + tag3 | 10 | + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c postgres +-- ADD allowed_values +ALTER TAG tag1 ADD ALLOWED_VALUES 'val1'; +ALTER TAG tag1 ADD ALLOWED_VALUES 'val1'; -- error +ERROR: allowed value "val1" has been added +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES 'val1'; -- error +ERROR: allowed value "val1" has been added +ALTER TAG tag1 ADD ALLOWED_VALUES 'val2', 'val2'; -- error +ERROR: allowed value "val2" has been added +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES 'val2', 'val2'; -- error +ERROR: allowed value "val2" has been added +ALTER TAG tag1 ADD ALLOWED_VALUES 'val2', 'val3'; +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES 'val4', 'val5'; +ALTER TAG tag1 ADD ALLOWED_VALUES '', ''; -- error +ERROR: allowed value "" has been added +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES '', ''; --error +ERROR: allowed value "" has been added +ALTER TAG tag1 ADD ALLOWED_VALUES ' ', ' '; -- error +ERROR: allowed value " " has been added +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES ' '; +ALTER TAG tag1 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ERROR: Allowed_values only allow 300 values. +ALTER TAG IF EXISTS tag1 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ERROR: Allowed_values only allow 300 values. +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+-------------------------------- + tag1 | 10 | {val1,val2,val3,val4,val5," "} + tag2 | 10 | + tag3 | 10 | + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+-------------------------------- + tag1 | 10 | {val1,val2,val3,val4,val5," "} + tag2 | 10 | + tag3 | 10 | + tag4 | 10 | {123,456," "} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c postgres +ALTER TAG tag2 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ALTER TAG IF EXISTS tag2 ADD ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ERROR: allowed value "1" has been added +ALTER TAG tag3 ADD ALLOWED_VALUES 'nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqwef' +'fjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwef' +'qifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdas' +'iqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho'; -- error +ERROR: added allowed value "nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqweffjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwefqifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdasiqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho" has exceeded max 256 length +ALTER TAG IF EXISTS tag3 ADD ALLOWED_VALUES 'nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqwef' +'fjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwef' +'qifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdas' +'iqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho'; -- error +ERROR: added allowed value "nqwenfqpjenpjqnpufnqwpiuenfuiasqwefqfsafqwefnfiunl;jfa;lskdfjqpwefjqpewe234dfqweffjhsudfiueqihfsakdljfqeqfhqoufhoaisuehfqoiuwehfqoifhqoiuwehfoqihfosfqwfeqwfqwefqwefqwfefqefqfqewfqwefweqfsdfqwefqifquhowifhoiuqhfuosdfqjfqkepfqjfpishdfuiqh2139u108wefoiuqwhefoiuqwehfoiuqwhfoiuweqfheiasuohfioquwehfqwoeiufhdasiqeqwejfpqwifjipqwfjqwiefjpiqwehfpiquwehfqwiufhqwpiuefhqwui0fhpiiohfoqiuwehfoquwefoiweqfewoqifqwoiufhho" has exceeded max 256 length +ALTER TAG tag3 ADD ALLOWED_VALUES 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'; +ALTER TAG tag4 ADD ALLOWED_VALUES ' '; -- error +ERROR: allowed value " " has been added +ALTER TAG IF EXISTS tag4 ADD ALLOWED_VALUES ' '; -- error +ERROR: allowed value " " has been added +ALTER TAG tag4 ADD ALLOWED_VALUES ''; +ALTER TAG tag4 ADD ALLOWED_VALUES ''; -- error +ERROR: allowed value "" has been added +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3,val4,val5," "} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3,val4,val5," "} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c postgres +-- DROP allowed_values +ALTER TAG tag1 DROP ALLOWED_VALUES 'unknown'; -- error; +ERROR: allowed value "unknown" not found +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES 'unknown'; -- error; +ERROR: allowed value "unknown" not found +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', -- error + '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', + '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', + '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', + '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', + '97', '98', '99', '100', '101', '102', '103', '104', '105', '106', '107', '108', '109', '110', '111', '112', '113', '114', '115', '116', +'117', '118', '119', '120', '121', '122', '123', '124', '125', '126', '127', '128', '129', '130', '131', '132', '133', '134', '135', '136', +'137', '138', '139', '140', '141', '142', '143', '144', '145', '146', '147', '148', '149', '150', '151', '152', '153', '154', '155', '156', +'157', '158', '159', '160', '161', '162', '163', '164', '165', '166', '167', '168', '169', '170', '171', '172', '173', '174', '175', '176', +'177', '178', '179', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189', '190', '191', '192', '193', '194', '195', '196', +'197', '198', '199', '200', '201', '202', '203', '204', '205', '206', '207', '208', '209', '210', '211', '212', '213', '214', '215', '216', +'217', '218', '219', '220', '221', '222', '223', '224', '225', '226', '227', '228', '229', '230', '231', '232', '233', '234', '235', '236', +'237', '238', '239', '240', '241', '242', '243', '244', '245', '246', '247', '248', '249', '250', '251', '252', '253', '254', '255', '256', +'257', '258', '259', '260', '261', '262', '263', '264', '265', '266', '267', '268', '269', '270', '271', '272', '273', '274', '275', '276', +'277', '278', '279', '280', '281', '282', '283', '284', '285', '286', '287', '288', '289', '290', '291', '292', '293', '294', '295', '296', +'297', '298', '299', '300'; +ERROR: allowed value "1" not found +ALTER TAG tag1 DROP ALLOWED_VALUES '1'; -- error +ERROR: allowed value "1" not found +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES '1'; -- error +ERROR: allowed value "1" not found +ALTER TAG tag1 DROP ALLOWED_VALUES ''; -- error +ERROR: allowed value "" not found +ALTER TAG IF EXISTS tag1 DROP ALLOWED_VALUES ''; -- error +ERROR: allowed value "" not found +ALTER TAG tag1 UNSET ALLOWED_VALUES; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +ALTER TAG tag1 ADD ALLOWED_VALUES 'val1', 'val2', 'val3'; +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c other_db +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +SELECT count(*) FROM pg_tag_description; + count +------- + 0 +(1 row) + +\c postgres +-- Cleanup +DROP USER tag_user; +-- Test database with tag +-- Create database +CREATE DATABASE tag_db1 TAG (tag1 = 'novalue'); -- error +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE DATABASE tag_db1 TAG (tag1 = 'val1'); +CREATE DATABASE tag_db2 TAG; -- error +ERROR: syntax error at or near ";" +LINE 1: CREATE DATABASE tag_db2 TAG; + ^ +CREATE DATABASE tag_db2 TAG (); -- error +ERROR: syntax error at or near ")" +LINE 1: CREATE DATABASE tag_db2 TAG (); + ^ +CREATE DATABASE tag_db2 TAG (tag1 = ''); -- error +ERROR: tag value "" is not in tag "tag1" allowed values +CREATE DATABASE tag_db2 TAG (tag1 = 'val1', tag2 = '10'); +CREATE DATABASE tag_db3 TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +ERROR: tag "tag1" value has been added for object "tag_db3". +CREATE DATABASE tag_db3 TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE DATABASE tag_db3 TAG (tag1 = 'val1', tag2 = '1'); +CREATE DATABASE tag_db4 TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +CREATE DATABASE tag_db5 TAG (tag2 = '300', tag4 = ' '); +CREATE DATABASE tag_db6 TAG (tag4 = '', tag4 = ' '); -- error +ERROR: tag "tag4" value has been added for object "tag_db6". +CREATE DATABASE tag_db6 TAG (tag4 = '', tag4 = ''); -- error +ERROR: tag "tag4" value has been added for object "tag_db6". +CREATE DATABASE tag_db6 TAG (tag4 = ' ', tag4 = ' '); -- error +ERROR: tag "tag4" value has been added for object "tag_db6". +CREATE DATABASE tag_db6 TAG (tag4 = ''); +CREATE DATABASE tag_db7 TAG (tag4 = ' '); +CREATE DATABASE tag_db8 TAG (tag3 = ''); -- error +ERROR: tag value "" is not in tag "tag3" allowed values +CREATE DATABASE tag_db8 WITH TEMPLATE = template0 ENCODING='UTF-8' LC_COLLATE='C' LC_CTYPE='C' TAG (tag1 = 'novalue'); -- error +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE DATABASE tag_db8 WITH TEMPLATE = template0 ENCODING='UTF-8' LC_COLLATE='C' LC_CTYPE='C' TAG (tag1 = 'val1'); +CREATE DATABASE tag_db9 WITH TEMPLATE = template0 ENCODING='UTF-8' LC_COLLATE='C' LC_CTYPE='C'; +CREATE DATABASE tag_db10 WITH TEMPLATE = template0 TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); +SELECT * FROM database_tag_descriptions +ORDER BY 1, 2, 3, 4; + databaseid | datname | tagname | tagvalue +------------+----------+---------+----------------------------------------------------------------------------------- + 0 | tag_db1 | tag1 | val1 + 0 | tag_db10 | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + 0 | tag_db2 | tag1 | val1 + 0 | tag_db2 | tag2 | 10 + 0 | tag_db3 | tag1 | val1 + 0 | tag_db3 | tag2 | 1 + 0 | tag_db4 | tag1 | val1 + 0 | tag_db4 | tag2 | 3 + 0 | tag_db4 | tag4 | + 0 | tag_db5 | tag2 | 300 + 0 | tag_db5 | tag4 | + 0 | tag_db6 | tag4 | + 0 | tag_db7 | tag4 | + 0 | tag_db8 | tag1 | val1 +(14 rows) + +SELECT datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit +FROM pg_database ORDER BY 1; + datname | datdba | encoding | datcollate | datctype | datistemplate | datallowconn | datconnlimit +------------+--------+----------+------------+------------+---------------+--------------+-------------- + other_db | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + postgres | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | t | -1 + regression | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db1 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db10 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db2 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db3 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db4 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db5 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db6 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db7 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db8 | 10 | 6 | C | C | f | t | -1 + tag_db9 | 10 | 6 | C | C | f | t | -1 + template0 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | f | -1 + template1 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | t | -1 +(15 rows) + +DROP TAG tag1; -- error +ERROR: tag "tag1" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +DROP TAG tag2; -- error +ERROR: tag "tag2" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag2 +tag of tag description with tag tag2 +tag of tag description with tag tag2 +tag of tag description with tag tag2 +DROP TAG tag3; -- error +ERROR: tag "tag3" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag3 +DROP TAG tag4; -- error +ERROR: tag "tag4" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +-- Alter Database +ALTER DATABASE tag_db1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER DATABASE tag_db2 TAG (tag2 = '10'); +ALTER DATABASE tag_db3 TAG (tag3 = ''); -- error +ERROR: tag value "" is not in tag "tag3" allowed values +ALTER DATABASE tag_db4 UNSET TAG (tag1, tag2); +ALTER DATABASE tag_db4 TAG (tag1 = 'val3', tag4 = ''); +ALTER DATABASE tag_db5 TAG (tag4 = '', tag4 = ' '); +ALTER DATABASE tag_db6 TAG (tag4 = ' '); +ALTER DATABASE tag_db7 TAG (tag1 = 'val2', tag2 = '3'); +WARNING: object "tag_db7" does not have tag "tag1", creating +WARNING: object "tag_db7" does not have tag "tag2", creating +ALTER DATABASE tag_db7 UNSET TAG (tag1); +ALTER DATABASE tag_db8 TAG (tag4 = '123', tag4 = '123'); +WARNING: object "tag_db8" does not have tag "tag4", creating +ALTER DATABASE tag_db9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +WARNING: object "tag_db9" does not have tag "tag4", creating +ALTER DATABASE tag_db9 TAG (tag4 = '123'); +SELECT * FROM database_tag_descriptions +ORDER BY 1, 2, 3, 4; + databaseid | datname | tagname | tagvalue +------------+----------+---------+----------------------------------------------------------------------------------- + 0 | tag_db1 | tag1 | val1 + 0 | tag_db10 | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + 0 | tag_db2 | tag1 | val1 + 0 | tag_db2 | tag2 | 10 + 0 | tag_db3 | tag1 | val1 + 0 | tag_db3 | tag2 | 1 + 0 | tag_db4 | tag1 | val3 + 0 | tag_db4 | tag2 | + 0 | tag_db4 | tag4 | + 0 | tag_db5 | tag2 | 300 + 0 | tag_db5 | tag4 | + 0 | tag_db6 | tag4 | + 0 | tag_db7 | tag1 | + 0 | tag_db7 | tag2 | 3 + 0 | tag_db7 | tag4 | + 0 | tag_db8 | tag1 | val1 + 0 | tag_db8 | tag4 | 123 + 0 | tag_db9 | tag4 | 123 +(18 rows) + +SELECT datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit +FROM pg_database ORDER BY 1; + datname | datdba | encoding | datcollate | datctype | datistemplate | datallowconn | datconnlimit +------------+--------+----------+------------+------------+---------------+--------------+-------------- + other_db | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + postgres | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | t | -1 + regression | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db1 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db10 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db2 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db3 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db4 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db5 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db6 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db7 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + tag_db8 | 10 | 6 | C | C | f | t | -1 + tag_db9 | 10 | 6 | C | C | f | t | -1 + template0 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | f | -1 + template1 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | t | -1 +(15 rows) + +-- Drop Database +DROP DATABASE tag_db1; +DROP DATABASE tag_db2; +DROP DATABASE tag_db3; +DROP DATABASE tag_db4; +DROP DATABASE tag_db5; +DROP DATABASE tag_db6; +DROP DATABASE tag_db7; +DROP DATABASE tag_db8; +DROP DATABASE tag_db9; +DROP DATABASE tag_db10; +SELECT * FROM database_tag_descriptions +ORDER BY 1, 2, 3, 4; + databaseid | datname | tagname | tagvalue +------------+---------+---------+---------- +(0 rows) + +SELECT datname, datdba, encoding, datcollate, datctype, datistemplate, datallowconn, datconnlimit +FROM pg_database ORDER BY 1; + datname | datdba | encoding | datcollate | datctype | datistemplate | datallowconn | datconnlimit +------------+--------+----------+------------+------------+---------------+--------------+-------------- + other_db | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + postgres | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | t | -1 + regression | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | f | t | -1 + template0 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | f | -1 + template1 | 10 | 6 | zh_CN.utf8 | zh_CN.utf8 | t | t | -1 +(5 rows) + +-- Test user with tag +-- Create User +CREATE USER tag_user1 TAG (tag1 = 'novalue'); -- error +NOTICE: resource queue required -- using default resource queue "pg_default" +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE USER tag_user1 TAG (tag1 = 'val1'); +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER tag_user2 TAG; -- error +ERROR: syntax error at or near ";" +LINE 1: CREATE USER tag_user2 TAG; + ^ +CREATE USER tag_user2 TAG (); -- error +ERROR: syntax error at or near ")" +LINE 1: CREATE USER tag_user2 TAG (); + ^ +CREATE USER tag_user2 TAG (tag1 = ''); -- error +NOTICE: resource queue required -- using default resource queue "pg_default" +ERROR: tag value "" is not in tag "tag1" allowed values +CREATE USER tag_user2 TAG (tag1 = 'val1', tag2 = '10'); +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER tag_user3 TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +NOTICE: resource queue required -- using default resource queue "pg_default" +ERROR: tag "tag1" value has been added for object "tag_user3". +CREATE USER tag_user3 TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +NOTICE: resource queue required -- using default resource queue "pg_default" +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE USER tag_user3 TAG (tag1 = 'val1', tag2 = '1'); +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER tag_user4 TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER tag_user5 TAG (tag2 = '300', tag4 = ' '); +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER tag_user6 TAG (tag4 = '', tag4 = ''); -- error +NOTICE: resource queue required -- using default resource queue "pg_default" +ERROR: tag "tag4" value has been added for object "tag_user6". +CREATE USER tag_user6 TAG (tag4 = ' ', tag4 = ' '); -- error +NOTICE: resource queue required -- using default resource queue "pg_default" +ERROR: tag "tag4" value has been added for object "tag_user6". +CREATE USER tag_user6 TAG (tag4 = ''); +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER tag_user7 CONNECTION LIMIT 10 TAG (tag4 = ' '); +NOTICE: resource queue required -- using default resource queue "pg_default" +CREATE USER tag_user8 TAG (tag3 = ''); -- error +NOTICE: resource queue required -- using default resource queue "pg_default" +ERROR: tag value "" is not in tag "tag3" allowed values +CREATE USER tag_user8 superuser TAG (tag1 = 'novalue'); -- error +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE USER tag_user8 superuser TAG (tag1 = 'val1'); +CREATE USER tag_user9 superuser; +CREATE USER tag_user10 superuser TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); +SELECT * FROM user_tag_descriptions +WHERE rolname like '%tag_user%' +ORDER BY 1, 2, 3, 4; + databaseid | rolname | tagname | tagvalue +------------+------------+---------+----------------------------------------------------------------------------------- + 0 | tag_user1 | tag1 | val1 + 0 | tag_user10 | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + 0 | tag_user2 | tag1 | val1 + 0 | tag_user2 | tag2 | 10 + 0 | tag_user3 | tag1 | val1 + 0 | tag_user3 | tag2 | 1 + 0 | tag_user4 | tag1 | val1 + 0 | tag_user4 | tag2 | 3 + 0 | tag_user4 | tag4 | + 0 | tag_user5 | tag2 | 300 + 0 | tag_user5 | tag4 | + 0 | tag_user6 | tag4 | + 0 | tag_user7 | tag4 | + 0 | tag_user8 | tag1 | val1 +(14 rows) + +SELECT rolname, rolsuper, rolconnlimit FROM pg_authid +WHERE rolname like '%tag_user%' +ORDER BY 1; + rolname | rolsuper | rolconnlimit +------------+----------+-------------- + tag_user1 | f | -1 + tag_user10 | t | -1 + tag_user2 | f | -1 + tag_user3 | f | -1 + tag_user4 | f | -1 + tag_user5 | f | -1 + tag_user6 | f | -1 + tag_user7 | f | 10 + tag_user8 | t | -1 + tag_user9 | t | -1 +(10 rows) + +DROP TAG tag1; -- error +ERROR: tag "tag1" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +DROP TAG tag2; -- error +ERROR: tag "tag2" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag2 +tag of tag description with tag tag2 +tag of tag description with tag tag2 +tag of tag description with tag tag2 +DROP TAG tag3; -- error +ERROR: tag "tag3" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag3 +DROP TAG tag4; -- error +ERROR: tag "tag4" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +-- Alter User +ALTER USER tag_user1 CONNECTION LIMIT 3 TAG (tag1 = 'val1', tag1 = 'val1'); -- error +ERROR: syntax error at or near "TAG" +LINE 1: ALTER USER tag_user1 CONNECTION LIMIT 3 TAG (tag1 = 'val1', ... + ^ +ALTER USER tag_user1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER USER tag_user2 TAG (tag2 = '10'); +ALTER USER tag_user3 TAG (tag3 = ''); -- error +ERROR: tag value "" is not in tag "tag3" allowed values +ALTER USER tag_user4 UNSET TAG (tag1, tag2); +ALTER USER tag_user4 TAG (tag1 = 'val3', tag4 = ''); +ALTER USER tag_user5 TAG (tag4 = '', tag4 = ' '); +ALTER USER tag_user6 TAG (tag4 = ' '); +ALTER USER tag_user7 TAG (tag1 = 'val2', tag2 = '3'); +WARNING: object "tag_user7" does not have tag "tag1", creating +WARNING: object "tag_user7" does not have tag "tag2", creating +ALTER USER tag_user7 UNSET TAG (tag1); +ALTER USER tag_user8 TAG (tag4 = '123', tag4 = '123'); +WARNING: object "tag_user8" does not have tag "tag4", creating +ALTER USER tag_user9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +WARNING: object "tag_user9" does not have tag "tag4", creating +ALTER USER tag_user9 TAG (tag4 = '123'); +SELECT * FROM user_tag_descriptions +WHERE rolname like '%tag_user%' +ORDER BY 1, 2, 3, 4; + databaseid | rolname | tagname | tagvalue +------------+------------+---------+----------------------------------------------------------------------------------- + 0 | tag_user1 | tag1 | val1 + 0 | tag_user10 | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + 0 | tag_user2 | tag1 | val1 + 0 | tag_user2 | tag2 | 10 + 0 | tag_user3 | tag1 | val1 + 0 | tag_user3 | tag2 | 1 + 0 | tag_user4 | tag1 | val3 + 0 | tag_user4 | tag2 | + 0 | tag_user4 | tag4 | + 0 | tag_user5 | tag2 | 300 + 0 | tag_user5 | tag4 | + 0 | tag_user6 | tag4 | + 0 | tag_user7 | tag1 | + 0 | tag_user7 | tag2 | 3 + 0 | tag_user7 | tag4 | + 0 | tag_user8 | tag1 | val1 + 0 | tag_user8 | tag4 | 123 + 0 | tag_user9 | tag4 | 123 +(18 rows) + +SELECT rolname, rolsuper, rolconnlimit FROM pg_authid +WHERE rolname like '%tag_user%' +ORDER BY 1; + rolname | rolsuper | rolconnlimit +------------+----------+-------------- + tag_user1 | f | -1 + tag_user10 | t | -1 + tag_user2 | f | -1 + tag_user3 | f | -1 + tag_user4 | f | -1 + tag_user5 | f | -1 + tag_user6 | f | -1 + tag_user7 | f | 10 + tag_user8 | t | -1 + tag_user9 | t | -1 +(10 rows) + +-- Drop User +DROP USER tag_user1; +DROP USER tag_user2; +DROP USER tag_user3; +DROP USER tag_user4; +DROP USER tag_user5; +DROP USER tag_user6; +DROP USER tag_user7; +DROP USER tag_user8; +DROP USER tag_user9; +DROP USER tag_user10; +SELECT * FROM user_tag_descriptions +WHERE rolname like '%tag_user%' +ORDER BY 1, 2, 3, 4; + databaseid | rolname | tagname | tagvalue +------------+---------+---------+---------- +(0 rows) + +SELECT rolname, rolsuper, rolconnlimit FROM pg_authid +WHERE rolname like '%tag_user%' +ORDER BY 1; + rolname | rolsuper | rolconnlimit +---------+----------+-------------- +(0 rows) + +-- Test tablespace with tag +-- Create tablespace +CREATE TABLESPACE tag_tablespace LOCATION '@testtablespace@' WITH (random_page_cost = 3.0) TAG (tag1 = 'test'); -- error +ERROR: tag value "test" is not in tag "tag1" allowed values +CREATE TABLESPACE tag_tablespace LOCATION '@testtablespace@' WITH (random_page_cost = 3.0) TAG (tag1 = 'val1', tag2 = '301'); -- error +ERROR: tag value "301" is not in tag "tag2" allowed values +CREATE TABLESPACE tag_tablespace LOCATION '@testtablespace@' WITH (random_page_cost = 3.0) TAG (tag1 = 'val1', tag2 = '2'); +SELECT * FROM tablespace_tag_descriptions +ORDER BY 1, 2, 3, 4; + databaseid | spcname | tagname | tagvalue +------------+----------------+---------+---------- + 0 | tag_tablespace | tag1 | val1 + 0 | tag_tablespace | tag2 | 2 +(2 rows) + +SELECT spcname FROM pg_tablespace +ORDER BY 1; + spcname +---------------- + pg_default + pg_global + tag_tablespace +(3 rows) + +-- Alter tablespace +ALTER TABLESPACE tag_tablespace SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag2 = '10'); -- error +ERROR: syntax error at or near "TAG" +LINE 1: ...SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag2 ... + ^ +ALTER TABLESPACE tag_tablespace SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag3 = ''); -- error +ERROR: syntax error at or near "TAG" +LINE 1: ...SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag3 ... + ^ +ALTER TABLESPACE tag_tablespace SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag4 = '', tag1 = 'val1'); -- error +ERROR: syntax error at or near "TAG" +LINE 1: ...SET (random_page_cost = 1.0, seq_page_cost = 1.1) TAG (tag4 ... + ^ +ALTER TABLESPACE tag_tablespace TAG (tag4 = '', tag1 = 'val1'); +WARNING: object "tag_tablespace" does not have tag "tag4", creating +ALTER TABLESPACE tag_tablespace UNSET TAG (tag1, tag2); +ALTER TABLESPACE tag_tablespace UNSET TAG (tag2); +ALTER TABLESPACE tag_tablespace TAG (tag1 = 'val2', tag1 = 'val3'); +SELECT * FROM tablespace_tag_descriptions +ORDER BY 1, 2, 3, 4; + databaseid | spcname | tagname | tagvalue +------------+----------------+---------+---------- + 0 | tag_tablespace | tag1 | val3 + 0 | tag_tablespace | tag2 | + 0 | tag_tablespace | tag4 | +(3 rows) + +SELECT spcname FROM pg_tablespace +ORDER BY 1; + spcname +---------------- + pg_default + pg_global + tag_tablespace +(3 rows) + +DROP TAG tag1; -- error +ERROR: tag "tag1" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag1 +DROP TAG tag2; -- error +ERROR: tag "tag2" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag2 +DROP TAG tag4; -- error +ERROR: tag "tag4" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag4 +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +-- Drop tablespace +DROP TABLESPACE tag_tablespace; +SELECT * FROM tablespace_tag_descriptions +ORDER BY 1, 2, 3, 4; + databaseid | spcname | tagname | tagvalue +------------+---------+---------+---------- +(0 rows) + +SELECT spcname FROM pg_tablespace +ORDER BY 1; + spcname +------------ + pg_default + pg_global +(2 rows) + +-- Test Schema with Tag +-- Create Schema +CREATE SCHEMA tag_schema1 TAG (tag1 = 'val1'); -- error +ERROR: syntax error at or near "TAG" +LINE 1: CREATE SCHEMA tag_schema1 TAG (tag1 = 'val1'); + ^ +CREATE SCHEMA tag_schema1 WITH TAG (tag1 = 'novalue'); -- error +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE SCHEMA tag_schema1 WITH TAG (tag1 = 'val1'); +CREATE SCHEMA tag_schema2 WITH TAG; -- error +ERROR: syntax error at or near ";" +LINE 1: CREATE SCHEMA tag_schema2 WITH TAG; + ^ +CREATE SCHEMA tag_schema2 WITH TAG (); -- error +ERROR: syntax error at or near ")" +LINE 1: CREATE SCHEMA tag_schema2 WITH TAG (); + ^ +CREATE SCHEMA tag_schema2 WITH TAG (tag1 = ''); -- error +ERROR: tag value "" is not in tag "tag1" allowed values +CREATE SCHEMA tag_schema2 WITH TAG (tag1 = 'val1', tag2 = '10'); +CREATE SCHEMA tag_schema3 WITH TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +ERROR: tag "tag1" value has been added for object "tag_schema3". +CREATE SCHEMA tag_schema3 WITH TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE SCHEMA tag_schema3 WITH TAG (tag1 = 'val1', tag2 = '1'); +CREATE SCHEMA tag_schema4 WITH TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +CREATE SCHEMA tag_schema5 WITH TAG (tag2 = '300', tag4 = ' '); +CREATE SCHEMA tag_schema6 WITH TAG (tag4 = '', tag4 = ''); -- error +ERROR: tag "tag4" value has been added for object "tag_schema6". +CREATE SCHEMA tag_schema6 WITH TAG (tag4 = ' ', tag4 = ' '); -- error +ERROR: tag "tag4" value has been added for object "tag_schema6". +CREATE SCHEMA tag_schema6 WITH TAG (tag4 = ''); +CREATE SCHEMA tag_schema7 WITH TAG (tag4 = ' '); +CREATE SCHEMA tag_schema8 WITH TAG (tag3 = ''); -- error +ERROR: tag value "" is not in tag "tag3" allowed values +CREATE SCHEMA tag_schema8 WITH TAG (tag1 = 'novalue'); -- error +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE SCHEMA tag_schema8 WITH TAG (tag1 = 'val1'); +CREATE SCHEMA tag_schema9; +CREATE SCHEMA tag_schema10 WITH TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); +SELECT * FROM schema_tag_descriptions +WHERE nspname like '%tag_schema%' +ORDER BY 1, 2, 3, 4; + datname | nspname | tagname | tagvalue +----------+--------------+---------+----------------------------------------------------------------------------------- + postgres | tag_schema1 | tag1 | val1 + postgres | tag_schema10 | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + postgres | tag_schema2 | tag1 | val1 + postgres | tag_schema2 | tag2 | 10 + postgres | tag_schema3 | tag1 | val1 + postgres | tag_schema3 | tag2 | 1 + postgres | tag_schema4 | tag1 | val1 + postgres | tag_schema4 | tag2 | 3 + postgres | tag_schema4 | tag4 | + postgres | tag_schema5 | tag2 | 300 + postgres | tag_schema5 | tag4 | + postgres | tag_schema6 | tag4 | + postgres | tag_schema7 | tag4 | + postgres | tag_schema8 | tag1 | val1 +(14 rows) + +SELECT nspname, nspowner FROM pg_namespace +WHERE nspname like '%tag_schema%' +ORDER BY 1; + nspname | nspowner +--------------+---------- + tag_schema1 | 10 + tag_schema10 | 10 + tag_schema2 | 10 + tag_schema3 | 10 + tag_schema4 | 10 + tag_schema5 | 10 + tag_schema6 | 10 + tag_schema7 | 10 + tag_schema8 | 10 + tag_schema9 | 10 +(10 rows) + +DROP TAG tag1; -- error +ERROR: tag "tag1" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +tag of tag description with tag tag1 +DROP TAG tag2; -- error +ERROR: tag "tag2" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag2 +tag of tag description with tag tag2 +tag of tag description with tag tag2 +tag of tag description with tag tag2 +DROP TAG tag3; -- error +ERROR: tag "tag3" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag3 +DROP TAG tag4; -- error +ERROR: tag "tag4" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +-- Alter Schema +ALTER SCHEMA tag_schema1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER SCHEMA tag_schema2 TAG (tag2 = '10'); +ALTER SCHEMA tag_schema3 TAG (tag3 = ''); -- error +ERROR: tag value "" is not in tag "tag3" allowed values +ALTER SCHEMA tag_schema4 UNSET TAG (tag1, tag2); +ALTER SCHEMA tag_schema4 TAG (tag1 = 'val3', tag4 = ''); +ALTER SCHEMA tag_schema5 TAG (tag4 = '', tag4 = ' '); +ALTER SCHEMA tag_schema6 TAG (tag4 = ' '); +ALTER SCHEMA tag_schema7 TAG (tag1 = 'val2', tag2 = '3'); +WARNING: object "tag_schema7" does not have tag "tag1", creating +WARNING: object "tag_schema7" does not have tag "tag2", creating +ALTER SCHEMA tag_schema7 UNSET TAG (tag1); +ALTER SCHEMA tag_schema8 TAG (tag4 = '123', tag4 = '123'); +WARNING: object "tag_schema8" does not have tag "tag4", creating +ALTER SCHEMA tag_schema9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +WARNING: object "tag_schema9" does not have tag "tag4", creating +ALTER SCHEMA tag_schema9 TAG (tag4 = '123'); +SELECT * FROM schema_tag_descriptions +WHERE nspname like '%tag_schema%' +ORDER BY 1, 2, 3, 4; + datname | nspname | tagname | tagvalue +----------+--------------+---------+----------------------------------------------------------------------------------- + postgres | tag_schema1 | tag1 | val1 + postgres | tag_schema10 | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + postgres | tag_schema2 | tag1 | val1 + postgres | tag_schema2 | tag2 | 10 + postgres | tag_schema3 | tag1 | val1 + postgres | tag_schema3 | tag2 | 1 + postgres | tag_schema4 | tag1 | val3 + postgres | tag_schema4 | tag2 | + postgres | tag_schema4 | tag4 | + postgres | tag_schema5 | tag2 | 300 + postgres | tag_schema5 | tag4 | + postgres | tag_schema6 | tag4 | + postgres | tag_schema7 | tag1 | + postgres | tag_schema7 | tag2 | 3 + postgres | tag_schema7 | tag4 | + postgres | tag_schema8 | tag1 | val1 + postgres | tag_schema8 | tag4 | 123 + postgres | tag_schema9 | tag4 | 123 +(18 rows) + +SELECT nspname, nspowner FROM pg_namespace +WHERE nspname like '%tag_schema%' +ORDER BY 1; + nspname | nspowner +--------------+---------- + tag_schema1 | 10 + tag_schema10 | 10 + tag_schema2 | 10 + tag_schema3 | 10 + tag_schema4 | 10 + tag_schema5 | 10 + tag_schema6 | 10 + tag_schema7 | 10 + tag_schema8 | 10 + tag_schema9 | 10 +(10 rows) + +-- Drop Schema +DROP SCHEMA tag_schema1; +DROP SCHEMA tag_schema2; +DROP SCHEMA tag_schema3; +DROP SCHEMA tag_schema4; +DROP SCHEMA tag_schema5; +DROP SCHEMA tag_schema6; +DROP SCHEMA tag_schema7; +DROP SCHEMA tag_schema8; +DROP SCHEMA tag_schema9; +DROP SCHEMA tag_schema10; +SELECT * FROM schema_tag_descriptions +WHERE nspname like '%tag_schema%' +ORDER BY 1, 2, 3, 4; + datname | nspname | tagname | tagvalue +---------+---------+---------+---------- +(0 rows) + +SELECT nspname, nspowner FROM pg_namespace +WHERE nspname like '%tag_schema%' +ORDER BY 1; + nspname | nspowner +---------+---------- +(0 rows) + +-- Test Table with Tag +-- Create Table +CREATE TABLE tag_table1(a int, b varchar) TAG (tag1 = 'novalue'); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE TEMP TABLE tag_table1(a int, b varchar) TAG (tag1 = 'val1'); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TEMP TABLE tag_table2(a int, b varchar) TAG; -- error +ERROR: syntax error at or near ";" +LINE 1: CREATE TEMP TABLE tag_table2(a int, b varchar) TAG; + ^ +CREATE TEMP TABLE tag_table2(a int, b varchar) TAG (); -- error +ERROR: syntax error at or near ")" +LINE 1: CREATE TEMP TABLE tag_table2(a int, b varchar) TAG (); + ^ +CREATE TABLE tag_table2(a int, b varchar) TAG (tag1 = ''); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag value "" is not in tag "tag1" allowed values +CREATE TEMP TABLE tag_table2(a int, b varchar) TAG (tag1 = 'val1', tag2 = '10'); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table3(a int, b varchar) TAG (tag1 = 'val1', tag1 = 'val2', tag1 = 'val1'); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag "tag1" value has been added for object "tag_table3". +CREATE TABLE tag_table3(a int, b varchar) TAG (tag1 = 'val1', tag1 = 'novalue'); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE TEMP TABLE tag_table3(a int, b varchar) TAG (tag1 = 'val1', tag2 = '1'); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table4(a int, b varchar) TAG (tag1 = 'val1', tag2 = '3', tag4 = ''); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table5(a int, b varchar) TAG (tag2 = '300', tag4 = ' '); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table6(a int, b varchar) TAG (tag4 = '', tag4 = ''); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag "tag4" value has been added for object "tag_table6". +CREATE TABLE tag_table6(a int, b varchar) TAG (tag4 = ' ', tag4 = ' '); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag "tag4" value has been added for object "tag_table6". +CREATE TABLE tag_table6(a int, b varchar) TAG (tag4 = ''); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table7(a int, b varchar) TAG (tag4 = ' '); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table8(a int, b varchar) TAG (tag3 = ''); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag value "" is not in tag "tag3" allowed values +CREATE TABLE tag_table8(a int, b varchar) TAG (tag1 = 'novalue'); -- error +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +ERROR: tag value "novalue" is not in tag "tag1" allowed values +CREATE TABLE tag_table8(a int, b varchar) TAG (tag1 = 'val1'); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table9(a int, b varchar); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +CREATE TABLE tag_table10(a int, b varchar) TAG (tag3 = 'dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef'); +NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Cloudberry Database data distribution key for this table. +HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. +SELECT * FROM relation_tag_descriptions +WHERE relname like '%tag_table%' +ORDER BY 1, 2, 3, 4, 5, 6; + datname | relname | relnamespace | relkind | tagname | tagvalue +----------+-------------+--------------+---------+---------+----------------------------------------------------------------------------------- + postgres | tag_table10 | public | r | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + postgres | tag_table4 | public | r | tag1 | val1 + postgres | tag_table4 | public | r | tag2 | 3 + postgres | tag_table4 | public | r | tag4 | + postgres | tag_table5 | public | r | tag2 | 300 + postgres | tag_table5 | public | r | tag4 | + postgres | tag_table6 | public | r | tag4 | + postgres | tag_table7 | public | r | tag4 | + postgres | tag_table8 | public | r | tag1 | val1 +(9 rows) + +SELECT relname, relpersistence FROM pg_class +WHERE relname like '%tag_table%' +ORDER BY 1; + relname | relpersistence +-------------+---------------- + tag_table1 | t + tag_table10 | p + tag_table2 | t + tag_table3 | t + tag_table4 | p + tag_table5 | p + tag_table6 | p + tag_table7 | p + tag_table8 | p + tag_table9 | p +(10 rows) + +DROP TAG tag1; -- error +ERROR: tag "tag1" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag1 +tag of tag description with tag tag1 +DROP TAG tag2; -- error +ERROR: tag "tag2" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag2 +tag of tag description with tag tag2 +DROP TAG tag3; -- error +ERROR: tag "tag3" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag3 +DROP TAG tag4; -- error +ERROR: tag "tag4" cannot be dropped because some objects depend on it +DETAIL: tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +tag of tag description with tag tag4 +SELECT tagname, tagowner, allowed_values FROM pg_tag ORDER BY 1; + tagname | tagowner | allowed_values +---------+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + tag1 | 10 | {val1,val2,val3} + tag2 | 10 | {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300} + tag3 | 10 | {dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef} + tag4 | 10 | {123,456," ",""} +(4 rows) + +-- Alter Table +ALTER TABLE tag_table1 TAG (tag1 = 'val1', tag1 = 'val1'); +ALTER TABLE tag_table2 TAG (tag2 = '10'); +ALTER TABLE tag_table3 TAG (tag3 = ''); +ALTER TABLE tag_table4 UNSET TAG (tag1, tag2); +ALTER TABLE tag_table4 TAG (tag1 = 'val3', tag4 = ''); +ALTER TABLE tag_table5 TAG (tag4 = '', tag4 = ' '); +ALTER TABLE tag_table6 TAG (tag4 = ' '); +ALTER TABLE tag_table7 TAG (tag1 = 'val2', tag2 = '3'); +WARNING: object "tag_table7" does not have tag "tag1", creating +WARNING: object "tag_table7" does not have tag "tag2", creating +ALTER TABLE tag_table7 UNSET TAG (tag1); +ALTER TABLE tag_table8 TAG (tag4 = '123', tag4 = '123'); +WARNING: object "tag_table8" does not have tag "tag4", creating +ALTER TABLE tag_table9 TAG (tag4 = '', tag4 = '123', tag4 = '456'); +WARNING: object "tag_table9" does not have tag "tag4", creating +ALTER TABLE tag_table9 TAG (tag4 = '123'); +SELECT * FROM relation_tag_descriptions +WHERE relname like '%tag_table%' +ORDER BY 1, 2, 3, 4, 5, 6; + datname | relname | relnamespace | relkind | tagname | tagvalue +----------+-------------+--------------+---------+---------+----------------------------------------------------------------------------------- + postgres | tag_table10 | public | r | tag3 | dadkqjefpqfqfqe4l123j9i1snkqenp3412n4jnflqjenfaddpiqepj21304i12;kfnqpqnepfqefqwef + postgres | tag_table4 | public | r | tag1 | val3 + postgres | tag_table4 | public | r | tag2 | + postgres | tag_table4 | public | r | tag4 | + postgres | tag_table5 | public | r | tag2 | 300 + postgres | tag_table5 | public | r | tag4 | + postgres | tag_table6 | public | r | tag4 | + postgres | tag_table7 | public | r | tag1 | + postgres | tag_table7 | public | r | tag2 | 3 + postgres | tag_table7 | public | r | tag4 | + postgres | tag_table8 | public | r | tag1 | val1 + postgres | tag_table8 | public | r | tag4 | 123 + postgres | tag_table9 | public | r | tag4 | 123 +(13 rows) + +SELECT relname, relpersistence FROM pg_class +WHERE relname like '%tag_table%' +ORDER BY 1; + relname | relpersistence +-------------+---------------- + tag_table1 | t + tag_table10 | p + tag_table2 | t + tag_table3 | t + tag_table4 | p + tag_table5 | p + tag_table6 | p + tag_table7 | p + tag_table8 | p + tag_table9 | p +(10 rows) + +-- Drop Table +DROP TABLE tag_table1; +DROP TABLE tag_table2; +DROP TABLE tag_table3; +DROP TABLE tag_table4; +DROP TABLE tag_table5; +DROP TABLE tag_table6; +DROP TABLE tag_table7; +DROP TABLE tag_table8; +DROP TABLE tag_table9; +DROP TABLE tag_table10; +SELECT * FROM relation_tag_descriptions +WHERE relname like '%tag_table%' +ORDER BY 1, 2, 3, 4, 5, 6; + datname | relname | relnamespace | relkind | tagname | tagvalue +---------+---------+--------------+---------+---------+---------- +(0 rows) + +SELECT relname, relpersistence FROM pg_class +WHERE relname like '%tag_table%' +ORDER BY 1; + relname | relpersistence +---------+---------------- +(0 rows) + +-- Cleanup +DROP TAG tag1; +DROP TAG tag2; +DROP TAG tag3; +DROP TAG tag4; +DROP DATABASE other_db; diff --git a/src/test/singlenode_regress/expected/misc_sanity.out b/src/test/singlenode_regress/expected/misc_sanity.out index 7e1df68863b..0dff5fe6374 100644 --- a/src/test/singlenode_regress/expected/misc_sanity.out +++ b/src/test/singlenode_regress/expected/misc_sanity.out @@ -123,6 +123,8 @@ ORDER BY 1, 2; pg_resqueuecapability | ressetting | text pg_stat_last_operation | stasubtype | text pg_stat_last_shoperation | stasubtype | text + pg_tag | allowed_values | text[] + pg_tag_description | tagvalue | text pg_task | command | text pg_task | database | text pg_task | jobname | text @@ -134,7 +136,7 @@ ORDER BY 1, 2; pg_task_run_history | return_message | text pg_task_run_history | status | text pg_task_run_history | username | text -(31 rows) +(33 rows) -- system catalogs without primary keys -- diff --git a/src/test/singlenode_regress/expected/oidjoins.out b/src/test/singlenode_regress/expected/oidjoins.out index 4d6ad39fbb8..124b1da4dc2 100644 --- a/src/test/singlenode_regress/expected/oidjoins.out +++ b/src/test/singlenode_regress/expected/oidjoins.out @@ -199,6 +199,10 @@ NOTICE: checking pg_database {dattablespace} => pg_tablespace {oid} NOTICE: checking pg_db_role_setting {setdatabase} => pg_database {oid} NOTICE: checking pg_db_role_setting {setrole} => pg_authid {oid} NOTICE: checking pg_tablespace {spcowner} => pg_authid {oid} +NOTICE: checking pg_tag {tagowner} => pg_authid {oid} +NOTICE: checking pg_tag_description {classid} => pg_class {oid} +NOTICE: checking pg_tag_description {databaseid} => pg_database {oid} +NOTICE: checking pg_tag_description {tagid} => pg_tag {oid} NOTICE: checking pg_auth_members {roleid} => pg_authid {oid} NOTICE: checking pg_auth_members {member} => pg_authid {oid} NOTICE: checking pg_auth_members {grantor} => pg_authid {oid} diff --git a/src/test/singlenode_regress/expected/sanity_check.out b/src/test/singlenode_regress/expected/sanity_check.out index b47c31bc7e6..484b3ea50d6 100644 --- a/src/test/singlenode_regress/expected/sanity_check.out +++ b/src/test/singlenode_regress/expected/sanity_check.out @@ -174,6 +174,8 @@ pg_statistic_ext_data|t pg_subscription|t pg_subscription_rel|t pg_tablespace|t +pg_tag|t +pg_tag_description|t pg_task|t pg_task_run_history|t pg_transform|t diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 9cecc124ce3..c496a76a87a 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -66,6 +66,7 @@ AlterCollationStmt AlterDatabaseSetStmt AlterDatabaseStmt AlterDefaultPrivilegesStmt +AlterDirectoryTableStmt AlterDomainStmt AlterEnumStmt AlterEventTrigStmt @@ -84,6 +85,7 @@ AlterProfileStmt AlterPublicationStmt AlterRoleSetStmt AlterRoleStmt +AlterSchemaStmt AlterSeqStmt AlterStatsStmt AlterStorageServer @@ -91,6 +93,7 @@ AlterStorageUserMappingStmt AlterSubscriptionStmt AlterSubscriptionType AlterSystemStmt +AlterTagStmt AlterTSConfigType AlterTSConfigurationStmt AlterTSDictionaryStmt @@ -462,6 +465,7 @@ CoverPos CreateAmStmt CreateCastStmt CreateConversionStmt +CreateDirectoryTableStmt CreateDomainStmt CreateEnumStmt CreateEventTrigStmt @@ -491,6 +495,7 @@ CreateStorageUserMappingStmt CreateSubscriptionStmt CreateTableAsStmt CreateTableSpaceStmt +CreateTagStmt CreateTransformStmt CreateTrigStmt CreateUserMappingStmt @@ -580,6 +585,7 @@ DropStorageServer DropStorageUserMappingStmt DropSubscriptionStmt DropTableSpaceStmt +DropTagStmt DropUserMappingStmt DropdbStmt DumpComponents