unchanged: --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -604,7 +604,8 @@ get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, } otherNamespace = QualifiedNameGetCreationNamespace(otherOp, - &otherName); + &otherName, + false); if (strcmp(otherName, operatorName) == 0 && otherNamespace == operatorNamespace && unchanged: --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -101,7 +101,7 @@ DefineAggregate(ParseState *pstate, ListCell *pl; /* Convert list of names to a name and namespace */ - aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName); + aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE); unchanged: --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -384,6 +384,7 @@ ExecRenameStmt(RenameStmt *stmt) case OBJECT_OPCLASS: case OBJECT_OPFAMILY: case OBJECT_LANGUAGE: + case OBJECT_MODULE: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: case OBJECT_STATISTIC_EXT: unchanged: --- a/src/backend/commands/collationcmds.c +++ b/src/backend/commands/collationcmds.c @@ -73,7 +73,7 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e Oid newoid; ObjectAddress address; - collNamespace = QualifiedNameGetCreationNamespace(names, &collName); + collNamespace = QualifiedNameGetCreationNamespace(names, &collName, false); aclresult = pg_namespace_aclcheck(collNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) unchanged: --- a/src/backend/commands/conversioncmds.c +++ b/src/backend/commands/conversioncmds.c @@ -51,7 +51,7 @@ CreateConversionCommand(CreateConversionStmt *stmt) /* Convert list of names to a name and namespace */ namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name, - &conversion_name); + &conversion_name, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); unchanged: --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -967,6 +967,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_LANGUAGE: case OBJECT_LARGEOBJECT: case OBJECT_MATVIEW: + case OBJECT_MODULE: case OBJECT_OPCLASS: case OBJECT_OPERATOR: case OBJECT_OPFAMILY: @@ -2087,6 +2088,8 @@ stringify_grant_objtype(ObjectType objtype) return "LANGUAGE"; case OBJECT_LARGEOBJECT: return "LARGE OBJECT"; + case OBJECT_MODULE: + return "MODULE"; case OBJECT_SCHEMA: return "SCHEMA"; case OBJECT_PROCEDURE: @@ -2169,6 +2172,8 @@ stringify_adefprivs_objtype(ObjectType objtype) return "LANGUAGES"; case OBJECT_LARGEOBJECT: return "LARGE OBJECTS"; + case OBJECT_MODULE: + return "MODULES"; case OBJECT_SCHEMA: return "SCHEMAS"; case OBJECT_PROCEDURE: unchanged: --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -148,7 +148,7 @@ compute_return_type(TypeName *returnType, Oid languageOid, errmsg("type \"%s\" is not yet defined", typnam), errdetail("Creating a shell type definition."))); namespaceId = QualifiedNameGetCreationNamespace(returnType->names, - &typname); + &typname, false); aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) @@ -1050,7 +1050,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) /* Convert list of names to a name and namespace */ namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname, - &funcname); + &funcname, true); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); unchanged: --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -2039,7 +2039,7 @@ ResolveOpClass(List *opclass, Oid attrType, */ /* deconstruct the name list */ - DeconstructQualifiedName(opclass, &schemaname, &opcname); + DeconstructQualifiedName(opclass, &schemaname, NULL, &opcname, false); if (schemaname) { @@ -2787,7 +2787,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind, */ if (objectKind == REINDEX_OBJECT_SCHEMA) { - objectOid = get_namespace_oid(objectName, false); + objectOid = get_namespace_oid(objectName, InvalidOid, false); if (!pg_namespace_ownercheck(objectOid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA, unchanged: --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -85,7 +85,7 @@ OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok) HeapTuple htup; /* deconstruct the name list */ - DeconstructQualifiedName(opfamilyname, &schemaname, &opfname); + DeconstructQualifiedName(opfamilyname, &schemaname, NULL, &opfname, false); if (schemaname) { @@ -166,7 +166,7 @@ OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok) HeapTuple htup; /* deconstruct the name list */ - DeconstructQualifiedName(opclassname, &schemaname, &opcname); + DeconstructQualifiedName(opclassname, &schemaname, NULL, &opcname, false); if (schemaname) { @@ -354,7 +354,7 @@ DefineOpClass(CreateOpClassStmt *stmt) /* Convert list of names to a name and namespace */ namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname, - &opcname); + &opcname, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE); @@ -769,7 +769,7 @@ DefineOpFamily(CreateOpFamilyStmt *stmt) /* Convert list of names to a name and namespace */ namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname, - &opfname); + &opfname, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE); unchanged: --- a/src/backend/commands/operatorcmds.c +++ b/src/backend/commands/operatorcmds.c @@ -87,7 +87,7 @@ DefineOperator(List *names, List *parameters) ListCell *pl; /* Convert list of names to a name and namespace */ - oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName); + oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE); unchanged: --- a/src/backend/commands/seclabel.c +++ b/src/backend/commands/seclabel.c @@ -48,6 +48,7 @@ SecLabelSupportsObjectType(ObjectType objtype) case OBJECT_LANGUAGE: case OBJECT_LARGEOBJECT: case OBJECT_MATVIEW: + case OBJECT_MODULE: case OBJECT_PROCEDURE: case OBJECT_PUBLICATION: case OBJECT_ROLE: unchanged: --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -163,7 +163,7 @@ CreateStatistics(CreateStatsStmt *stmt) */ if (stmt->defnames) namespaceId = QualifiedNameGetCreationNamespace(stmt->defnames, - &namestr); + &namestr, false); else { namespaceId = RelationGetNamespace(rel); @@ -630,7 +630,7 @@ AlterStatistics(AlterStatsStmt *stmt) Assert(stmt->missing_ok); - DeconstructQualifiedName(stmt->defnames, &schemaname, &statname); + DeconstructQualifiedName(stmt->defnames, &schemaname, NULL, &statname, false); if (schemaname) ereport(NOTICE, unchanged: --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -196,7 +196,7 @@ DefineTSParser(List *names, List *parameters) prsRel = table_open(TSParserRelationId, RowExclusiveLock); /* Convert list of names to a name and namespace */ - namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname); + namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname, false); /* initialize tuple fields with name/namespace */ memset(values, 0, sizeof(values)); @@ -405,7 +405,7 @@ DefineTSDictionary(List *names, List *parameters) ObjectAddress address; /* Convert list of names to a name and namespace */ - namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname); + namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE); @@ -701,7 +701,7 @@ DefineTSTemplate(List *names, List *parameters) errmsg("must be superuser to create text search templates"))); /* Convert list of names to a name and namespace */ - namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname); + namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname, false); tmplRel = table_open(TSTemplateRelationId, RowExclusiveLock); @@ -908,7 +908,7 @@ DefineTSConfiguration(List *names, List *parameters, ObjectAddress *copied) ObjectAddress address; /* Convert list of names to a name and namespace */ - namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname); + namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE); unchanged: --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -217,7 +217,7 @@ DefineType(ParseState *pstate, List *names, List *parameters) errmsg("must be superuser to create a base type"))); /* Convert list of names to a name and namespace */ - typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName); + typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName, false); #ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ @@ -733,7 +733,7 @@ DefineDomain(CreateDomainStmt *stmt) /* Convert list of names to a name and namespace */ domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname, - &domainName); + &domainName, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(), @@ -1149,7 +1149,7 @@ DefineEnum(CreateEnumStmt *stmt) /* Convert list of names to a name and namespace */ enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, - &enumName); + &enumName, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE); @@ -1369,7 +1369,7 @@ DefineRange(CreateRangeStmt *stmt) /* Convert list of names to a name and namespace */ typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, - &typeName); + &typeName, false); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(typeNamespace, GetUserId(), ACL_CREATE); @@ -1457,7 +1457,7 @@ DefineRange(CreateRangeStmt *stmt) errmsg("conflicting or redundant options"))); /* we can look up the subtype name immediately */ multirangeNamespace = QualifiedNameGetCreationNamespace(defGetQualifiedName(defel), - &multirangeTypeName); + &multirangeTypeName, false); } else ereport(ERROR, unchanged: --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -262,7 +262,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); struct GroupClause *groupclause; } -%type stmt toplevel_stmt schema_stmt routine_body_stmt +%type stmt toplevel_stmt schema_stmt routine_body_stmt module_stmt AlterEventTrigStmt AlterCollationStmt AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt @@ -301,6 +301,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CreateMatViewStmt RefreshMatViewStmt CreateAmStmt CreatePublicationStmt AlterPublicationStmt CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt + CreateModuleStmt %type select_no_parens select_with_parens select_clause simple_select values_clause @@ -344,7 +345,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type opt_in_database %type OptSchemaName -%type OptSchemaEltList +%type OptSchemaEltList OptModuleEltList %type am_type @@ -368,7 +369,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type func_name handler_name qual_Op qual_all_Op subquery_Op opt_class opt_inline_handler opt_validator validator_clause - opt_collate + opt_collate module_name %type qualified_name insert_target OptConstrFromTable @@ -681,7 +682,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED - MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE + MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MODULE + MONTH_P MOVE NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE NORMALIZE NORMALIZED @@ -954,6 +956,7 @@ stmt: | CreateFunctionStmt | CreateGroupStmt | CreateMatViewStmt + | CreateModuleStmt | CreateOpClassStmt | CreateOpFamilyStmt | CreatePublicationStmt @@ -1466,6 +1469,84 @@ schema_stmt: | ViewStmt ; +/***************************************************************************** + * + * Manipulate a module + * + *****************************************************************************/ + +CreateModuleStmt: + CREATE MODULE module_name OptModuleEltList + { + CreateModuleStmt *n = makeNode(CreateModuleStmt); + n->modulename = $3; + n->authrole = NULL; + n->moduleElts = $4; + n->if_not_exists = false; + $$ = (Node *)n; + } + | CREATE MODULE module_name OWNER RoleSpec OptModuleEltList + { + CreateModuleStmt *n = makeNode(CreateModuleStmt); + n->modulename = $3; + n->authrole = $5; + n->moduleElts = $6; + n->if_not_exists = false; + $$ = (Node *)n; + } + | CREATE MODULE IF_P NOT EXISTS module_name OptModuleEltList + { + CreateModuleStmt *n = makeNode(CreateModuleStmt); + n->modulename = $6; + n->authrole = NULL; + if ($7 != NIL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("CREATE MODULE IF NOT EXISTS cannot include module elements"), + parser_errposition(@7))); + n->moduleElts = $7; + n->if_not_exists = true; + $$ = (Node *)n; + } + | CREATE MODULE IF_P NOT EXISTS module_name OWNER RoleSpec OptModuleEltList + { + CreateModuleStmt *n = makeNode(CreateModuleStmt); + n->modulename = $6; + n->authrole = $8; + if ($9 != NIL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("CREATE MODULE IF NOT EXISTS cannot include module elements"), + parser_errposition(@9))); + n->moduleElts = $9; + n->if_not_exists = true; + $$ = (Node *)n; + } + ; + +module_name: + name { $$ = list_make1(makeString($1)); } + | name attrs { $$ = lcons(makeString($1), $2); } + ; + +OptModuleEltList: + OptModuleEltList module_stmt + { + if (@$ < 0) /* see comments for YYLLOC_DEFAULT */ + @$ = @2; + $$ = lappend($1, $2); + } + | /* EMPTY */ + { $$ = NIL; } + ; + +/* + * module_stmt are the ones that can show up inside a CREATE MODULE statement. + */ +module_stmt: + CreateFunctionStmt + ; + /***************************************************************************** * @@ -6308,6 +6389,26 @@ DropStmt: DROP object_type_any_name IF_P EXISTS any_name_list opt_drop_behavior n->concurrent = true; $$ = (Node *)n; } + | DROP MODULE any_name_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_MODULE; + n->objects = $3; + n->behavior = $4; + n->missing_ok = false; + n->concurrent = false; + $$ = (Node *)n; + } + | DROP MODULE IF_P EXISTS any_name_list opt_drop_behavior + { + DropStmt *n = makeNode(DropStmt); + n->removeType = OBJECT_MODULE; + n->objects = $5; + n->behavior = $6; + n->missing_ok = true; + n->concurrent = false; + $$ = (Node *)n; + } ; /* object types taking any_name/any_name_list */ @@ -8569,6 +8670,15 @@ RenameStmt: ALTER AGGREGATE aggregate_with_argtypes RENAME TO name n->missing_ok = false; $$ = (Node *)n; } + | ALTER MODULE module_name RENAME TO name + { + RenameStmt *n = makeNode(RenameStmt); + n->renameType = OBJECT_MODULE; + n->object = (Node *) $3; + n->newname = $6; + n->missing_ok = false; + $$ = (Node *)n; + } | ALTER opt_procedural LANGUAGE name RENAME TO name { RenameStmt *n = makeNode(RenameStmt); @@ -15639,6 +15749,7 @@ unreserved_keyword: | MINUTE_P | MINVALUE | MODE + | MODULE | MONTH_P | MOVE | NAME_P @@ -16205,6 +16316,7 @@ bare_label_keyword: | METHOD | MINVALUE | MODE + | MODULE | MOVE | NAME_P | NAMES unchanged: --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -18,8 +18,10 @@ #include "catalog/pg_aggregate.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "commands/dbcommands.h" #include "funcapi.h" #include "lib/stringinfo.h" +#include "miscadmin.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "parser/parse_agg.h" @@ -1421,7 +1423,6 @@ func_get_detail(List *funcname, raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames, expand_variadic, expand_defaults, false); - /* * Quickly check if there is an exact match to the input datatypes (there * can be only one) @@ -1549,7 +1550,6 @@ func_get_detail(List *funcname, /* one match only? then run with it... */ if (ncandidates == 1) best_candidate = current_candidates; - /* * multiple candidates? then better decide or throw an error... */ @@ -1882,6 +1882,16 @@ FuncNameAsType(List *funcname) Oid result; Type typtup; + /* + * check if this may be in a module. If it could be, don't check if it + * may be a type since they can not be in a module + */ + if (list_length(funcname) == 3) + { + if (strcmp(strVal(linitial(funcname)), get_database_name(MyDatabaseId)) != 0) + return InvalidOid; + } + /* * temp_ok=false protects the * contract for writing SECURITY DEFINER functions safely. @@ -2058,7 +2068,6 @@ LookupFuncNameInternal(List *funcname, int nargs, const Oid *argtypes, clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, missing_ok); - /* * If no arguments were specified, the name must yield a unique candidate. */ unchanged: --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -954,7 +954,7 @@ make_oper_cache_key(ParseState *pstate, OprCacheKey *key, List *opname, char *opername; /* deconstruct the name list */ - DeconstructQualifiedName(opname, &schemaname, &opername); + DeconstructQualifiedName(opname, &schemaname, NULL, &opername, false); /* ensure zero-fill for stable hashing */ MemSet(key, 0, sizeof(OprCacheKey)); unchanged: --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -166,7 +166,7 @@ LookupTypeNameExtended(ParseState *pstate, char *typname; /* deconstruct the name list */ - DeconstructQualifiedName(typeName->names, &schemaname, &typname); + DeconstructQualifiedName(typeName->names, &schemaname, NULL, &typname, false); if (schemaname) { unchanged: --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -113,6 +113,14 @@ typedef struct List *grants; /* GRANT items */ } CreateSchemaStmtContext; +/* State shared by transformCreateModuleStmt and its subroutines */ +typedef struct +{ + const char *stmtType; /* "CREATE MODULE" or "ALTER MODULE" */ + List *modulename; /* name of module */ + RoleSpec *authrole; /* owner of module */ + List *functions; /* CREATE FUNCTION items */ +} CreateModuleStmtContext; static void transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column); @@ -3944,6 +3952,70 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt) return result; } +/* + * transformCreateModuleStmt - + * analyzes the CREATE MODULE statement + * + * Split the module element list into individual commands and place + * them in the result list in an order such that there are no forward + * references. Currently there are only functions allowed in modules + * but the spec allows variables and temp tables so this provides a + * way to have them created before the functions that could use them. + * + * The functions are also checked to make sure there is not an explicit + * namespace attempted to be used. + */ +List * +transformCreateModuleStmt(CreateModuleStmt *stmt) +{ + CreateModuleStmtContext cxt; + List *result; + ListCell *elements; + + + cxt.stmtType = "CREATE MODULE"; + cxt.modulename = stmt->modulename; + cxt.authrole = (RoleSpec *) stmt->authrole; + cxt.functions = NIL; + + /* + * Run through each module element in the module element list. Separate + * statements by type, and do preliminary analysis. + */ + foreach(elements, stmt->moduleElts) + { + Node *element = lfirst(elements); + + switch (nodeTag(element)) + { + case T_CreateFunctionStmt: + { + CreateFunctionStmt *elp = (CreateFunctionStmt *) element; + + if (list_length(elp->funcname) > 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), + errmsg("CREATE FUNCTION (%s) specifies a " + "namespace inside of CREATE MODULE (%s)", + NameListToString(elp->funcname), + NameListToString(cxt.modulename)))); + + cxt.functions = lappend(cxt.functions, element); + } + break; + + default: + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(element)); + } + } + + result = NIL; + result = list_concat(result, cxt.functions); + + return result; +} + /* * setSchemaName * Set or check schema name in an element of a CREATE SCHEMA command unchanged: --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -42,6 +42,7 @@ #include "commands/extension.h" #include "commands/lockcmds.h" #include "commands/matview.h" +#include "commands/modulecmds.h" #include "commands/policy.h" #include "commands/portalcmds.h" #include "commands/prepare.h" @@ -178,6 +179,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_CreateForeignServerStmt: case T_CreateForeignTableStmt: case T_CreateFunctionStmt: + case T_CreateModuleStmt: case T_CreateOpClassStmt: case T_CreateOpFamilyStmt: case T_CreatePLangStmt: @@ -1097,6 +1099,19 @@ ProcessUtilitySlow(ParseState *pstate, commandCollected = true; break; + case T_CreateModuleStmt: /* CREATE Module */ + CreateModuleCommand(pstate, (CreateModuleStmt *) parsetree, + queryString, + pstmt->stmt_location, + pstmt->stmt_len); + /* + * EventTriggerCollectSimpleCommand called by + * CreateModuleCommand + */ + commandCollected = true; + break; + + case T_CreateStmt: case T_CreateForeignTableStmt: { @@ -2280,6 +2295,9 @@ AlterObjectTypeCommandTag(ObjectType objtype) case OBJECT_STATISTIC_EXT: tag = CMDTAG_ALTER_STATISTICS; break; + case OBJECT_MODULE: + tag = CMDTAG_ALTER_MODULE; + break; default: tag = CMDTAG_UNKNOWN; break; @@ -2584,6 +2602,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_STATISTIC_EXT: tag = CMDTAG_DROP_STATISTICS; break; + case OBJECT_MODULE: + tag = CMDTAG_DROP_MODULE; + break; default: tag = CMDTAG_UNKNOWN; } @@ -2739,6 +2760,10 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_CREATE_FUNCTION; break; + case T_CreateModuleStmt: + tag = CMDTAG_CREATE_MODULE; + break; + case T_IndexStmt: tag = CMDTAG_CREATE_INDEX; break; @@ -3382,6 +3407,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_CreateModuleStmt: + lev = LOGSTMT_DDL; + break; + case T_IndexStmt: lev = LOGSTMT_DDL; break; only in patch2: unchanged: --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -432,6 +432,7 @@ typedef enum NodeTag T_AlterCollationStmt, T_CallStmt, T_AlterStatsStmt, + T_CreateModuleStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) only in patch2: unchanged: --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1798,6 +1798,7 @@ typedef enum ObjectType OBJECT_LANGUAGE, OBJECT_LARGEOBJECT, OBJECT_MATVIEW, + OBJECT_MODULE, OBJECT_OPCLASS, OBJECT_OPERATOR, OBJECT_OPFAMILY, @@ -2975,6 +2976,24 @@ typedef struct AlterFunctionStmt List *actions; /* list of DefElem */ } AlterFunctionStmt; +/* ---------------------- + * Create Module Statement + * + * NOTE: the moduleElts list contains raw parsetrees for component statements + * of the schema, such as CREATE FUNCTION, CREATE PROCEDURE, etc. These are + * analyzed and executed after the module itself is created. + * ---------------------- + */ +typedef struct CreateModuleStmt +{ + NodeTag type; + List *modulename; /* the name of the schema to create */ + RoleSpec *authrole; /* the owner of the created schema */ + List *moduleElts; /* module components (list of parsenodes) */ + bool if_not_exists; /* just do nothing if module already exists? */ +} CreateModuleStmt; + + /* ---------------------- * DO Statement * only in patch2: unchanged: --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -257,6 +257,7 @@ PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("module", MODULE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("month", MONTH_P, UNRESERVED_KEYWORD, AS_LABEL) PG_KEYWORD("move", MOVE, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("name", NAME_P, UNRESERVED_KEYWORD, BARE_LABEL) only in patch2: unchanged: --- a/src/include/parser/parse_utilcmd.h +++ b/src/include/parser/parse_utilcmd.h @@ -31,6 +31,7 @@ extern CreateStatsStmt *transformStatsStmt(Oid relid, CreateStatsStmt *stmt, extern void transformRuleStmt(RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause); extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt); +extern List *transformCreateModuleStmt(CreateModuleStmt *stmt); extern PartitionBoundSpec *transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec); extern List *expandTableLikeClause(RangeVar *heapRel, only in patch2: unchanged: --- a/src/include/tcop/cmdtaglist.h +++ b/src/include/tcop/cmdtaglist.h @@ -43,6 +43,7 @@ PG_CMDTAG(CMDTAG_ALTER_INDEX, "ALTER INDEX", true, false, false) PG_CMDTAG(CMDTAG_ALTER_LANGUAGE, "ALTER LANGUAGE", true, false, false) PG_CMDTAG(CMDTAG_ALTER_LARGE_OBJECT, "ALTER LARGE OBJECT", true, false, false) PG_CMDTAG(CMDTAG_ALTER_MATERIALIZED_VIEW, "ALTER MATERIALIZED VIEW", true, false, false) +PG_CMDTAG(CMDTAG_ALTER_MODULE, "ALTER MODULE", true, false, false) PG_CMDTAG(CMDTAG_ALTER_OPERATOR, "ALTER OPERATOR", true, false, false) PG_CMDTAG(CMDTAG_ALTER_OPERATOR_CLASS, "ALTER OPERATOR CLASS", true, false, false) PG_CMDTAG(CMDTAG_ALTER_OPERATOR_FAMILY, "ALTER OPERATOR FAMILY", true, false, false) @@ -98,6 +99,7 @@ PG_CMDTAG(CMDTAG_CREATE_FUNCTION, "CREATE FUNCTION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_INDEX, "CREATE INDEX", true, false, false) PG_CMDTAG(CMDTAG_CREATE_LANGUAGE, "CREATE LANGUAGE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_MATERIALIZED_VIEW, "CREATE MATERIALIZED VIEW", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_MODULE, "CREATE MODULE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_OPERATOR, "CREATE OPERATOR", true, false, false) PG_CMDTAG(CMDTAG_CREATE_OPERATOR_CLASS, "CREATE OPERATOR CLASS", true, false, false) PG_CMDTAG(CMDTAG_CREATE_OPERATOR_FAMILY, "CREATE OPERATOR FAMILY", true, false, false) @@ -150,6 +152,7 @@ PG_CMDTAG(CMDTAG_DROP_FUNCTION, "DROP FUNCTION", true, false, false) PG_CMDTAG(CMDTAG_DROP_INDEX, "DROP INDEX", true, false, false) PG_CMDTAG(CMDTAG_DROP_LANGUAGE, "DROP LANGUAGE", true, false, false) PG_CMDTAG(CMDTAG_DROP_MATERIALIZED_VIEW, "DROP MATERIALIZED VIEW", true, false, false) +PG_CMDTAG(CMDTAG_DROP_MODULE, "DROP MODULE", true, false, false) PG_CMDTAG(CMDTAG_DROP_OPERATOR, "DROP OPERATOR", true, false, false) PG_CMDTAG(CMDTAG_DROP_OPERATOR_CLASS, "DROP OPERATOR CLASS", true, false, false) PG_CMDTAG(CMDTAG_DROP_OPERATOR_FAMILY, "DROP OPERATOR FAMILY", true, false, false)