实现事件触发器

This commit is contained in:
kenxx 2023-03-02 11:09:39 -05:00
parent 5a69c46920
commit 9f8064bb24
256 changed files with 17124 additions and 3664 deletions

View File

@ -228,7 +228,9 @@ static void pgss_ProcessUtility(processutility_context* processutility_cxt,
#ifdef PGXC
bool sentToRemote,
#endif /* PGXC */
char* completionTag);
char* completionTag,
ProcessUtilityContext context,
bool isCTAS);
static uint32 pgss_hash_fn(const void* key, Size keysize);
static int pgss_match_fn(const void* key1, const void* key2, Size keysize);
static uint32 pgss_hash_string(const char* str);
@ -727,7 +729,9 @@ static void pgss_ProcessUtility(processutility_context* processutility_cxt,
#ifdef PGXC
bool sentToRemote,
#endif /* PGXC */
char* completionTag)
char* completionTag,
ProcessUtilityContext context,
bool isCTAS)
{
Node* parsetree = processutility_cxt->parse_tree;
const char* queryString = processutility_cxt->query_string;
@ -761,14 +765,18 @@ static void pgss_ProcessUtility(processutility_context* processutility_cxt,
#ifdef PGXC
sentToRemote,
#endif /* PGXC */
completionTag);
completionTag,
context,
isCTAS);
else
standard_ProcessUtility(processutility_cxt,
dest,
#ifdef PGXC
sentToRemote,
#endif /* PGXC */
completionTag);
completionTag,
context,
isCTAS);
nested_level--;
}
PG_CATCH();
@ -818,14 +826,18 @@ static void pgss_ProcessUtility(processutility_context* processutility_cxt,
#ifdef PGXC
sentToRemote,
#endif /* PGXC */
completionTag);
completionTag,
context,
isCTAS);
else
standard_ProcessUtility(processutility_cxt,
dest,
#ifdef PGXC
sentToRemote,
#endif /* PGXC */
completionTag);
completionTag,
context,
isCTAS);
}
}

View File

@ -4698,7 +4698,6 @@ create operator public.>^ (
procedure = int4gt
);
create operator family my_op_family using btree;
ERROR: user defined operator is not yet supported.
create function my_op_cmp(a int, b int) returns int as
$$begin return btint4cmp(a, b); end $$ language plpgsql;
create operator class my_op_class for type int using btree family my_op_family as
@ -4706,23 +4705,34 @@ create operator class my_op_class for type int using btree family my_op_family a
operator 3 public.=^,
operator 5 public.>^,
function 1 my_op_cmp(int, int);
ERROR: operator family "my_op_family" does not exist for access method "btree"
-- NOTICES:
-- openGauss not support create operator class. remove the case. If you want to restore the test case later, refer to README in the file header.
-- This will not be pushed as sort operator is now removed from the extension.
explain (verbose, costs off)
select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
ERROR: operator <^ is not a valid ordering operator
LINE 2: select array_agg(c1 order by c1 using operator(public.<^)) f...
^
HINT: Ordering operators must be "<" or ">" members of btree operator families.
CONTEXT: referenced column: array_agg
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
GroupAggregate
Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
Group By Key: ft2.c2
-> Foreign Scan on public.ft2
Output: c2, c1
Node ID: 1
Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
FDW remote plans:
Node 1: EXPLAIN (VERBOSE ON, COSTS OFF) SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
Index Scan using t1_pkey on "S 1"."T 1"
Output: "C 1", c2
Index Cond: ("T 1"."C 1" < 100)
Filter: ("T 1".c2 = 6)
(15 rows)
-- Cleanup
drop operator class my_op_class using btree;
ERROR: operator class "my_op_class" does not exist for access method "btree"
drop function my_op_cmp(a int, b int);
drop operator family my_op_family using btree;
ERROR: operator family "my_op_family" does not exist for access method "btree"
drop operator public.>^(int, int);
drop operator public.=^(int, int);
drop operator public.<^(int, int);

View File

@ -5547,7 +5547,6 @@ create operator public.>^ (
procedure = int4gt
);
create operator family my_op_family using btree;
ERROR: user defined operator is not yet supported.
create function my_op_cmp(a int, b int) returns int as
$$begin return btint4cmp(a, b); end $$ language plpgsql;
create operator class my_op_class for type int using btree family my_op_family as
@ -5555,23 +5554,35 @@ create operator class my_op_class for type int using btree family my_op_family a
operator 3 public.=^,
operator 5 public.>^,
function 1 my_op_cmp(int, int);
ERROR: operator family "my_op_family" does not exist for access method "btree"
-- NOTICES:
-- openGauss not support create operator class. remove the case. If you want to restore the test case later, refer to README in the file header.
-- This will not be pushed as sort operator is now removed from the extension.
explain (verbose, costs off)
select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
ERROR: operator <^ is not a valid ordering operator
LINE 2: select array_agg(c1 order by c1 using operator(public.<^)) f...
^
HINT: Ordering operators must be "<" or ">" members of btree operator families.
CONTEXT: referenced column: array_agg
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------
GroupAggregate
Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
Group By Key: ft2.c2
-> Foreign Scan on public.ft2
Output: c2, c1
Node ID: 1
Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
FDW remote plans:
Node 1: EXPLAIN (VERBOSE ON, COSTS OFF) SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
Partitioned Index Scan using t1_pkey on "S 1"."T 1"
Output: "C 1", c2
Index Cond: ("T 1"."C 1" < 100)
Filter: ("T 1".c2 = 6)
Selected Partitions: 1
(16 rows)
-- Cleanup
drop operator class my_op_class using btree;
ERROR: operator class "my_op_class" does not exist for access method "btree"
drop function my_op_cmp(a int, b int);
drop operator family my_op_family using btree;
ERROR: operator family "my_op_family" does not exist for access method "btree"
drop operator public.>^(int, int);
drop operator public.=^(int, int);
drop operator public.<^(int, int);

View File

@ -806,7 +806,7 @@ static void light_unified_audit_executor(const Query *query)
}
static void gsaudit_ProcessUtility_hook(processutility_context* processutility_cxt,
DestReceiver *dest, bool sentToRemote, char *completionTag, bool isCTAS = false)
DestReceiver *dest, bool sentToRemote, char *completionTag, ProcessUtilityContext context,bool isCTAS = false)
{
/* do nothing when enable_security_policy is off */
if (!u_sess->attr.attr_security.Enable_Security_Policy || !IsConnFromApp() ||
@ -814,10 +814,10 @@ static void gsaudit_ProcessUtility_hook(processutility_context* processutility_c
!is_audit_policy_exist_load_policy_info()) {
if (next_ProcessUtility_hook) {
next_ProcessUtility_hook(processutility_cxt, dest, sentToRemote, completionTag,
false);
context, false);
} else {
standard_ProcessUtility(processutility_cxt, dest, sentToRemote, completionTag,
false);
context, false);
}
return;
}
@ -1611,10 +1611,10 @@ static void gsaudit_ProcessUtility_hook(processutility_context* processutility_c
{
if (next_ProcessUtility_hook) {
next_ProcessUtility_hook(processutility_cxt, dest, sentToRemote, completionTag,
false);
context, false);
} else {
standard_ProcessUtility(processutility_cxt, dest, sentToRemote, completionTag,
false);
context, false);
}
flush_access_logs(AUDIT_OK);
send_mng_events(AUDIT_OK);

View File

@ -12,6 +12,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY alterDatabase SYSTEM "alter_database.sgml">
<!ENTITY alterDefaultPrivileges SYSTEM "alter_default_privileges.sgml">
<!ENTITY alterDomain SYSTEM "alter_domain.sgml">
<!ENTITY alterEventTrigger SYSTEM "alter_event_trigger.sgml">
<!ENTITY alterExtension SYSTEM "alter_extension.sgml">
<!ENTITY alterForeignDataWrapper SYSTEM "alter_foreign_data_wrapper.sgml">
<!ENTITY alterForeignTable SYSTEM "alter_foreign_table.sgml">
@ -64,6 +65,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY createConversion SYSTEM "create_conversion.sgml">
<!ENTITY createDatabase SYSTEM "create_database.sgml">
<!ENTITY createDomain SYSTEM "create_domain.sgml">
<!ENTITY createEventTrigger SYSTEM "create_event_trigger.sgml">
<!ENTITY createExtension SYSTEM "create_extension.sgml">
<!ENTITY createForeignDataWrapper SYSTEM "create_foreign_data_wrapper.sgml">
<!ENTITY createForeignTable SYSTEM "create_foreign_table.sgml">
@ -108,6 +110,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY dropConversion SYSTEM "drop_conversion.sgml">
<!ENTITY dropDatabase SYSTEM "drop_database.sgml">
<!ENTITY dropDomain SYSTEM "drop_domain.sgml">
<!ENTITY dropEventTrigger SYSTEM "drop_event_trigger.sgml">
<!ENTITY dropExtension SYSTEM "drop_extension.sgml">
<!ENTITY dropForeignDataWrapper SYSTEM "drop_foreign_data_wrapper.sgml">
<!ENTITY dropForeignTable SYSTEM "drop_foreign_table.sgml">

View File

@ -0,0 +1,23 @@
<refentry id="SQL-ALTEREVENTTRIGGER">
<refmeta>
<refentrytitle>ALTER EVENT TRIGGER</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>ALTER EVENT TRIGGER</refname>
<refpurpose>change the definition of an event trigger</refpurpose>
</refnamediv>
<refsynopsisdiv>
<indexterm zone="sql-altereventtrigger">
<primary>ALTER EVENT TRIGGER</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
ALTER EVENT TRIGGER name DISABLE
ALTER EVENT TRIGGER name ENABLE [ REPLICA | ALWAYS ]
ALTER EVENT TRIGGER name OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
ALTER EVENT TRIGGER name RENAME TO new_name
</synopsis>
</refsynopsisdiv>
</refentry>

View File

@ -0,0 +1,23 @@
<refentry id="SQL-CREATEEVENTTRIGGER">
<refmeta>
<refentrytitle>CREATE EVENT TRIGGER</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>CREATE EVENT TRIGGER</refname>
<refpurpose>define a new event trigger</refpurpose>
</refnamediv>
<refsynopsisdiv>
<indexterm zone="sql-createeventtrigger">
<primary>CREATE EVENT TRIGGER</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
CREATE EVENT TRIGGER name
ON event
[ WHEN filter_variable IN (filter_value [, ... ]) [ AND ... ] ]
EXECUTE PROCEDURE function name()
</synopsis>
</refsynopsisdiv>
</refentry>

View File

@ -0,0 +1,20 @@
<refentry id="SQL-DROPEVENTTRIGGER">
<refmeta>
<refentrytitle>DROP EVENT TRIGGER</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DROP EVENT TRIGGER</refname>
<refpurpose>remove an event trigger</refpurpose>
</refnamediv>
<refsynopsisdiv>
<indexterm zone="sql-dropeventtrigger">
<primary>DROP EVENT TRIGGER</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
DROP EVENT TRIGGER [ IF EXISTS ] name [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
</refentry>

View File

@ -277,7 +277,6 @@ static bool BuildCheckReplChannel(const char* ChannelInfo)
if (ReplStr == NULL) {
return false;
} else {
/* check localhost */
iter = strstr(ReplStr, "localhost");
if (iter == NULL) {
free(ReplStr);
@ -295,7 +294,6 @@ static bool BuildCheckReplChannel(const char* ChannelInfo)
return false;
}
/* check localport */
iter = strstr(ReplStr, "localport");
if (iter == NULL) {
free(ReplStr);
@ -312,7 +310,6 @@ static bool BuildCheckReplChannel(const char* ChannelInfo)
return false;
}
/* check remotehost */
iter = strstr(ReplStr, "remotehost");
if (NULL == iter) {
free(ReplStr);
@ -330,7 +327,6 @@ static bool BuildCheckReplChannel(const char* ChannelInfo)
return false;
}
/* check remoteport */
iter = strstr(ReplStr, "remoteport");
if (iter == NULL) {
free(ReplStr);

View File

@ -97,6 +97,7 @@ TableInfo* getSchemaData(Archive* fout, int* numTablesPtr)
int numForeignDataWrappers;
int numForeignServers;
int numDefaultACLs;
int numEventTriggers;
int numEvents;
if (g_verbose)
write_msg(NULL, "reading schemas\n");
@ -276,6 +277,10 @@ TableInfo* getSchemaData(Archive* fout, int* numTablesPtr)
write_msg(NULL, "reading subscriptions\n");
}
getSubscriptions(fout);
if (g_verbose) {
write_msg(NULL, "reading event triggers\n");
}
getEventTriggers(fout, &numEventTriggers);
*numTablesPtr = numTables;
GS_FREE(inhinfo);
@ -623,7 +628,7 @@ static int DOCatalogIdCompare(const void* p1, const void* p2)
/*
* Build an array of pointers to all known dumpable objects
*
*
* This simply creates a modifiable copy of the internal map.
*/
void getDumpableObjects(DumpableObject*** objs, int* numObjs)

View File

@ -55,6 +55,7 @@
#include "catalog/pg_class.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h"
#include "catalog/pg_partition.h"
@ -72,7 +73,7 @@
#include "dumputils.h"
#include "postgres.h"
#include "knl/knl_variable.h"
#include "common/fe_memutils.h"
#include "openssl/rand.h"
#include "miscadmin.h"
#include "bin/elog.h"
@ -243,6 +244,7 @@ const uint32 SUBSCRIPTION_VERSION = 92580;
const uint32 SUBSCRIPTION_BINARY_VERSION_NUM = 92656;
const uint32 B_DUMP_TRIGGER_VERSION_NUM = 92843;
const uint32 EVENT_VERSION = 92844;
const uint32 EVENT_TRIGGER_VERSION_NUM = 92845;
#ifdef DUMPSYSLOG
char* syslogpath = NULL;
@ -493,6 +495,7 @@ static void DumpHashDistribution(PQExpBuffer resultBuf, const TableInfo* tbinfo)
static void get_password_pipeline();
static void get_role_password();
static void get_encrypt_key();
static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
static void dumpUniquePrimaryDef(PQExpBuffer buf, ConstraintInfo* coninfo, IndxInfo* indxinfo, bool isBcompatibility);
static bool findDBCompatibility(Archive* fout, const char* databasename);
static void dumpTableAutoIncrement(Archive* fout, PQExpBuffer sqlbuf, TableInfo* tbinfo);
@ -10927,6 +10930,9 @@ static void dumpDumpableObject(Archive* fout, DumpableObject* dobj)
case DO_TSCONFIG:
dumpTSConfig(fout, (TSConfigInfo*)dobj);
break;
case DO_EVENT_TRIGGER:
dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
break;
case DO_FDW:
dumpForeignDataWrapper(fout, (FdwInfo*)dobj);
break;
@ -17903,7 +17909,6 @@ static void GenerateSubPartitionBy(PQExpBuffer result, Archive *fout, TableInfo
} else {
GetPartkeyexprSrc(result, fout, tbinfo, true);
}
appendPQExpBuffer(result, ")\n");
PQclear(res);
@ -22548,6 +22553,7 @@ static void addBoundaryDependencies(DumpableObject** dobjs, int numObjs, Dumpabl
break;
case DO_INDEX:
case DO_TRIGGER:
case DO_EVENT_TRIGGER:
case DO_DEFAULT_ACL:
case DO_RLSPOLICY:
case DO_PUBLICATION:
@ -23168,6 +23174,148 @@ static bool IsPackageObject(Archive* fout, Oid classid, Oid objid)
return count > 0;
}
/*
* getEventTriggers
* get information about event triggers
*/
EventTriggerInfo *
getEventTriggers(Archive *fout, int *numEventTriggers)
{
/* Before 9.3, there are no event triggers */
if (GetVersionNum(fout) < EVENT_TRIGGER_VERSION_NUM) {
*numEventTriggers = 0;
return NULL;
}
int i;
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
EventTriggerInfo *evtinfo;
int i_tableoid;
int i_oid;
int i_evtname;
int i_evtevent;
int i_evtowner;
int i_evttags;
int i_evtfname;
int i_evtenabled;
int ntups;
/* Make sure we are in proper schema */
selectSourceSchema(fout, "pg_catalog");
appendPQExpBuffer(query,
"SELECT e.tableoid, e.oid, evtname, evtenabled, "
"evtevent, (%s evtowner) AS evtowner, "
"array_to_string(array("
"select quote_literal(x) "
" from unnest(evttags) as t(x)), ', ') as evttags, "
"e.evtfoid::regproc as evtfname "
"FROM pg_event_trigger e "
"ORDER BY e.oid",
username_subquery);
res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
ntups = PQntuples(res);
*numEventTriggers = ntups;
if (ntups == 0) {
PQclear(res);
destroyPQExpBuffer(query);
return NULL;
}
evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
i_tableoid = PQfnumber(res, "tableoid");
i_oid = PQfnumber(res, "oid");
i_evtname = PQfnumber(res, "evtname");
i_evtevent = PQfnumber(res, "evtevent");
i_evtowner = PQfnumber(res, "evtowner");
i_evttags = PQfnumber(res, "evttags");
i_evtfname = PQfnumber(res, "evtfname");
i_evtenabled = PQfnumber(res, "evtenabled");
for (i = 0; i < ntups; i++) {
evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
AssignDumpId(&evtinfo[i].dobj);
evtinfo[i].dobj.name = gs_strdup(PQgetvalue(res, i, i_evtname));
evtinfo[i].evtname = gs_strdup(PQgetvalue(res, i, i_evtname));
evtinfo[i].evtevent = gs_strdup(PQgetvalue(res, i, i_evtevent));
evtinfo[i].evtowner = gs_strdup(PQgetvalue(res, i, i_evtowner));
evtinfo[i].evttags = gs_strdup(PQgetvalue(res, i, i_evttags));
evtinfo[i].evtfname = gs_strdup(PQgetvalue(res, i, i_evtfname));
evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
}
PQclear(res);
destroyPQExpBuffer(query);
return evtinfo;
}
static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
{
PQExpBuffer query;
PQExpBuffer labelq;
/* Skip if not to be dumped */
if (!evtinfo->dobj.dump || dataOnly)
return;
query = createPQExpBuffer();
labelq = createPQExpBuffer();
appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
appendPQExpBuffer(query, " ON ");
appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
appendPQExpBufferStr(query, " ");
if (strcmp("", evtinfo->evttags) != 0) {
appendPQExpBufferStr(query, "\n WHEN TAG IN (");
appendPQExpBufferStr(query, evtinfo->evttags);
appendPQExpBufferStr(query, ") ");
}
appendPQExpBuffer(query, "\n EXECUTE PROCEDURE ");
appendPQExpBufferStr(query, evtinfo->evtfname);
appendPQExpBuffer(query, "();\n");
if (evtinfo->evtenabled != 'O') {
appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
fmtId(evtinfo->dobj.name));
switch (evtinfo->evtenabled) {
case 'D':
appendPQExpBuffer(query, "DISABLE");
break;
case 'A':
appendPQExpBuffer(query, "ENABLE ALWAYS");
break;
case 'R':
appendPQExpBuffer(query, "ENABLE REPLICA");
break;
default:
appendPQExpBuffer(query, "ENABLE");
break;
}
appendPQExpBuffer(query, ";\n");
}
appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
fmtId(evtinfo->dobj.name));
ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
"EVENT TRIGGER", SECTION_POST_DATA,
query->data, "", NULL, NULL, 0, NULL, NULL);
dumpComment(fout, labelq->data, NULL, NULL,evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
destroyPQExpBuffer(query);
destroyPQExpBuffer(labelq);
}
static void dumpUniquePrimaryDef(PQExpBuffer buf, ConstraintInfo* coninfo, IndxInfo* indxinfo, bool isBcompatibility)
{
appendPQExpBuffer(buf, "%s ", coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");

View File

@ -93,7 +93,8 @@ typedef enum {
DO_PUBLICATION,
DO_PUBLICATION_REL,
DO_SUBSCRIPTION,
DO_EVENT
DO_EVENT,
DO_EVENT_TRIGGER
} DumpableObjectType;
typedef struct _dumpableObject {
@ -109,6 +110,16 @@ typedef struct _dumpableObject {
int allocDeps; /* allocated size of dependencies[] */
} DumpableObject;
typedef struct _evttriggerInfo {
DumpableObject dobj;
char *evtname;
char *evtevent;
char *evtowner;
char *evttags;
char *evtfname;
char evtenabled;
} EventTriggerInfo;
typedef struct _namespaceInfo {
DumpableObject dobj;
char* rolname; /* name of owner, or empty string */
@ -608,6 +619,7 @@ extern uint32 GetVersionNum(Archive* fout);
extern void getPublications(Archive *fout);
extern void getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables);
extern void getSubscriptions(Archive *fout);
extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers);
#ifdef GSDUMP_LLT
void stopLLT();

View File

@ -103,6 +103,7 @@ static const int newObjectTypePriority[] = {
30, /* DO_FK_CONSTRAINT */
2, /* DO_PROCLANG */
10, /* DO_CAST */
23, /* DO_PACKAGE */
23, /* DO_TABLE_DATA */
19, /* DO_DUMMY_TYPE */
12, /* DO_TSPARSER */
@ -121,7 +122,8 @@ static const int newObjectTypePriority[] = {
34, /* DO_PUBLICATION */
35, /* DO_PUBLICATION_REL */
36, /* DO_SUBSCRIPTION */
18 /* DO_EVENT */
18, /* DO_EVENT */
37 /* DO_EVENT_TRIGGER */
};
static DumpId postDataBoundId;
@ -1012,6 +1014,13 @@ static void describeDumpableObject(DumpableObject* obj, char* buf, int bufsize)
buf, bufsize, bufsize - 1, "SCHEMA %s (ID %d OID %u)", obj->name, obj->dumpId, obj->catId.oid);
securec_check_ss_c(nRet, "\0", "\0");
return;
case DO_EVENT_TRIGGER:
nRet = snprintf_s(
buf, bufsize, bufsize - 1, "EVENT TRIGGER %s (ID %d OID %u)", obj->name, obj->dumpId, obj->catId.oid);
securec_check_ss_c(nRet, "\0", "\0");
return;
case DO_EXTENSION:
if (true == include_extensions) {
nRet = snprintf_s(

View File

@ -531,6 +531,9 @@ static backslashResult exec_command(const char* cmd, PsqlScanState scan_state, P
success = listExtensions(pattern);
}
break;
case 'y': /* Event Triggers */
success = listEventTriggers(pattern, show_verbose);
break;
default:
status = PSQL_CMD_UNKNOWN;
}

View File

@ -5095,6 +5095,73 @@ static bool listOneExtensionContents(const char* extname, const char* oid)
return true;
}
/*
* \dy
*
* Describes Event Triggers.
*/
bool listEventTriggers(const char *pattern, bool verbose)
{
PQExpBufferData buf;
PGresult *res;
printQueryOpt myopt = pset.popt;
static const bool translate_columns[] =
{false, false, false, true, false, false, false};
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf,
"SELECT evtname as \"%s\", "
"evtevent as \"%s\", "
"pg_catalog.pg_get_userbyid(e.evtowner) as \"%s\",\n"
" case evtenabled when 'O' then '%s'"
" when 'R' then '%s'"
" when 'A' then '%s'"
" when 'D' then '%s' end as \"%s\",\n"
" e.evtfoid::pg_catalog.regproc as \"%s\", "
"pg_catalog.array_to_string(array(select x"
" from pg_catalog.unnest(evttags) as t(x)), ', ') as \"%s\"",
gettext_noop("Name"),
gettext_noop("Event"),
gettext_noop("Owner"),
gettext_noop("enabled"),
gettext_noop("replica"),
gettext_noop("always"),
gettext_noop("disabled"),
gettext_noop("Enabled"),
gettext_noop("Function"),
gettext_noop("Tags"));
if (verbose)
appendPQExpBuffer(&buf,
",\npg_catalog.obj_description(e.oid, 'pg_event_trigger') as \"%s\"",
gettext_noop("Description"));
appendPQExpBufferStr(&buf,
"\nFROM pg_catalog.pg_event_trigger e ");
processSQLNamePattern(pset.db, &buf, pattern, false, false,
NULL, "evtname", NULL, NULL);
appendPQExpBufferStr(&buf, "ORDER BY 1");
res = PSQLexec(buf.data, false);
termPQExpBuffer(&buf);
if (!res) {
return false;
}
myopt.nullPrint = NULL;
myopt.title = _("List of event triggers");
myopt.translate_header = true;
myopt.translate_columns = translate_columns;
printQuery(res, &myopt, pset.queryFout, pset.logfile);
PQclear(res);
return true;
}
#ifdef ENABLE_UT
void ut_test_listOneExtensionContents()
{

View File

@ -98,5 +98,8 @@ extern bool listExtensionContents(const char* pattern);
/* \ded+ */
extern bool listDataSource(const char* pattern, bool verbose);
/* \dy */
extern bool listEventTriggers(const char *pattern, bool verbose);
#endif /* DESCRIBE_H */

View File

@ -292,6 +292,7 @@ void slashUsage(unsigned short int pager)
fprintf(output, _(" \\dv[S+] [PATTERN] list views\n"));
fprintf(output, _(" \\dE[S+] [PATTERN] list foreign tables\n"));
fprintf(output, _(" \\dx[+] [PATTERN] list extensions\n"));
fprintf(output, _(" \\dy [PATTERN] list event triggers\n"));
fprintf(output, _(" \\l[+] list all databases\n"));
fprintf(output, _(" \\sf[+] FUNCNAME show a function's definition\n"));
fprintf(output, _(" \\z [PATTERN] same as \\dp\n"));

View File

@ -3,7 +3,7 @@ set(POSTGRES_BKI_SRCS_S
"@pg_proc.h @pg_type.h @pg_attribute.h @pg_class.h @pg_partition.h @pg_attrdef.h @pg_constraint.h
@pg_inherits.h @pg_index.h @pg_operator.data @pg_opfamily.h @pg_opclass.h @pg_am.h @pg_amop.data @pg_amproc.h
@pg_language.h @pg_largeobject_metadata.h @pg_largeobject.h @pg_aggregate.h @pg_statistic.h @pg_rewrite.h
@pg_trigger.h @pg_description.h @pg_cast.h @pg_enum.h @pg_set.h @pg_namespace.h @pg_conversion.h @pg_depend.h @pg_database.h
@pg_trigger.h @pg_event_trigger.h @pg_description.h @pg_cast.h @pg_enum.h @pg_set.h @pg_namespace.h @pg_conversion.h @pg_depend.h @pg_database.h
@pg_db_role_setting.h @pg_tablespace.h @pg_pltemplate.h @pg_authid.h @pg_auth_members.h @pg_shdepend.h @pg_shdescription.h
@pg_ts_config.h @pg_ts_config_map.h @pg_ts_dict.h @pg_ts_parser.h @pg_ts_template.h @pg_auth_history.h @pg_user_status.h
@pg_extension.h @pg_obsscaninfo.h @pg_foreign_data_wrapper.h @pg_foreign_server.h @pg_user_mapping.h @pgxc_class.h @pgxc_node.h

View File

@ -41,7 +41,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.data \
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.data pg_amproc.h \
pg_language.h pg_largeobject_metadata.h pg_largeobject.h pg_aggregate.h \
pg_statistic.h pg_rewrite.h pg_trigger.h pg_description.h \
pg_statistic.h pg_rewrite.h pg_trigger.h pg_event_trigger.h pg_description.h \
pg_cast.h pg_enum.h pg_set.h pg_namespace.h pg_conversion.h pg_depend.h \
pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \

View File

@ -35,6 +35,7 @@
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_directory.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
@ -61,6 +62,7 @@
#include "catalog/gs_global_config.h"
#include "catalog/gs_db_privilege.h"
#include "commands/dbcommands.h"
#include "commands/event_trigger.h"
#include "commands/proclang.h"
#include "commands/sec_rls_cmds.h"
#include "commands/tablecmds.h"
@ -186,6 +188,7 @@ const struct AclObjKind {
{ACL_KIND_DIRECTORY, ACL_ALL_RIGHTS_DIRECTORY, ACL_ALL_DDL_RIGHTS_DIRECTORY},
{ACL_KIND_COLUMN_SETTING, ACL_ALL_RIGHTS_KEY, ACL_ALL_DDL_RIGHTS_KEY},
{ACL_KIND_GLOBAL_SETTING, ACL_ALL_RIGHTS_KEY, ACL_ALL_DDL_RIGHTS_KEY},
{ACL_KIND_EVENT_TRIGGER, ACL_NO_RIGHTS, ACL_NO_DDL_RIGHTS},
};
const struct AclClassId {
@ -375,6 +378,11 @@ static void restrict_and_check_grant(AclMode* this_privileges, bool is_grant,
whole_ddl_mask = ACL_NO_DDL_RIGHTS;
}
if ((whole_mask == ACL_NO_RIGHTS) && (objkind == ACL_KIND_EVENT_TRIGGER)) {
elog(ERROR, "grantable rights not supported for event triggers");
/* not reached, but keep compiler quiet */
return ;
}
/*
* If we found no grant options, consider whether to issue a hard error.
* Per spec, having any privilege at all on the object will get you by
@ -733,6 +741,15 @@ static void ExecGrantStmt_oids(InternalGrant* istmt)
errcause("The object type is not supported for GRANT/REVOKE."),
erraction("Check GRANT/REVOKE syntax to obtain the supported object types.")));
}
/*
* Pass the info to event triggers about the just-executed GRANT. Note
* that we prefer to do it after actually executing it, because that gives
* the functions a chance to adjust the istmt with privileges actually
* granted.
*/
if (EventTriggerSupportsGrantObjectType(istmt->objtype))
EventTriggerCollectGrant(istmt);
}
static void get_global_objects(const List *objnames, List **objects)
@ -4695,6 +4712,8 @@ static const char* const no_priv_msg[MAX_ACL_KIND] = {
gettext_noop("permission denied for client master key %s"),
/* ACL_KIND_PACKAGE */
gettext_noop("permission denied for package %s"),
/* ACL_KIND_EVENT_TRIGGER */
gettext_noop("permission denied for event trigger %s"),
};
static const char* const not_owner_msg[MAX_ACL_KIND] = {
@ -4754,6 +4773,8 @@ static const char* const not_owner_msg[MAX_ACL_KIND] = {
gettext_noop("must be owner of publication %s"),
/* ACL_KIND_SUBSCRIPTION */
gettext_noop("must be owner of subscription %s"),
/* ACL_KIND_EVENT_TRIGGER */
gettext_noop("must be owner of event trigger %s"),
};
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char* objectname)
@ -4872,6 +4893,10 @@ static AclMode pg_aclmask(
return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_FOREIGN_SERVER:
return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_EVENT_TRIGGER:
elog(ERROR, "grantable rights not supported for event triggers");
/* not reached, but keep compiler quiet */
return ACL_NO_RIGHTS;
case ACL_KIND_TYPE:
return pg_type_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_DATA_SOURCE:
@ -7000,6 +7025,32 @@ bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
return has_privs_of_role(roleid, ownerId);
}
/*
* Ownership check for an event trigger (specified by OID).
*/
bool pg_event_trigger_ownercheck(Oid et_oid, Oid roleid)
{
HeapTuple tuple;
Oid ownerId;
/* Superusers bypass all permission checking. */
if (superuser_arg(roleid))
return true;
tuple = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(et_oid));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("event trigger with OID %u does not exist",
et_oid)));
ownerId = ((Form_pg_event_trigger) GETSTRUCT(tuple))->evtowner;
ReleaseSysCache(tuple);
return has_privs_of_role(roleid, ownerId);
}
/*
* Ownership check for a database (specified by OID).
*/

View File

@ -2617,6 +2617,14 @@
"eqsel", 1,
AddBuiltinFunc(_0(EQSELRETURNOID), _1("eqsel"), _2(4), _3(true), _4(false), _5(eqsel), _6(701), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(4, 2281, 26, 2281, 23), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("eqsel"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("restriction selectivity of = and related operators"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
),
AddFuncGroup(
"event_trigger_in", 1,
AddBuiltinFunc(_0(3594), _1("event_trigger_in"), _2(1), _3(false), _4(false), _5(event_trigger_in), _6(3838), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 2275), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("event_trigger_in"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"event_trigger_out", 1,
AddBuiltinFunc(_0(3595), _1("event_trigger_out"), _2(1), _3(false), _4(false), _5(event_trigger_out), _6(2275), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 3838), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("event_trigger_out"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"every", 1,
AddBuiltinFunc(_0(EVERYFUNCOID), _1("every"), _2(1), _3(false), _4(false), _5(aggregate_dummy), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(true), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 16), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("the average (arithmetic mean) as numeric of all bigint values"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
@ -8090,6 +8098,22 @@
AddBuiltinFunc(_0(2168), _1("pg_database_size"), _2(1), _3(true), _4(false), _5(pg_database_size_name), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1, 19), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_database_size_name"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("total disk space usage for the specified database"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)),
AddBuiltinFunc(_0(2324), _1("pg_database_size"), _2(1), _3(true), _4(false), _5(pg_database_size_oid), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1, 26), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_database_size_oid"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("total disk space usage for the specified database"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
),
AddFuncGroup(
"pg_ddl_command_in", 1,
AddBuiltinFunc(_0(5801), _1("pg_ddl_command_in"), _2(0), _3(true), _4(false), _5(pg_ddl_command_in), _6(5729), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2275), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_ddl_command_in"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false)),
),
AddFuncGroup(
"pg_ddl_command_out", 1,
AddBuiltinFunc(_0(5803), _1("pg_ddl_command_out"), _2(0), _3(true), _4(false), _5(pg_ddl_command_out), _6(2275), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 5729), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_ddl_command_out"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false)),
),
AddFuncGroup(
"pg_ddl_command_recv", 1,
AddBuiltinFunc(_0(5807), _1("pg_ddl_command_recv"), _2(0), _3(true), _4(false), _5(pg_ddl_command_recv), _6(5729), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2281), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_ddl_command_recv"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false)),
),
AddFuncGroup(
"pg_ddl_command_send", 1,
AddBuiltinFunc(_0(5809), _1("pg_ddl_command_send"), _2(0), _3(true), _4(false), _5(pg_ddl_command_send), _6(17), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 5729), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_ddl_command_send"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false)),
),
AddFuncGroup(
"pg_delete_audit", 1,
AddBuiltinFunc(_0(3781), _1("pg_delete_audit"), _2(2), _3(false), _4(false), _5(pg_delete_audit), _6(2278), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(2, 1184, 1184), _21(2, 1184, 1184), _22(2, 'i', 'i'), _23(2, "begin", "end"), _24(NULL), _25("pg_delete_audit"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
@ -8126,6 +8150,23 @@
"pg_encoding_to_char", 1,
AddBuiltinFunc(_0(PGENCODINGTOCHARFUNCOID), _1("pg_encoding_to_char"), _2(1), _3(true), _4(false), _5(PG_encoding_to_char), _6(19), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 23), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("PG_encoding_to_char"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(true), _32(false), _33("convert encoding id to encoding name"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
),
AddFuncGroup(
"pg_event_trigger_ddl_commands", 1,
AddBuiltinFunc(_0(8852), _1("pg_event_trigger_ddl_commands"), _2(0), _3(true), _4(false), _5(pg_event_trigger_ddl_commands), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(9,26,26,23,25,25,25,25,16,5729), _22(9,'o','o','o','o','o','o','o','o','o'), _23(9, "classid", "objid", "objsubid", "command_tag", "object_type", "schema_name", "object_identity", "in_extension", "command"), _24(NULL), _25("pg_event_trigger_ddl_commands"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"pg_event_trigger_dropped_objects", 1,
AddBuiltinFunc(_0(5724), _1("pg_event_trigger_dropped_objects"), _2(0), _3(true), _4(false), _5(pg_event_trigger_dropped_objects), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(12,26,26,23,16,16,16,25,25,25,25,1009,1009), _22(12,'o','o','o','o','o','o','o','o','o','o','o','o'), _23(12, "classid", "objid", "objsubid", "original", "normal", "is_temporary", "object_type", "schema_name", "object_name", "object_identity", "address_names", "address_args"), _24(NULL), _25("pg_event_trigger_dropped_objects"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"pg_event_trigger_table_rewrite_oid", 1,
AddBuiltinFunc(_0(5726), _1("pg_event_trigger_table_rewrite_oid"), _2(0), _3(true), _4(false), _5(pg_event_trigger_table_rewrite_oid), _6(26), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(1,26), _22(1,'o'), _23(1, "oid"), _24(NULL), _25("pg_event_trigger_table_rewrite_oid"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"pg_event_trigger_table_rewrite_reason", 1,
AddBuiltinFunc(_0(5727), _1("pg_event_trigger_table_rewrite_reason"), _2(0), _3(true), _4(false), _5(pg_event_trigger_table_rewrite_reason), _6(23), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_event_trigger_table_rewrite_reason"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"pg_export_snapshot", 1,
AddBuiltinFunc(_0(3809), _1("pg_export_snapshot"), _2(0), _3(true), _4(false), _5(pg_export_snapshot), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_export_snapshot"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("export a snapshot"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
@ -8202,6 +8243,10 @@
"pg_get_keywords", 1,
AddBuiltinFunc(_0(1686), _1("pg_get_keywords"), _2(0), _3(true), _4(true), _5(pg_get_keywords), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(10), _11(400), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(3, 25, 18, 25), _22(3, 'o', 'o', 'o'), _23(3, "word", "catcode", "catdesc"), _24(NULL), _25("pg_get_keywords"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("list of SQL keywords"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
),
AddFuncGroup(
"pg_get_object_address", 1,
AddBuiltinFunc(_0(5728), _1("pg_get_object_address"), _2(3), _3(true), _4(false), _5(pg_get_object_address), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(3,25,1009,1009), _21(6,25,1009,1009,26,26,23), _22(6,'i','i','i','o','o','o'), _23(6, "type", "name", "args", "classid", "objid", "subobjid"), _24(NULL), _25("pg_get_object_address"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"pg_get_publication_tables", 1,
AddBuiltinFunc(_0(2801), _1("pg_get_publication_tables"), _2(1), _3(true), _4(true), _5(pg_get_publication_tables), _6(26), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1000), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 25), _21(2, 25, 26), _22(2, 'i', 'o'), _23(2, "pubname", "relid"), _24(NULL), _25("pg_get_publication_tables"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("get OIDs of tables in a publication"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
@ -8277,6 +8322,10 @@
AddBuiltinFunc(_0(2709), _1("pg_has_role"), _2(2), _3(true), _4(false), _5(pg_has_role_name), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(2, 19, 25), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_has_role_name"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("current user privilege on role by role name"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)),
AddBuiltinFunc(_0(2710), _1("pg_has_role"), _2(2), _3(true), _4(false), _5(pg_has_role_id), _6(16), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(2, 26, 25), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_has_role_id"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("current user privilege on role by role oid"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))
),
AddFuncGroup(
"pg_identify_object", 1,
AddBuiltinFunc(_0(5725), _1("pg_identify_object"), _2(3), _3(true), _4(false), _5(pg_identify_object), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(3,26,26,23), _21(7,26,26,23,25,25,25,25), _22(7,'i','i','i','o','o','o','o'), _23(7, "classid", "objid", "subobjid", "type", "schema", "name", "identity"), _24(NULL), _25("pg_identify_object"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false))
),
AddFuncGroup(
"pg_indexes_size", 1,
AddBuiltinFunc(_0(2998), _1("pg_indexes_size"), _2(1), _3(true), _4(false), _5(pg_indexes_size), _6(20), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1, 2205), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_indexes_size"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("disk space usage for all indexes attached to the specified table"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0))

View File

@ -42,6 +42,7 @@
#include "catalog/pg_default_acl.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_directory.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
@ -86,6 +87,7 @@
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/matview.h"
#include "commands/proclang.h"
@ -155,9 +157,9 @@ static const Oid object_classes[MAX_OCLASS] = {
PgJobRelationId, /* OCLASS_PG_JOB */
PublicationRelationId, /* OCLASS_PUBLICATION */
PublicationRelRelationId, /* OCLASS_PUBLICATION_REL */
SubscriptionRelationId /* OCLASS_SUBSCRIPTION */
SubscriptionRelationId, /* OCLASS_SUBSCRIPTION */
EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */
#ifdef PGXC
,
PgxcClassRelationId /* OCLASS_PGXCCLASS */
#endif
@ -184,6 +186,48 @@ static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
extern char* pg_get_viewdef_worker(Oid viewoid, int prettyFlags, int wrapColumn);
extern char* pg_get_functiondef_worker(Oid funcid, int* headerlines);
/*
* Go through the objects given running the final actions on them, and execute
* the actual deletion.
*/
static void deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel,
int flags)
{
int i;
/*
* Keep track of objects for event triggers, if necessary.
*/
if (trackDroppedObjectsNeeded()) {
for (i = 0; i < targetObjects->numrefs; i++) {
const ObjectAddress *thisobj = &targetObjects->refs[i];
const ObjectAddressExtra *extra = &targetObjects->extras[i];
bool original = false;
bool normal = false;
if (extra->flags & DEPFLAG_ORIGINAL)
original = true;
if (extra->flags & DEPFLAG_NORMAL)
normal = true;
if (extra->flags & DEPFLAG_REVERSE)
normal = true;
if (EventTriggerSupportsObjectClass(getObjectClass(thisobj))) {
EventTriggerSQLDropAddObject(thisobj, original, normal);
}
}
}
/*
* Delete all the objects in the proper order.
*/
for (i = 0; i < targetObjects->numrefs; i++) {
ObjectAddress *thisobj = targetObjects->refs + i;
deleteOneObject(thisobj, depRel, flags);
}
}
/*
* performDeletion: attempt to drop the specified object. If CASCADE
* behavior is specified, also drop any dependent objects (recursively).
@ -210,7 +254,6 @@ void performDeletion(const ObjectAddress* object, DropBehavior behavior, int fla
{
Relation depRel;
ObjectAddresses* targetObjects = NULL;
int i;
/*
* We save some cycles by opening pg_depend just once and passing the
@ -248,11 +291,8 @@ void performDeletion(const ObjectAddress* object, DropBehavior behavior, int fla
/*
* Delete all the objects in the proper order.
*/
for (i = 0; i < targetObjects->numrefs; i++) {
ObjectAddress *thisobj = targetObjects->refs + i;
deleteOneObject(thisobj, &depRel, flags);
}
/* do the deed */
deleteObjectsInList(targetObjects, &depRel, flags);
}
/* And clean up */
@ -348,10 +388,9 @@ void performMultipleDeletions(const ObjectAddresses* objects, DropBehavior behav
/*
* Delete all the objects in the proper order.
*/
for (i = 0; i < targetObjects->numrefs; i++) {
if (i > 0) {
(void)MemoryContextSwitchTo(objDelCxt);
ObjectAddress* thisobj = targetObjects->refs + i;
deleteOneObject(thisobj, &depRel, flags);
deleteObjectsInList(targetObjects, &depRel, flags);
MemoryContextReset(objDelCxt);
}
@ -1388,6 +1427,10 @@ static void doDeletion(const ObjectAddress* object, int flags)
case OCLASS_SYNONYM:
RemoveSynonymById(object->objectId);
break;
case OCLASS_EVENT_TRIGGER:
RemoveEventTriggerById(object->objectId);
break;
case OCLASS_DB4AI_MODEL:
remove_model_by_oid(object->objectId);
break;
@ -2391,6 +2434,8 @@ ObjectClass getObjectClass(const ObjectAddress* object)
case DbPrivilegeId:
return OCLASS_DB_PRIVILEGE;
case EventTriggerRelationId:
return OCLASS_EVENT_TRIGGER;
case ExtensionRelationId:
return OCLASS_EXTENSION;
@ -3040,6 +3085,19 @@ char* getObjectDescription(const ObjectAddress* object)
break;
}
case OCLASS_EVENT_TRIGGER: {
HeapTuple tup;
tup = SearchSysCache1(EVENTTRIGGEROID,
ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for event trigger %u",
object->objectId);
appendStringInfo(&buffer, _("event trigger %s"),
NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
ReleaseSysCache(tup);
} break;
case OCLASS_GLOBAL_SETTING:
get_global_setting_description(&buffer, object);
break;

View File

@ -156,7 +156,7 @@ static void addNewPartitionTupleForValuePartitionedTable(Relation pg_partition_r
static void heapDropPartitionTable(Relation relation);
static Oid AddNewRelationType(const char* typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, Oid ownerid,
static ObjectAddress AddNewRelationType(const char* typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, Oid ownerid,
Oid new_row_type, Oid new_array_type);
static void RelationRemoveInheritance(Oid relid);
static Oid StoreRelCheck(
@ -2464,7 +2464,7 @@ Oid* SortRelationDistributionNodes(Oid* nodeoids, int numnodes)
* define a composite type corresponding to the new relation
* --------------------------------
*/
static Oid AddNewRelationType(const char* typname, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, Oid ownerid,
static ObjectAddress AddNewRelationType(const char* typname, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, Oid ownerid,
Oid new_row_type, Oid new_array_type)
{
return TypeCreate(new_row_type, /* optional predetermined OID */
@ -2587,6 +2587,8 @@ static bool CheckPartitionExprKey(List* keys, char partStrategy, bool* isFunc)
* use_user_acl: TRUE if should look for user-defined default permissions;
* if FALSE, relacl is always set NULL
* allow_system_table_mods: TRUE to allow creation in system namespaces
* Output parameters:
* typaddress: if not null, gets the object address of the new pg_type entry
*
* Returns the OID of the new relation
* --------------------------------
@ -2597,7 +2599,7 @@ Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltable
int oidinhcount, OnCommitAction oncommit, Datum reloptions, bool use_user_acl,
bool allow_system_table_mods, PartitionState *partTableState, int8 row_compress,
HashBucketInfo *bucketinfo, bool record_dependce, List *ceLst, StorageType storage_type,
LOCKMODE partLockMode)
LOCKMODE partLockMode, ObjectAddress *typaddress)
{
Relation pg_class_desc;
Relation new_rel_desc;
@ -2612,6 +2614,7 @@ Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltable
Oid relbucketOid = InvalidOid;
int2vector* bucketcol = NULL;
bool relhasbucket = false;
ObjectAddress new_type_addr;
bool relhasuids = false;
if (IsInitdb && EnableInitDBSegment) {
@ -2885,7 +2888,11 @@ Oid heap_create_with_catalog(const char *relname, Oid relnamespace, Oid reltable
* we checked for a duplicate name above. in such case we try to emit a
* nicer error message using try...catch
*/
new_type_oid = AddNewRelationType(relname, relnamespace, relid, relkind, ownerid, reltypeid, new_array_oid);
new_type_addr = AddNewRelationType(relname, relnamespace, relid, relkind, ownerid, reltypeid, new_array_oid);
new_type_oid = new_type_addr.objectId;
if (typaddress)
*typaddress = new_type_addr;
}
PG_CATCH();
{
@ -3744,7 +3751,7 @@ void heap_drop_with_catalog(Oid relid)
/*
* Store a default expression for column attnum of relation rel.
*/
void StoreAttrDefault(Relation rel, AttrNumber attnum, Node* expr, char generatedCol, Node* update_expr, bool skip_dep)
Oid StoreAttrDefault(Relation rel, AttrNumber attnum, Node* expr, char generatedCol, Node* update_expr, bool skip_dep)
{
char* adbin = NULL;
char* adbin_on_update = NULL;
@ -3886,7 +3893,7 @@ void StoreAttrDefault(Relation rel, AttrNumber attnum, Node* expr, char generate
recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);
if (skip_dep) {
return;
return InvalidOid;
}
/*
* Record dependencies on objects used in the expression, too.
@ -3906,6 +3913,7 @@ void StoreAttrDefault(Relation rel, AttrNumber attnum, Node* expr, char generate
*/
recordDependencyOnExpr(&defobject, expr, NIL, DEPENDENCY_NORMAL);
}
return attrdefOid;
}
/*
@ -3913,6 +3921,7 @@ void StoreAttrDefault(Relation rel, AttrNumber attnum, Node* expr, char generate
*
* Caller is responsible for updating the count of constraints
* in the pg_class entry for the relation.
* The OID of the new constraint is returned.
*/
static Oid StoreRelCheck(
Relation rel, const char* ccname, Node* expr, bool is_validated, bool is_local, int inhcount, bool is_no_inherit)
@ -3922,6 +3931,7 @@ static Oid StoreRelCheck(
List* varList = NIL;
int keycount;
int16* attNos = NULL;
Oid constrOid;
/*
* Flatten expression to string form for storage.
@ -3966,7 +3976,7 @@ static Oid StoreRelCheck(
/*
* Create the Check Constraint
*/
Oid oid = CreateConstraintEntry(ccname, /* Constraint Name */
constrOid = CreateConstraintEntry(ccname, /* Constraint Name */
RelationGetNamespace(rel), /* namespace */
CONSTRAINT_CHECK, /* Constraint Type */
false, /* Is Deferrable */
@ -3998,7 +4008,7 @@ static Oid StoreRelCheck(
pfree(ccbin);
pfree(ccsrc);
return oid;
return constrOid;
}
/*
@ -4014,7 +4024,7 @@ static void StoreConstraints(Relation rel, List* cooked_constraints)
int numchecks = 0;
ListCell* lc = NULL;
if (cooked_constraints == NULL)
if (cooked_constraints == NIL)
return; /* nothing to do */
/*
@ -4029,13 +4039,13 @@ static void StoreConstraints(Relation rel, List* cooked_constraints)
switch (con->contype) {
case CONSTR_DEFAULT:
StoreAttrDefault(rel, con->attnum, con->expr, 0, con->update_expr);
con->conoid = StoreAttrDefault(rel, con->attnum, con->expr, 0,con->update_expr);
break;
case CONSTR_GENERATED:
StoreAttrDefault(rel, con->attnum, con->expr, ATTRIBUTE_GENERATED_STORED, NULL);
con->conoid = StoreAttrDefault(rel, con->attnum, con->expr, ATTRIBUTE_GENERATED_STORED, NULL);
break;
case CONSTR_CHECK:
StoreRelCheck(
con->conoid = StoreRelCheck(
rel, con->name, con->expr, !con->skip_validation, con->is_local, con->inhcount, con->is_no_inherit);
numchecks++;
break;
@ -4127,6 +4137,7 @@ List* AddRelationNewConstraints(
ListCell* cell = NULL;
Node* expr = NULL;
CookedConstraint* cooked = NULL;
Oid defOid;
AttrNumber autoinc_attnum = RelAutoIncAttrNum(rel);
Node* update_expr = NULL;
Bitmapset* generated_by_attrs = NULL;
@ -4190,10 +4201,11 @@ List* AddRelationNewConstraints(
if (expr != NULL && !colDef->generatedCol && IsA(expr, Const) && ((Const *)expr)->constisnull)
continue;
StoreAttrDefault(rel, colDef->attnum, expr, colDef->generatedCol, update_expr);
defOid = StoreAttrDefault(rel, colDef->attnum, expr, colDef->generatedCol, update_expr);
cooked = (CookedConstraint*)palloc(sizeof(CookedConstraint));
cooked->contype = CONSTR_DEFAULT;
cooked->conoid = defOid;
cooked->name = NULL;
cooked->attnum = colDef->attnum;
cooked->expr = expr;
@ -4222,6 +4234,7 @@ List* AddRelationNewConstraints(
foreach (cell, newConstraints) {
Constraint* cdef = (Constraint*)lfirst(cell);
char* ccname = NULL;
Oid constrOid;
if (cdef->contype != CONSTR_CHECK)
continue;
@ -4310,13 +4323,14 @@ List* AddRelationNewConstraints(
/*
* OK, store it.
*/
Oid oid = StoreRelCheck(rel, ccname, expr, !cdef->skip_validation, is_local, is_local ? 0 : 1, cdef->is_no_inherit);
constrOid = StoreRelCheck(rel, ccname, expr, !cdef->skip_validation,
is_local, is_local ? 0 : 1, cdef->is_no_inherit);
ListCell *cell = NULL;
foreach (cell, cdef->constraintOptions) {
void *pointer = lfirst(cell);
if (IsA(pointer, CommentStmt)) {
CommentStmt *commentStmt = (CommentStmt *)pointer;
CreateComments(oid, ConstraintRelationId, 0, commentStmt->comment);
CreateComments(constrOid, ConstraintRelationId, 0, commentStmt->comment);
break;
}
}
@ -4324,6 +4338,7 @@ List* AddRelationNewConstraints(
cooked = (CookedConstraint*)palloc(sizeof(CookedConstraint));
cooked->contype = CONSTR_CHECK;
cooked->conoid = constrOid;
cooked->name = ccname;
cooked->attnum = 0;
cooked->expr = expr;
@ -7738,9 +7753,12 @@ void SetRelHasClusterKey(Relation rel, bool has)
/*
* Add cluster key constraint for relation.
* return address List of constraint
*/
List* AddRelClusterConstraints(Relation rel, List* clusterKeys)
{
List *result = NIL;
if (!RelationIsColStore(rel)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
@ -7753,7 +7771,7 @@ List* AddRelClusterConstraints(Relation rel, List* clusterKeys)
foreach (cell, clusterKeys) {
Constraint* cdef = (Constraint*)lfirst(cell);
ObjectAddress * address = NULL;
Assert(cdef->contype == CONSTR_CLUSTER);
List* colNameList = cdef->keys;
@ -7776,11 +7794,12 @@ List* AddRelClusterConstraints(Relation rel, List* clusterKeys)
conname =
ChooseConstraintName(RelationGetRelationName(rel), NULL, "cluster", RelationGetNamespace(rel), NIL);
}
address = (ObjectAddress *)palloc0(sizeof(ObjectAddress));
address->classId = ConstraintRelationId;
/*
* Create the Check Constraint
*/
Oid constraintOid = CreateConstraintEntry(conname, /* Constraint Name */
address->objectId = CreateConstraintEntry(conname, /* Constraint Name */
RelationGetNamespace(rel), /* namespace */
CONSTRAINT_CLUSTER, /* Constraint Type */
false, /* Is Deferrable */
@ -7809,14 +7828,15 @@ List* AddRelClusterConstraints(Relation rel, List* clusterKeys)
0, /* coninhcount */
true, /* connoinherit */
cdef->inforConstraint); /* @hdfs informational constraint */
CreateNonColumnComment(constraintOid, cdef->constraintOptions, ConstraintRelationId);
CreateNonColumnComment(address->objectId, cdef->constraintOptions, ConstraintRelationId);
pfree(attNums);
result = lappend(result, address);
}
if (nKeys > 0)
SetRelHasClusterKey(rel, true);
return NULL;
return result;
}
/*

View File

@ -53,6 +53,7 @@
#include "catalog/pg_description.h"
#include "catalog/storage.h"
#include "catalog/storage_gtt.h"
#include "commands/event_trigger.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "commands/vacuum.h"
@ -204,7 +205,7 @@ static bool relationHasPrimaryKey(Relation rel)
* Caller had better have at least ShareLock on the table, else the not-null
* checking isn't trustworthy.
*/
void index_check_primary_key(Relation heapRel, IndexInfo* indexInfo, bool is_alter_table, bool is_modify_primary)
void index_check_primary_key(Relation heapRel, IndexInfo* indexInfo, bool is_alter_table, IndexStmt *stmt, bool is_modify_primary)
{
List* cmds = NIL;
int i;
@ -275,8 +276,11 @@ void index_check_primary_key(Relation heapRel, IndexInfo* indexInfo, bool is_alt
* as to avoid two scans. But that seems to complicate DefineIndex's API
* unduly.
*/
if (cmds != NULL)
if (cmds != NULL) {
EventTriggerAlterTableStart((Node *) stmt);
AlterTableInternal(RelationGetRelid(heapRel), cmds, false);
EventTriggerAlterTableEnd();
}
}
/*
@ -2085,7 +2089,8 @@ void index_concurrently_part_swap(Oid newIndexPartId, Oid oldIndexPartId, const
/*
* index_constraint_create
*
* Set up a constraint associated with an index
* Set up a constraint associated with an index. Return the new constraint's
* address.
*
* heapRelation: table owning the index (must be suitably locked by caller)
* indexRelationId: OID of the index
@ -2101,7 +2106,7 @@ void index_concurrently_part_swap(Oid newIndexPartId, Oid oldIndexPartId, const
* on table's columns
* allow_system_table_mods: allow table to be a system catalog
*/
void index_constraint_create(Relation heapRelation, Oid indexRelationId, IndexInfo* indexInfo,
ObjectAddress index_constraint_create(Relation heapRelation, Oid indexRelationId, IndexInfo* indexInfo,
const char* constraintName, char constraintType, bool deferrable, bool initdeferred, bool mark_as_primary,
bool update_pgindex, bool remove_old_dependencies, bool allow_system_table_mods)
{
@ -2280,6 +2285,7 @@ void index_constraint_create(Relation heapRelation, Oid indexRelationId, IndexIn
heap_freetuple(indexTuple);
heap_close(pg_index, RowExclusiveLock);
}
return referenced;
}
#ifdef ENABLE_MOT

View File

@ -158,3 +158,78 @@ void CatalogUpdateIndexes(Relation heapRel, HeapTuple heapTuple)
CatalogIndexInsert(indstate, heapTuple);
CatalogCloseIndexes(indstate);
}
/*
* CatalogTupleUpdate - do heap and indexing work for updating a catalog tuple
*
* Update the tuple identified by "otid", replacing it with the data in "tup".
*
* This is a convenience routine for the common case of updating a single
* tuple in a system catalog; it updates one heap tuple, keeping indexes
* current. Avoid using it for multiple tuples, since opening the indexes
* and building the index info structures is moderately expensive.
* (Use CatalogTupleUpdateWithInfo in such cases.)
*/
void
CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
{
CatalogIndexState indstate;
indstate = CatalogOpenIndexes(heapRel);
simple_heap_update(heapRel, otid, tup);
CatalogIndexInsert(indstate, tup);
CatalogCloseIndexes(indstate);
}
/*
* CatalogTupleInsert - do heap and indexing work for a new catalog tuple
*
* Insert the tuple data in "tup" into the specified catalog relation.
* The Oid of the inserted tuple is returned.
*
* This is a convenience routine for the common case of inserting a single
* tuple in a system catalog; it inserts a new heap tuple, keeping indexes
* current. Avoid using it for multiple tuples, since opening the indexes
* and building the index info structures is moderately expensive.
* (Use CatalogTupleInsertWithInfo in such cases.)
*/
Oid
CatalogTupleInsert(Relation heapRel, HeapTuple tup)
{
CatalogIndexState indstate;
Oid oid;
indstate = CatalogOpenIndexes(heapRel);
oid = simple_heap_insert(heapRel, tup);
CatalogIndexInsert(indstate, tup);
CatalogCloseIndexes(indstate);
return oid;
}
/*
* CatalogTupleDelete - do heap and indexing work for deleting a catalog tuple
*
* Delete the tuple identified by "tid" in the specified catalog.
*
* With Postgres heaps, there is no index work to do at deletion time;
* cleanup will be done later by VACUUM. However, callers of this function
* shouldn't have to know that; we'd like a uniform abstraction for all
* catalog tuple changes. Hence, provide this currently-trivial wrapper.
*
* The abstraction is a bit leaky in that we don't provide an optimized
* CatalogTupleDeleteWithInfo version, because there is currently nothing to
* optimize. If we ever need that, rather than touching a lot of call sites,
* it might be better to do something about caching CatalogIndexState.
*/
void
CatalogTupleDelete(Relation heapRel, ItemPointer tid)
{
simple_heap_delete(heapRel, tid);
}

View File

@ -4580,7 +4580,7 @@ static void InitTempTableNamespace(void)
proutility_cxt.readOnlyTree = false;
proutility_cxt.params = NULL;
proutility_cxt.is_top_level = false;
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL);
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL, PROCESS_UTILITY_GENERATED);
if (IS_PGXC_COORDINATOR)
if (PoolManagerSetCommand(POOL_CMD_TEMP, namespaceName) < 0)
@ -4640,7 +4640,7 @@ static void InitTempTableNamespace(void)
proutility_cxt.readOnlyTree = false;
proutility_cxt.params = NULL;
proutility_cxt.is_top_level = false;
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL);
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL, PROCESS_UTILITY_GENERATED);
/* Advance command counter to make namespace visible */
CommandCounterIncrement();
@ -5493,7 +5493,7 @@ dropExistTempNamespace(char *namespaceName)
proutility_cxt.readOnlyTree = false;
proutility_cxt.params = NULL;
proutility_cxt.is_top_level = false;
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL);
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL, PROCESS_UTILITY_GENERATED);
CommandCounterIncrement();
}

File diff suppressed because it is too large Load Diff

View File

@ -4692,5 +4692,5 @@ CREATE OR REPLACE VIEW DBE_PERF.local_active_session AS
tlevel, smpid, userid, application_name, client_addr, client_hostname, client_port, query_id, unique_query_id,
user_id, cn_id, unique_query, locktag, lockmode, block_sessionid, final_block_sessionid, wait_status, global_sessionid, xact_start_time, query_start_time, state FROM tt
WHERE level = (SELECT pg_catalog.MAX(level) FROM tt t1 WHERE t1.sampleid = tt.sampleid AND t1.sessionid = tt.sessionid);
grant select on all tables in schema dbe_perf to public;

View File

@ -99,7 +99,7 @@ void CheckAggregateCreatePrivilege(Oid aggNamespace, const char* aggName)
* AggregateCreate
* aggKind, aggregation function kind, 'n' for normal aggregation, 'o' for ordered set aggregation.
*/
void AggregateCreate(const char* aggName, Oid aggNamespace, char aggKind, Oid* aggArgTypes, int numArgs,
ObjectAddress AggregateCreate(const char* aggName, Oid aggNamespace, char aggKind, Oid* aggArgTypes, int numArgs,
List* aggtransfnName,
#ifdef PGXC
List* aggcollectfnName,
@ -345,7 +345,7 @@ void AggregateCreate(const char* aggName, Oid aggNamespace, char aggKind, Oid* a
* Fenced mode is not supportted for create aggregate, so set false for
* argument fenced.
*/
procOid = ProcedureCreate(aggName,
myself = ProcedureCreate(aggName,
aggNamespace,
InvalidOid,
false, /* A db compatible*/
@ -379,7 +379,7 @@ void AggregateCreate(const char* aggName, Oid aggNamespace, char aggKind, Oid* a
false,
false,
NULL); /* default value for proisprocedure */
procOid = myself.objectId;
/*
* Okay to create the pg_aggregate entry.
*/
@ -461,6 +461,7 @@ void AggregateCreate(const char* aggName, Oid aggNamespace, char aggKind, Oid* a
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
return myself;
}
/*

View File

@ -37,7 +37,7 @@
*
* Add a new tuple to pg_conversion.
*/
Oid ConversionCreate(const char* conname, Oid connamespace, Oid conowner, int32 conforencoding, int32 contoencoding,
ObjectAddress ConversionCreate(const char* conname, Oid connamespace, Oid conowner, int32 conforencoding, int32 contoencoding,
Oid conproc, bool def)
{
int i;
@ -128,7 +128,7 @@ Oid ConversionCreate(const char* conname, Oid connamespace, Oid conowner, int32
heap_freetuple_ext(tup);
heap_close(rel, RowExclusiveLock);
return oid;
return myself;
}
/*

View File

@ -127,7 +127,7 @@ void LargeObjectDrop(Oid loid)
*
* Implementation of ALTER LARGE OBJECT statement
*/
void LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
ObjectAddress LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
{
Form_pg_largeobject_metadata form_lo_meta;
Relation pg_lo_meta;
@ -135,6 +135,8 @@ void LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
SysScanDesc scan;
HeapTuple oldtup;
HeapTuple newtup;
Oid loID;
ObjectAddress address;
pg_lo_meta = heap_open(LargeObjectMetadataRelationId, RowExclusiveLock);
@ -146,6 +148,7 @@ void LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
if (!HeapTupleIsValid(oldtup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("large object %u does not exist", loid)));
loID = HeapTupleGetOid(oldtup);
form_lo_meta = (Form_pg_largeobject_metadata)GETSTRUCT(oldtup);
if (form_lo_meta->lomowner != newOwnerId) {
Datum values[Natts_pg_largeobject_metadata];
@ -206,6 +209,8 @@ void LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
systable_endscan(scan);
heap_close(pg_lo_meta, RowExclusiveLock);
ObjectAddressSet(address, LargeObjectRelationId, loID);
return address;
}
/*

View File

@ -47,7 +47,7 @@ static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
static Oid get_other_operator(List* otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char* operatorName,
Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, bool isCommutator);
static void makeOperatorDependencies(HeapTuple tuple, bool isUpdate);
static ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate);
/*
* Check whether a proposed operator name is legal
@ -289,7 +289,7 @@ static Oid OperatorShellMake(const char* operatorName, Oid operatorNamespace, Oi
* Forward declaration is used only for this purpose, it is
* not available to the user as it is for type definition.
*/
void OperatorCreate(const char* operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId,
ObjectAddress OperatorCreate(const char* operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId,
List* commutatorName, List* negatorName, Oid restrictionId, Oid joinId, bool canMerge, bool canHash)
{
Relation pg_operator_desc;
@ -307,6 +307,8 @@ void OperatorCreate(const char* operatorName, Oid operatorNamespace, Oid leftTyp
int i;
Oid oprowner = InvalidOid;
bool isUpdate = false;
ObjectAddress address;
/*
* isalter is true, change the owner of the objects as the owner of the
* namespace, if the owner of the namespce has the same name as the namescpe
@ -476,7 +478,7 @@ void OperatorCreate(const char* operatorName, Oid operatorNamespace, Oid leftTyp
CatalogUpdateIndexes(pg_operator_desc, tup);
/* Add dependencies for the entry */
makeOperatorDependencies(tup, isUpdate);
address = makeOperatorDependencies(tup, isUpdate);
/* Post creation hook for new operator */
InvokeObjectAccessHook(OAT_POST_CREATE, OperatorRelationId, operatorObjectId, 0, NULL);
@ -499,6 +501,7 @@ void OperatorCreate(const char* operatorName, Oid operatorNamespace, Oid leftTyp
if (OidIsValid(commutatorId) || OidIsValid(negatorId))
OperatorUpd(operatorObjectId, commutatorId, negatorId);
return address;
}
/*
@ -682,7 +685,7 @@ static void OperatorUpd(Oid baseId, Oid commId, Oid negId)
* NB: the OidIsValid tests in this routine are necessary, in case
* the given operator is a shell.
*/
static void makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
static ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
{
Form_pg_operator oper = (Form_pg_operator)GETSTRUCT(tuple);
ObjectAddress myself, referenced;
@ -770,4 +773,5 @@ static void makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
/* Dependency on extension */
recordDependencyOnCurrentExtension(&myself, isUpdate);
return myself;
}

View File

@ -1037,7 +1037,7 @@ static bool user_define_func_check(Oid languageId, const char* probin, char** ab
* not "ArrayType *", to avoid importing array.h into pg_proc_fn.h.
* ----------------------------------------------------------------
*/
Oid ProcedureCreate(const char* procedureName, Oid procNamespace, Oid propackageid, bool isOraStyle, bool replace, bool returnsSet,
ObjectAddress ProcedureCreate(const char* procedureName, Oid procNamespace, Oid propackageid, bool isOraStyle, bool replace, bool returnsSet,
Oid returnType, Oid proowner, Oid languageObjectId, Oid languageValidator, const char* prosrc, const char* probin,
bool isAgg, bool isWindowFunc, bool security_definer, bool isLeakProof, bool isStrict, char volatility,
oidvector* parameterTypes, Datum allParameterTypes, Datum parameterModes, Datum parameterNames,
@ -1783,7 +1783,7 @@ Oid ProcedureCreate(const char* procedureName, Oid procNamespace, Oid propackage
}
pfree_ext(final_file_name);
return retval;
return myself;
}
/*

View File

@ -29,6 +29,7 @@
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
@ -49,6 +50,7 @@
#include "commands/collationcmds.h"
#include "commands/conversioncmds.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/publicationcmds.h"
@ -1397,6 +1399,10 @@ void shdepReassignOwned(List* roleids, Oid newrole)
AlterForeignDataWrapperOwner_oid(sdepForm->objid, newrole);
break;
case EventTriggerRelationId:
AlterEventTriggerOwner_oid(sdepForm->objid, newrole);
break;
case ExtensionRelationId:
AlterExtensionOwner_oid(sdepForm->objid, newrole);
break;

View File

@ -310,12 +310,13 @@ static void SynonymDrop(Oid synNamespace, char* synName, DropBehavior behavior,
/*
* ALTER Synonym name OWNER TO newowner
*/
void AlterSynonymOwner(List* name, Oid newOwnerId)
ObjectAddress AlterSynonymOwner(List* name, Oid newOwnerId)
{
HeapTuple tuple = NULL;
Relation rel = NULL;
Oid synNamespace;
Oid synNamespace, synOid;
char* synName = NULL;
ObjectAddress address;
/* Convert list of synonym names to a synName and a synNamespace. */
synNamespace = QualifiedNameGetCreationNamespace(name, &synName);
@ -328,6 +329,7 @@ void AlterSynonymOwner(List* name, Oid newOwnerId)
heap_close(rel, RowExclusiveLock);
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("synonym \"%s\" does not exist", synName)));
}
synOid = HeapTupleGetOid(tuple);
Form_pg_synonym synForm = (Form_pg_synonym)GETSTRUCT(tuple);
/*
@ -361,11 +363,13 @@ void AlterSynonymOwner(List* name, Oid newOwnerId)
CatalogUpdateIndexes(rel, tuple);
/* Update owner dependency reference. */
changeDependencyOnOwner(PgSynonymRelationId, HeapTupleGetOid(tuple), newOwnerId);
changeDependencyOnOwner(PgSynonymRelationId, synOid, newOwnerId);
}
heap_freetuple_ext(tuple);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, PgSynonymRelationId, synOid);
return address;
}
/*

View File

@ -51,7 +51,7 @@
* with correct ones, and "typisdefined" will be set to true.
* ----------------------------------------------------------------
*/
Oid TypeShellMake(const char* typname, Oid typeNamespace, Oid ownerId)
ObjectAddress TypeShellMake(const char* typname, Oid typeNamespace, Oid ownerId)
{
Relation pg_type_desc;
TupleDesc tupDesc;
@ -61,6 +61,7 @@ Oid TypeShellMake(const char* typname, Oid typeNamespace, Oid ownerId)
bool nulls[Natts_pg_type];
Oid typoid;
NameData name;
ObjectAddress address;
Assert(PointerIsValid(typname));
@ -166,6 +167,7 @@ Oid TypeShellMake(const char* typname, Oid typeNamespace, Oid ownerId)
/* Post creation hook for new shell type */
InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typoid, 0, NULL);
ObjectAddressSet(address, TypeRelationId, typoid);
/*
* clean up and return the type-oid
@ -173,7 +175,7 @@ Oid TypeShellMake(const char* typname, Oid typeNamespace, Oid ownerId)
heap_freetuple_ext(tup);
heap_close(pg_type_desc, RowExclusiveLock);
return typoid;
return address;
}
/* ----------------------------------------------------------------
@ -186,7 +188,7 @@ Oid TypeShellMake(const char* typname, Oid typeNamespace, Oid ownerId)
* use exactly that OID.
* ----------------------------------------------------------------
*/
Oid TypeCreate(Oid newTypeOid, const char* typname, Oid typeNamespace, Oid relationOid, /* only for relation rowtypes */
ObjectAddress TypeCreate(Oid newTypeOid, const char* typname, Oid typeNamespace, Oid relationOid, /* only for relation rowtypes */
char relationKind, /* ditto */
Oid ownerId, int16 internalSize, char typeType, char typeCategory, bool typePreferred, char typDelim,
Oid inputProcedure, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, Oid typmodinProcedure,
@ -206,6 +208,7 @@ Oid TypeCreate(Oid newTypeOid, const char* typname, Oid typeNamespace, Oid relat
NameData name;
int i;
Acl* typacl = NULL;
ObjectAddress address;
/*
* We assume that the caller validated the arguments individually, but did
@ -454,13 +457,13 @@ Oid TypeCreate(Oid newTypeOid, const char* typname, Oid typeNamespace, Oid relat
/* Post creation hook for new type */
InvokeObjectAccessHook(OAT_POST_CREATE, TypeRelationId, typeObjectId, 0, NULL);
ObjectAddressSet(address, TypeRelationId, typeObjectId);
/*
* finish up
*/
heap_close(pg_type_desc, RowExclusiveLock);
return typeObjectId;
return address;
}
/*

View File

@ -689,6 +689,19 @@ FROM
WHERE
l.objsubid = 0
UNION ALL
SELECT
l.objoid, l.classoid, l.objsubid,
'event trigger'::text AS objtype,
NULL::oid AS objnamespace,
quote_ident(evt.evtname) AS objname,
l.provider, l.label
FROM
pg_seclabel l
JOIN pg_event_trigger evt ON l.classoid = evt.tableoid
AND l.objoid = evt.oid
WHERE
l.objsubid = 0
UNION ALL
SELECT
l.objoid, l.classoid, 0::int4 AS objsubid,
'database'::text AS objtype,

View File

@ -754,7 +754,7 @@ static void InitLobTempToastNamespace(void)
proutility_cxt.readOnlyTree = false;
proutility_cxt.params = NULL;
proutility_cxt.is_top_level = false;
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL);
ProcessUtility(&proutility_cxt, None_Receiver, false, NULL, PROCESS_UTILITY_GENERATED);
/* Advance command counter to make namespace visible */
CommandCounterIncrement();

View File

@ -109,6 +109,164 @@ void appendStringInfo(StringInfo str, const char* fmt, ...)
}
}
/*
* pvsnprintf
*
* Attempt to format text data under the control of fmt (an sprintf-style
* format string) and insert it into buf (which has length len, len > 0).
*
* If successful, return the number of bytes emitted, not counting the
* trailing zero byte. This will always be strictly less than len.
*
* If there's not enough space in buf, return an estimate of the buffer size
* needed to succeed (this *must* be more than the given len, else callers
* might loop infinitely).
*
* Other error cases do not return, but exit via elog(ERROR) or exit().
* Hence, this shouldn't be used inside libpq.
*
* This function exists mainly to centralize our workarounds for
* non-C99-compliant vsnprintf implementations. Generally, any call that
* pays any attention to the return value should go through here rather
* than calling snprintf or vsnprintf directly.
*
* Note that the semantics of the return value are not exactly C99's.
* First, we don't promise that the estimated buffer size is exactly right;
* callers must be prepared to loop multiple times to get the right size.
* Second, we return the recommended buffer size, not one less than that;
* this lets overflow concerns be handled here rather than in the callers.
*/
static size_t
pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
static size_t
pvsnprintf(char *buf, size_t len, const char *fmt, va_list args)
{
int nprinted;
Assert(len > 0);
errno = 0;
/*
* Assert check here is to catch buggy vsnprintf that overruns the
* specified buffer length. Solaris 7 in 64-bit mode is an example of a
* platform with such a bug.
*/
#ifdef USE_ASSERT_CHECKING
buf[len - 1] = '\0';
#endif
nprinted = vsnprintf(buf, len, fmt, args);
Assert(buf[len - 1] == '\0');
/*
* If vsnprintf reports an error other than ENOMEM, fail. The possible
* causes of this are not user-facing errors, so elog should be enough.
*/
if (nprinted < 0 && errno != 0 && errno != ENOMEM) {
#ifndef FRONTEND
elog(ERROR, "vsnprintf failed: %m with format string \"%s\"", fmt);
#else
fprintf(stderr, "vsnprintf failed: %s with format string \"%s\"\n",
strerror(errno), fmt);
exit(EXIT_FAILURE);
#endif
}
/*
* Note: some versions of vsnprintf return the number of chars actually
* stored, not the total space needed as C99 specifies. And at least one
* returns -1 on failure. Be conservative about believing whether the
* print worked.
*/
if (nprinted >= 0 && (size_t) nprinted < len - 1) {
/* Success. Note nprinted does not include trailing null. */
return (size_t) nprinted;
}
if (nprinted >= 0 && (size_t) nprinted > len) {
/*
* This appears to be a C99-compliant vsnprintf, so believe its
* estimate of the required space. (If it's wrong, the logic will
* still work, but we may loop multiple times.) Note that the space
* needed should be only nprinted+1 bytes, but we'd better allocate
* one more than that so that the test above will succeed next time.
*
* In the corner case where the required space just barely overflows,
* fall through so that we'll error out below (possibly after
* looping).
*/
if ((size_t) nprinted <= MaxAllocSize - 2)
return nprinted + 2;
}
/*
* Buffer overrun, and we don't know how much space is needed. Estimate
* twice the previous buffer size, but not more than MaxAllocSize; if we
* are already at MaxAllocSize, choke. Note we use this palloc-oriented
* overflow limit even when in frontend.
*/
if (len >= MaxAllocSize) {
#ifndef FRONTEND
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("out of memory")));
#else
fprintf(stderr, _("out of memory\n"));
exit(EXIT_FAILURE);
#endif
}
if (len >= MaxAllocSize / 2)
return MaxAllocSize;
return len * 2;
}
/*
* psprintf
*
* Format text data under the control of fmt (an sprintf-style format string)
* and return it in an allocated-on-demand buffer. The buffer is allocated
* with palloc in the backend, or malloc in frontend builds. Caller is
* responsible to free the buffer when no longer needed, if appropriate.
*
* Errors are not returned to the caller, but are reported via elog(ERROR)
* in the backend, or printf-to-stderr-and-exit() in frontend builds.
* One should therefore think twice about using this in libpq.
*/
char *psprintf(const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
char *
psprintf(const char *fmt,...)
{
size_t len = 128; /* initial assumption about buffer size */
for (;;) {
char *result;
va_list args;
size_t newlen;
/*
|* Allocate result buffer. Note that in frontend this maps to malloc
|* with exit-on-error.
|*/
result = (char *) palloc(len);
/* Try to format the data. */
va_start(args, fmt);
newlen = pvsnprintf(result, len, fmt, args);
va_end(args);
if (newlen < len)
return result; /* success */
/* Release buffer and loop around to try again with larger len. */
pfree(result);
len = newlen;
}
}
/*
* appendStringInfoVA
*

View File

@ -6232,6 +6232,30 @@ static CreateTrigStmt* _copyCreateTrigStmt(const CreateTrigStmt* from)
return newnode;
}
static CreateEventTrigStmt *
_copyCreateEventTrigStmt(const CreateEventTrigStmt *from)
{
CreateEventTrigStmt *newnode = makeNode(CreateEventTrigStmt);
COPY_STRING_FIELD(trigname);
COPY_SCALAR_FIELD(eventname);
COPY_NODE_FIELD(whenclause);
COPY_NODE_FIELD(funcname);
return newnode;
}
static AlterEventTrigStmt *
_copyAlterEventTrigStmt(const AlterEventTrigStmt *from)
{
AlterEventTrigStmt *newnode = makeNode(AlterEventTrigStmt);
COPY_STRING_FIELD(trigname);
COPY_SCALAR_FIELD(tgenabled);
return newnode;
}
static CreatePLangStmt* _copyCreatePLangStmt(const CreatePLangStmt* from)
{
CreatePLangStmt* newnode = makeNode(CreatePLangStmt);
@ -6439,6 +6463,7 @@ static AlterTSConfigurationStmt* _copyAlterTSConfigurationStmt(const AlterTSConf
{
AlterTSConfigurationStmt* newnode = makeNode(AlterTSConfigurationStmt);
COPY_SCALAR_FIELD(kind);
COPY_NODE_FIELD(cfgname);
COPY_NODE_FIELD(tokentype);
COPY_NODE_FIELD(dicts);
@ -8119,6 +8144,12 @@ void* copyObject(const void* from)
case T_CreateTrigStmt:
retval = _copyCreateTrigStmt((CreateTrigStmt*)from);
break;
case T_CreateEventTrigStmt:
retval = _copyCreateEventTrigStmt((CreateEventTrigStmt*)from);
break;
case T_AlterEventTrigStmt:
retval = _copyAlterEventTrigStmt((AlterEventTrigStmt*)from);
break;
case T_CreatePLangStmt:
retval = _copyCreatePLangStmt((CreatePLangStmt*)from);
break;

View File

@ -2273,6 +2273,26 @@ static bool _equalCreateTrigStmt(const CreateTrigStmt* a, const CreateTrigStmt*
return true;
}
static bool
_equalCreateEventTrigStmt(const CreateEventTrigStmt *a, const CreateEventTrigStmt *b)
{
COMPARE_STRING_FIELD(trigname);
COMPARE_SCALAR_FIELD(eventname);
COMPARE_NODE_FIELD(funcname);
COMPARE_NODE_FIELD(whenclause);
return true;
}
static bool
_equalAlterEventTrigStmt(const AlterEventTrigStmt *a, const AlterEventTrigStmt *b)
{
COMPARE_STRING_FIELD(trigname);
COMPARE_SCALAR_FIELD(tgenabled);
return true;
}
static bool _equalCreatePLangStmt(const CreatePLangStmt* a, const CreatePLangStmt* b)
{
COMPARE_SCALAR_FIELD(replace);
@ -2441,6 +2461,7 @@ static bool _equalAlterTSDictionaryStmt(const AlterTSDictionaryStmt* a, const Al
static bool _equalAlterTSConfigurationStmt(const AlterTSConfigurationStmt* a, const AlterTSConfigurationStmt* b)
{
COMPARE_SCALAR_FIELD(kind);
COMPARE_NODE_FIELD(cfgname);
COMPARE_NODE_FIELD(tokentype);
COMPARE_NODE_FIELD(dicts);
@ -4077,6 +4098,12 @@ bool equal(const void* a, const void* b)
case T_CreateTrigStmt:
retval = _equalCreateTrigStmt((CreateTrigStmt*)a, (CreateTrigStmt*)b);
break;
case T_CreateEventTrigStmt:
retval = _equalCreateEventTrigStmt((CreateEventTrigStmt*)a, (CreateEventTrigStmt*)b);
break;
case T_AlterEventTrigStmt:
retval = _equalAlterEventTrigStmt((AlterEventTrigStmt*)a, (AlterEventTrigStmt*)b);
break;
case T_CreatePLangStmt:
retval = _equalCreatePLangStmt((CreatePLangStmt*)a, (CreatePLangStmt*)b);
break;

View File

@ -60,6 +60,7 @@
#include "catalog/gs_package.h"
#include "catalog/pg_trigger.h"
#include "commands/defrem.h"
#include "commands/trigger.h"
#ifdef ENABLE_MULTIPLE_NODES
#include "distribute_core.h"
#endif
@ -340,6 +341,7 @@ static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStm
}
%type <node> stmt schema_stmt
AlterEventTrigStmt
AlterDatabaseStmt AlterDatabaseSetStmt AlterDataSourceStmt AlterDomainStmt AlterEnumStmt AlterEventStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterSchemaStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
@ -355,7 +357,7 @@ static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStm
CreateSchemaStmt CreateSeqStmt CreateStmt CreateStreamStmt CreateTableSpaceStmt
CreateFdwStmt CreateForeignServerStmt CreateForeignTableStmt
CreateDataSourceStmt
CreateAssertStmt CreateTrigStmt
CreateAssertStmt CreateTrigStmt CreateEventTrigStmt
CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreateRlsPolicyStmt CreateSynonymStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt DropEventStmt ShowEventStmt
@ -453,6 +455,9 @@ static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStm
%type <list> TriggerEvents TriggerOneEvent
%type <value> TriggerFuncArg
%type <node> TriggerWhen
%type <list> event_trigger_when_list event_trigger_value_list
%type <defelt> event_trigger_when_item
%type <chr> enable_trigger
%type <str> copy_file_name definer_opt user ev_body ev_where_body event_where_clause
database_name access_method_clause access_method access_method_clause_without_keyword attr_name
@ -501,7 +506,7 @@ static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStm
opt_include opt_c_include index_including_params
sort_clause opt_sort_clause sortby_list index_params constraint_params
name_list UserIdList from_clause from_list opt_array_bounds
qualified_name_list any_name any_name_list collate_name
qualified_name_list any_name any_name_list type_name_list collate_name
any_operator expr_list attrs callfunc_args
target_list insert_column_list set_target_list rename_clause_list rename_clause
set_clause_list set_clause multiple_set_clause
@ -960,6 +965,7 @@ static void setDelimiterName(core_yyscan_t yyscanner, char*input, VariableSetStm
END_OF_INPUT
END_OF_INPUT_COLON
END_OF_PROC
EVENT_TRIGGER
NOT_IN NOT_BETWEEN NOT_LIKE NOT_ILIKE NOT_SIMILAR
FORCE_INDEX USE_INDEX
@ -1140,6 +1146,7 @@ stmt :
| AlterDefaultPrivilegesStmt
| AlterDomainStmt
| AlterEnumStmt
| AlterEventTrigStmt
| AlterExtensionStmt
| AlterExtensionContentsStmt
| AlterFdwStmt
@ -1191,6 +1198,7 @@ stmt :
| CreateConversionStmt
| CreateDomainStmt
| CreateDirectoryStmt
| CreateEventTrigStmt
| CreateExtensionStmt
| CreateFdwStmt
| CreateForeignServerStmt
@ -10229,6 +10237,21 @@ AlterExtensionContentsStmt:
n->objargs = $7;
$$ = (Node *)n;
}
| ALTER EXTENSION name add_drop EVENT_TRIGGER name
{
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_EVENT_TRIGGER;
n->objname = list_make1(makeString($6));
$$ = (Node *)n;
}
| ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')'
{
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
@ -10301,8 +10324,7 @@ AlterExtensionContentsStmt:
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_OPCLASS;
n->objname = $7;
n->objargs = list_make1(makeString($9));
n->objname = lcons(makeString($9), $7);
$$ = (Node *)n;
}
| ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING access_method
@ -10311,8 +10333,7 @@ AlterExtensionContentsStmt:
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_OPFAMILY;
n->objname = $7;
n->objargs = list_make1(makeString($9));
n->objname = lcons(makeString($9), $7);
$$ = (Node *)n;
}
| ALTER EXTENSION name add_drop SCHEMA name
@ -11935,6 +11956,84 @@ ConstraintAttributeElem:
;
CreateEventTrigStmt:
CREATE EVENT_TRIGGER name ON ColLabel
EXECUTE PROCEDURE func_name '(' ')'
{
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
n->trigname = $3;
n->eventname = $5;
n->whenclause = NULL;
n->funcname = $8;
$$ = (Node *)n;
}
| CREATE EVENT_TRIGGER name ON ColLabel
WHEN event_trigger_when_list
EXECUTE PROCEDURE func_name '(' ')'
{
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
CreateEventTrigStmt *n = makeNode(CreateEventTrigStmt);
n->trigname = $3;
n->eventname = $5;
n->whenclause = $7;
n->funcname = $10;
$$ = (Node *)n;
}
;
event_trigger_when_list:
event_trigger_when_item
{ $$ = list_make1($1); }
| event_trigger_when_list AND event_trigger_when_item
{ $$ = lappend($1, $3); }
;
event_trigger_when_item:
ColId IN_P '(' event_trigger_value_list ')'
{ $$ = makeDefElem($1, (Node *) $4); }
;
event_trigger_value_list:
SCONST
{ $$ = list_make1(makeString($1)); }
| event_trigger_value_list ',' SCONST
{ $$ = lappend($1, makeString($3)); }
;
AlterEventTrigStmt:
ALTER EVENT_TRIGGER name enable_trigger
{
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
AlterEventTrigStmt *n = makeNode(AlterEventTrigStmt);
n->trigname = $3;
n->tgenabled = $4;
$$ = (Node *) n;
}
;
enable_trigger:
ENABLE_P { $$ = TRIGGER_FIRES_ON_ORIGIN; }
| ENABLE_P REPLICA { $$ = TRIGGER_FIRES_ON_REPLICA; }
| ENABLE_P ALWAYS { $$ = TRIGGER_FIRES_ALWAYS; }
| DISABLE_P { $$ = TRIGGER_DISABLED; }
;
DropTrigStmt:
DROP TRIGGER name ON any_name opt_drop_behavior
{
@ -12523,8 +12622,7 @@ DropOpClassStmt:
DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->objects = list_make1($4);
n->arguments = list_make1(list_make1(makeString($6)));
n->objects = list_make1(lcons(makeString($6), $4));
n->removeType = OBJECT_OPCLASS;
n->behavior = $7;
n->missing_ok = false;
@ -12534,8 +12632,7 @@ DropOpClassStmt:
| DROP OPERATOR CLASS IF_P EXISTS any_name USING access_method opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->objects = list_make1($6);
n->arguments = list_make1(list_make1(makeString($8)));
n->objects = list_make1(lcons(makeString($8), $6));
n->removeType = OBJECT_OPCLASS;
n->behavior = $9;
n->missing_ok = true;
@ -12548,8 +12645,7 @@ DropOpFamilyStmt:
DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->objects = list_make1($4);
n->arguments = list_make1(list_make1(makeString($6)));
n->objects = list_make1(lcons(makeString($6), $4));
n->removeType = OBJECT_OPFAMILY;
n->behavior = $7;
n->missing_ok = false;
@ -12560,7 +12656,7 @@ DropOpFamilyStmt:
{
DropStmt *n = makeNode(DropStmt);
n->objects = list_make1($6);
n->arguments = list_make1(list_make1(makeString($8)));
n->objects = list_make1(lcons(makeString($8), $6));
n->removeType = OBJECT_OPFAMILY;
n->behavior = $9;
n->missing_ok = true;
@ -12617,6 +12713,12 @@ DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior opt_purge
n->behavior = $6;
n->concurrent = false;
n->purge = $7;
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT && n->removeType==OBJECT_EVENT_TRIGGER)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
if (n->removeType != OBJECT_TABLE && n->purge) {
const char* message = "PURGE clause only allowed in \"DROP TABLE\" statement";
InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
@ -12638,6 +12740,12 @@ DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior opt_purge
n->behavior = $4;
n->concurrent = false;
n->purge = $5;
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT && n->removeType==OBJECT_EVENT_TRIGGER)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
if (n->removeType != OBJECT_TABLE && n->purge) {
const char* message = "PURGE clause only allowed in \"DROP TABLE\" statement";
InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
@ -12648,6 +12756,46 @@ DropStmt: DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior opt_purge
}
$$ = (Node *)n;
}
| DROP TYPE_P type_name_list opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->removeType = OBJECT_TYPE;
n->missing_ok = FALSE;
n->objects = $3;
n->behavior = $4;
n->concurrent = false;
$$ = (Node *) n;
}
| DROP TYPE_P IF_P EXISTS type_name_list opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->removeType = OBJECT_TYPE;
n->missing_ok = TRUE;
n->objects = $5;
n->behavior = $6;
n->concurrent = false;
$$ = (Node *) n;
}
| DROP DOMAIN_P type_name_list opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->removeType = OBJECT_DOMAIN;
n->missing_ok = FALSE;
n->objects = $3;
n->behavior = $4;
n->concurrent = false;
$$ = (Node *) n;
}
| DROP DOMAIN_P IF_P EXISTS type_name_list opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
n->removeType = OBJECT_DOMAIN;
n->missing_ok = TRUE;
n->objects = $5;
n->behavior = $6;
n->concurrent = false;
$$ = (Node *) n;
}
| DROP INDEX CONCURRENTLY any_name_list opt_drop_behavior
{
DropStmt *n = makeNode(DropStmt);
@ -12687,11 +12835,10 @@ drop_type: TABLE { $$ = OBJECT_TABLE; }
| MATERIALIZED VIEW { $$ = OBJECT_MATVIEW; }
| INDEX { $$ = OBJECT_INDEX; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| TYPE_P { $$ = OBJECT_TYPE; }
| DOMAIN_P { $$ = OBJECT_DOMAIN; }
| COLLATION { $$ = OBJECT_COLLATION; }
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
| EVENT_TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| EXTENSION { $$ = OBJECT_EXTENSION; }
| TEXT_P SEARCH PARSER { $$ = OBJECT_TSPARSER; }
| TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; }
@ -12707,6 +12854,10 @@ collate_name: any_name { $$ = $1; }
| Sconst { $$ = list_make1(makeString($1)); }
;
type_name_list:
Typename { $$ = list_make1(list_make1($1)); }
| type_name_list ',' Typename { $$ = lappend($1, list_make1($3)); }
any_name_list:
any_name { $$ = list_make1($1); }
| any_name_list ',' any_name { $$ = lappend($1, $3); }
@ -12759,7 +12910,7 @@ opt_restart_seqs:
* EXTENSION | ROLE | TEXT SEARCH PARSER |
* TEXT SEARCH DICTIONARY | TEXT SEARCH TEMPLATE |
* TEXT SEARCH CONFIGURATION | FOREIGN TABLE |
* FOREIGN DATA WRAPPER | SERVER | EVENT TRIGGER |
* FOREIGN DATA WRAPPER | SERVER | EVENT_TRIGGER |
* MATERIALIZED VIEW | SNAPSHOT] <objname> |
* AGGREGATE <aggname> (arg1, ...) |
* FUNCTION <funcname> (arg1, arg2, ...) |
@ -12779,6 +12930,12 @@ CommentStmt:
n->objname = $4;
n->objargs = NIL;
n->comment = $6;
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT && n->objtype==OBJECT_EVENT_TRIGGER)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
$$ = (Node *) n;
}
| COMMENT ON AGGREGATE func_name aggr_args IS comment_text
@ -12811,12 +12968,26 @@ CommentStmt:
| COMMENT ON CONSTRAINT name ON any_name IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
n->objtype = OBJECT_CONSTRAINT;
n->objtype = OBJECT_TABCONSTRAINT;
n->objname = lappend($6, makeString($4));
n->objargs = NIL;
n->comment = $8;
$$ = (Node *) n;
}
| COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
n->objtype = OBJECT_DOMCONSTRAINT;
/*
* should use Typename not any_name in the production, but
* there's a shift/reduce conflict if we do that, so fix it
* up here.
*/
n->objname = list_make1(makeTypeNameFromNameList($7));
n->objargs = list_make1(makeString($4));
n->comment = $9;
$$ = (Node *) n;
}
| COMMENT ON RULE name ON any_name IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
@ -12940,6 +13111,7 @@ comment_type:
| COLLATION { $$ = OBJECT_COLLATION; }
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
| TABLESPACE { $$ = OBJECT_TABLESPACE; }
| EVENT_TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| EXTENSION { $$ = OBJECT_EXTENSION; }
| ROLE { $$ = OBJECT_ROLE; }
| USER { $$ = OBJECT_USER; }
@ -12966,13 +13138,19 @@ comment_text:
SecLabelStmt:
SECURITY LABEL opt_provider ON security_label_type any_name
IS security_label
{
{
SecLabelStmt *n = makeNode(SecLabelStmt);
n->provider = $3;
n->objtype = $5;
n->objname = $6;
n->objargs = NIL;
n->label = $8;
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT && n->objtype==OBJECT_EVENT_TRIGGER)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
$$ = (Node *) n;
}
| SECURITY LABEL opt_provider ON AGGREGATE func_name aggr_args
@ -13028,6 +13206,7 @@ opt_provider: FOR ColId_or_Sconst { $$ = $2; }
security_label_type:
COLUMN { $$ = OBJECT_COLUMN; }
| DATABASE { $$ = OBJECT_DATABASE; }
| EVENT_TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
@ -17082,11 +17261,39 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
n->newname = $8;
$$ = (Node *)n;
}
| ALTER EVENT_TRIGGER name RENAME TO name
{
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_EVENT_TRIGGER;
n->object = list_make1(makeString($3));
n->newname = $6;
$$ = (Node *)n;
}
| ALTER EVENT_TRIGGER name OWNER TO RoleId
{
if(u_sess->attr.attr_sql.sql_compatibility != PG_FORMAT)
{
ereport(errstate,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("EVENT TRIGGER is only supported in PG compatibility database")));
}
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
n->object = list_make1(makeString($3));
n->newowner = $6;
$$ = (Node *)n;
}
| ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_FDW;
n->subname = $5;
n->object = list_make1(makeString($5));
n->newname = $8;
n->missing_ok = false;
$$ = (Node *)n;
@ -17124,7 +17331,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_LANGUAGE;
n->subname = $4;
n->object = list_make1(makeString($4));
n->newname = $7;
n->missing_ok = false;
$$ = (Node *)n;
@ -17133,8 +17340,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_OPCLASS;
n->object = $4;
n->subname = $6;
n->object = lcons(makeString($6), $4);
n->newname = $9;
n->missing_ok = false;
$$ = (Node *)n;
@ -17143,8 +17349,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_OPFAMILY;
n->object = $4;
n->subname = $6;
n->object = lcons(makeString($6), $4);
n->newname = $9;
n->missing_ok = false;
$$ = (Node *)n;
@ -17191,7 +17396,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_FOREIGN_SERVER;
n->subname = $3;
n->object = list_make1(makeString($3));
n->newname = $6;
n->missing_ok = false;
$$ = (Node *)n;
@ -17446,8 +17651,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| ALTER TABLE relation_expr RENAME CONSTRAINT name TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_CONSTRAINT;
n->relationType = OBJECT_TABLE;
n->renameType = OBJECT_TABCONSTRAINT;
n->relation = $3;
n->subname = $6;
n->newname = $8;
@ -17458,8 +17662,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| ALTER TABLE IF_P EXISTS relation_expr RENAME CONSTRAINT name TO name
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_CONSTRAINT;
n->relationType = OBJECT_TABLE;
n->renameType = OBJECT_TABCONSTRAINT;
n->relation = $5;
n->subname = $8;
n->newname = $10;
@ -17805,8 +18008,7 @@ AlterObjectSchemaStmt:
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_OPCLASS;
n->object = $4;
n->addname = $6;
n->object = lcons(makeString($6), $4);
n->newschema = $9;
n->missing_ok = false;
$$ = (Node *)n;
@ -17815,8 +18017,7 @@ AlterObjectSchemaStmt:
{
AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
n->objectType = OBJECT_OPFAMILY;
n->object = $4;
n->addname = $6;
n->object = lcons(makeString($6), $4);
n->newschema = $9;
n->missing_ok = false;
$$ = (Node *)n;
@ -18087,8 +18288,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
n->object = $4;
n->addname = $6;
n->object = lcons(makeString($6), $4);
n->newowner = $9;
$$ = (Node *)n;
}
@ -18096,8 +18296,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
n->object = $4;
n->addname = $6;
n->object = lcons(makeString($6), $4);
n->newowner = $9;
$$ = (Node *)n;
}
@ -19432,6 +19631,7 @@ AlterTSConfigurationStmt:
ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list WITH any_name_list
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_ADD_MAPPING;
n->cfgname = $5;
n->tokentype = $9;
n->cfoptions = NIL;
@ -19444,6 +19644,7 @@ AlterTSConfigurationStmt:
| ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list WITH any_name_list
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN;
n->cfgname = $5;
n->tokentype = $9;
n->cfoptions = NIL;
@ -19456,6 +19657,7 @@ AlterTSConfigurationStmt:
| ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name WITH any_name
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_REPLACE_DICT;
n->cfgname = $5;
n->tokentype = NIL;
n->cfoptions = NIL;
@ -19468,6 +19670,7 @@ AlterTSConfigurationStmt:
| ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name WITH any_name
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN;
n->cfgname = $5;
n->tokentype = $9;
n->cfoptions = NIL;
@ -19480,6 +19683,7 @@ AlterTSConfigurationStmt:
| ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_DROP_MAPPING;
n->cfgname = $5;
n->tokentype = $9;
n->cfoptions = NIL;
@ -19490,6 +19694,7 @@ AlterTSConfigurationStmt:
| ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_DROP_MAPPING;
n->cfgname = $5;
n->tokentype = $11;
n->cfoptions = NIL;
@ -19500,6 +19705,7 @@ AlterTSConfigurationStmt:
| ALTER TEXT_P SEARCH CONFIGURATION any_name SET cfoptions
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN;
n->cfgname = $5;
n->tokentype = NIL;
n->cfoptions = $7;
@ -19512,6 +19718,7 @@ AlterTSConfigurationStmt:
| ALTER TEXT_P SEARCH CONFIGURATION any_name RESET cfoptions
{
AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt);
n->kind = ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN;
n->cfgname = $5;
n->tokentype = NIL;
n->cfoptions = $7;

View File

@ -1904,7 +1904,7 @@ void CheckOutParamIsConst(PLpgSQL_expr* expr)
PLpgSQL_execstate *estate = (PLpgSQL_execstate*)palloc(sizeof(PLpgSQL_execstate));
expr->func = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function));
function = expr->func;
function->fn_is_trigger = false;
function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
function->fn_input_collation = InvalidOid;
function->out_param_varno = -1; /* set up for no OUT param */
function->resolve_option = GetResolveOption();

View File

@ -891,6 +891,7 @@ static void pts_error_callback(void* arg)
void parseTypeString(const char* str, Oid* typeid_p, int32* typmod_p)
{
StringInfoData buf;
buf.data = NULL;
List* raw_parsetree_list = NIL;
SelectStmt* stmt = NULL;
ResTarget* restarget = NULL;
@ -958,10 +959,92 @@ void parseTypeString(const char* str, Oid* typeid_p, int32* typmod_p)
return;
fail:
pfree_ext(buf.data);
InsertErrorMessage("invalid type name", u_sess->plsql_cxt.plpgsql_yylloc);
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid type name \"%s\"", str)));
}
/*
* Given a string that is supposed to be a SQL-compatible type declaration,
* such as "int4" or "integer" or "character varying(32)", parse
* the string and return the result as a TypeName.
* If the string cannot be parsed as a type, an error is raised.
*/
TypeName * typeStringToTypeName(const char *str)
{
StringInfoData buf;
buf.data = NULL;
List* raw_parsetree_list = NIL;
SelectStmt* stmt = NULL;
ResTarget* restarget = NULL;
TypeCast* typecast = NULL;
TypeName* typname = NULL;
ErrorContextCallback ptserrcontext;
/* make sure we give useful error for empty input */
if (strspn(str, " \t\n\r\f") == strlen(str)) {
goto fail;
}
initStringInfo(&buf);
appendStringInfo(&buf, "SELECT NULL::%s", str);
/*
* Setup error traceback support in case of ereport() during parse
*/
ptserrcontext.callback = pts_error_callback;
ptserrcontext.arg = (void*)str;
ptserrcontext.previous = t_thrd.log_cxt.error_context_stack;
t_thrd.log_cxt.error_context_stack = &ptserrcontext;
raw_parsetree_list = raw_parser(buf.data);
t_thrd.log_cxt.error_context_stack = ptserrcontext.previous;
/*
* Make sure we got back exactly what we expected and no more; paranoia is
* justified since the string might contain anything.
*/
if (list_length(raw_parsetree_list) != 1)
goto fail;
stmt = (SelectStmt*)linitial(raw_parsetree_list);
if (stmt == NULL || !IsA(stmt, SelectStmt) || stmt->distinctClause != NIL || stmt->intoClause != NULL ||
stmt->fromClause != NIL || stmt->whereClause != NULL || stmt->groupClause != NIL ||
stmt->havingClause != NULL || stmt->windowClause != NIL || stmt->withClause != NULL ||
stmt->valuesLists != NIL || stmt->sortClause != NIL || stmt->limitOffset != NULL || stmt->limitCount != NULL ||
stmt->lockingClause != NIL || stmt->op != SETOP_NONE) {
goto fail;
}
if (list_length(stmt->targetList) != 1) {
goto fail;
}
restarget = (ResTarget*)linitial(stmt->targetList);
if (restarget == NULL || !IsA(restarget, ResTarget) || restarget->name != NULL || restarget->indirection != NIL) {
goto fail;
}
typecast = (TypeCast*)restarget->val;
if (typecast == NULL || !IsA(typecast, TypeCast) || typecast->arg == NULL || !IsA(typecast->arg, A_Const)) {
goto fail;
}
typname = typecast->typname;
if (typname == NULL || !IsA(typname, TypeName)) {
goto fail;
}
if (typname->setof) {
goto fail;
}
pfree_ext(buf.data);
return typname;
fail:
pfree_ext(buf.data);
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid type name \"%s\"", str)));
return NULL;
}
/*
* IsTypeSupportedByCStore
* Return true if the type is supported by column store

View File

@ -995,7 +995,7 @@ static bool DropSetOwnedByTable(CreateStmtContext* cxt, char *colname)
DropStmt *stmt = makeNode(DropStmt);
stmt->removeType = OBJECT_TYPE;
stmt->objects = list_make1(list_make2(makeString(nspace), makeString(typname)));
stmt->objects = list_make1(list_make1(makeTypeNameFromNameList(list_make2(makeString(nspace), makeString(typname)))));
stmt->behavior = DROP_CASCADE;
stmt->arguments = NIL;
stmt->missing_ok = true;
@ -6473,7 +6473,7 @@ Oid generateClonedIndex(Relation source_idx, Relation source_relation, char* tem
Relation heap_rel;
TupleDesc tupleDesc;
Oid source_relid = RelationGetRelid(source_idx);
Oid ret;
ObjectAddress ret;
/* get the relation that the index is created on */
heap_relid = IndexGetRelation(source_relid, false);
@ -6529,7 +6529,7 @@ Oid generateClonedIndex(Relation source_idx, Relation source_relation, char* tem
pfree_ext(attmap);
relation_close(heap_rel, AccessShareLock);
return ret;
return ret.objectId;
}
/*

View File

@ -257,6 +257,25 @@ int base_yylex(YYSTYPE* lvalp, YYLTYPE* llocp, core_yyscan_t yyscanner)
}
break;
case EVENT:
/*
* Event trigger must be reduced to one token
*/
GET_NEXT_TOKEN();
switch (next_token) {
case TRIGGER:
cur_token = EVENT_TRIGGER;
break;
default:
/* save the lookahead token for next time */
SET_LOOKAHEAD_TOKEN();
/* and back up the output info to cur_token */
lvalp->core_yystype = cur_yylval;
*llocp = cur_yylloc;
break;
}
break;
case WITH:
/*
* WITH TIME must be reduced to one token

View File

@ -891,6 +891,7 @@ static int lexescape(struct vars* v)
break;
}
Assert(NOTREACHED);
FAILW(REG_EESCAPE);
}
/*

View File

@ -94,6 +94,12 @@ char* format_type_be(Oid type_oid)
return format_type_internal(type_oid, -1, false, false);
}
char *
format_type_be_qualified(Oid type_oid)
{
return format_type_internal(type_oid, -1, false, false, true);
}
/*
* This version is for use within send PARSE message with specified
* statement/plan down to the Datanode
@ -330,9 +336,9 @@ static char* format_type_internal(
/* get namespace string if we foce to deparse namespace name */
if (include_nspname && PG_CATALOG_NAMESPACE != typeform->typnamespace)
nspname = get_namespace_name(typeform->typnamespace);
nspname = get_namespace_name_or_temp(typeform->typnamespace);
} else {
nspname = get_namespace_name(typeform->typnamespace);
nspname = get_namespace_name_or_temp(typeform->typnamespace);
}
typname = NameStr(typeform->typname);

View File

@ -1214,7 +1214,7 @@ Datum generate_series_step_int4(PG_FUNCTION_ARGS)
/* do when there is more left to send */
SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
} else
}
/* do when there is no more left */
SRF_RETURN_DONE(funcctx);
}

View File

@ -1312,7 +1312,7 @@ Datum generate_series_step_int8(PG_FUNCTION_ARGS)
/* do when there is more left to send */
SRF_RETURN_NEXT(funcctx, Int64GetDatum(result));
} else
}
/* do when there is no more left */
SRF_RETURN_DONE(funcctx);
}

View File

@ -255,6 +255,32 @@ Datum trigger_out(PG_FUNCTION_ARGS)
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* event_trigger_in - input routine for pseudo-type event_trigger.
*/
Datum
event_trigger_in(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type event_trigger")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* event_trigger_out - output routine for pseudo-type event_trigger.
*/
Datum
event_trigger_out(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot display a value of type event_trigger")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* language_handler_in - input routine for pseudo-type LANGUAGE_HANDLER.
*/
@ -446,6 +472,67 @@ Datum pg_node_tree_send(PG_FUNCTION_ARGS)
{
return textsend(fcinfo);
}
/*
* pg_ddl_command_in - input routine for type PG_DDL_COMMAND.
*
* Like pg_node_tree, pg_ddl_command isn't really a pseudotype; it's here for
* the same reasons as that one.
*/
Datum
pg_ddl_command_in(PG_FUNCTION_ARGS)
{
/*
* Disallow input of pg_ddl_command value.
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_ddl_command")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/*
* pg_ddl_command_out - output routine for type PG_DDL_COMMAND.
*
* We don't have any good way to output this type directly, so punt.
*/
Datum
pg_ddl_command_out(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot output a value of type %s", "pg_ddl_command")));
PG_RETURN_VOID();
}
/*
* pg_ddl_command_recv - binary input routine for type PG_DDL_COMMAND.
*/
Datum
pg_ddl_command_recv(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_ddl_command")));
PG_RETURN_VOID();
}
/*
* pg_ddl_command_send - binary output routine for type PG_DDL_COMMAND.
*/
Datum
pg_ddl_command_send(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot output a value of type %s", "pg_ddl_command")));
PG_RETURN_VOID();
}
/*
* anyset_in - input routine for pseudo-type ANYSET.

View File

@ -44,6 +44,9 @@
static void parseNameAndArgTypes(const char* string, bool allowNone, List** names, int* nargs, Oid* argtypes);
static char *format_operator_internal(Oid operator_oid, bool force_qualify);
static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
static Datum regprocin_booststrap(char* procname)
{
RegProcedure result = InvalidOid;
@ -291,6 +294,61 @@ Datum regprocedurein(PG_FUNCTION_ARGS)
* in other backend modules. The result is a palloc'd string.
*/
char* format_procedure(Oid procedure_oid)
{
return format_procedure_internal(procedure_oid, false);
}
char *
format_procedure_qualified(Oid procedure_oid)
{
return format_procedure_internal(procedure_oid, true);
}
/*
* Output an objname/objargs representation for the procedure with the
* given OID. If it doesn't exist, an error is thrown.
*
* This can be used to feed get_object_address.
*/
void
format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
{
HeapTuple proctup;
Form_pg_proc procform;
int nargs;
int i;
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
procform = (Form_pg_proc) GETSTRUCT(proctup);
nargs = procform->pronargs;
*objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
pstrdup(NameStr(procform->proname)));
*objargs = NIL;
for (i = 0; i < nargs; i++)
{
Oid thisargtype = procform->proargtypes.values[i];
*objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
}
ReleaseSysCache(proctup);
}
/*
* Routine to produce regprocedure names; see format_procedure above.
*
* force_qualify says whether to schema-qualify; if true, the name is always
* qualified regardless of search_path visibility. Otherwise the name is only
* qualified if the function is not in path.
*/
static char *
format_procedure_internal(Oid procedure_oid, bool force_qualify)
{
char* result = NULL;
HeapTuple proctup;
@ -601,12 +659,12 @@ Datum regoperatorin(PG_FUNCTION_ARGS)
}
/*
* format_operator - converts operator OID to "opr_name(args)"
* format_operator_internal - converts operator OID to "opr_name(args)"
*
* This exports the useful functionality of regoperatorout for use
* in other backend modules. The result is a palloc'd string.
*/
char* format_operator(Oid operator_oid)
char* format_operator_internal(Oid operator_oid, bool force_qualify)
{
char* result = NULL;
HeapTuple opertup;
@ -627,7 +685,7 @@ char* format_operator(Oid operator_oid)
* Would this oper be found (given the right args) by regoperatorin?
* If not, we need to qualify it.
*/
if (!OperatorIsVisible(operator_oid)) {
if (force_qualify || !OperatorIsVisible(operator_oid)) {
nspname = get_namespace_name(operform->oprnamespace);
appendStringInfo(&buf, "%s.", quote_identifier(nspname));
}
@ -635,12 +693,14 @@ char* format_operator(Oid operator_oid)
appendStringInfo(&buf, "%s(", oprname);
if (operform->oprleft)
appendStringInfo(&buf, "%s,", format_type_be(operform->oprleft));
appendStringInfo(&buf, "%s,", force_qualify ?
format_type_be_qualified(operform->oprleft):format_type_be(operform->oprleft));
else
appendStringInfo(&buf, "NONE,");
if (operform->oprright)
appendStringInfo(&buf, "%s)", format_type_be(operform->oprright));
appendStringInfo(&buf, "%s)", force_qualify ?
format_type_be_qualified(operform->oprleft):format_type_be(operform->oprright));
else
appendStringInfo(&buf, "NONE)");
@ -659,6 +719,18 @@ char* format_operator(Oid operator_oid)
return result;
}
char *
format_operator(Oid operator_oid)
{
return format_operator_internal(operator_oid, false);
}
char *
format_operator_qualified(Oid operator_oid)
{
return format_operator_internal(operator_oid, true);
}
/*
* regoperatorout - converts operator OID to "opr_name(args)"
*/
@ -693,6 +765,31 @@ Datum regoperatorsend(PG_FUNCTION_ARGS)
return oidsend(fcinfo);
}
void
format_operator_parts(Oid operator_oid, List **objnames, List **objargs)
{
HeapTuple opertup;
Form_pg_operator oprForm;
opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
if (!HeapTupleIsValid(opertup))
elog(ERROR, "cache lookup failed for operator with OID %u",
operator_oid);
oprForm = (Form_pg_operator) GETSTRUCT(opertup);
*objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
pstrdup(NameStr(oprForm->oprname)));
*objargs = NIL;
if (oprForm->oprleft)
*objargs = lappend(*objargs,
format_type_be_qualified(oprForm->oprleft));
if (oprForm->oprright)
*objargs = lappend(*objargs,
format_type_be_qualified(oprForm->oprright));
ReleaseSysCache(opertup);
}
/*
* regclassin - converts "classname" to class OID
*

View File

@ -26,6 +26,6 @@ OBJS = attoptcache.o catcache.o inval.o plancache.o relcache.o relmapper.o \
knl_localsysdbcache.o \
knl_globalsystabcache.o knl_globalsystupcache.o knl_globalbasedefcache.o knl_globaltabdefcache.o knl_globalpartdefcache.o \
knl_localsystabcache.o knl_localsystupcache.o knl_localbasedefcache.o knl_localtabdefcache.o knl_localpartdefcache.o \
knl_globalrelmapcache.o knl_globalbucketlist.o knl_globaldbstatmanager.o
knl_globalrelmapcache.o knl_globalbucketlist.o knl_globaldbstatmanager.o evtcache.o
include $(top_srcdir)/src/gausskernel/common.mk

View File

@ -0,0 +1,238 @@
/*-------------------------------------------------------------------------
*
* evtcache.cpp
* Special-purpose cache for event trigger data.
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* src/common/backend/utils/cache/evtcache.cpp
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/indexing.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/evtcache.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/hsearch.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "knl/knl_session.h"
typedef struct {
EventTriggerEvent event;
List *triggerlist;
} EventTriggerCacheEntry;
static void BuildEventTriggerCache(void);
static void InvalidateEventCacheCallback(Datum arg,
int cacheid, uint32 hashvalue);
static int DecodeTextArrayToCString(Datum array, char ***cstringp);
/*
* Search the event cache by trigger event.
*
* Note that the caller had better copy any data it wants to keep around
* across any operation that might touch a system catalog into some other
* memory context, since a cache reset could blow the return value away.
*/
List * EventCacheLookup(EventTriggerEvent event)
{
EventTriggerCacheEntry *entry;
if (u_sess->exec_cxt.EventTriggerCache == NULL)
BuildEventTriggerCache();
entry = (EventTriggerCacheEntry*)hash_search(u_sess->exec_cxt.EventTriggerCache, &event, HASH_FIND, NULL);
return entry != NULL ? entry->triggerlist : NULL;
}
/*
* Rebuild the event trigger cache.
*/
static void BuildEventTriggerCache(void)
{
HASHCTL ctl;
HTAB *cache;
MemoryContext oldcontext;
Relation rel;
Relation irel;
SysScanDesc scan;
if (u_sess->exec_cxt.EventTriggerCacheContext != NULL) {
/*
* The cache has been previously built, and subsequently invalidated,
* and now we're trying to rebuild it. Normally, there won't be
* anything in the context at this point, because the invalidation
* will have already reset it. But if the previous attempt to rebuild
* the cache failed, then there might be some junk lying around
* that we want to reclaim.
*/
MemoryContextReset(u_sess->exec_cxt.EventTriggerCacheContext);
}
else {
/*
* This is our first time attempting to build the cache, so we need
* to set up the memory context and register a syscache callback to
* capture future invalidation events.
*/
u_sess->exec_cxt.EventTriggerCacheContext =
AllocSetContextCreate(SESS_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_EXECUTOR),
"EventTriggerCache",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
CacheRegisterSessionSyscacheCallback(EVENTTRIGGEROID,
InvalidateEventCacheCallback,
(Datum) 0);
}
/* Switch to correct memory context. */
oldcontext = MemoryContextSwitchTo(u_sess->exec_cxt.EventTriggerCacheContext);
/*
* Create a new hash table, but don't assign it to the global variable
* until it accurately represents the state of the catalogs, so that
* if we fail midway through this we won't end up with incorrect cache
* contents.
*/
MemSet(&ctl, 0, sizeof(ctl));
ctl.keysize = sizeof(EventTriggerEvent);
ctl.entrysize = sizeof(EventTriggerCacheEntry);
ctl.hash = tag_hash;
ctl.hcxt = (MemoryContext)u_sess->exec_cxt.EventTriggerCacheContext;
cache = hash_create("Event Trigger Cache", 32, &ctl,
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
/*
* Prepare to scan pg_event_trigger in name order. We use an MVCC
* snapshot to avoid getting inconsistent results if the table is
* being concurrently updated.
*/
rel = relation_open(EventTriggerRelationId, AccessShareLock);
irel = index_open(EventTriggerNameIndexId, AccessShareLock);
scan = systable_beginscan_ordered(rel, irel, GetLatestSnapshot(), 0, NULL);
/*
* Build a cache item for each pg_event_trigger tuple, and append each
* one to the appropriate cache entry.
*/
for (;;) {
HeapTuple tup;
Form_pg_event_trigger form;
char *evtevent;
EventTriggerEvent event;
EventTriggerCacheItem *item;
Datum evttags;
bool evttags_isnull;
EventTriggerCacheEntry *entry;
bool found;
/* Get next tuple. */
tup = systable_getnext_ordered(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tup))
break;
/* Skip trigger if disabled. */
form = (Form_pg_event_trigger) GETSTRUCT(tup);
if (form->evtenabled == TRIGGER_DISABLED)
continue;
/* Decode event name. */
evtevent = NameStr(form->evtevent);
if (strcmp(evtevent, "ddl_command_start") == 0)
event = EVT_DDLCommandStart;
else if (strcmp(evtevent, "ddl_command_end") == 0)
event = EVT_DDLCommandEnd;
else if (strcmp(evtevent, "sql_drop") == 0)
event = EVT_SQLDrop;
else if (strcmp(evtevent, "table_rewrite") == 0)
event = EVT_TableRewrite;
else
continue;
/* Allocate new cache item. */
item = (EventTriggerCacheItem*)palloc0(sizeof(EventTriggerCacheItem));
item->fnoid = form->evtfoid;
item->enabled = form->evtenabled;
/* Decode and sort tags array. */
evttags = heap_getattr(tup, Anum_pg_event_trigger_evttags,
RelationGetDescr(rel), &evttags_isnull);
if (!evttags_isnull)
{
item->ntags = DecodeTextArrayToCString(evttags, &item->tag);
qsort(item->tag, item->ntags, sizeof(char *), pg_qsort_strcmp);
}
/* Add to cache entry. */
entry = (EventTriggerCacheEntry*)hash_search(cache, &event, HASH_ENTER, &found);
if (found)
entry->triggerlist = lappend(entry->triggerlist, item);
else
entry->triggerlist = list_make1(item);
}
/* Done with pg_event_trigger scan. */
systable_endscan_ordered(scan);
index_close(irel, AccessShareLock);
relation_close(rel, AccessShareLock);
/* Restore previous memory context. */
MemoryContextSwitchTo(oldcontext);
/* Cache is now valid. */
u_sess->exec_cxt.EventTriggerCache = cache;
}
/*
* Decode text[] to an array of C strings.
*
* We could avoid a bit of overhead here if we were willing to duplicate some
* of the logic from deconstruct_array, but it doesn't seem worth the code
* complexity.
*/
static int DecodeTextArrayToCString(Datum array, char ***cstringp)
{
ArrayType *arr = DatumGetArrayTypeP(array);
Datum *elems;
char **cstring;
int i;
int nelems;
if (ARR_NDIM(arr) != 1 || ARR_HASNULL(arr) || ARR_ELEMTYPE(arr) != TEXTOID)
elog(ERROR, "expected 1-D text array");
deconstruct_array(arr, TEXTOID, -1, false, 'i', &elems, NULL, &nelems);
cstring = (char**)palloc(nelems * sizeof(char *));
for (i = 0; i < nelems; ++i)
cstring[i] = TextDatumGetCString(elems[i]);
pfree(elems);
*cstringp = cstring;
return nelems;
}
/*
* Flush all cache entries when pg_event_trigger is updated.
*
* This should be rare enough that we don't need to be very granular about
* it, so we just blow away everything, which also avoids the possibility of
* memory leaks.
*/
static void InvalidateEventCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
{
MemoryContextReset(u_sess->exec_cxt.EventTriggerCacheContext);
u_sess->exec_cxt.EventTriggerCache = NULL;
}

View File

@ -5042,6 +5042,20 @@ char* get_namespace_name(Oid nspid)
return NULL;
}
/*
* get_namespace_name_or_temp
* As above, but if it is this backend's temporary namespace, return
* "pg_temp" instead.
*/
char *
get_namespace_name_or_temp(Oid nspid)
{
if (isTempNamespace(nspid))
return "pg_temp";
else
return get_namespace_name(nspid);
}
/* ---------- PG_RANGE CACHE ---------- */
/*

View File

@ -54,6 +54,7 @@
#include "catalog/pg_description.h"
#include "catalog/pg_directory.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
@ -649,6 +650,7 @@ const cachedesc cacheinfo[] = {
1,
{ObjectIdAttributeNumber, 0, 0, 0},
STREAMING_CONT_QUERY_OID_INDEX_ID_NBUCKETS},
#ifdef ENABLE_MULTIPLE_NODES
{StreamingContQueryRelationId, /* STREAMCQRELID */
StreamingContQueryRelidIndexId,
1,
@ -659,6 +661,31 @@ const cachedesc cacheinfo[] = {
2,
{Anum_streaming_cont_query_matrelid, Anum_streaming_cont_query_active, 0, 0},
STREAMING_CONT_QUERY_SCHEMA_CHANGE_INDEX_ID_NBUCKETS},
#endif
#ifndef ENABLE_MULTIPLE_NODES
{EventTriggerRelationId, /* EVENTTRIGGERNAME */
EventTriggerNameIndexId,
1,
{
Anum_pg_event_trigger_evtname,
0,
0,
0
},
8
},
{EventTriggerRelationId, /* EVENTTRIGGEROID */
EventTriggerOidIndexId,
1,
{
ObjectIdAttributeNumber,
0,
0,
0
},
8
},
#endif
{StreamingStreamRelationId, /* STREAMOID */
StreamingStreamOidIndexId,
1,

View File

@ -59,7 +59,7 @@ bool open_join_children = true;
bool will_shutdown = false;
/* hard-wired binary version number */
const uint32 GRAND_VERSION_NUM = 92845;
const uint32 GRAND_VERSION_NUM = 92846;
const uint32 INNER_UNIQUE_VERSION_NUM = 92845;
const uint32 PARTITION_ENHANCE_VERSION_NUM = 92844;

View File

@ -7049,7 +7049,7 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign, bool eate
PLpgSQL_execstate *estate = (PLpgSQL_execstate*)palloc(sizeof(PLpgSQL_execstate));
expr->func = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function));
function = expr->func;
function->fn_is_trigger = false;
function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
function->fn_input_collation = InvalidOid;
function->out_param_varno = -1; /* set up for no OUT param */
function->resolve_option = GetResolveOption();
@ -12088,6 +12088,8 @@ static Oid plpgsql_build_package_record_type(const char* typname, List* list, bo
static void plpgsql_build_package_array_type(const char* typname,Oid elemtypoid, char arraytype)
{
char typtyp;
ObjectAddress myself, referenced;
char* casttypename = CastPackageTypeName(typname, u_sess->plsql_cxt.curr_compile_context->plpgsql_curr_compile_package->pkg_oid, true,
u_sess->plsql_cxt.curr_compile_context->plpgsql_curr_compile_package->is_spec_compiling);
if (strlen(casttypename) >= NAMEDATALEN ) {
@ -12135,7 +12137,7 @@ static void plpgsql_build_package_array_type(const char* typname,Oid elemtypoid
ownerId = GetUserId();
}
Oid typoid = TypeCreate(InvalidOid, /* force the type's OID to this */
referenced = TypeCreate(InvalidOid, /* force the type's OID to this */
casttypename, /* Array type name */
pkgNamespaceOid, /* Same namespace as parent */
InvalidOid, /* Not composite, no relationOid */
@ -12170,13 +12172,9 @@ static void plpgsql_build_package_array_type(const char* typname,Oid elemtypoid
CommandCounterIncrement();
/* build dependency on created composite type. */
ObjectAddress myself, referenced;
myself.classId = PackageRelationId;
myself.objectId = u_sess->plsql_cxt.curr_compile_context->plpgsql_curr_compile_package->pkg_oid;
myself.objectSubId = 0;
referenced.classId = TypeRelationId;
referenced.objectId = typoid;
referenced.objectSubId = 0;
recordDependencyOn(&referenced, &myself, DEPENDENCY_AUTO);
CommandCounterIncrement();
pfree_ext(casttypename);

View File

@ -47,6 +47,8 @@
#include "utils/syscache.h"
#include "miscadmin.h"
#include "tcop/tcopprot.h"
#include "commands/event_trigger.h"
/* functions reference other modules */
extern THR_LOCAL List* baseSearchPath;
@ -566,7 +568,8 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
PLpgSQL_func_hashkey* hashkey, bool for_validator)
{
Form_pg_proc proc_struct = (Form_pg_proc)GETSTRUCT(proc_tup);
bool is_trigger = CALLED_AS_TRIGGER(fcinfo);
bool is_dml_trigger = CALLED_AS_TRIGGER(fcinfo);
bool is_event_trigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
Datum proisprivatedatum;
bool isnull = false;
HeapTuple type_tup = NULL;
@ -723,7 +726,6 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
func->fn_oid = fcinfo->flinfo->fn_oid;
func->fn_xmin = HeapTupleGetRawXmin(proc_tup);
func->fn_tid = proc_tup->t_self;
func->fn_is_trigger = is_trigger;
func->fn_input_collation = fcinfo->fncollation;
func->fn_cxt = curr_compile->compile_cxt;
func->out_param_varno = -1; /* set up for no OUT param */
@ -736,6 +738,14 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
func->fn_searchpath->addCatalog = true;
func->fn_searchpath->addTemp = true;
func->ns_top = curr_compile->ns_top;
if (is_dml_trigger)
func->fn_is_trigger = PLPGSQL_DML_TRIGGER;
else if (is_event_trigger)
func->fn_is_trigger = PLPGSQL_EVENT_TRIGGER;
else
func->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
if (proc_struct->pronamespace == PG_CATALOG_NAMESPACE || proc_struct->pronamespace == PG_DB4AI_NAMESPACE) {
current_searchpath = fetch_search_path(false);
if (current_searchpath == NIL) {
@ -823,8 +833,8 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
Oid base_oid = InvalidOid;
bool isHaveTableOfIndexArgs = false;
bool isHaveOutRefCursorArgs = false;
switch ((int)is_trigger) {
case false:
switch (func->fn_is_trigger) {
case PLPGSQL_NOT_TRIGGER:
/*
* Fetch info about the procedure's parameters. Allocations aren't
@ -994,7 +1004,7 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
if (type_struct->typtype == TYPTYPE_PSEUDO) {
if (rettypeid == VOIDOID || rettypeid == RECORDOID) {
/* okay */;
} else if (rettypeid == TRIGGEROID) {
} else if (rettypeid == TRIGGEROID || rettypeid == EVTTRIGGEROID) {
ereport(ERROR, (errmodule(MOD_PLSQL), errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("trigger functions can only be called as triggers")));
} else {
@ -1024,7 +1034,7 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
ReleaseSysCache(type_tup);
break;
case true:
case PLPGSQL_DML_TRIGGER:
/* Trigger procedure's return type is unknown yet */
func->fn_rettype = InvalidOid;
func->fn_retbyval = false;
@ -1090,10 +1100,39 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
func->tg_argv_varno = var->dno;
break;
case PLPGSQL_EVENT_TRIGGER:
func->fn_rettype = VOIDOID;
func->fn_retbyval = false;
func->fn_retistuple = true;
func->fn_retset = false;
/* shouldn't be any declared arguments */
if (proc_struct->pronargs != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("event trigger functions cannot have declared arguments")));
/* Add the variable tg_event */
var = plpgsql_build_variable("tg_event", 0,
plpgsql_build_datatype(TEXTOID,
-1,
func->fn_input_collation),
true);
func->tg_event_varno = var->dno;
/* Add the variable tg_tag */
var = plpgsql_build_variable("tg_tag", 0,
plpgsql_build_datatype(TEXTOID,
-1,
func->fn_input_collation),
true);
func->tg_tag_varno = var->dno;
break;
default:
ereport(ERROR, (errmodule(MOD_PLSQL), errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized function typecode: %d", (int)is_trigger),
errmsg("unrecognized function typecode: %d", (int)func->fn_is_trigger),
errhint("This node type is expected to be a function or trigger.")));
break;
}
@ -1179,7 +1218,7 @@ static PLpgSQL_function* do_compile(FunctionCallInfo fcinfo, HeapTuple proc_tup,
}
func->action = curr_compile->plpgsql_parse_result;
if (is_trigger && func->action->isAutonomous) {
if (is_dml_trigger && func->action->isAutonomous) {
ereport(ERROR,
(errmodule(MOD_PLSQL),
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@ -1377,7 +1416,7 @@ PLpgSQL_function* plpgsql_compile_inline(char* proc_source)
curr_compile->compile_tmp_cxt = MemoryContextSwitchTo(curr_compile->compile_cxt);
func->fn_signature = pstrdup(func_name);
func->fn_is_trigger = false;
func->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
func->fn_input_collation = InvalidOid;
func->fn_cxt = curr_compile->compile_cxt;
func->out_param_varno = -1; /* set up for no OUT param */
@ -4394,6 +4433,7 @@ static void compute_function_hashkey(HeapTuple proc_tup, FunctionCallInfo fcinfo
hashkey->packageOid = packageOid;
/* get call context */
hashkey->isTrigger = CALLED_AS_TRIGGER(fcinfo);
hashkey->isEventTrigger = CALLED_AS_EVENT_TRIGGER(fcinfo);
/*
* if trigger, get relation OID. In validation mode we do not know what
@ -4855,7 +4895,8 @@ TupleDesc getCursorTupleDesc(PLpgSQL_expr* expr, bool isOnlySelect, bool isOnlyP
expr->func->fn_cxt = CurrentMemoryContext;
} else {
expr->func = u_sess->plsql_cxt.curr_compile_context->plpgsql_curr_compile;
if (expr->func->fn_is_trigger) {
/* if trigger or event trigger return NULL */
if (expr->func->fn_is_trigger != PLPGSQL_NOT_TRIGGER) {
return NULL;
}
}

View File

@ -69,6 +69,7 @@
#include "storage/mot/jit_exec.h"
#include "storage/mot/mot_fdw.h"
#endif
#include "commands/event_trigger.h"
extern bool checkRecompileCondition(CachedPlanSource* plansource);
static const char* const raise_skip_msg = "RAISE";
@ -8867,6 +8868,12 @@ static void evalSubscriptList(PLpgSQL_execstate* estate, const List* subscripts,
}
i++;
}
if (i - tableof_level != 1) {
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmodule(MOD_PLSQL),
errmsg("subscripts list has members less than tableof value %s expected", valname)));
}
Assert(estate->eval_tuptable == NULL);
estate->eval_tuptable = save_eval_tuptable;
return;
@ -12236,6 +12243,99 @@ static void exec_set_sql_notfound(PLpgSQL_execstate* estate, PLpgSQL_state state
}
}
void
plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
{
PLpgSQL_execstate estate;
ErrorContextCallback plerrcontext;
int i;
int rc;
PLpgSQL_var *var;
/*
* Setup the execution state
*/
plpgsql_estate_setup(&estate, func, NULL);
/*
* Setup error traceback support for ereport()
*/
plerrcontext.callback = plpgsql_exec_error_callback;
plerrcontext.arg = &estate;
plerrcontext.previous = t_thrd.log_cxt.error_context_stack;
t_thrd.log_cxt.error_context_stack = &plerrcontext;
/*
* Make local execution copies of all the datums
*/
estate.err_text = gettext_noop("during initialization of execution state");
for (i = 0; i < estate.ndatums; i++)
estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
/*
* Assign the special tg_ variables
*/
var = (PLpgSQL_var *) (estate.datums[func->tg_event_varno]);
var->value = CStringGetTextDatum(trigdata->event);
var->isnull = false;
var->freeval = true;
var = (PLpgSQL_var *) (estate.datums[func->tg_tag_varno]);
var->value = CStringGetTextDatum(trigdata->tag);
var->isnull = false;
var->freeval = true;
/*
* Let the instrumentation plugin peek at this function
*/
if (*u_sess->plsql_cxt.plugin_ptr && (*u_sess->plsql_cxt.plugin_ptr)->func_beg)
((*u_sess->plsql_cxt.plugin_ptr)->func_beg) (&estate, func);
/*
* Now call the toplevel block of statements
*/
estate.err_text = NULL;
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
rc = exec_stmt_block(&estate, func->action);
if (rc != PLPGSQL_RC_RETURN) {
estate.err_stmt = NULL;
estate.err_text = NULL;
/*
|* Provide a more helpful message if a CONTINUE or RAISE has been used
|* outside the context it can work in.
|*/
if (rc == PLPGSQL_RC_CONTINUE)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("CONTINUE cannot be used outside a loop")));
else
ereport(ERROR,
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
errmsg("control reached end of trigger procedure without RETURN")));
}
estate.err_stmt = NULL;
estate.err_text = gettext_noop("during function exit");
/*
* Let the instrumentation plugin peek at this function
*/
if (*u_sess->plsql_cxt.plugin_ptr && (*u_sess->plsql_cxt.plugin_ptr)->func_end)
((*u_sess->plsql_cxt.plugin_ptr)->func_end) (&estate, func);
/* Clean up any leftover temporary memory */
plpgsql_destroy_econtext(&estate);
exec_eval_cleanup(&estate);
/*
* Pop the error context stack
*/
t_thrd.log_cxt.error_context_stack = plerrcontext.previous;
return;
}
/*
* Set the global implicit cursor attribute isopen variable to true/false
*/

View File

@ -42,6 +42,7 @@
#include "utils/timestamp.h"
#include "executor/spi_priv.h"
#include "distributelayer/streamMain.h"
#include "commands/event_trigger.h"
#ifdef STREAMPLAN
#include "optimizer/streamplan.h"
@ -836,6 +837,10 @@ Datum plpgsql_call_handler(PG_FUNCTION_ARGS)
*/
if (CALLED_AS_TRIGGER(fcinfo)) {
retval = PointerGetDatum(plpgsql_exec_trigger(func, (TriggerData*)fcinfo->context));
} else if (CALLED_AS_EVENT_TRIGGER(fcinfo)) {
plpgsql_exec_event_trigger(func,
(EventTriggerData *) fcinfo->context);
} else {
if (func->is_private && !u_sess->is_autonomous_session) {
if (OidIsValid(secondLevelPkgOid)) {
@ -1242,7 +1247,9 @@ Datum plpgsql_validator(PG_FUNCTION_ARGS)
Oid* argtypes = NULL;
char** argnames;
char* argmodes = NULL;
bool istrigger = false;
bool is_dml_trigger = false;
bool is_event_trigger = false;
int i;
/*
* 3 means the number of arguments of function plpgsql_validator, while 'is_place' is the third one,
@ -1275,7 +1282,9 @@ Datum plpgsql_validator(PG_FUNCTION_ARGS)
if (functyptype == TYPTYPE_PSEUDO) {
/* we assume OPAQUE with no arguments means a trigger */
if (proc->prorettype == TRIGGEROID || (proc->prorettype == OPAQUEOID && proc->pronargs == 0)) {
istrigger = true;
is_dml_trigger = true;
} else if (proc->prorettype == EVTTRIGGEROID) {
is_event_trigger = true;
} else if (proc->prorettype != RECORDOID && proc->prorettype != VOIDOID && !IsPolymorphicType(proc->prorettype)) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@ -1301,7 +1310,8 @@ Datum plpgsql_validator(PG_FUNCTION_ARGS)
if (u_sess->attr.attr_sql.check_function_bodies) {
FunctionCallInfoData fake_fcinfo;
FmgrInfo flinfo;
TriggerData trigdata;
TriggerData dml_trigdata;
EventTriggerData event_trigdata;
PLpgSQL_function* func = NULL;
/*
* Set up a fake fcinfo with just enough info to satisfy
@ -1316,11 +1326,15 @@ Datum plpgsql_validator(PG_FUNCTION_ARGS)
fake_fcinfo.arg[0] = fcinfo->arg[1];
flinfo.fn_oid = funcoid;
flinfo.fn_mcxt = CurrentMemoryContext;
if (istrigger) {
errorno = memset_s(&trigdata, sizeof(trigdata), 0, sizeof(trigdata));
if (is_dml_trigger) {
errorno = memset_s(&dml_trigdata, sizeof(dml_trigdata), 0, sizeof(dml_trigdata));
securec_check(errorno, "", "");
trigdata.type = T_TriggerData;
fake_fcinfo.context = (Node*)&trigdata;
dml_trigdata.type = T_TriggerData;
fake_fcinfo.context = (Node*)&dml_trigdata;
} else if (is_event_trigger) {
MemSet(&event_trigdata, 0, sizeof(event_trigdata));
event_trigdata.type = T_EventTriggerData;
fake_fcinfo.context = (Node *) &event_trigdata;
}
/* save flag for nest plpgsql compile */
PLpgSQL_compile_context* save_compile_context = u_sess->plsql_cxt.curr_compile_context;

View File

@ -191,7 +191,7 @@ static PLyProcedure* PLy_procedure_create(HeapTuple procTup, Oid fn_oid, bool is
rvTypeStruct = (Form_pg_type)GETSTRUCT(rvTypeTup);
/* Disallow pseudotype result, except for void or record */
if (rvTypeStruct->typtype == TYPTYPE_PSEUDO) {
if (procStruct->prorettype == TRIGGEROID) {
if (procStruct->prorettype == TRIGGEROID || rettype == EVTTRIGGEROID) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("trigger functions can only be called as triggers")));

View File

@ -51,4 +51,14 @@
#define ST_SCOPE
#define ST_DECLARE
#define ST_DEFINE
#include "lib/sort_template.h"
#include "lib/sort_template.h"
/*
* qsort wrapper for strcmp.
*/
int
pg_qsort_strcmp(const void *a, const void *b)
{
return strcmp(*(char *const *) a, *(char *const *) b);
}

View File

@ -276,6 +276,7 @@ Boot_CreateStmt:
NULL, // partTableState add by data partition
REL_CMPRS_NOT_SUPPORT,
NULL,
NULL,
NULL);
if (id == DescriptionRelationId) {
InsertBuiltinFuncDescInBootstrap();

View File

@ -1264,7 +1264,7 @@ static void InitTupleAttr(FuncCallContext** funcctx)
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "thread_id", INT8OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "sessionid", INT8OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "start_time", TIMESTAMPTZOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "event", TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "cur_event", TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "lwtid", INT4OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "psessionid", INT8OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber)++i, "tlevel", INT4OID, -1, 0);

View File

@ -404,8 +404,8 @@ Datum hll_hash_anys(PG_FUNCTION_ARGS)
}
} else { /* typelen only can be -1/-2 or positive ,so can never reach here */
ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("invalid type internal size %d", typelen)));
return 0; /* keep compiler quiet */
}
return 0; /* keep compiler quiet */
}
Datum hll_eq(PG_FUNCTION_ARGS)

View File

@ -68,7 +68,7 @@ extern Oid GetIndexOpClass(List *opclass, Oid attrType, const char *accessMethod
extern void CheckPredicate(Expr *predicate);
extern bool CheckMutability(Expr *expr);
static void hypo_utility_hook(processutility_context* processutility_cxt,
DestReceiver *dest, bool sentToRemote, char *completionTag, bool isCtas);
DestReceiver *dest, bool sentToRemote, char *completionTag, ProcessUtilityContext context, bool isCtas);
static void hypo_executorEnd_hook(QueryDesc *queryDesc);
static void hypo_get_relation_info_hook(PlannerInfo *root, Oid relationObjectId, bool inhparent, RelOptInfo *rel);
static const char *hypo_explain_get_index_name_hook(Oid indexId);
@ -157,15 +157,15 @@ static Oid hypo_getNewOid(Oid relid)
* If this flag is setup, we can add hypothetical indexes.
*/
void hypo_utility_hook(processutility_context* processutility_cxt,
DestReceiver *dest, bool sentToRemote, char *completionTag, bool isCtas)
DestReceiver *dest, bool sentToRemote, char *completionTag, ProcessUtilityContext context, bool isCtas)
{
Node* parsetree = processutility_cxt->parse_tree;
isExplain = query_or_expression_tree_walker(parsetree, (bool (*)())hypo_query_walker, NULL, 0);
if (prev_utility_hook) {
prev_utility_hook(processutility_cxt, dest, sentToRemote, completionTag, isCtas);
prev_utility_hook(processutility_cxt, dest, sentToRemote, completionTag, context, isCtas);
} else {
standard_ProcessUtility(processutility_cxt, dest, sentToRemote, completionTag, isCtas);
standard_ProcessUtility(processutility_cxt, dest, sentToRemote, completionTag, context, isCtas);
}
}

View File

@ -22,7 +22,7 @@ SUBDIRS = sequence
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
collationcmds.o constraint.o conversioncmds.o copy.o createas.o \
dbcommands.o define.o discard.o dropcmds.o explain.o extension.o \
foreigncmds.o functioncmds.o \
event_trigger.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o matview.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o packagecmds.o publicationcmds.o\
schemacmds.o seclabel.o sec_rls_cmds.o subscriptioncmds.o tablecmds.o tablespace.o trigger.o \

View File

@ -49,7 +49,7 @@
* is specified by a BASETYPE element in the parameters. Otherwise,
* "args" defines the input type(s).
*/
void DefineAggregate(List* name, List* args, bool oldstyle, List* parameters)
ObjectAddress DefineAggregate(List* name, List* args, bool oldstyle, List* parameters)
{
char* aggName = NULL;
Oid aggNamespace;
@ -215,7 +215,7 @@ void DefineAggregate(List* name, List* args, bool oldstyle, List* parameters)
/*
* Most of the argument-checking is done inside of AggregateCreate
*/
AggregateCreate(aggName, /* aggregate name */
return AggregateCreate(aggName, /* aggregate name */
aggNamespace, /* namespace */
aggKind, /* agg kind */
aggArgTypes, /* input data type(s) */
@ -309,13 +309,16 @@ void RenameAggregate(List* name, List* args, const char* newname)
/*
* Change aggregate owner
*/
void AlterAggregateOwner(List* name, List* args, Oid newOwnerId)
ObjectAddress AlterAggregateOwner(List* name, List* args, Oid newOwnerId)
{
Oid procOid;
ObjectAddress address;
/* Look up function and make sure it's an aggregate */
procOid = LookupAggNameTypeNames(name, args, false);
/* The rest is just like a function */
AlterFunctionOwner_oid(procOid, newOwnerId);
ObjectAddressSet(address, ProcedureRelationId, procOid);
return address;
}

View File

@ -19,6 +19,20 @@
#include "access/tableam.h"
#include "catalog/dependency.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_language.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_dict.h"
#include "catalog/pg_ts_template.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_config_map.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_largeobject.h"
@ -31,6 +45,7 @@
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/directory.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/proclang.h"
#include "commands/publicationcmds.h"
@ -49,102 +64,320 @@
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "utils/syscache.h"
#include "gs_policy/gs_policy_masking.h"
/*
* Executes an ALTER OBJECT / RENAME TO statement. Based on the object
* type, the function appropriate to that type is executed.
*/
void ExecRenameStmt(RenameStmt* stmt)
static void
report_name_conflict(Oid classId, const char *name)
{
char *msgfmt;
switch (classId) {
case EventTriggerRelationId:
msgfmt = gettext_noop("event trigger \"%s\" already exists");
break;
case ForeignDataWrapperRelationId:
msgfmt = gettext_noop("foreign-data wrapper \"%s\" already exists");
break;
case ForeignServerRelationId:
msgfmt = gettext_noop("server \"%s\" already exists");
break;
case LanguageRelationId:
msgfmt = gettext_noop("language \"%s\" already exists");
break;
default:
elog(ERROR, "unsupported object class %u", classId);
break;
}
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg(msgfmt, name)));
}
static void
report_namespace_conflict(Oid classId, const char *name, Oid nspOid)
{
char *msgfmt;
Assert(OidIsValid(nspOid));
switch (classId) {
case ConversionRelationId:
Assert(OidIsValid(nspOid));
msgfmt = gettext_noop("conversion \"%s\" already exists in schema \"%s\"");
break;
case TSParserRelationId:
Assert(OidIsValid(nspOid));
msgfmt = gettext_noop("text search parser \"%s\" already exists in schema \"%s\"");
break;
case TSDictionaryRelationId:
Assert(OidIsValid(nspOid));
msgfmt = gettext_noop("text search dictionary \"%s\" already exists in schema \"%s\"");
break;
case TSTemplateRelationId:
Assert(OidIsValid(nspOid));
msgfmt = gettext_noop("text search template \"%s\" already exists in schema \"%s\"");
break;
case TSConfigRelationId:
Assert(OidIsValid(nspOid));
msgfmt = gettext_noop("text search configuration \"%s\" already exists in schema \"%s\"");
break;
default:
elog(ERROR, "unsupported object class %u", classId);
break;
}
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg(msgfmt, name, get_namespace_name(nspOid))));
}
/*
* AlterObjectRename_internal
*
* Generic function to rename the given object, for simple cases (won't
* work for tables, nor other cases where we need to do more than change
* the name column of a single catalog entry).
*
* rel: catalog relation containing object (RowExclusiveLock'd by caller)
* objectId: OID of object to be renamed
* new_name: CString representation of new name
*/
static void
AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
{
Oid classId = RelationGetRelid(rel);
int oidCacheId = get_object_catcache_oid(classId);
int nameCacheId = get_object_catcache_name(classId);
AttrNumber Anum_name = get_object_attnum_name(classId);
AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
HeapTuple oldtup;
HeapTuple newtup;
bool isnull;
Oid namespaceId;
Oid userId;
char *old_name;
AclResult aclresult;
Datum *values;
bool *nulls;
bool *replaces;
NameData nameattrdata;
Datum datum;
oldtup = SearchSysCache1(oidCacheId, ObjectIdGetDatum(objectId));
if (!HeapTupleIsValid(oldtup))
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
objectId, RelationGetRelationName(rel));
datum = heap_getattr(oldtup, Anum_name,
RelationGetDescr(rel), &isnull);
Assert(!isnull);
old_name = NameStr(*(DatumGetName(datum)));
/* Get OID of namespace */
if (Anum_namespace > 0) {
datum = heap_getattr(oldtup, Anum_namespace,
RelationGetDescr(rel), &isnull);
Assert(!isnull);
namespaceId = DatumGetObjectId(datum);
}
else
namespaceId = InvalidOid;
/* Permission checks ... superusers can always do it */
if (!superuser()) {
ObjectType objType = get_object_type(classId, objectId);
if (objType == OBJECT_TSTEMPLATE) {
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be system admin to rename text search templates")));
} else if (objType == OBJECT_TSPARSER) {
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be system admin to rename text search parser")));
}
userId = GetUserId();
switch (objType) {
/*OBJECT_AGGREGATE's classid is ProcedureRelationId, so objType should be OBJECT_FUNCTION*/
case OBJECT_FUNCTION:
if (pg_proc_aclcheck(objectId, userId, ACL_ALTER) != ACLCHECK_OK &&
!pg_proc_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC, old_name);
break;
case OBJECT_COLLATION:
if (pg_collation_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION, old_name);
break;
case OBJECT_CONVERSION:
if (pg_conversion_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, old_name);
break;
case OBJECT_EVENT_TRIGGER:
if (!pg_event_trigger_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER, old_name);
break;
case OBJECT_FDW:
if (!pg_foreign_data_wrapper_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FDW, old_name);
break;
case OBJECT_FOREIGN_SERVER:
if (pg_foreign_server_aclcheck(objectId, userId, ACL_ALTER) != ACLCHECK_OK &&
!pg_foreign_server_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_FOREIGN_SERVER, old_name);
break;
case OBJECT_OPCLASS:
if (!pg_opclass_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, old_name);
break;
case OBJECT_OPFAMILY:
if (!pg_opfamily_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY, old_name);
break;
case OBJECT_LANGUAGE:
if (pg_language_aclcheck(objectId, userId, ACL_ALTER) != ACLCHECK_OK &&
!pg_language_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE, old_name);
break;
case OBJECT_TSDICTIONARY:
if (!pg_ts_dict_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY, old_name);
break;
case OBJECT_TSCONFIGURATION:
if (!pg_ts_config_ownercheck(objectId, userId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, old_name);
break;
default: {
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized object type: %d", (int)objType)));
} break;
}
/* User must have CREATE privilege on the namespace */
if (OidIsValid(namespaceId)) {
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceId));
}
}
/*
* Check for duplicate name (more friendly than unique-index failure).
* Since this is just a friendliness check, we can just skip it in cases
* where there isn't suitable support.
*/
if (classId == ProcedureRelationId) {
Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(oldtup);
IsThereFunctionInNamespace(new_name, proc->pronargs,
&(proc->proargtypes), proc->pronamespace);
}
else if (classId == CollationRelationId) {
Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(oldtup);
IsThereCollationInNamespace(new_name, coll->collnamespace);
}
else if (classId == OperatorClassRelationId) {
Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(oldtup);
IsThereOpClassInNamespace(new_name, opc->opcmethod,
opc->opcnamespace);
}
else if (classId == OperatorFamilyRelationId) {
Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(oldtup);
IsThereOpFamilyInNamespace(new_name, opf->opfmethod,
opf->opfnamespace);
}
else if (classId == SubscriptionRelationId) {
if (SearchSysCacheExists2(SUBSCRIPTIONNAME, u_sess->proc_cxt.MyDatabaseId,
CStringGetDatum(new_name)))
report_name_conflict(classId, new_name);
}
else if (nameCacheId >= 0) {
if (OidIsValid(namespaceId)) {
if (SearchSysCacheExists2(nameCacheId,
CStringGetDatum(new_name),
ObjectIdGetDatum(namespaceId)))
report_namespace_conflict(classId, new_name, namespaceId);
}
else {
if (SearchSysCacheExists1(nameCacheId,
CStringGetDatum(new_name)))
report_name_conflict(classId, new_name);
}
}
/* Build modified tuple */
values = (Datum*)palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
nulls = (bool*)palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
replaces = (bool*)palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
namestrcpy(&nameattrdata, new_name);
values[Anum_name - 1] = NameGetDatum(&nameattrdata);
replaces[Anum_name - 1] = true;
newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
values, nulls, replaces);
/* Perform actual update */
simple_heap_update(rel, &oldtup->t_self, newtup);
CatalogUpdateIndexes(rel, newtup);
/* Release memory */
pfree(values);
pfree(nulls);
pfree(replaces);
heap_freetuple(newtup);
ReleaseSysCache(oldtup);
}
/*
* Executes an ALTER OBJECT / RENAME TO statement. Based on the object
* type, the function appropriate to that type is executed.
*/
ObjectAddress
ExecRenameStmt(RenameStmt *stmt)
{
ObjectAddress address;
switch (stmt->renameType) {
case OBJECT_AGGREGATE:
/* Given ordered set aggregate with no direct args, aggr_args variable is modified in gram.y.
So the parse of aggr_args should be changed. See gram.y for detail. */
stmt->objarg = (List*)linitial(stmt->objarg);
RenameAggregate(stmt->object, stmt->objarg, stmt->newname);
break;
case OBJECT_COLLATION:
RenameCollation(stmt->object, stmt->newname);
break;
case OBJECT_CONSTRAINT:
RenameConstraint(stmt);
break;
case OBJECT_CONVERSION:
RenameConversion(stmt->object, stmt->newname);
break;
case OBJECT_TABCONSTRAINT:
case OBJECT_DOMCONSTRAINT:
return RenameConstraint(stmt);
case OBJECT_DATABASE:
RenameDatabase(stmt->subname, stmt->newname);
break;
case OBJECT_FDW:
RenameForeignDataWrapper(stmt->subname, stmt->newname);
break;
case OBJECT_FOREIGN_SERVER:
RenameForeignServer(stmt->subname, stmt->newname);
break;
case OBJECT_FUNCTION:
RenameFunction(stmt->object, stmt->objarg, stmt->newname);
break;
case OBJECT_LANGUAGE:
RenameLanguage(stmt->subname, stmt->newname);
break;
case OBJECT_OPCLASS:
RenameOpClass(stmt->object, stmt->subname, stmt->newname);
break;
case OBJECT_OPFAMILY:
RenameOpFamily(stmt->object, stmt->subname, stmt->newname);
break;
return RenameDatabase(stmt->subname, stmt->newname);
case OBJECT_PARTITION:
renamePartition(stmt);
break;
return renamePartition(stmt);
case OBJECT_PARTITION_INDEX:
renamePartitionIndex(stmt);
break;
case OBJECT_PUBLICATION:
RenamePublication(stmt->object, stmt->newname);
break;
case OBJECT_SUBSCRIPTION:
RenameSubscription(stmt->object, stmt->newname);
break;
return renamePartitionIndex(stmt);
case OBJECT_RLSPOLICY:
RenameRlsPolicy(stmt);
break;
return RenameRlsPolicy(stmt);
case OBJECT_ROLE:
RenameRole(stmt->subname, stmt->newname);
break;
return RenameRole(stmt->subname, stmt->newname);
case OBJECT_USER:
RenameRole(stmt->subname, stmt->newname);
case OBJECT_USER: {
address = RenameRole(stmt->subname, stmt->newname);
/*
* Rename user need rename the schema that has the same name which
* owned by the user.
*/
RenameSchema(stmt->subname, stmt->newname);
break;
return address;
}
case OBJECT_SCHEMA:
RenameSchema(stmt->subname, stmt->newname);
break;
return RenameSchema(stmt->subname, stmt->newname);
case OBJECT_TABLESPACE:
RenameTableSpace(stmt->subname, stmt->newname);
break;
return RenameTableSpace(stmt->subname, stmt->newname);
case OBJECT_TABLE:
case OBJECT_SEQUENCE:
@ -155,92 +388,80 @@ void ExecRenameStmt(RenameStmt* stmt)
case OBJECT_INDEX:
case OBJECT_FOREIGN_TABLE:
case OBJECT_STREAM:
RenameRelation(stmt);
break;
return RenameRelation(stmt);
case OBJECT_COLUMN:
case OBJECT_ATTRIBUTE:
renameatt(stmt);
break;
return renameatt(stmt);
case OBJECT_TRIGGER:
renametrig(stmt);
break;
case OBJECT_TSPARSER:
RenameTSParser(stmt->object, stmt->newname);
break;
case OBJECT_TSDICTIONARY:
RenameTSDictionary(stmt->object, stmt->newname);
break;
case OBJECT_TSTEMPLATE:
RenameTSTemplate(stmt->object, stmt->newname);
break;
case OBJECT_TSCONFIGURATION:
RenameTSConfiguration(stmt->object, stmt->newname);
break;
return renametrig(stmt);
case OBJECT_DOMAIN:
case OBJECT_TYPE:
RenameType(stmt);
break;
return RenameType(stmt);
case OBJECT_FUNCTION:
return RenameFunction(stmt->object, stmt->objarg, stmt->newname);
case OBJECT_AGGREGATE:
case OBJECT_COLLATION:
case OBJECT_CONVERSION:
case OBJECT_EVENT_TRIGGER:
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
case OBJECT_OPCLASS:
case OBJECT_OPFAMILY:
case OBJECT_LANGUAGE:
case OBJECT_TSCONFIGURATION:
case OBJECT_TSDICTIONARY:
case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
case OBJECT_PUBLICATION:
case OBJECT_SUBSCRIPTION:
{
ObjectAddress address;
Relation catalog;
Relation relation;
address = get_object_address(stmt->renameType,
stmt->object, stmt->objarg,
&relation,
AccessExclusiveLock, false);
Assert(relation == NULL);
catalog = heap_open(address.classId, RowExclusiveLock);
AlterObjectRename_internal(catalog,
address.objectId,
stmt->newname);
heap_close(catalog, RowExclusiveLock);
return address;
}
case OBJECT_DATA_SOURCE:
RenameDataSource(stmt->subname, stmt->newname);
break;
return RenameDataSource(stmt->subname, stmt->newname);
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized rename stmt type: %d", (int)stmt->renameType)));
return InvalidObjectAddress;
}
return InvalidObjectAddress;
}
/*
* Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object
* type, the function appropriate to that type is executed.
*/
void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt* stmt)
ObjectAddress ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt* stmt, ObjectAddress *oldSchemaAddr)
{
ObjectAddress address;
Oid oldNspOid;
switch (stmt->objectType) {
case OBJECT_AGGREGATE:
/* Given ordered set aggregate with no direct args, aggr_args variable is modified in gram.y.
So the parse of aggr_args should be changed. See gram.y for detail. */
stmt->objarg = (List*)linitial(stmt->objarg);
AlterFunctionNamespace(stmt->object, stmt->objarg, true, stmt->newschema);
break;
case OBJECT_COLLATION:
AlterCollationNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_CONVERSION:
AlterConversionNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_EXTENSION:
AlterExtensionNamespace(stmt->object, stmt->newschema);
address = AlterExtensionNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_FUNCTION:
AlterFunctionNamespace(stmt->object, stmt->objarg, false, stmt->newschema);
break;
case OBJECT_OPERATOR:
AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
address = AlterOperatorNamespace(stmt->object, stmt->objarg, stmt->newschema);
break;
case OBJECT_OPCLASS:
AlterOpClassNamespace(stmt->object, stmt->addname, stmt->newschema);
break;
case OBJECT_OPFAMILY:
AlterOpFamilyNamespace(stmt->object, stmt->addname, stmt->newschema);
break;
case OBJECT_SEQUENCE:
case OBJECT_LARGE_SEQUENCE:
case OBJECT_TABLE:
@ -254,35 +475,72 @@ void ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt* stmt)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Un-support feature"),
errdetail("target table is a stream")));
AlterTableNamespace(stmt);
break;
case OBJECT_TSPARSER:
AlterTSParserNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_TSDICTIONARY:
AlterTSDictionaryNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_TSTEMPLATE:
AlterTSTemplateNamespace(stmt->object, stmt->newschema);
address = AlterTableNamespace(stmt, oldSchemaAddr ? &oldNspOid : NULL);
break;
/* generic code path */
case OBJECT_AGGREGATE:
case OBJECT_COLLATION:
case OBJECT_CONVERSION:
case OBJECT_FUNCTION:
case OBJECT_OPCLASS:
case OBJECT_OPFAMILY:
case OBJECT_TSCONFIGURATION:
AlterTSConfigurationNamespace(stmt->object, stmt->newschema);
break;
case OBJECT_TSDICTIONARY:
case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
{
Relation catalog;
Relation relation;
Oid classId;
Oid nspOid;
address = get_object_address(stmt->objectType,
stmt->object,
stmt->objarg,
&relation,
AccessExclusiveLock,
false);
Assert(relation == NULL);
classId = address.classId;
nspOid = LookupCreationNamespace(stmt->newschema);
if (stmt->objectType == OBJECT_FUNCTION) {
/*
* Check function name to ensure that it doesn't conflict with existing synonym.
*/
Relation procRel = heap_open(ProcedureRelationId, RowExclusiveLock);
HeapTuple tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(address.objectId));
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", address.objectId)));
Form_pg_proc proc = (Form_pg_proc)GETSTRUCT(tup);
heap_close(procRel, RowExclusiveLock);
if (!IsInitdb && GetSynonymOid(NameStr(proc->proname), nspOid, true) != InvalidOid) {
ereport(ERROR,
(errmsg("function name is already used by an existing synonym in schema \"%s\"",
get_namespace_name(nspOid))));
}
}
catalog = heap_open(classId, RowExclusiveLock);
oldNspOid = AlterObjectNamespace_internal(catalog, address.objectId,
nspOid);
heap_close(catalog, RowExclusiveLock);
}
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
AlterTypeNamespace(stmt->object, stmt->newschema, stmt->objectType);
address = AlterTypeNamespace(stmt->object, stmt->newschema, stmt->objectType);
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized AlterObjectSchemaStmt type: %d", (int)stmt->objectType)));
return InvalidObjectAddress;
}
return address;
}
/*
@ -371,6 +629,146 @@ Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses
return oldNspOid;
}
/*
* Generic function to change the namespace of a given object, for simple
* cases (won't work for tables, nor other cases where we need to do more
* than change the namespace column of a single catalog entry).
*
* rel: catalog relation containing object (RowExclusiveLock'd by caller)
* objid: OID of object to change the namespace of
* nspOid: OID of new namespace
*
* Returns the OID of the object's previous namespace.
*/
Oid
AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
{
Oid classId = RelationGetRelid(rel);
int oidCacheId = get_object_catcache_oid(classId);
int nameCacheId = get_object_catcache_name(classId);
AttrNumber Anum_name = get_object_attnum_name(classId);
AttrNumber Anum_namespace = get_object_attnum_namespace(classId);
AttrNumber Anum_owner = get_object_attnum_owner(classId);
Oid oldNspOid;
Datum name,
obj_namespace;
bool isnull;
HeapTuple tup,
newtup;
Datum *values;
bool *nulls;
bool *replaces;
tup = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objid));
if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for object %u of catalog \"%s\"",
objid, RelationGetRelationName(rel));
name = heap_getattr(tup, Anum_name, RelationGetDescr(rel), &isnull);
Assert(!isnull);
obj_namespace = (Datum)heap_getattr(tup, Anum_namespace, RelationGetDescr(rel),
&isnull);
Assert(!isnull);
oldNspOid = DatumGetObjectId(obj_namespace);
/*
* If the object is already in the correct namespace, we don't need to do
* anything except fire the object access hook.
*/
if (oldNspOid == nspOid) {
return oldNspOid;
}
/* Check basic namespace related issues */
CheckSetNamespace(oldNspOid, nspOid, classId, objid);
/* Permission checks ... superusers can always do it */
if (!superuser()) {
Datum owner;
Oid ownerId;
AclResult aclresult;
/* Fail if object does not have an explicit owner */
if (Anum_owner <= 0)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to set schema of %s",
getObjectDescriptionOids(classId, objid)))));
/* Otherwise, must be owner of the existing object */
owner = heap_getattr(tup, Anum_owner, RelationGetDescr(rel), &isnull);
Assert(!isnull);
ownerId = DatumGetObjectId(owner);
if (!has_privs_of_role(GetUserId(), ownerId))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
NameStr(*(DatumGetName(name))));
/* User must have CREATE privilege on new namespace */
aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(nspOid));
}
/*
* Check for duplicate name (more friendly than unique-index failure).
* Since this is just a friendliness check, we can just skip it in cases
* where there isn't suitable support.
*/
if (classId == ProcedureRelationId) {
Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tup);
IsThereFunctionInNamespace(NameStr(proc->proname), proc->pronargs,
&proc->proargtypes, nspOid);
}
else if (classId == CollationRelationId) {
Form_pg_collation coll = (Form_pg_collation) GETSTRUCT(tup);
IsThereCollationInNamespace(NameStr(coll->collname), nspOid);
}
else if (classId == OperatorClassRelationId) {
Form_pg_opclass opc = (Form_pg_opclass) GETSTRUCT(tup);
IsThereOpClassInNamespace(NameStr(opc->opcname),
opc->opcmethod, nspOid);
}
else if (classId == OperatorFamilyRelationId) {
Form_pg_opfamily opf = (Form_pg_opfamily) GETSTRUCT(tup);
IsThereOpFamilyInNamespace(NameStr(opf->opfname),
opf->opfmethod, nspOid);
}
else if (nameCacheId >= 0 &&
SearchSysCacheExists2(nameCacheId, name,
ObjectIdGetDatum(nspOid)))
report_namespace_conflict(classId,
NameStr(*(DatumGetName(name))),
nspOid);
/* Build modified tuple */
values = (Datum*)palloc0(RelationGetNumberOfAttributes(rel) * sizeof(Datum));
nulls = (bool*)palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
replaces = (bool*)palloc0(RelationGetNumberOfAttributes(rel) * sizeof(bool));
values[Anum_namespace - 1] = ObjectIdGetDatum(nspOid);
replaces[Anum_namespace - 1] = true;
newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
values, nulls, replaces);
/* Perform actual update */
CatalogTupleUpdate(rel, &tup->t_self, newtup);
/* Release memory */
pfree(values);
pfree(nulls);
pfree(replaces);
/* update dependencies to point to the new schema */
changeDependencyFor(classId, objid,
NamespaceRelationId, oldNspOid, nspOid);
return oldNspOid;
}
/*
* Generic function to change the namespace of a given object, for simple
@ -489,7 +887,7 @@ Oid AlterObjectNamespace(Relation rel, int oidCacheId, int nameCacheId, Oid obji
* Executes an ALTER OBJECT / OWNER TO statement. Based on the object
* type, the function appropriate to that type is executed.
*/
void ExecAlterOwnerStmt(AlterOwnerStmt* stmt)
ObjectAddress ExecAlterOwnerStmt(AlterOwnerStmt* stmt)
{
const char* newOwnerName = stmt->newowner;
Oid newowner;
@ -509,101 +907,98 @@ void ExecAlterOwnerStmt(AlterOwnerStmt* stmt)
/* Given ordered set aggregate with no direct args, aggr_args variable is modified in gram.y.
So the parse of aggr_args should be changed. See gram.y for detail. */
stmt->objarg = (List*)linitial(stmt->objarg);
AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
break;
return AlterAggregateOwner(stmt->object, stmt->objarg, newowner);
case OBJECT_COLLATION:
AlterCollationOwner(stmt->object, newowner);
break;
return AlterCollationOwner(stmt->object, newowner);
case OBJECT_CONVERSION:
AlterConversionOwner(stmt->object, newowner);
break;
return AlterConversionOwner(stmt->object, newowner);
case OBJECT_DATABASE:
AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_EVENT_TRIGGER:
return AlterEventTriggerOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_FUNCTION:
AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
break;
return AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
case OBJECT_PACKAGE:
AlterPackageOwner(stmt->object, newowner);
return AlterPackageOwner(stmt->object, newowner);
break;
case OBJECT_LANGUAGE:
AlterLanguageOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterLanguageOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_LARGEOBJECT:
LargeObjectAlterOwner(oidparse((Node*)linitial(stmt->object)), newowner);
break;
return LargeObjectAlterOwner(oidparse((Node*)linitial(stmt->object)), newowner);
case OBJECT_OPERATOR:
Assert(list_length(stmt->objarg) == 2);
AlterOperatorOwner(
return AlterOperatorOwner(
stmt->object, (TypeName*)linitial(stmt->objarg), (TypeName*)lsecond(stmt->objarg), newowner);
break;
case OBJECT_OPCLASS:
AlterOpClassOwner(stmt->object, stmt->addname, newowner);
break;
{
List* object_names;
object_names=list_copy(stmt->object);
object_names=list_delete_first(object_names);
ObjectAddress obj_opclass=AlterOpClassOwner(object_names, ((Value*)linitial(stmt->object))->val.str, newowner);
list_free_ext(object_names);
return obj_opclass;
}
case OBJECT_OPFAMILY:
AlterOpFamilyOwner(stmt->object, stmt->addname, newowner);
break;
{
List* object_names;
object_names=list_copy(stmt->object);
object_names=list_delete_first(object_names);
ObjectAddress obj_opfamily=AlterOpFamilyOwner(object_names, ((Value*)linitial(stmt->object))->val.str, newowner);
list_free_ext(object_names);
return obj_opfamily;
}
case OBJECT_SCHEMA:
AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_TABLESPACE:
AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterTableSpaceOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_TYPE:
case OBJECT_DOMAIN: /* same as TYPE */
AlterTypeOwner(stmt->object, newowner, stmt->objectType, true);
break;
return AlterTypeOwner(stmt->object, newowner, stmt->objectType, true);
case OBJECT_TSDICTIONARY:
AlterTSDictionaryOwner(stmt->object, newowner);
break;
return AlterTSDictionaryOwner(stmt->object, newowner);
case OBJECT_TSCONFIGURATION:
AlterTSConfigurationOwner(stmt->object, newowner);
break;
return AlterTSConfigurationOwner(stmt->object, newowner);
case OBJECT_FDW:
AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_FOREIGN_SERVER:
AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_DATA_SOURCE:
AlterDataSourceOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterDataSourceOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_DIRECTORY:
AlterDirectoryOwner(strVal(linitial(stmt->object)), newowner);
break;
return AlterDirectoryOwner(strVal(linitial(stmt->object)), newowner);
case OBJECT_SYNONYM:
AlterSynonymOwner(stmt->object, newowner);
break;
return AlterSynonymOwner(stmt->object, newowner);
case OBJECT_PUBLICATION:
AlterPublicationOwner(strVal(linitial(stmt->object)), newowner);
return AlterPublicationOwner(strVal(linitial(stmt->object)), newowner);
break;
case OBJECT_SUBSCRIPTION:
AlterSubscriptionOwner(strVal(linitial(stmt->object)), newowner);
return AlterSubscriptionOwner(strVal(linitial(stmt->object)), newowner);
break;
default:
ereport(ERROR,
(errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE),
errmsg("unrecognized AlterOwnerStmt type: %d", (int)stmt->objectType)));
return InvalidObjectAddress;
}
}

View File

@ -42,7 +42,7 @@ static void AlterCollationOwner_internal(Relation rel, Oid collationOid, Oid new
/*
* CREATE COLLATION
*/
void DefineCollation(List* names, List* parameters)
ObjectAddress DefineCollation(List* names, List* parameters)
{
char* collName = NULL;
Oid collNamespace;
@ -55,6 +55,7 @@ void DefineCollation(List* names, List* parameters)
char* collcollate = NULL;
char* collctype = NULL;
Oid newoid;
ObjectAddress address;
collNamespace = QualifiedNameGetCreationNamespace(names, &collName);
@ -125,10 +126,12 @@ void DefineCollation(List* names, List* parameters)
check_encoding_locale_matches(GetDatabaseEncoding(), collcollate, collctype);
newoid = CollationCreate(collName, collNamespace, GetUserId(), GetDatabaseEncoding(), collcollate, collctype);
ObjectAddressSet(address, CollationRelationId, newoid);
/* check that the locales can be loaded */
CommandCounterIncrement();
(void)pg_newlocale_from_collation(newoid);
return address;
}
/*
@ -194,10 +197,11 @@ void RenameCollation(List* name, const char* newname)
/*
* Change collation owner, by name
*/
void AlterCollationOwner(List* name, Oid newOwnerId)
ObjectAddress AlterCollationOwner(List* name, Oid newOwnerId)
{
Oid collationOid;
Relation rel;
ObjectAddress address;
rel = heap_open(CollationRelationId, RowExclusiveLock);
@ -206,6 +210,8 @@ void AlterCollationOwner(List* name, Oid newOwnerId)
AlterCollationOwner_internal(rel, collationOid, newOwnerId);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, CollationRelationId, collationOid);
return address;
}
/*
@ -283,15 +289,18 @@ static void AlterCollationOwner_internal(Relation rel, Oid collationOid, Oid new
/*
* Execute ALTER COLLATION SET SCHEMA
*/
void AlterCollationNamespace(List* name, const char* newschema)
ObjectAddress AlterCollationNamespace(List* name, const char* newschema)
{
Oid collOid, nspOid;
ObjectAddress address;
collOid = get_collation_oid(name, false);
nspOid = LookupCreationNamespace(newschema);
AlterCollationNamespace_oid(collOid, nspOid);
ObjectAddressSet(address, CollationRelationId, collOid);
return address;
}
/*
@ -350,3 +359,36 @@ Oid AlterCollationNamespace_oid(Oid collOid, Oid newNspOid)
return oldNspOid;
}
/*
* Subroutine for ALTER COLLATION SET SCHEMA and RENAME
*
* Is there a collation with the same name of the given collation already in
* the given namespace? If so, raise an appropriate error message.
*/
void
IsThereCollationInNamespace(const char *collname, Oid nspOid)
{
/* make sure the name doesn't already exist in new schema */
if (SearchSysCacheExists3(COLLNAMEENCNSP,
CStringGetDatum(collname),
Int32GetDatum(GetDatabaseEncoding()),
ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"",
collname, GetDatabaseEncodingName(),
get_namespace_name(nspOid))));
/* mustn't match an any-encoding entry, either */
if (SearchSysCacheExists3(COLLNAMEENCNSP,
CStringGetDatum(collname),
Int32GetDatum(-1),
ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("collation \"%s\" already exists in schema \"%s\"",
collname, get_namespace_name(nspOid))));
}

View File

@ -108,10 +108,10 @@ static AclResult CheckObjectCommentPrivilege(const CommentStmt* stmt, Oid object
* This routine is used to add the associated comment into
* pg_description for the object specified by the given SQL command.
*/
void CommentObject(CommentStmt* stmt)
ObjectAddress CommentObject(CommentStmt* stmt)
{
ObjectAddress address;
Relation relation;
ObjectAddress address = InvalidObjectAddress;
/*
* When loading a dump, we may see a COMMENT ON DATABASE for the old name
@ -127,7 +127,7 @@ void CommentObject(CommentStmt* stmt)
if (!OidIsValid(get_database_oid(database, true))) {
ereport(WARNING, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", database)));
return;
return address;
}
}
@ -200,6 +200,8 @@ void CommentObject(CommentStmt* stmt)
*/
if (relation != NULL)
relation_close(relation, NoLock);
return address;
}
/*

View File

@ -41,7 +41,7 @@ static const Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OI
/*
* CREATE CONVERSION
*/
void CreateConversionCommand(CreateConversionStmt* stmt)
ObjectAddress CreateConversionCommand(CreateConversionStmt* stmt)
{
Oid namespaceId;
char* conversion_name = NULL;
@ -107,7 +107,7 @@ void CreateConversionCommand(CreateConversionStmt* stmt)
* All seem ok, go ahead (possible failure would be a duplicate conversion
* name)
*/
ConversionCreate(conversion_name, namespaceId, GetUserId(), from_encoding, to_encoding, funcoid, stmt->def);
return ConversionCreate(conversion_name, namespaceId, GetUserId(), from_encoding, to_encoding, funcoid, stmt->def);
}
/*
@ -159,10 +159,11 @@ void RenameConversion(List* name, const char* newname)
/*
* Change conversion owner, by name
*/
void AlterConversionOwner(List* name, Oid newOwnerId)
ObjectAddress AlterConversionOwner(List* name, Oid newOwnerId)
{
Oid conversionOid;
Relation rel;
ObjectAddress address;
rel = heap_open(ConversionRelationId, RowExclusiveLock);
@ -171,6 +172,9 @@ void AlterConversionOwner(List* name, Oid newOwnerId)
AlterConversionOwner_internal(rel, conversionOid, newOwnerId);
heap_close(rel, NoLock);
ObjectAddressSet(address, ConversionRelationId, conversionOid);
return address;
}
/*
@ -246,10 +250,11 @@ static void AlterConversionOwner_internal(Relation rel, Oid conversionOid, Oid n
/*
* Execute ALTER CONVERSION SET SCHEMA
*/
void AlterConversionNamespace(List* name, const char* newschema)
ObjectAddress AlterConversionNamespace(List* name, const char* newschema)
{
Oid convOid, nspOid;
Relation rel;
ObjectAddress address;
rel = heap_open(ConversionRelationId, RowExclusiveLock);
@ -269,6 +274,8 @@ void AlterConversionNamespace(List* name, const char* newschema)
ACL_KIND_CONVERSION);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, ConversionRelationId, convOid);
return address;
}
/*

View File

@ -981,15 +981,16 @@ static void CheckCopyFilePermission(char *filename)
* Do not allow the copy if user doesn't have proper permission to access
* the table or the specifically requested columns.
*/
uint64 DoCopy(CopyStmt* stmt, const char* queryString)
Oid DoCopy(CopyStmt* stmt, const char* queryString, uint64 *processed)
{
CopyState cstate;
bool is_from = stmt->is_from;
bool pipe = (stmt->filename == NULL);
Relation rel;
uint64 processed = 0;
RangeTblEntry* rte = NULL;
Node* query = NULL;
Oid relid;
stmt->hashstate.has_histhash = false;
/*
* we can't retry gsql \copy from command and JDBC 'CopyManager.copyIn' operation,
@ -1046,6 +1047,7 @@ uint64 DoCopy(CopyStmt* stmt, const char* queryString)
(errcode(ERRCODE_INVALID_OPERATION),
errmsg("%s is redistributing, please retry later.", rel->rd_rel->relname.data)));
relid = RelationGetRelid(rel);
rte = makeNode(RangeTblEntry);
rte->rtekind = RTE_RELATION;
rte->relid = RelationGetRelid(rel);
@ -1113,7 +1115,7 @@ uint64 DoCopy(CopyStmt* stmt, const char* queryString)
{
SyncBulkloadStates(cstate);
processed = CopyFrom(cstate); /* copy from file to database */
*processed = CopyFrom(cstate); /* copy from file to database */
/* Record copy from to gchain. */
if (cstate->hashstate.has_histhash) {
@ -1136,7 +1138,7 @@ uint64 DoCopy(CopyStmt* stmt, const char* queryString)
pgstat_set_stmt_tag(STMTTAG_READ);
cstate = BeginCopyTo(rel, query, queryString, stmt->filename, stmt->attlist, stmt->options, stmt->filetype);
cstate->range_table = list_make1(rte);
processed = DoCopyTo(cstate); /* copy from database to file */
*processed = DoCopyTo(cstate); /* copy from database to file */
EndCopyTo(cstate);
}
@ -1155,7 +1157,7 @@ uint64 DoCopy(CopyStmt* stmt, const char* queryString)
audit_report(AUDIT_COPY_TO, AUDIT_OK, stmt->filename ? stmt->filename : "stdout", queryString);
}
return processed;
return relid;
}
static void TransformFormatter(CopyState cstate, List* formatter)

View File

@ -56,6 +56,7 @@ typedef struct {
/* These fields are filled by intorel_startup: */
Relation rel; /* relation to write to */
CommandId output_cid; /* cmin to insert in output tuples */
ObjectAddress reladdr; /* address of rel, for ExecCreateTableAs */
int hi_options; /* heap_insert performance options */
BulkInsertState bistate; /* bulk insert state */
} DR_intorel;
@ -120,7 +121,7 @@ SetupForCreateTableAs(Query *query, IntoClause *into, const char *queryString,
/*
* ExecCreateTableAs -- execute a CREATE TABLE AS command
*/
void ExecCreateTableAs(CreateTableAsStmt* stmt, const char* queryString, ParamListInfo params, char* completionTag)
ObjectAddress ExecCreateTableAs(CreateTableAsStmt* stmt, const char* queryString, ParamListInfo params, char* completionTag)
{
Query* query = (Query*)stmt->query;
IntoClause* into = stmt->into;
@ -128,7 +129,8 @@ void ExecCreateTableAs(CreateTableAsStmt* stmt, const char* queryString, ParamLi
PlannedStmt* plan = NULL;
QueryDesc* queryDesc = NULL;
ScanDirection dir;
ObjectAddress address;
if (stmt->into->ivm) {
return ExecCreateMatViewInc(stmt, queryString, params);
}
@ -148,7 +150,10 @@ void ExecCreateTableAs(CreateTableAsStmt* stmt, const char* queryString, ParamLi
ExecuteQuery(estmt, into, queryString, params, dest, completionTag);
return;
/* get object address that intorel_startup saved for us */
address = ((DR_intorel *) dest)->reladdr;
return address;
}
query = SetupForCreateTableAs(query, into, queryString, params, dest);
@ -230,6 +235,9 @@ void ExecCreateTableAs(CreateTableAsStmt* stmt, const char* queryString, ParamLi
securec_check_ss(rc, "\0", "\0");
}
/* get object address that intorel_startup saved for us */
address = ((DR_intorel *) dest)->reladdr;
/* and clean up */
ExecutorFinish(queryDesc);
ExecutorEnd(queryDesc);
@ -237,6 +245,7 @@ void ExecCreateTableAs(CreateTableAsStmt* stmt, const char* queryString, ParamLi
FreeQueryDesc(queryDesc);
PopActiveSnapshot();
return address;
}
/*
@ -298,6 +307,7 @@ static void intorel_startup(DestReceiver* self, int operation, TupleDesc typeinf
IntoClause* into = myState->into;
CreateStmt* create = NULL;
Oid intoRelationId;
ObjectAddress intoRelationAddr;
Relation intoRelationDesc;
RangeTblEntry* rte = NULL;
Datum toast_options;
@ -413,8 +423,8 @@ static void intorel_startup(DestReceiver* self, int operation, TupleDesc typeinf
/*
* Actually create the target table
*/
intoRelationId = DefineRelation(create, into->relkind, InvalidOid);
intoRelationAddr = DefineRelation(create, into->relkind, InvalidOid, NULL);
intoRelationId = intoRelationAddr.objectId;
/*
* If necessary, create a TOAST table for the target table. Note that
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so that
@ -482,7 +492,7 @@ static void intorel_startup(DestReceiver* self, int operation, TupleDesc typeinf
*/
myState->rel = intoRelationDesc;
myState->output_cid = GetCurrentCommandId(true);
myState->reladdr = intoRelationAddr;
/*
* We can skip WAL-logging the insertions, unless PITR or streaming
* replication is in use. We can skip the FSM in any case.

View File

@ -350,10 +350,12 @@ void RemoveDataSourceById(Oid src_Id)
* @IN newname: new name
* @RETURN : void
*/
void RenameDataSource(const char* oldname, const char* newname)
ObjectAddress RenameDataSource(const char* oldname, const char* newname)
{
HeapTuple tup;
Relation rel;
Oid DSOid;
ObjectAddress address;
rel = heap_open(DataSourceRelationId, RowExclusiveLock);
@ -365,6 +367,7 @@ void RenameDataSource(const char* oldname, const char* newname)
errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("data source \"%s\" does not exist", oldname)));
DSOid = HeapTupleGetOid(tup);
/* make sure the new name doesn't exist */
if (SearchSysCacheExists1(DATASOURCENAME, CStringGetDatum(newname)))
ereport(ERROR,
@ -373,7 +376,7 @@ void RenameDataSource(const char* oldname, const char* newname)
errmsg("data source \"%s\" already exists", newname)));
/* must be owner of server */
if (!pg_extension_data_source_ownercheck(HeapTupleGetOid(tup), GetUserId()))
if (!pg_extension_data_source_ownercheck(DSOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATA_SOURCE, oldname);
/* rename */
@ -383,6 +386,9 @@ void RenameDataSource(const char* oldname, const char* newname)
tableam_tops_free_tuple(tup);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, DataSourceRelationId, DSOid);
return address;
}
/*
@ -437,10 +443,12 @@ static void AlterDataSourceOwner_Internal(Relation rel, HeapTuple tup, Oid newOw
* @IN newOwnerId: new owner's Oid
* @RETURN: void
*/
void AlterDataSourceOwner(const char* name, Oid newOwnerId)
ObjectAddress AlterDataSourceOwner(const char* name, Oid newOwnerId)
{
HeapTuple tup;
Relation rel;
Oid dsId;
ObjectAddress address;
rel = heap_open(DataSourceRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(DATASOURCENAME, CStringGetDatum(name));
@ -448,7 +456,10 @@ void AlterDataSourceOwner(const char* name, Oid newOwnerId)
ereport(ERROR,
(errmodule(MOD_EC), errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("data source \"%s\" does not exist", name)));
dsId = HeapTupleGetOid(tup);
AlterDataSourceOwner_Internal(rel, tup, newOwnerId);
tableam_tops_free_tuple(tup);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, DataSourceRelationId, dsId);
return address;
}

View File

@ -142,7 +142,7 @@ bool userbindlc(Oid rolid)
/*
* CREATE DATABASE
*/
void createdb(const CreatedbStmt* stmt)
Oid createdb(const CreatedbStmt* stmt)
{
TableScanDesc scan;
Relation rel;
@ -478,7 +478,7 @@ void createdb(const CreatedbStmt* stmt)
if (OidIsValid(get_database_oid(dbname, true))) {
if (stmt->missing_ok) {
ereport(NOTICE, (errmsg("database \"%s\" already exists, skipping", dbname)));
return;
return InvalidOid;
} else {
ereport(ERROR, (errcode(ERRCODE_DUPLICATE_DATABASE), errmsg("database \"%s\" already exists", dbname)));
}
@ -641,7 +641,7 @@ void createdb(const CreatedbStmt* stmt)
dsttablespace = dst_deftablespace;
else
dsttablespace = srctablespace;
dstpath = GetDatabasePath(dboid, dsttablespace);
/*
@ -731,6 +731,7 @@ void createdb(const CreatedbStmt* stmt)
*/
set_dbcleanup_callback(createdb_xact_callback, &fparms.dest_dboid, sizeof(fparms.dest_dboid));
#endif
return dboid;
}
/*
@ -1228,13 +1229,14 @@ void AlterDatabasePermissionCheck(Oid dboid, const char* dbname)
/*
* Rename database
*/
void RenameDatabase(const char* oldname, const char* newname)
ObjectAddress RenameDatabase(const char* oldname, const char* newname)
{
Oid db_id;
HeapTuple newtup;
Relation rel;
int notherbackends;
int npreparedxacts;
ObjectAddress address;
Relation pg_job_tbl = NULL;
TableScanDesc scan = NULL;
HeapTuple tuple = NULL;
@ -1323,6 +1325,9 @@ void RenameDatabase(const char* oldname, const char* newname)
heap_endscan(scan);
heap_close(pg_job_tbl, ExclusiveLock);
ObjectAddressSet(address, DatabaseRelationId, db_id);
return address;
}
@ -1700,8 +1705,9 @@ static void movedb_failure_callback(int code, Datum arg)
/*
* ALTER DATABASE name ...
*/
void AlterDatabase(AlterDatabaseStmt* stmt, bool isTopLevel)
Oid AlterDatabase(AlterDatabaseStmt* stmt, bool isTopLevel)
{
Oid dboid;
Relation rel;
HeapTuple tuple, newtuple;
ScanKeyData scankey;
@ -1749,7 +1755,7 @@ void AlterDatabase(AlterDatabaseStmt* stmt, bool isTopLevel)
PreventTransactionChain(isTopLevel, "ALTER DATABASE SET TABLESPACE");
movedb(stmt->dbname, strVal(dtablespace->arg));
return;
return InvalidOid;
}
if (dconnlimit != NULL) {
@ -1771,6 +1777,7 @@ void AlterDatabase(AlterDatabaseStmt* stmt, bool isTopLevel)
if (!HeapTupleIsValid(tuple))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", stmt->dbname)));
dboid = HeapTupleGetOid(tuple);
/* Permmision Check */
AlterDatabasePermissionCheck(HeapTupleGetOid(tuple), stmt->dbname);
@ -1811,12 +1818,13 @@ void AlterDatabase(AlterDatabaseStmt* stmt, bool isTopLevel)
/* Close pg_database, but keep lock till commit */
heap_close(rel, NoLock);
return dboid;
}
/*
* ALTER DATABASE name SET ...
*/
void AlterDatabaseSet(AlterDatabaseSetStmt* stmt)
Oid AlterDatabaseSet(AlterDatabaseSetStmt* stmt)
{
Oid datid = get_database_oid(stmt->dbname, false);
@ -1836,18 +1844,21 @@ void AlterDatabaseSet(AlterDatabaseSetStmt* stmt)
#endif
UnlockSharedObject(DatabaseRelationId, datid, 0, AccessShareLock);
return datid;
}
/*
* ALTER DATABASE name OWNER TO newowner
*/
void AlterDatabaseOwner(const char* dbname, Oid newOwnerId)
ObjectAddress AlterDatabaseOwner(const char* dbname, Oid newOwnerId)
{
Oid db_id;
HeapTuple tuple;
Relation rel;
ScanKeyData scankey;
SysScanDesc scan;
Form_pg_database datForm;
ObjectAddress address;
if (userbindlc(newOwnerId))
ereport(ERROR,
@ -1865,6 +1876,7 @@ void AlterDatabaseOwner(const char* dbname, Oid newOwnerId)
if (!HeapTupleIsValid(tuple))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname)));
db_id = HeapTupleGetOid(tuple);
datForm = (Form_pg_database)GETSTRUCT(tuple);
/*
@ -1930,11 +1942,13 @@ void AlterDatabaseOwner(const char* dbname, Oid newOwnerId)
/* Update owner dependency reference */
changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple), newOwnerId);
}
ObjectAddressSet(address, DatabaseRelationId, db_id);
systable_endscan(scan);
/* Close pg_database, but keep lock till commit */
heap_close(rel, NoLock);
return address;
}
/*

View File

@ -395,16 +395,20 @@ void RemoveDirectoryById(Oid dirOid)
heap_close(relation, RowExclusiveLock);
}
static void AlterPgDirectoryOwner_internal(Relation rel, HeapTuple tuple, Oid newOwnerId)
static ObjectAddress AlterPgDirectoryOwner_internal(Relation rel, HeapTuple tuple, Oid newOwnerId)
{
Form_pg_directory dirForm = (Form_pg_directory)GETSTRUCT(tuple);
Oid dOid;
ObjectAddress address;
dOid = HeapTupleGetOid(tuple);
ObjectAddressSet(address, PgDirectoryRelationId, dOid);
/*
* If the new owner is the same as the existing owner, consider the
* command to have succeeded. This is to be consistent with other
* objects.
*/
if (dirForm->owner == newOwnerId) {
return;
return address;
}
Datum repl_val[Natts_pg_directory];
@ -459,17 +463,21 @@ static void AlterPgDirectoryOwner_internal(Relation rel, HeapTuple tuple, Oid ne
/* Update owner dependency reference */
changeDependencyOnOwner(PgDirectoryRelationId, HeapTupleGetOid(tuple), newOwnerId);
return address;
}
/*
* ALTER Directory name OWNER TO newowner
*/
void AlterDirectoryOwner(const char* dirname, Oid newOwnerId)
ObjectAddress AlterDirectoryOwner(const char* dirname, Oid newOwnerId)
{
HeapTuple tuple = NULL;
Relation rel;
ScanKeyData scankey;
SysScanDesc scan = NULL;
Oid dOid;
ObjectAddress address;
/*
* Get the old tuple. We don't need a lock on the directory per se,
@ -485,12 +493,15 @@ void AlterDirectoryOwner(const char* dirname, Oid newOwnerId)
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("directory \"%s\" does not exist", dirname)));
}
dOid = HeapTupleGetOid(tuple);
AlterPgDirectoryOwner_internal(rel, tuple, newOwnerId);
systable_endscan(scan);
/* Close pg_database, but keep lock till commit */
heap_close(rel, NoLock);
ObjectAddressSet(address, PgDirectoryRelationId, dOid);
return address;
}

View File

@ -38,6 +38,7 @@
#include "utils/syscache.h"
static void does_not_exist_skipping(ObjectType objtype, List* objname, List* objargs, bool missing_ok);
static bool schema_does_not_exist_skipping(List *object, char **msg, char **name);
static bool CheckObjectDropPrivilege(ObjectType removeType, Oid objectId, const Relation relation)
{
@ -301,6 +302,34 @@ void RemoveObjects(DropStmt* stmt, bool missing_ok, bool is_securityadmin)
free_object_addresses(objects);
}
/*
* schema_does_not_exist_skipping
* Subroutine for RemoveObjects
*
* After determining that a specification for a schema-qualifiable object
* refers to an object that does not exist, test whether the specified schema
* exists or not. If no schema was specified, or if the schema does exist,
* return false -- the object itself is missing instead. If the specified
* schema does not exist, fill the error message format string and the
* specified schema name, and return true.
*/
static bool schema_does_not_exist_skipping(List *object, char **msg, char **name)
{
RangeVar *rel;
rel = makeRangeVarFromNameList(object);
if (rel->schemaname != NULL &&
!OidIsValid(LookupNamespaceNoError(rel->schemaname))) {
*msg = gettext_noop("schema \"%s\" does not exist, skipping");
*name = rel->schemaname;
return true;
}
return false;
}
/*
* Generate a NOTICE stating that the named object was not found, and is
* being skipped. This is only relevant when "IF EXISTS" is used; otherwise,
@ -316,9 +345,23 @@ static void does_not_exist_skipping(ObjectType objtype, List* objname, List* obj
switch (objtype) {
case OBJECT_TYPE:
case OBJECT_DOMAIN:
msg = gettext_noop("type \"%s\" does not exist");
name = TypeNameToString(makeTypeNameFromNameList(objname));
break;
{
/*objname migth be a TypeName list or a String list, check its node type firstly*/
Node * ptype = (Node*) linitial(objname);
TypeName *typ = NULL;
if (ptype->type == T_String)
typ = makeTypeNameFromNameList(objname);
else if (ptype->type == T_TypeName)
typ = (TypeName*)linitial(objname);
else
ereport(ERROR, (errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), (errmsg("unknown type: %d",(int)ptype->type))));
if (!schema_does_not_exist_skipping(typ->names, &msg, &name)) {
msg = gettext_noop("type \"%s\" does not exist");
name = TypeNameToString(typ);
}
} break;
case OBJECT_COLLATION:
msg = gettext_noop("collation \"%s\" does not exist");
name = NameListToString(objname);
@ -395,6 +438,10 @@ static void does_not_exist_skipping(ObjectType objtype, List* objname, List* obj
args = NameListToString(list_truncate(list_copy(objname), list_length(objname) - 1));
break;
}
case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
name = NameListToString(objname);
break;
case OBJECT_RULE:
msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist");
name = strVal(llast(objname));
@ -409,15 +456,25 @@ static void does_not_exist_skipping(ObjectType objtype, List* objname, List* obj
name = NameListToString(objname);
break;
case OBJECT_OPCLASS:
msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\"");
name = NameListToString(objname);
args = strVal(linitial(objargs));
break;
{
List *opcname = list_copy_tail(objname, 1);
if (!schema_does_not_exist_skipping(opcname, &msg, &name)) {
msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\"");
name = NameListToString(opcname);
args = strVal(linitial(objname));
}
list_free_ext(opcname);
} break;
case OBJECT_OPFAMILY:
msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\"");
name = NameListToString(objname);
args = strVal(linitial(objargs));
break;
{
List *opfname = list_copy_tail(objname, 1);
if (!schema_does_not_exist_skipping(opfname, &msg, &name)) {
msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\"");
name = NameListToString(opfname);
args = strVal(linitial(objname));
}
list_free_ext(opfname);
} break;
case OBJECT_DATA_SOURCE:
msg = gettext_noop("data source \"%s\" does not exist");
name = NameListToString(objname);

File diff suppressed because it is too large Load Diff

View File

@ -770,7 +770,8 @@ static void execute_sql_string(const char* sql, const char* filename)
#ifdef PGXC
true, /* this is created at remote node level */
#endif /* PGXC */
NULL);
NULL,
PROCESS_UTILITY_QUERY);
}
PopActiveSnapshot();
@ -1154,7 +1155,7 @@ static List* find_update_path(
/*
* CREATE EXTENSION
*/
void CreateExtension(CreateExtensionStmt* stmt)
ObjectAddress CreateExtension(CreateExtensionStmt* stmt)
{
DefElem* d_schema = NULL;
DefElem* d_new_version = NULL;
@ -1175,6 +1176,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
char* c_sql = NULL;
int keylen;
uint32 hashvalue = 0;
ObjectAddress address;
/* User defined extension only support postgis. */
if (!IsInitdb && !u_sess->attr.attr_common.IsInplaceUpgrade &&
@ -1209,7 +1211,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
ereport(NOTICE,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("extension \"%s\" already exists in schema \"%s\", skipping", stmt->extname, schemaName)));
return;
return InvalidObjectAddress;
} else {
#ifndef ENABLE_MULTIPLE_NODES
ereport(ERROR,
@ -1435,7 +1437,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
/*
* Insert new tuple into pg_extension, and create dependency entries.
*/
extensionOid = InsertExtensionTuple(control->name,
address = InsertExtensionTuple(control->name,
extowner,
schemaOid,
control->relocatable,
@ -1444,6 +1446,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
PointerGetDatum(NULL),
requiredExtensions);
extensionOid = address.objectId;
/*
* Apply any control-file comment on extension
*/
@ -1470,6 +1473,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
u_sess->attr.attr_sql.whale = true;
}
#endif
return address;
}
/*
@ -1485,7 +1489,7 @@ void CreateExtension(CreateExtensionStmt* stmt)
* extConfig and extCondition should be arrays or PointerGetDatum(NULL).
* We declare them as plain Datum to avoid needing array.h in extension.h.
*/
Oid InsertExtensionTuple(const char* extName, Oid extOwner, Oid schemaOid, bool relocatable, const char* extVersion,
ObjectAddress InsertExtensionTuple(const char* extName, Oid extOwner, Oid schemaOid, bool relocatable, const char* extVersion,
Datum extConfig, Datum extCondition, List* requiredExtensions)
{
Oid extensionOid;
@ -1560,7 +1564,7 @@ Oid InsertExtensionTuple(const char* extName, Oid extOwner, Oid schemaOid, bool
/* Post creation hook for new extension */
InvokeObjectAccessHook(OAT_POST_CREATE, ExtensionRelationId, extensionOid, 0, NULL);
return extensionOid;
return myself;
}
/*
@ -2328,7 +2332,7 @@ static void extension_config_remove(Oid extensionoid, Oid tableoid)
/*
* Execute ALTER EXTENSION SET SCHEMA
*/
void AlterExtensionNamespace(List* names, const char* newschema)
ObjectAddress AlterExtensionNamespace(List* names, const char* newschema)
{
char* extensionName = NULL;
Oid extensionOid;
@ -2344,7 +2348,7 @@ void AlterExtensionNamespace(List* names, const char* newschema)
SysScanDesc depScan;
HeapTuple depTup;
ObjectAddresses* objsMoved = NULL;
ObjectAddress extAddr;
if (list_length(names) != 1)
ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("extension name cannot be qualified")));
extensionName = strVal(linitial(names));
@ -2402,7 +2406,7 @@ void AlterExtensionNamespace(List* names, const char* newschema)
*/
if (extForm->extnamespace == nspOid) {
heap_close(extRel, RowExclusiveLock);
return;
return InvalidObjectAddress;
}
/* Check extension is supposed to be relocatable */
@ -2482,12 +2486,16 @@ void AlterExtensionNamespace(List* names, const char* newschema)
/* update dependencies to point to the new schema */
changeDependencyFor(ExtensionRelationId, extensionOid, NamespaceRelationId, oldNspOid, nspOid);
ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
return extAddr;
}
/*
* Execute ALTER EXTENSION UPDATE
*/
void ExecAlterExtensionStmt(AlterExtensionStmt* stmt)
ObjectAddress ExecAlterExtensionStmt(AlterExtensionStmt* stmt)
{
DefElem* d_new_version = NULL;
char* versionName = NULL;
@ -2502,6 +2510,7 @@ void ExecAlterExtensionStmt(AlterExtensionStmt* stmt)
Datum datum;
bool isnull = false;
ListCell* lc = NULL;
ObjectAddress address;
/*
* We use global variables to track the extension being created, so we can
@ -2583,7 +2592,7 @@ void ExecAlterExtensionStmt(AlterExtensionStmt* stmt)
if (strcmp(oldVersionName, versionName) == 0) {
ereport(
NOTICE, (errmsg("version \"%s\" of extension \"%s\" is already installed", versionName, stmt->extname)));
return;
return InvalidObjectAddress;
}
/*
@ -2596,6 +2605,9 @@ void ExecAlterExtensionStmt(AlterExtensionStmt* stmt)
* time
*/
ApplyExtensionUpdates(extensionOid, control, oldVersionName, updateVersions);
ObjectAddressSet(address, ExtensionRelationId, extensionOid);
return address;
}
/*
@ -2744,7 +2756,7 @@ static void ApplyExtensionUpdates(
/*
* Execute ALTER EXTENSION ADD/DROP
*/
void ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt* stmt)
ObjectAddress ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt* stmt, ObjectAddress *objAddr)
{
ObjectAddress extension;
ObjectAddress object;
@ -2768,6 +2780,10 @@ void ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt* stmt)
object =
get_object_address(stmt->objtype, stmt->objname, stmt->objargs, &relation, ShareUpdateExclusiveLock, false);
Assert(object.objectSubId == 0);
if (objAddr)
*objAddr = object;
/* Permission check: must own target object, too */
check_object_ownership(GetUserId(), stmt->objtype, object, stmt->objname, stmt->objargs, relation);
@ -2836,6 +2852,8 @@ void ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt* stmt)
*/
if (relation != NULL)
relation_close(relation, NoLock);
return extension;
}
/*

View File

@ -202,39 +202,6 @@ static Oid GetUserOidFromMapping(const char* username, bool missing_ok)
return get_role_oid(username, missing_ok);
}
/*
* Rename foreign-data wrapper
*/
void RenameForeignDataWrapper(const char* oldname, const char* newname)
{
HeapTuple tup;
Relation rel;
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(oldname));
if (!HeapTupleIsValid(tup))
ereport(
ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("foreign-data wrapper \"%s\" does not exist", oldname)));
/* make sure the new name doesn't exist */
if (SearchSysCacheExists1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(newname)))
ereport(
ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("foreign-data wrapper \"%s\" already exists", newname)));
/* must be owner of FDW */
if (!pg_foreign_data_wrapper_ownercheck(HeapTupleGetOid(tup), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FDW, oldname);
/* rename */
(void)namestrcpy(&(((Form_pg_foreign_data_wrapper)GETSTRUCT(tup))->fdwname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_close(rel, NoLock);
heap_freetuple(tup);
}
/*
* Must be owner or have alter privilege to alter server
*/
@ -246,36 +213,6 @@ static void AlterServerPermissionCheck(Oid srvId, const char* servername)
}
}
/*
* Rename foreign server
*/
void RenameForeignServer(const char* oldname, const char* newname)
{
HeapTuple tup;
Relation rel;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(oldname));
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("server \"%s\" does not exist", oldname)));
/* make sure the new name doesn't exist */
if (SearchSysCacheExists1(FOREIGNSERVERNAME, CStringGetDatum(newname)))
ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("server \"%s\" already exists", newname)));
/* Permission check. */
AlterServerPermissionCheck(HeapTupleGetOid(tup), oldname);
/* rename */
(void)namestrcpy(&(((Form_pg_foreign_server)GETSTRUCT(tup))->srvname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_close(rel, NoLock);
heap_freetuple(tup);
}
/*
* Internal workhorse for changing a data wrapper's owner.
*
@ -319,10 +256,12 @@ static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, O
*
* Note restrictions in the "_internal" function, above.
*/
void AlterForeignDataWrapperOwner(const char* name, Oid newOwnerId)
ObjectAddress AlterForeignDataWrapperOwner(const char* name, Oid newOwnerId)
{
Oid fdwId;
HeapTuple tup;
Relation rel;
ObjectAddress address;
rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
@ -330,12 +269,14 @@ void AlterForeignDataWrapperOwner(const char* name, Oid newOwnerId)
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("foreign-data wrapper \"%s\" does not exist", name)));
fdwId = HeapTupleGetOid(tup);
AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
ObjectAddressSet(address, ForeignDataWrapperRelationId, fdwId);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
return address;
}
/*
@ -409,10 +350,12 @@ static void AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid ne
/*
* Change foreign server owner -- by name
*/
void AlterForeignServerOwner(const char* name, Oid newOwnerId)
ObjectAddress AlterForeignServerOwner(const char* name, Oid newOwnerId)
{
Oid servOid;
HeapTuple tup;
Relation rel;
ObjectAddress address;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
@ -420,12 +363,14 @@ void AlterForeignServerOwner(const char* name, Oid newOwnerId)
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("server \"%s\" does not exist", name)));
servOid = HeapTupleGetOid(tup);
AlterForeignServerOwner_internal(rel, tup, newOwnerId);
ObjectAddressSet(address, ForeignServerRelationId, servOid);
heap_freetuple(tup);
heap_close(rel, RowExclusiveLock);
return address;
}
/*
@ -525,7 +470,7 @@ static void parse_func_options(
/*
* Create a foreign-data wrapper
*/
void CreateForeignDataWrapper(CreateFdwStmt* stmt)
ObjectAddress CreateForeignDataWrapper(CreateFdwStmt* stmt)
{
Relation rel;
Datum values[Natts_pg_foreign_data_wrapper];
@ -623,12 +568,13 @@ void CreateForeignDataWrapper(CreateFdwStmt* stmt)
InvokeObjectAccessHook(OAT_POST_CREATE, ForeignDataWrapperRelationId, fdwId, 0, NULL);
heap_close(rel, RowExclusiveLock);
return myself;
}
/*
* Alter foreign-data wrapper
*/
void AlterForeignDataWrapper(AlterFdwStmt* stmt)
ObjectAddress AlterForeignDataWrapper(AlterFdwStmt* stmt)
{
Relation rel;
HeapTuple tp;
@ -644,6 +590,7 @@ void AlterForeignDataWrapper(AlterFdwStmt* stmt)
Oid fdwhandler;
Oid fdwvalidator;
errno_t ret = EOK;
ObjectAddress myself;
/* Must be super user */
if (!superuser())
@ -730,9 +677,10 @@ void AlterForeignDataWrapper(AlterFdwStmt* stmt)
heap_freetuple(tp);
ObjectAddressSet(myself, ForeignDataWrapperRelationId, fdwId);
/* Update function dependencies if we changed them */
if (handler_given || validator_given) {
ObjectAddress myself;
ObjectAddress referenced;
/*
@ -742,10 +690,6 @@ void AlterForeignDataWrapper(AlterFdwStmt* stmt)
(void)deleteDependencyRecordsForClass(
ForeignDataWrapperRelationId, fdwId, ProcedureRelationId, DEPENDENCY_NORMAL);
/* And build new ones. */
myself.classId = ForeignDataWrapperRelationId;
myself.objectId = fdwId;
myself.objectSubId = 0;
if (OidIsValid(fdwhandler)) {
referenced.classId = ProcedureRelationId;
@ -763,6 +707,7 @@ void AlterForeignDataWrapper(AlterFdwStmt* stmt)
}
heap_close(rel, RowExclusiveLock);
return myself;
}
/*
@ -791,7 +736,7 @@ void RemoveForeignDataWrapperById(Oid fdwId)
/*
* Create a foreign server
*/
void CreateForeignServer(CreateForeignServerStmt* stmt)
ObjectAddress CreateForeignServer(CreateForeignServerStmt* stmt)
{
Relation rel;
Datum srvoptions;
@ -928,12 +873,13 @@ void CreateForeignServer(CreateForeignServerStmt* stmt)
relation_close(tmp_rel, ShareUpdateExclusiveLock);
}
}
return myself;
}
/*
* Alter foreign server
*/
void AlterForeignServer(AlterForeignServerStmt* stmt)
ObjectAddress AlterForeignServer(AlterForeignServerStmt* stmt)
{
Relation rel;
HeapTuple tp;
@ -943,6 +889,7 @@ void AlterForeignServer(AlterForeignServerStmt* stmt)
Oid srvId;
Form_pg_foreign_server srvForm;
errno_t ret = EOK;
ObjectAddress address;
rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
@ -1039,6 +986,9 @@ void AlterForeignServer(AlterForeignServerStmt* stmt)
} else if (0 == pg_strcasecmp(typeName, DUMMY_SERVER)) {
InvalidDummyServerCache(srvId);
}
ObjectAddressSet(address, ForeignServerRelationId, srvId);
return address;
}
/*
@ -1098,7 +1048,7 @@ static void user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char* se
/*
* Create user mapping
*/
void CreateUserMapping(CreateUserMappingStmt* stmt)
ObjectAddress CreateUserMapping(CreateUserMappingStmt* stmt)
{
Relation rel;
Datum useoptions;
@ -1185,12 +1135,13 @@ void CreateUserMapping(CreateUserMappingStmt* stmt)
InvokeObjectAccessHook(OAT_POST_CREATE, UserMappingRelationId, umId, 0, NULL);
heap_close(rel, RowExclusiveLock);
return myself;
}
/*
* Alter user mapping
*/
void AlterUserMapping(AlterUserMappingStmt* stmt)
ObjectAddress AlterUserMapping(AlterUserMappingStmt* stmt)
{
Relation rel;
HeapTuple tp;
@ -1201,6 +1152,7 @@ void AlterUserMapping(AlterUserMappingStmt* stmt)
Oid umId;
ForeignServer* srv = NULL;
errno_t ret = EOK;
ObjectAddress address;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
@ -1242,7 +1194,6 @@ void AlterUserMapping(AlterUserMappingStmt* stmt)
datum = PointerGetDatum(NULL);
EncryptGenericOptions(stmt->options, g_sensitiveOptionsArray, g_sensitiveArrayLength, USER_MAPPING_MODE);
/* Prepare the options array */
datum = transformGenericOptions(UserMappingRelationId, datum, stmt->options, fdw->fdwvalidator);
@ -1260,15 +1211,17 @@ void AlterUserMapping(AlterUserMappingStmt* stmt)
simple_heap_update(rel, &tp->t_self, tp);
CatalogUpdateIndexes(rel, tp);
ObjectAddressSet(address, UserMappingRelationId, umId);
heap_freetuple(tp);
heap_close(rel, RowExclusiveLock);
return address;
}
/*
* Drop user mapping
*/
void RemoveUserMapping(DropUserMappingStmt* stmt)
Oid RemoveUserMapping(DropUserMappingStmt* stmt)
{
ObjectAddress object;
Oid useId;
@ -1286,7 +1239,7 @@ void RemoveUserMapping(DropUserMappingStmt* stmt)
ereport(NOTICE,
(errcode(ERRCODE_INVALID_ROLE_SPECIFICATION),
errmsg("role \"%s\" does not exist, skipping", stmt->username)));
return;
return InvalidOid;
}
if (srv == NULL) {
@ -1295,7 +1248,7 @@ void RemoveUserMapping(DropUserMappingStmt* stmt)
ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("server \"%s\" does not exist", stmt->servername)));
/* IF EXISTS, just note it */
ereport(NOTICE, (errcode(ERRCODE_LOG), (errmsg("server does not exist, skipping"))));
return;
return InvalidOid;
}
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, ObjectIdGetDatum(useId), ObjectIdGetDatum(srv->serverid));
@ -1309,7 +1262,7 @@ void RemoveUserMapping(DropUserMappingStmt* stmt)
/* IF EXISTS specified, just note it */
ereport(
NOTICE, (errmsg("user mapping \"%s\" does not exist for the server, skipping", MappingUserName(useId))));
return;
return InvalidOid;
}
user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
@ -1322,6 +1275,7 @@ void RemoveUserMapping(DropUserMappingStmt* stmt)
object.objectSubId = 0;
performDeletion(&object, DROP_CASCADE, 0);
return umId;
}
/*
@ -1604,10 +1558,6 @@ void encryptOBSForeignTableOption(List** options)
securec_check(rc, "", "");
}
/*
* Create a foreign table
* call after DefineRelation().
*/
void CreateForeignTable(CreateForeignTableStmt* stmt, Oid relid)
{
Relation ftrel;
@ -1770,6 +1720,7 @@ void CreateForeignTable(CreateForeignTableStmt* stmt, Oid relid)
static const char* const validnsps[] = HEAP_RELOPT_NAMESPACES;
List* colList = NIL;
ColumnDef* col = NULL;
ObjectAddress tmp;
CreateStmt* errorStmt = makeNode(CreateStmt);
char* schemaname =
((CreateStmt*)stmt)->relation->schemaname ? pstrdup(((CreateStmt*)stmt)->relation->schemaname) : NULL;
@ -1879,8 +1830,8 @@ void CreateForeignTable(CreateForeignTableStmt* stmt, Oid relid)
errorStmt->subcluster->members = list_make1(makeString(group_name));
}
errortableOid = DefineRelation(errorStmt, RELKIND_RELATION, InvalidOid);
tmp = DefineRelation(errorStmt, RELKIND_RELATION, InvalidOid, NULL);
errortableOid = tmp.objectId;
/*
* Let AlterTableCreateToastTable decide if this one
* needs a secondary relation too.

View File

@ -138,6 +138,8 @@ static void compute_return_type(
Type typtup;
AclResult aclresult;
Oid typowner = InvalidOid;
ObjectAddress address;
/*
* isalter is true, change the owner of the objects as the owner of the
* namespace, if the owner of the namespce has the same name as the namescpe
@ -245,7 +247,8 @@ static void compute_return_type(
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId));
}
rettype = TypeShellMake(typname, namespaceId, typowner);
address = TypeShellMake(typname, namespaceId, typowner);
rettype = address.objectId;
Assert(OidIsValid(rettype));
}
@ -952,7 +955,7 @@ extern HeapTuple SearchUserHostName(const char* userName, Oid* oid);
* CreateFunction
* Execute a CREATE FUNCTION utility statement.
*/
void CreateFunction(CreateFunctionStmt* stmt, const char* queryString, Oid pkg_oid)
ObjectAddress CreateFunction(CreateFunctionStmt* stmt, const char* queryString, Oid pkg_oid)
{
char* probin_str = NULL;
char* prosrc_str = NULL;
@ -1222,8 +1225,16 @@ void CreateFunction(CreateFunctionStmt* stmt, const char* queryString, Oid pkg_o
* And now that we have all the parameters, and know we're permitted to do
* so, go ahead and create the function.
*/
Oid procedureOid = ProcedureCreate(funcname, namespaceId, pkg_oid, stmt->isOraStyle, stmt->replace,
returnsSet, prorettype, proowner, languageOid, languageValidator,
ObjectAddress address=ProcedureCreate(funcname,
namespaceId,
pkg_oid,
stmt->isOraStyle,
stmt->replace,
returnsSet,
prorettype,
proowner,
languageOid,
languageValidator,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
false, /* not an aggregate */
@ -1242,7 +1253,7 @@ void CreateFunction(CreateFunctionStmt* stmt, const char* queryString, Oid pkg_o
stmt->inputHeaderSrc,
stmt->isPrivate);
CreateFunctionComment(procedureOid, functionOptions);
CreateFunctionComment(address.objectId, functionOptions);
u_sess->plsql_cxt.procedure_start_line = 0;
u_sess->plsql_cxt.procedure_first_line = 0;
@ -1250,6 +1261,7 @@ void CreateFunction(CreateFunctionStmt* stmt, const char* queryString, Oid pkg_o
if (u_sess->plsql_cxt.debug_query_string != NULL && !OidIsValid(pkg_oid)) {
pfree_ext(u_sess->plsql_cxt.debug_query_string);
}
return address;
}
/*
@ -1567,7 +1579,7 @@ void DeleteFunctionByPackageOid(Oid package_oid)
/*
* Rename function
*/
void RenameFunction(List* name, List* argtypes, const char* newname)
ObjectAddress RenameFunction(List* name, List* argtypes, const char* newname)
{
Oid procOid;
Oid namespaceOid;
@ -1575,6 +1587,8 @@ void RenameFunction(List* name, List* argtypes, const char* newname)
Form_pg_proc procForm;
Relation rel;
AclResult aclresult;
ObjectAddress address;
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
procOid = LookupFuncNameTypeNames(name, argtypes, false);
@ -1593,6 +1607,8 @@ void RenameFunction(List* name, List* argtypes, const char* newname)
errmsg("the masking function \"%s\" can not be renamed", get_func_name(procOid))));
}
ObjectAddressSubSet(address, ProcedureRelationId, procOid, 0);
tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(procOid));
if (!HeapTupleIsValid(tup)) /* should not happen */
ereport(ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for function %u", procOid)));
@ -1683,16 +1699,19 @@ void RenameFunction(List* name, List* argtypes, const char* newname)
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
return address;
}
/*
* Change function owner by name and args
*/
void AlterFunctionOwner(List* name, List* argtypes, Oid newOwnerId)
ObjectAddress AlterFunctionOwner(List* name, List* argtypes, Oid newOwnerId)
{
Relation rel;
Oid procOid;
HeapTuple tup;
ObjectAddress address;
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
procOid = LookupFuncNameTypeNames(name, argtypes, false);
@ -1732,6 +1751,8 @@ void AlterFunctionOwner(List* name, List* argtypes, Oid newOwnerId)
UpdatePgObjectMtime(procOid, OBJECT_TYPE_PROC);
heap_close(rel, NoLock);
ObjectAddressSet(address, ProcedureRelationId, procOid);
return address;
}
/*
@ -1933,7 +1954,7 @@ bool IsFunctionTemp(AlterFunctionStmt* stmt)
* RENAME and OWNER clauses, which are handled as part of the generic
* ALTER framework).
*/
void AlterFunction(AlterFunctionStmt* stmt)
ObjectAddress AlterFunction(AlterFunctionStmt* stmt)
{
HeapTuple tup;
Oid funcOid;
@ -1950,6 +1971,7 @@ void AlterFunction(AlterFunctionStmt* stmt)
DefElem* fencedItem = NULL;
DefElem* shippable_item = NULL;
DefElem* package_item = NULL;
ObjectAddress address;
bool isNull = false;
funcOid = LookupFuncNameTypeNames(stmt->func->funcname, stmt->func->funcargs, false);
@ -2148,8 +2170,10 @@ void AlterFunction(AlterFunctionStmt* stmt)
InvalidRelcacheForTriggerFunction(funcOid, procForm->prorettype);
}
ObjectAddressSet(address, ProcedureRelationId, funcOid);
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
return address;
}
/*
@ -2242,7 +2266,7 @@ void SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType)
/*
* CREATE CAST
*/
void CreateCast(CreateCastStmt* stmt)
ObjectAddress CreateCast(CreateCastStmt* stmt)
{
Oid sourcetypeid;
Oid targettypeid;
@ -2543,6 +2567,7 @@ void CreateCast(CreateCastStmt* stmt)
tableam_tops_free_tuple(tuple);
heap_close(relation, RowExclusiveLock);
return myself;
}
/*
@ -2591,10 +2616,11 @@ void DropCastById(Oid castOid)
*
* These commands are identical except for the lookup procedure, so share code.
*/
void AlterFunctionNamespace(List* name, List* argtypes, bool isagg, const char* newschema)
ObjectAddress AlterFunctionNamespace(List* name, List* argtypes, bool isagg, const char* newschema)
{
Oid procOid;
Oid nspOid;
ObjectAddress address;
/* get function OID */
if (isagg)
@ -2608,6 +2634,8 @@ void AlterFunctionNamespace(List* name, List* argtypes, bool isagg, const char*
TrForbidAccessRbObject(ProcedureRelationId, nspOid);
(void)AlterFunctionNamespace_oid(procOid, nspOid);
ObjectAddressSet(address, ProcedureRelationId, procOid);
return address;
}
Oid AlterFunctionNamespace_oid(Oid procOid, Oid nspOid)
@ -3077,3 +3105,26 @@ static void checkAllowAlter(HeapTuple tup) {
erraction("rebuild package")));
}
}
/*
* Subroutine for ALTER FUNCTION/AGGREGATE SET SCHEMA/RENAME
*
* Is there a function with the given name and signature already in the given
* namespace? If so, raise an appropriate error message.
*/
void
IsThereFunctionInNamespace(const char *proname, int pronargs,
oidvector *proargtypes, Oid nspOid)
{
/* check for duplicate name (more friendly than unique-index failure) */
if (SearchSysCacheExists3(PROCNAMEARGSNSP,
CStringGetDatum(proname),
PointerGetDatum(proargtypes),
ObjectIdGetDatum(nspOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_FUNCTION),
errmsg("function %s already exists in schema \"%s\"",
funcname_signature_string(proname, pronargs,
NIL, proargtypes->values),
get_namespace_name(nspOid))));
}

View File

@ -653,9 +653,9 @@ static bool parseVisibleStateFromOptions(List* options)
* it will be filled later.
* 'quiet': suppress the NOTICE chatter ordinarily provided for constraints.
*
* Returns the OID of the created index.
* Returns the object address of the created index.
*/
Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_alter_table, bool check_rights,
ObjectAddress DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_alter_table, bool check_rights,
bool skip_build, bool quiet, bool is_modify_primary)
{
char* indexRelationName = NULL;
@ -666,9 +666,11 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
Oid accessMethodId = InvalidOid;
Oid namespaceId = InvalidOid;
Oid tablespaceId = InvalidOid;
//Oid relfilenode = InvalidOid;
bool dfsTablespace = false;
List* indexColNames = NIL;
List* allIndexParams = NIL;
//List *filenodeList = NIL;
Relation rel;
HeapTuple tuple;
Form_pg_am accessMethodForm;
@ -690,6 +692,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
List* partitiontspList = NIL;
char relPersistence;
bool concurrent;
ObjectAddress address;
StdRdOptions* index_relopts;
int8 indexsplitMethod = INDEXSPLIT_NO_DEFAULT;
int crossbucketopt = -1;
@ -800,7 +803,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
(errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("relation \"%s\" already exists, skipping", stmt->idxname)));
heap_close(rel, NoLock);
return indexRelationId;
return address;
}
if (stmt->schemaname != NULL) {
@ -1384,7 +1387,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
* If be informational constraint, we are not to set not null in pg_attribute.
*/
if (stmt->primary && !stmt->internal_flag)
index_check_primary_key(rel, indexInfo, is_alter_table, is_modify_primary);
index_check_primary_key(rel, indexInfo, is_alter_table, stmt, is_modify_primary);
/*
* Report index creation if appropriate (delay this till after most of the
@ -1492,16 +1495,18 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
if (idxNameChanged) {
stmt->idxname = NULL;
}
return indexRelationId;
ObjectAddressSet(address, RelationRelationId, indexRelationId);
return address;
}
/* Roll back any GUC changes executed by index functions. */
AtEOXact_GUC(false, root_save_nestlevel);
/* Restore userid and security context */
SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
return buildInformationalConstraint(stmt, indexRelationId, indexRelationName, rel, indexInfo, namespaceId);
ObjectAddressSet(address, RelationRelationId, indexRelationId);
buildInformationalConstraint(stmt, indexRelationId, indexRelationName, rel, indexInfo, namespaceId);
return address;
}
#endif
/* Roll back any GUC changes executed by index functions. */
@ -1510,7 +1515,9 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
/* Restore userid and security context */
SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
return buildInformationalConstraint(stmt, indexRelationId, indexRelationName, rel, indexInfo, namespaceId);
buildInformationalConstraint(stmt, indexRelationId, indexRelationName, rel, indexInfo, namespaceId);
ObjectAddressSet(address, RelationRelationId, indexRelationId);
return address;
}
/* workload client manager */
@ -1570,6 +1577,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
if (stmt->idxcomment != NULL)
CreateComments(indexRelationId, RelationRelationId, 0, stmt->idxcomment);
ObjectAddressSet(address, RelationRelationId, indexRelationId);
/* create the LOCAL index partition */
if (stmt->isPartitioned && !stmt->isGlobal) {
Relation partitionedIndex = index_open(indexRelationId, AccessExclusiveLock);
@ -1792,15 +1800,8 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
heap_close(partitionedIndex, NoLock);
heap_close(rel, NoLock);
return indexRelationId;
}
if (RELATION_IS_PARTITIONED(rel)) {
releasePartitionOidList(&partitionOidList);
}
if (RelationIsSubPartitioned(rel)) {
ReleaseSubPartitionOidList(&subPartitionOidList);
ObjectAddressSet(address, RelationRelationId, indexRelationId);
return address;
}
/* Roll back any GUC changes executed by index functions. */
@ -1812,7 +1813,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
if (!concurrent) {
/* Close the heap and we're done, in the non-concurrent case */
heap_close(rel, NoLock);
return indexRelationId;
return address;
}
// cstore relation doesn't support concurrent INDEX now.
@ -1990,7 +1991,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
*/
UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
return indexRelationId;
return address;
}
/*
@ -2013,7 +2014,7 @@ Oid DefineIndex(Oid relationId, IndexStmt* stmt, Oid indexRelationId, bool is_al
*/
UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
return indexRelationId;
return address;
}
/*
@ -2918,7 +2919,7 @@ List* ChooseIndexColumnNames(const List* indexElems)
* ReindexIndex
* Recreate a specific index.
*/
void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem* mem_info, bool concurrent)
Oid ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem* mem_info, bool concurrent)
{
struct ReindexIndexCallbackState state;
Oid indOid;
@ -2969,7 +2970,6 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
ReindexRelationConcurrently(indOid, indPartOid, mem_info, false);
else {
reindex_index(indOid, indPartOid, false, mem_info, false);
#ifndef ENABLE_MULTIPLE_NODES
Oid relId = IndexGetRelation(indOid, false);
if (RelationIsCUFormatByOid(relId) && irel->rd_index != NULL && irel->rd_index->indisunique) {
/*
@ -2978,8 +2978,8 @@ void ReindexIndex(RangeVar* indexRelation, const char* partition_name, AdaptMem*
*/
ReindexDeltaIndex(indOid, indPartOid);
}
#endif
}
return indOid;
}
void PartitionNameCallbackForIndexPartition(Oid partitionedRelationOid, const char* partitionName, Oid partId,
@ -3145,7 +3145,7 @@ static void RangeVarCallbackForReindexIndex(
* ReindexTable
* Recreate all indexes of a table (and of its toast table, if any)
*/
void ReindexTable(RangeVar* relation, const char* partition_name, AdaptMem* mem_info, bool concurrent)
Oid ReindexTable(RangeVar* relation, const char* partition_name, AdaptMem* mem_info, bool concurrent)
{
Oid heapOid;
bool result;
@ -3188,6 +3188,7 @@ void ReindexTable(RangeVar* relation, const char* partition_name, AdaptMem* mem_
if (!result)
ereport(NOTICE, (errmsg("table \"%s\" has no indexes", relation->relname)));
}
return heapOid;
}
/*
@ -3197,7 +3198,7 @@ void ReindexTable(RangeVar* relation, const char* partition_name, AdaptMem* mem_
* @ in partition_name: the partition_table is used to execute the operation of 'reindex internal table name partition
*partition_name'.
*/
void ReindexInternal(RangeVar* relation, const char* partition_name)
Oid ReindexInternal(RangeVar* relation, const char* partition_name)
{
Oid heapOid;
Relation rel;
@ -3290,6 +3291,7 @@ void ReindexInternal(RangeVar* relation, const char* partition_name)
}
heap_close(rel, NoLock);
return heapOid;
}
/*
@ -3300,7 +3302,7 @@ void ReindexInternal(RangeVar* relation, const char* partition_name)
* separate transaction, so we can release the lock on it right away.
* That means this must not be called within a user transaction block!
*/
void ReindexDatabase(const char* databaseName, bool do_system, bool do_user, AdaptMem* mem_info, bool concurrent)
Oid ReindexDatabase(const char* databaseName, bool do_system, bool do_user, AdaptMem* mem_info, bool concurrent)
{
Relation relationRelation;
TableScanDesc scan;
@ -3476,6 +3478,7 @@ void ReindexDatabase(const char* databaseName, bool do_system, bool do_user, Ada
StartTransactionCommand();
MemoryContextDelete(private_context);
return u_sess->proc_cxt.MyDatabaseId;
}
/*

View File

@ -65,6 +65,7 @@ typedef struct {
Query* viewParse; /* the query which defines/populates data */
/* These fields are filled by intorel_startup: */
Relation rel; /* relation to write to */
ObjectAddress reladdr; /* address of rel, for ExecCreateTableAs */
CommandId output_cid; /* cmin to insert in output tuples */
int hi_options; /* heap_insert performance options */
BulkInsertState bistate; /* bulk insert state */
@ -804,7 +805,7 @@ static void ExecutorRefreshMatInc(QueryDesc* queryDesc, Query *query,
return;
}
void ExecRefreshMatViewInc(RefreshMatViewStmt *stmt, const char *queryString,
ObjectAddress ExecRefreshMatViewInc(RefreshMatViewStmt *stmt, const char *queryString,
ParamListInfo params, char *completionTag)
{
Oid matviewOid;
@ -818,6 +819,7 @@ void ExecRefreshMatViewInc(RefreshMatViewStmt *stmt, const char *queryString,
Oid save_userid;
int save_sec_context;
int save_nestlevel;
ObjectAddress address;
/* Get current timestamp */
curtime = DirectFunctionCall1(timestamptz_timestamp, GetCurrentTimestamp());
@ -834,7 +836,7 @@ void ExecRefreshMatViewInc(RefreshMatViewStmt *stmt, const char *queryString,
Datum oldTime = get_matview_refreshtime(matviewOid, &isTimeNULL);
if (timestamp_cmp_internal(DatumGetTimestamp(curtime),
DatumGetTimestamp(oldTime)) <= 0) {
return;
return InvalidObjectAddress;
}
matviewRel = heap_open(matviewOid, ExclusiveLock);
@ -897,6 +899,7 @@ void ExecRefreshMatViewInc(RefreshMatViewStmt *stmt, const char *queryString,
vacuum_mlog_for_matview(matviewOid);
ObjectAddressSet(address, RelationRelationId, matviewOid);
/* and clean up */
ExecutorFinish(queryDesc);
ExecutorEnd(queryDesc);
@ -911,14 +914,14 @@ void ExecRefreshMatViewInc(RefreshMatViewStmt *stmt, const char *queryString,
/* Restore userid and security context */
SetUserIdAndSecContext(save_userid, save_sec_context);
return;
return address;
}
/*
* ExecRefreshMatViewEpq -- execute a REFRESH MATERIALIZED VIEW command.
* The Matview must be INCREMENTAL.
*/
void ExecRefreshIncMatViewAll(RefreshMatViewStmt *stmt, const char *queryString,
ObjectAddress ExecRefreshIncMatViewAll(RefreshMatViewStmt *stmt, const char *queryString,
ParamListInfo params, char *completionTag)
{
Oid mapid;
@ -932,6 +935,7 @@ void ExecRefreshIncMatViewAll(RefreshMatViewStmt *stmt, const char *queryString,
Oid save_userid;
int save_sec_context;
int save_nestlevel;
ObjectAddress address;
/* Get current timestamp */
curtime = DirectFunctionCall1(timestamptz_timestamp, GetCurrentTimestamp());
@ -1016,18 +1020,18 @@ void ExecRefreshIncMatViewAll(RefreshMatViewStmt *stmt, const char *queryString,
ExecutorEnd(queryDesc);
FreeQueryDesc(queryDesc);
ObjectAddressSet(address, RelationRelationId, matviewOid);
heap_close(matviewRel, NoLock);
/* Roll back any GUC changes */
AtEOXact_GUC(false, save_nestlevel);
/* Restore userid and security context */
SetUserIdAndSecContext(save_userid, save_sec_context);
return;
return address;
}
void ExecRefreshCtasMatViewAll(RefreshMatViewStmt *stmt, const char *queryString,
ObjectAddress ExecRefreshCtasMatViewAll(RefreshMatViewStmt *stmt, const char *queryString,
ParamListInfo params, char *completionTag)
{
Oid matviewOid;
@ -1042,6 +1046,7 @@ void ExecRefreshCtasMatViewAll(RefreshMatViewStmt *stmt, const char *queryString
Oid save_userid;
int save_sec_context;
int save_nestlevel;
ObjectAddress address;
curtime = DirectFunctionCall1(timestamptz_timestamp, GetCurrentTimestamp());
@ -1154,6 +1159,8 @@ void ExecRefreshCtasMatViewAll(RefreshMatViewStmt *stmt, const char *queryString
/* Restore userid and security context */
SetUserIdAndSecContext(save_userid, save_sec_context);
ObjectAddressSet(address, RelationRelationId, matviewOid);
return address;
}
bool isIncMatView(RangeVar *rv)
@ -1198,7 +1205,7 @@ bool isIncMatView(RangeVar *rv)
* The scannable state is changed based on whether the contents reflect the
* result set of the materialized view's query.
*/
void ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
ObjectAddress ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
ParamListInfo params, char *completionTag)
{
if (isIncMatView(stmt->relation)) {
@ -1297,7 +1304,7 @@ static void ExecCreateMatInc(QueryDesc*queryDesc, Query *query, Relation matview
return;
}
void ExecCreateMatViewInc(CreateTableAsStmt* stmt, const char* queryString, ParamListInfo params)
ObjectAddress ExecCreateMatViewInc(CreateTableAsStmt* stmt, const char* queryString, ParamListInfo params)
{
Datum curtime;
Relation matview;
@ -1308,6 +1315,7 @@ void ExecCreateMatViewInc(CreateTableAsStmt* stmt, const char* queryString, Para
QueryDesc* queryDesc = NULL;
PlannedStmt* plan = NULL;
DestReceiver* dest = NULL;
ObjectAddress address;
/* Get current timestamp */
curtime = DirectFunctionCall1(timestamptz_timestamp, GetCurrentTimestamp());
@ -1350,7 +1358,7 @@ void ExecCreateMatViewInc(CreateTableAsStmt* stmt, const char* queryString, Para
update_matview_tuple(matviewid, true, curtime);
ExecCreateMatInc(queryDesc, query, matview, mapid, curtime);
address = ((DR_intorel *) dest)->reladdr;
(*dest->rShutdown)(dest);
/* and clean up */
@ -1368,6 +1376,7 @@ void ExecCreateMatViewInc(CreateTableAsStmt* stmt, const char* queryString, Para
}
CommandCounterIncrement();
return address;
}
/*

View File

@ -33,10 +33,12 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/opfam_internal.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
@ -49,22 +51,10 @@
#include "utils/syscache.h"
#include "utils/snapmgr.h"
/*
* We use lists of this struct type to keep track of both operators and
* procedures while building or adding to an opfamily.
*/
typedef struct {
Oid object; /* operator or support proc's OID */
int number; /* strategy or support proc number */
Oid lefttype; /* lefttype */
Oid righttype; /* righttype */
Oid sortfamily; /* ordering operator's sort opfamily, or 0 */
} OpFamilyMember;
static void AlterOpFamilyAdd(
List* opfamilyname, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items);
static void AlterOpFamilyDrop(
List* opfamilyname, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items);
static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt,
Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items);
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt,
Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items);
static void processTypesSpec(List* args, Oid* lefttype, Oid* righttype);
static void assignOperTypes(OpFamilyMember* member, Oid amoid, Oid typeoid);
static void assignProcTypes(OpFamilyMember* member, Oid amoid, Oid typeoid);
@ -219,7 +209,7 @@ Oid get_opclass_oid(Oid amID, List* opclassname, bool missing_ok)
*
* Caller must have done permissions checks etc. already.
*/
static Oid CreateOpFamily(char* amname, char* opfname, Oid namespaceoid, Oid amoid)
static ObjectAddress CreateOpFamily(char* amname, char* opfname, Oid namespaceoid, Oid amoid)
{
Oid opfamilyoid;
Relation rel;
@ -289,14 +279,14 @@ static Oid CreateOpFamily(char* amname, char* opfname, Oid namespaceoid, Oid amo
heap_close(rel, RowExclusiveLock);
return opfamilyoid;
return myself;
}
/*
* DefineOpClass
* Define a new index operator class.
*/
void DefineOpClass(CreateOpClassStmt* stmt)
ObjectAddress DefineOpClass(CreateOpClassStmt* stmt)
{
char* opcname = NULL; /* name of opclass we're creating */
Oid amoid, /* our AM's oid */
@ -401,7 +391,9 @@ void DefineOpClass(CreateOpClassStmt* stmt)
/*
* Create it ... again no need for more permissions ...
*/
opfamilyoid = CreateOpFamily(stmt->amname, opcname, namespaceoid, amoid);
ObjectAddress tmpAddr;
tmpAddr = CreateOpFamily(stmt->amname, opcname, namespaceoid, amoid);
opfamilyoid = tmpAddr.objectId;
}
}
@ -596,6 +588,9 @@ void DefineOpClass(CreateOpClassStmt* stmt)
storeOperators(stmt->opfamilyname, amoid, opfamilyoid, opclassoid, operators, false);
storeProcedures(stmt->opfamilyname, amoid, opfamilyoid, opclassoid, procedures, false);
/* let event triggers know what happened */
EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
/*
* Create dependencies for the opclass proper. Note: we do not create a
* dependency link to the AM, because we don't currently support DROP
@ -643,13 +638,15 @@ void DefineOpClass(CreateOpClassStmt* stmt)
heap_close(rel, RowExclusiveLock);
list_free(operators);
list_free(procedures);
return myself;
}
/*
* DefineOpFamily
* Define a new index operator family.
*/
void DefineOpFamily(CreateOpFamilyStmt* stmt)
ObjectAddress DefineOpFamily(CreateOpFamilyStmt* stmt)
{
char* opfname = NULL; /* name of opfamily we're creating */
Oid amoid, /* our AM's oid */
@ -677,7 +674,8 @@ void DefineOpFamily(CreateOpFamilyStmt* stmt)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be system admin to create an operator family")));
/* Insert pg_opfamily catalog entry */
(void)CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
}
/*
@ -688,7 +686,7 @@ void DefineOpFamily(CreateOpFamilyStmt* stmt)
* other commands called ALTER OPERATOR FAMILY exist, but go through
* different code paths.
*/
void AlterOpFamily(AlterOpFamilyStmt* stmt)
Oid AlterOpFamily(AlterOpFamilyStmt* stmt)
{
Oid amoid, /* our AM's oid */
opfamilyoid; /* oid of opfamily */
@ -730,16 +728,18 @@ void AlterOpFamily(AlterOpFamilyStmt* stmt)
* ADD and DROP cases need separate code from here on down.
*/
if (stmt->isDrop)
AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid, maxOpNumber, maxProcNumber, stmt->items);
AlterOpFamilyDrop(stmt, amoid, opfamilyoid, maxOpNumber, maxProcNumber, stmt->items);
else
AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid, maxOpNumber, maxProcNumber, stmt->items);
AlterOpFamilyAdd(stmt, amoid, opfamilyoid, maxOpNumber, maxProcNumber, stmt->items);
return opfamilyoid;
}
/*
* ADD part of ALTER OP FAMILY
*/
static void AlterOpFamilyAdd(
List* opfamilyname, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items)
AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items)
{
List* operators = NIL; /* OpFamilyMember list for operators */
List* procedures = NIL; /* OpFamilyMember list for support procs */
@ -843,17 +843,21 @@ static void AlterOpFamilyAdd(
* Add tuples to pg_amop and pg_amproc tying in the operators and
* functions. Dependencies on them are inserted, too.
*/
storeOperators(opfamilyname, amoid, opfamilyoid, InvalidOid, operators, true);
storeProcedures(opfamilyname, amoid, opfamilyoid, InvalidOid, procedures, true);
storeOperators(stmt->opfamilyname, amoid, opfamilyoid, InvalidOid, operators, true);
storeProcedures(stmt->opfamilyname, amoid, opfamilyoid, InvalidOid, procedures, true);
list_free(operators);
list_free(procedures);
/* make information available to event triggers */
EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
operators, procedures);
}
/*
* DROP part of ALTER OP FAMILY
*/
static void AlterOpFamilyDrop(
List* opfamilyname, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items)
AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List* items)
{
List* operators = NIL; /* OpFamilyMember list for operators */
List* procedures = NIL; /* OpFamilyMember list for support procs */
@ -913,8 +917,13 @@ static void AlterOpFamilyDrop(
/*
* Remove tuples from pg_amop and pg_amproc.
*/
dropOperators(opfamilyname, amoid, opfamilyoid, operators);
dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
/* make information available to event triggers */
EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
operators, procedures);
}
/*
@ -1626,15 +1635,80 @@ void RenameOpFamily(List* name, const char* access_method, const char* newname)
tableam_tops_free_tuple(tup);
}
char *
get_am_name(Oid amOid)
{
HeapTuple tup;
char *result = NULL;
tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
if (HeapTupleIsValid(tup)) {
result = pstrdup(NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
ReleaseSysCache(tup);
}
return result;
}
/*
* Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME
*
* Is there an operator class with the given name and signature already
* in the given namespace? If so, raise an appropriate error message.
*/
void
IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
Oid opcnamespace)
{
/* make sure the new name doesn't exist */
if (SearchSysCacheExists3(CLAAMNAMENSP,
ObjectIdGetDatum(opcmethod),
CStringGetDatum(opcname),
ObjectIdGetDatum(opcnamespace)))
{
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
opcname,
get_am_name(opcmethod),
get_namespace_name(opcnamespace))));
}
}
/*
* Subroutine for ALTER OPERATOR FAMILY SET SCHEMA/RENAME
*
* Is there an operator family with the given name and signature already
* in the given namespace? If so, raise an appropriate error message.
*/
void
IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
Oid opfnamespace)
{
/* make sure the new name doesn't exist */
if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(opfmethod),
CStringGetDatum(opfname),
ObjectIdGetDatum(opfnamespace)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
opfname,
get_am_name(opfmethod),
get_namespace_name(opfnamespace))));
}
/*
* Change opclass owner by name
*/
void AlterOpClassOwner(List* name, const char* access_method, Oid newOwnerId)
ObjectAddress AlterOpClassOwner(List* name, const char* access_method, Oid newOwnerId)
{
Oid amOid;
Relation rel;
HeapTuple tup;
HeapTuple origtup;
ObjectAddress address;
amOid = get_am_oid(access_method, false);
@ -1649,6 +1723,8 @@ void AlterOpClassOwner(List* name, const char* access_method, Oid newOwnerId)
tableam_tops_free_tuple(tup);
heap_close(rel, NoLock);
ObjectAddressSet(address, OperatorClassRelationId, amOid);
return address;
}
/*
@ -1726,12 +1802,13 @@ static void AlterOpClassOwner_internal(Relation rel, HeapTuple tup, Oid newOwner
/*
* ALTER OPERATOR CLASS any_name USING access_method SET SCHEMA name
*/
void AlterOpClassNamespace(List* name, const char* access_method, const char* newschema)
ObjectAddress AlterOpClassNamespace(List* name, const char* access_method, const char* newschema)
{
Oid amOid;
Relation rel;
Oid opclassOid;
Oid nspOid;
ObjectAddress address;
amOid = get_am_oid(access_method, false);
@ -1754,6 +1831,8 @@ void AlterOpClassNamespace(List* name, const char* access_method, const char* ne
ACL_KIND_OPCLASS);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
return address;
}
Oid AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
@ -1781,13 +1860,15 @@ Oid AlterOpClassNamespace_oid(Oid opclassOid, Oid newNspOid)
/*
* Change opfamily owner by name
*/
void AlterOpFamilyOwner(List* name, const char* access_method, Oid newOwnerId)
ObjectAddress AlterOpFamilyOwner(List* name, const char* access_method, Oid newOwnerId)
{
Oid amOid;
Oid amOid, opfOid;
Relation rel;
HeapTuple tup;
char* opfname = NULL;
char* schemaname = NULL;
ObjectAddress address;
amOid = get_am_oid(access_method, false);
@ -1809,8 +1890,8 @@ void AlterOpFamilyOwner(List* name, const char* access_method, Oid newOwnerId)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator family \"%s\" does not exist for access method \"%s\"", opfname, access_method)));
opfOid = HeapTupleGetOid(tup);
} else {
Oid opfOid;
opfOid = OpfamilynameGetOpfid(amOid, opfname);
if (!OidIsValid(opfOid))
@ -1828,6 +1909,8 @@ void AlterOpFamilyOwner(List* name, const char* access_method, Oid newOwnerId)
tableam_tops_free_tuple(tup);
heap_close(rel, NoLock);
ObjectAddressSet(address, OperatorFamilyRelationId, opfOid);
return address;
}
/*
@ -1921,12 +2004,13 @@ Oid get_am_oid(const char* amname, bool missing_ok)
/*
* ALTER OPERATOR FAMILY any_name USING access_method SET SCHEMA name
*/
void AlterOpFamilyNamespace(List* name, const char* access_method, const char* newschema)
ObjectAddress AlterOpFamilyNamespace(List* name, const char* access_method, const char* newschema)
{
Oid amOid;
Relation rel;
Oid opfamilyOid;
Oid nspOid;
ObjectAddress address;
amOid = get_am_oid(access_method, false);
@ -1949,6 +2033,8 @@ void AlterOpFamilyNamespace(List* name, const char* access_method, const char* n
ACL_KIND_OPFAMILY);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
return address;
}
Oid AlterOpFamilyNamespace_oid(Oid opfamilyOid, Oid newNspOid)

View File

@ -83,7 +83,7 @@ void CheckDefineOperatorPrivilege(Oid oprNamespace, const char* oprName)
*
* 'parameters' is a list of DefElem
*/
void DefineOperator(List* names, List* parameters)
ObjectAddress DefineOperator(List* names, List* parameters)
{
char* oprName = NULL;
Oid oprNamespace;
@ -341,7 +341,7 @@ void DefineOperator(List* names, List* parameters)
/*
* now have OperatorCreate do all the work..
*/
OperatorCreate(oprName, /* operator name */
return OperatorCreate(oprName, /* operator name */
oprNamespace, /* namespace */
typeId1, /* left type id */
typeId2, /* right type id */
@ -389,10 +389,11 @@ void AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId)
/*
* change operator owner
*/
void AlterOperatorOwner(List* name, TypeName* typeName1, TypeName* typeName2, Oid newOwnerId)
ObjectAddress AlterOperatorOwner(List* name, TypeName* typeName1, TypeName* typeName2, Oid newOwnerId)
{
Oid operOid;
Relation rel;
ObjectAddress address;
rel = heap_open(OperatorRelationId, RowExclusiveLock);
@ -401,6 +402,8 @@ void AlterOperatorOwner(List* name, TypeName* typeName1, TypeName* typeName2, Oi
AlterOperatorOwner_internal(rel, operOid, newOwnerId);
heap_close(rel, NoLock);
ObjectAddressSet(address, OperatorRelationId, operOid);
return address;
}
static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
@ -456,13 +459,14 @@ static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerI
/*
* Execute ALTER OPERATOR SET SCHEMA
*/
void AlterOperatorNamespace(List* names, List* argtypes, const char* newschema)
ObjectAddress AlterOperatorNamespace(List* names, List* argtypes, const char* newschema)
{
List* operatorName = names;
TypeName* typeName1 = (TypeName*)linitial(argtypes);
TypeName* typeName2 = (TypeName*)lsecond(argtypes);
Oid operOid, nspOid;
Relation rel;
ObjectAddress address;
rel = heap_open(OperatorRelationId, RowExclusiveLock);
@ -490,6 +494,8 @@ void AlterOperatorNamespace(List* names, List* argtypes, const char* newschema)
ACL_KIND_OPER);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, OperatorRelationId, operOid);
return address;
}
Oid AlterOperatorNamespace_oid(Oid operOid, Oid newNspOid)

View File

@ -231,7 +231,7 @@ void CreatePackageBodyCommand(CreatePackageBodyStmt* stmt, const char* queryStri
/*
* Change package owner by name
*/
void AlterPackageOwner(List* name, Oid newOwnerId)
ObjectAddress AlterPackageOwner(List* name, Oid newOwnerId)
{
#ifdef ENABLE_MULTIPLE_NODES
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@ -240,6 +240,7 @@ void AlterPackageOwner(List* name, Oid newOwnerId)
Oid pkgOid = PackageNameListGetOid(name, false);
Relation rel;
HeapTuple tup;
ObjectAddress address;
if (IsSystemObjOid(pkgOid)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PACKAGE_DEFINITION),
@ -265,7 +266,8 @@ void AlterPackageOwner(List* name, Oid newOwnerId)
/* Recode time of change the funciton owner. */
UpdatePgObjectMtime(pkgOid, OBJECT_TYPE_PKGSPEC);
heap_close(rel, NoLock);
return;
ObjectAddressSet(address, PackageRelationId, pkgOid);
return address;
}
Datum repl_val[Natts_gs_package];
@ -331,5 +333,6 @@ void AlterPackageOwner(List* name, Oid newOwnerId)
/* Recode time of change the funciton owner. */
UpdatePgObjectMtime(pkgOid, OBJECT_TYPE_PKGSPEC);
heap_close(rel, NoLock);
return;
ObjectAddressSet(address, PackageRelationId, pkgOid);
return address;
}

View File

@ -52,7 +52,7 @@ typedef struct {
char* tmpllibrary; /* path of shared library */
} PLTemplate;
static void create_proc_lang(
static ObjectAddress create_proc_lang(
const char* languageName, bool replace, Oid languageOwner, Oid handlerOid, Oid inlineOid, Oid valOid, bool trusted);
static PLTemplate* find_language_template(const char* languageName);
static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId);
@ -61,12 +61,13 @@ static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwne
* CREATE PROCEDURAL LANGUAGE
* ---------------------------------------------------------------------
*/
void CreateProceduralLanguage(CreatePLangStmt* stmt)
ObjectAddress CreateProceduralLanguage(CreatePLangStmt* stmt)
{
PLTemplate* pltemplate = NULL;
Oid handlerOid, inlineOid, valOid;
Oid funcrettype;
Oid funcargtypes[1];
ObjectAddress tmpAddr;
/*
* If we have template information for the language, ignore the supplied
@ -112,7 +113,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
* it is null here since that there is no default value. Fenced mode is not
* supportted for PROCEDURAL LANGUAGE, so set false for fenced.
*/
handlerOid = ProcedureCreate(pltemplate->tmplhandler,
tmpAddr = ProcedureCreate(pltemplate->tmplhandler,
PG_CATALOG_NAMESPACE,
InvalidOid,
false, /* not A db compatible */
@ -144,6 +145,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
false,
false,
NULL);
handlerOid = tmpAddr.objectId;
}
/*
@ -159,7 +161,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
* add an argument to record the position of agruments with default value,
* it is null here since that there is no default value
*/
inlineOid = ProcedureCreate(pltemplate->tmplinline,
tmpAddr = ProcedureCreate(pltemplate->tmplinline,
PG_CATALOG_NAMESPACE,
InvalidOid,
false, /* not A db compatible */
@ -191,6 +193,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
false,
false,
NULL);
inlineOid = tmpAddr.objectId;
}
} else
inlineOid = InvalidOid;
@ -208,7 +211,7 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
* add an argument to record the position of agruments with default value,
* it is null here since that there is no default value
*/
valOid = ProcedureCreate(pltemplate->tmplvalidator,
tmpAddr = ProcedureCreate(pltemplate->tmplvalidator,
PG_CATALOG_NAMESPACE,
InvalidOid,
false, /* not A db compatible */
@ -240,12 +243,13 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
false,
false,
NULL);
valOid = tmpAddr.objectId;
}
} else
valOid = InvalidOid;
/* ok, create it */
create_proc_lang(
return create_proc_lang(
stmt->plname, stmt->replace, GetUserId(), handlerOid, inlineOid, valOid, pltemplate->tmpltrusted);
} else {
/*
@ -309,14 +313,14 @@ void CreateProceduralLanguage(CreatePLangStmt* stmt)
valOid = InvalidOid;
/* ok, create it */
create_proc_lang(stmt->plname, stmt->replace, GetUserId(), handlerOid, inlineOid, valOid, stmt->pltrusted);
return create_proc_lang(stmt->plname, stmt->replace, GetUserId(), handlerOid, inlineOid, valOid, stmt->pltrusted);
}
}
/*
* Guts of language creation.
*/
static void create_proc_lang(
static ObjectAddress create_proc_lang(
const char* languageName, bool replace, Oid languageOwner, Oid handlerOid, Oid inlineOid, Oid valOid, bool trusted)
{
Relation rel;
@ -430,6 +434,7 @@ static void create_proc_lang(
InvokeObjectAccessHook(OAT_POST_CREATE, LanguageRelationId, myself.objectId, 0, NULL);
heap_close(rel, RowExclusiveLock);
return myself;
}
/*
@ -517,56 +522,29 @@ void DropProceduralLanguageById(Oid langOid)
heap_close(rel, RowExclusiveLock);
}
/*
* Rename language
*/
void RenameLanguage(const char* oldname, const char* newname)
{
HeapTuple tup;
Relation rel;
rel = heap_open(LanguageRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(LANGNAME, CStringGetDatum(oldname));
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("language \"%s\" does not exist", oldname)));
/* make sure the new name doesn't exist */
if (SearchSysCacheExists1(LANGNAME, CStringGetDatum(newname)))
ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("language \"%s\" already exists", newname)));
/* must be owner of PL */
if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE, oldname);
/* rename */
(void)namestrcpy(&(((Form_pg_language)GETSTRUCT(tup))->lanname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
}
/*
* Change language owner
*/
void AlterLanguageOwner(const char* name, Oid newOwnerId)
ObjectAddress AlterLanguageOwner(const char* name, Oid newOwnerId)
{
HeapTuple tup;
Relation rel;
Oid lanId;
ObjectAddress address;
rel = heap_open(LanguageRelationId, RowExclusiveLock);
tup = SearchSysCache1(LANGNAME, CStringGetDatum(name));
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("language \"%s\" does not exist", name)));
lanId = HeapTupleGetOid(tup);
AlterLanguageOwner_internal(tup, rel, newOwnerId);
ReleaseSysCache(tup);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, LanguageRelationId, lanId);
return address;
}
/*
@ -686,4 +664,4 @@ char* get_language_name(Oid languageOid)
heap_close(rel, NoLock);
heap_freetuple_ext(tup);
return languageName;
}
}

View File

@ -226,6 +226,7 @@ static void AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel, He
bool publish_update;
bool publish_delete;
int rc;
ObjectAddress obj;
parse_publication_options(stmt->options, &publish_given, &publish_insert, &publish_update, &publish_delete);
@ -278,6 +279,8 @@ static void AlterPublicationOptions(AlterPublicationStmt *stmt, Relation rel, He
CacheInvalidateRelcacheAll();
}
}
ObjectAddressSet(obj, PublicationRelationId, HeapTupleGetOid(tup));
EventTriggerCollectSimpleCommand(obj, InvalidObjectAddress, (Node *) stmt);
}
/*

View File

@ -27,6 +27,7 @@
#include "catalog/pg_namespace.h"
#include "catalog/gs_package.h"
#include "commands/dbcommands.h"
#include "commands/event_trigger.h"
#include "commands/schemacmds.h"
#include "miscadmin.h"
#include "parser/parse_utilcmd.h"
@ -87,9 +88,9 @@ static bool IsReservedSchemaName(const char* name)
*/
#ifdef PGXC
void CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString, bool sentToRemote)
Oid CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString, bool sentToRemote)
#else
void CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString)
Oid CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString)
#endif
{
const char* schemaName = stmt->schemaname;
@ -233,7 +234,7 @@ void CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString)
/* OK to skip */
ereport(NOTICE, (errmsg("schema \"%s\" already exists,skipping", schemaName)));
return;
return InvalidOid;
}
}
@ -265,6 +266,16 @@ void CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString)
/* XXX should we clear overridePath->useTemp? */
PushOverrideSearchPath(overridePath);
/*
* Report the new schema to possibly interested event triggers. Note we
* must do this here and not in ProcessUtilitySlow because otherwise the
* objects created below are reported before the schema, which would be
* wrong.
*/
ObjectAddressSet(address, NamespaceRelationId, namespaceId);
EventTriggerCollectSimpleCommand(address, InvalidObjectAddress,
(Node *) stmt);
/*
* Examine the list of commands embedded in the CREATE SCHEMA command, and
* reorganize them into a sequentially executable order with no forward
@ -345,7 +356,8 @@ void CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString)
#ifdef PGXC
true,
#endif /* PGXC */
NULL);
NULL,
PROCESS_UTILITY_SUBCOMMAND);
/* make sure later steps can see the object created here */
CommandCounterIncrement();
}
@ -357,6 +369,7 @@ void CreateSchemaCommand(CreateSchemaStmt* stmt, const char* queryString)
SetUserIdAndSecContext(saved_uid, save_sec_context);
list_free(parsetree_list);
return namespaceId;
}
void AlterSchemaCommand(AlterSchemaStmt* stmt)
@ -507,11 +520,13 @@ void RemoveSchemaById(Oid schemaOid)
/*
* Rename schema
*/
void RenameSchema(const char* oldname, const char* newname)
ObjectAddress RenameSchema(const char* oldname, const char* newname)
{
Oid nspOid;
HeapTuple tup;
Relation rel;
AclResult aclresult;
ObjectAddress address;
bool is_nspblockchain = false;
if (!g_instance.attr.attr_common.allowSystemTableMods && !u_sess->attr.attr_common.IsInplaceUpgrade &&
@ -526,6 +541,7 @@ void RenameSchema(const char* oldname, const char* newname)
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("schema \"%s\" does not exist", oldname)));
nspOid = HeapTupleGetOid(tup);
/* make sure the new name doesn't exist */
if (OidIsValid(get_namespace_oid(newname, true)))
ereport(ERROR, (errcode(ERRCODE_DUPLICATE_SCHEMA), errmsg("schema \"%s\" already exists", newname)));
@ -593,8 +609,10 @@ void RenameSchema(const char* oldname, const char* newname)
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
return address;
}
/*
@ -661,10 +679,12 @@ void AlterSchemaOwner_oid(Oid oid, Oid newOwnerId)
/*
* Change schema owner
*/
void AlterSchemaOwner(const char* name, Oid newOwnerId)
ObjectAddress AlterSchemaOwner(const char* name, Oid newOwnerId)
{
Oid nspOid;
HeapTuple tup;
Relation rel;
ObjectAddress address;
rel = heap_open(NamespaceRelationId, RowExclusiveLock);
@ -672,11 +692,14 @@ void AlterSchemaOwner(const char* name, Oid newOwnerId)
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("schema \"%s\" does not exist", name)));
nspOid = HeapTupleGetOid(tup);
AlterSchemaOwner_internal(tup, rel, newOwnerId);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
ReleaseSysCache(tup);
heap_close(rel, RowExclusiveLock);
return address;
}
static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)

View File

@ -461,12 +461,15 @@ void AlterRlsPolicy(AlterRlsPolicyStmt* stmt)
* @param (in) renameStmt: RenameStmt describes the policy name, table name and new rls policy name
* @return: void
*/
void RenameRlsPolicy(RenameStmt* renameStmt)
ObjectAddress RenameRlsPolicy(RenameStmt* renameStmt)
{
Oid rlsp_id;
ObjectAddress address;
Assert(renameStmt != NULL);
/* Check whether need to rename rls policy on current node */
if (SupportRlsOnCurrentNode() == false) {
return;
return InvalidObjectAddress;
}
/* Check license whether support this feature */
LicenseSupportRls();
@ -532,7 +535,7 @@ void RenameRlsPolicy(RenameStmt* renameStmt)
renameStmt->subname,
renameStmt->relation->relname)));
}
rlsp_id = HeapTupleGetOid(rlsPolicyTuple);
/* Copy tuple here, because of update index later */
rlsPolicyTuple = (HeapTuple)tableam_tops_copy_tuple(rlsPolicyTuple);
/* Update RLS policy name */
@ -551,7 +554,8 @@ void RenameRlsPolicy(RenameStmt* renameStmt)
systable_endscan(scanDesc);
heap_close(pg_rlspolicy, RowExclusiveLock);
heap_close(targetTable, NoLock);
return;
ObjectAddressSet(address, RlsPolicyRelationId, rlsp_id);
return address;
}
/*

View File

@ -42,7 +42,7 @@ typedef struct {
*
* Apply a security label to a database object.
*/
void ExecSecLabelStmt(SecLabelStmt* stmt)
ObjectAddress ExecSecLabelStmt(SecLabelStmt* stmt)
{
LabelProvider* provider = NULL;
ObjectAddress address;
@ -130,6 +130,7 @@ void ExecSecLabelStmt(SecLabelStmt* stmt)
*/
if (relation != NULL)
relation_close(relation, NoLock);
return address;
}
/*

View File

@ -70,9 +70,9 @@
template<typename T_Form>
static T_Form read_seq_tuple(SeqTable elm, Relation rel, Buffer* buf, HeapTuple seqtuple, GTM_UUID* uuid);
template<typename T_FormData, typename T_Int, bool large>
static void DefineSequence(CreateSeqStmt* seq);
static ObjectAddress DefineSequence(CreateSeqStmt* seq);
template<typename T_Form, typename T_Int, bool large>
static void AlterSequence(const AlterSeqStmt* stmt);
static ObjectAddress AlterSequence(const AlterSeqStmt* stmt);
#ifdef PGXC
template<typename T_Form, typename T_Int, bool large>
static void init_params(List* options, bool isInit, bool isUseLocalSeq, void* newm_p, List** owned_by,
@ -761,16 +761,16 @@ static Datum GetIntDefVal(TypeName* name, T value)
}
}
void DefineSequenceWrapper(CreateSeqStmt *seq)
ObjectAddress DefineSequenceWrapper(CreateSeqStmt* seq)
{
if (seq->is_large) {
if (t_thrd.proc->workingVersionNum < LARGE_SEQUENCE_VERSION_NUM) {
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("It is not supported to create large sequence during upgrade.")));
}
DefineSequence<FormData_pg_large_sequence, int128, true>(seq);
return DefineSequence<FormData_pg_large_sequence, int128, true>(seq);
} else {
DefineSequence<FormData_pg_sequence, int64, false>(seq);
return DefineSequence<FormData_pg_sequence, int64, false>(seq);
}
}
@ -804,7 +804,7 @@ int CreateSequenceWithUUIDGTMWrapper(FormData_pg_large_sequence newm, int64 uuid
* Creates a new sequence relation
*/
template<typename T_FormData, typename T_Int, bool large>
static void DefineSequence(CreateSeqStmt* seq)
static ObjectAddress DefineSequence(CreateSeqStmt* seq)
{
T_FormData newm;
List* owned_by = NIL;
@ -820,6 +820,8 @@ static void DefineSequence(CreateSeqStmt* seq)
bool need_seq_rewrite = false;
bool isUseLocalSeq = false;
Oid namespaceOid = InvalidOid;
ObjectAddress address;
#ifdef PGXC /* PGXC_COORD */
GTM_Sequence start_value = 1;
GTM_Sequence min_value = 1;
@ -995,7 +997,8 @@ static void DefineSequence(CreateSeqStmt* seq)
stmt->if_not_exists = false;
stmt->charset = PG_INVALID_ENCODING;
char rel_kind = large ? RELKIND_LARGE_SEQUENCE : RELKIND_SEQUENCE;
seqoid = DefineRelation(stmt, rel_kind, seq->ownerId);
address = DefineRelation(stmt, rel_kind, seq->ownerId, NULL);
seqoid = address.objectId;
Assert(seqoid != InvalidOid);
rel = heap_open(seqoid, AccessExclusiveLock);
@ -1032,6 +1035,7 @@ static void DefineSequence(CreateSeqStmt* seq)
register_sequence_cb(seq->uuid, GTM_CREATE_SEQ);
}
#endif
return address;
}
template<typename T_Form>
@ -1119,12 +1123,12 @@ void ResetSequence(Oid seq_relid, bool restart)
relation_close(seq_rel, NoLock);
}
void AlterSequenceWrapper(AlterSeqStmt* stmt)
ObjectAddress AlterSequenceWrapper(AlterSeqStmt* stmt)
{
if (stmt->is_large) {
AlterSequence<Form_pg_large_sequence, int128, true>(stmt);
return AlterSequence<Form_pg_large_sequence, int128, true>(stmt);
} else {
AlterSequence<Form_pg_sequence, int64, false>(stmt);
return AlterSequence<Form_pg_sequence, int64, false>(stmt);
}
}
@ -1155,7 +1159,7 @@ bool CheckSeqOwnedByAutoInc(Oid seqoid)
* Alter sequence maxvalue needs update info in GTM.
*/
template<typename T_Form, typename T_Int, bool large>
static void AlterSequence(const AlterSeqStmt* stmt)
static ObjectAddress AlterSequence(const AlterSeqStmt* stmt)
{
Oid relid;
SeqTable elm = NULL;
@ -1170,12 +1174,13 @@ static void AlterSequence(const AlterSeqStmt* stmt)
bool is_restart = false;
#endif
bool need_seq_rewrite = false;
ObjectAddress address;
/* Open and lock sequence. */
relid = RangeVarGetRelid(stmt->sequence, ShareRowExclusiveLock, stmt->missing_ok);
if (relid == InvalidOid) {
ereport(NOTICE, (errmsg("relation \"%s\" does not exist, skipping", stmt->sequence->relname)));
return;
return InvalidObjectAddress;
}
TrForbidAccessRbObject(RelationRelationId, relid, stmt->sequence->relname);
@ -1284,7 +1289,9 @@ static void AlterSequence(const AlterSeqStmt* stmt)
UpdatePgObjectMtime(seqrel->rd_id, objectType);
}
ObjectAddressSet(address, RelationRelationId, relid);
relation_close(seqrel, NoLock);
return address;
}
/*

View File

@ -30,7 +30,7 @@
#include "commands/defrem.h"
#include "commands/subscriptioncmds.h"
#include "commands/event_trigger.h"
#include "nodes/makefuncs.h"
#include "replication/logicallauncher.h"
@ -1093,6 +1093,7 @@ void DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
myself.classId = SubscriptionRelationId;
myself.objectId = subid;
myself.objectSubId = 0;
EventTriggerSQLDropAddObject(&myself, true, true);
/* Remove the tuple from catalog. */
simple_heap_delete(rel, &tup->t_self);

File diff suppressed because it is too large Load Diff

View File

@ -527,7 +527,7 @@ static void CheckAbsoluteLocationDataPath(const char *location)
* This seems a reasonable restriction since we're determining the system layout and, anyway, we probably have
* root if we're doing this kind of activity
*/
void CreateTableSpace(CreateTableSpaceStmt* stmt)
Oid CreateTableSpace(CreateTableSpaceStmt* stmt)
{
#ifdef HAVE_SYMLINK
Relation rel;
@ -841,6 +841,7 @@ void CreateTableSpace(CreateTableSpaceStmt* stmt)
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("tablespaces are not supported on this platform")));
#endif /* HAVE_SYMLINK */
return tablespaceoid;
}
/*
@ -1718,14 +1719,16 @@ void remove_tablespace_symlink(const char* linkloc)
/*
* Rename a tablespace
*/
void RenameTableSpace(const char* oldname, const char* newname)
ObjectAddress RenameTableSpace(const char* oldname, const char* newname)
{
Oid tspId;
Relation rel;
ScanKeyData entry[1];
TableScanDesc scan;
HeapTuple tup;
HeapTuple newtuple;
Form_pg_tablespace newform;
ObjectAddress address;
if (isSecurityMode) {
ereport(ERROR,
@ -1742,6 +1745,7 @@ void RenameTableSpace(const char* oldname, const char* newname)
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", oldname)));
tspId = HeapTupleGetOid(tup);
newtuple = heap_copytuple(tup);
newform = (Form_pg_tablespace)GETSTRUCT(newtuple);
@ -1775,19 +1779,24 @@ void RenameTableSpace(const char* oldname, const char* newname)
simple_heap_update(rel, &newtuple->t_self, newtuple);
CatalogUpdateIndexes(rel, newtuple);
ObjectAddressSet(address, TableSpaceRelationId, tspId);
heap_close(rel, NoLock);
return address;
}
/*
* Change tablespace owner
*/
void AlterTableSpaceOwner(const char* name, Oid newOwnerId)
ObjectAddress AlterTableSpaceOwner(const char* name, Oid newOwnerId)
{
Relation rel;
ScanKeyData entry[1];
TableScanDesc scandesc;
Form_pg_tablespace spcForm;
HeapTuple tup;
Oid tsId;
ObjectAddress address;
if (isSecurityMode) {
ereport(ERROR,
@ -1796,7 +1805,7 @@ void AlterTableSpaceOwner(const char* name, Oid newOwnerId)
}
/* Search pg_tablespace */
Relation rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
rel = heap_open(TableSpaceRelationId, RowExclusiveLock);
ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(name));
scandesc = tableam_scan_begin(rel, SnapshotNow, 1, entry);
@ -1804,6 +1813,7 @@ void AlterTableSpaceOwner(const char* name, Oid newOwnerId)
if (!HeapTupleIsValid(tup))
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", name)));
tsId = HeapTupleGetOid(tup);
spcForm = (Form_pg_tablespace)GETSTRUCT(tup);
/*
* If the new owner is the same as the existing owner, consider the
@ -1865,14 +1875,16 @@ void AlterTableSpaceOwner(const char* name, Oid newOwnerId)
changeDependencyOnOwner(TableSpaceRelationId, HeapTupleGetOid(tup), newOwnerId);
}
ObjectAddressSet(address, TableSpaceRelationId, tsId);
tableam_scan_end(scandesc);
heap_close(rel, NoLock);
return address;
}
/*
* Alter table space options
*/
void AlterTableSpaceOptions(AlterTableSpaceOptionsStmt* stmt)
Oid AlterTableSpaceOptions(AlterTableSpaceOptionsStmt* stmt)
{
Relation rel;
ScanKeyData entry[1];
@ -2014,6 +2026,8 @@ void AlterTableSpaceOptions(AlterTableSpaceOptionsStmt* stmt)
if (NULL != maxsize)
pfree_ext(maxsize);
return spc_oid;
}
/*

View File

@ -138,10 +138,10 @@ extern HeapTuple SearchUserHostName(const char* userName, Oid* oid);
* relation, as well as ACL_EXECUTE on the trigger function. For internal
* triggers the caller must apply any required permission checks.
*
* Note: can return InvalidOid if we decided to not create a trigger at all,
* Note: can return InvalidObjectAddress if we decided to not create a trigger at all,
* but a foreign-key constraint. This is a kluge for backwards compatibility.
*/
Oid CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relOid, Oid refRelOid, Oid constraintOid,
ObjectAddress CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relOid, Oid refRelOid, Oid constraintOid,
Oid indexOid, bool isInternal)
{
uint16 tgtype;
@ -481,7 +481,10 @@ Oid CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relOid, Oid
systable_endscan(tgscan);
heap_close(tgrel, RowExclusiveLock);
heap_close(rel, NoLock);
return trigoid;
myself.classId = TriggerRelationId;
myself.objectId = trigoid;
myself.objectSubId = 0;
return myself;
}
else {
systable_endscan(tgscan);
@ -617,7 +620,7 @@ Oid CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relOid, Oid
ConvertTriggerToFK(stmt, funcoid);
return InvalidOid;
return InvalidObjectAddress;
}
/*
@ -958,7 +961,7 @@ Oid CreateTrigger(CreateTrigStmt* stmt, const char* queryString, Oid relOid, Oid
/* Keep lock on target rel until end of xact */
heap_close(rel, NoLock);
return trigoid;
return myself;
}
/*
@ -1206,7 +1209,8 @@ static void ConvertTriggerToFK(CreateTrigStmt* stmt, Oid funcoid)
#ifdef PGXC
false,
#endif /* PGXC */
NULL);
NULL,
PROCESS_UTILITY_GENERATED);
/* Remove the matched item from the list */
u_sess->tri_cxt.info_list = list_delete_ptr(u_sess->tri_cxt.info_list, info);
@ -1421,7 +1425,7 @@ static void RangeVarCallbackForRenameTrigger(
* modify tgname in trigger tuple
* update row in catalog
*/
void renametrig(RenameStmt* stmt)
ObjectAddress renametrig(RenameStmt* stmt)
{
Relation targetrel;
Relation tgrel;
@ -1429,7 +1433,8 @@ void renametrig(RenameStmt* stmt)
SysScanDesc tgscan;
ScanKeyData key[2];
Oid relid;
ObjectAddress address;
Oid tgoid = InvalidOid;
/*
* Look up name, check permissions, and acquire lock (which we will NOT
* release until end of transaction).
@ -1478,7 +1483,7 @@ void renametrig(RenameStmt* stmt)
* Update pg_trigger tuple with new tgname.
*/
tuple = (HeapTuple)tableam_tops_copy_tuple(tuple); /* need a modifiable copy */
tgoid = HeapTupleGetOid(tuple);
(void)namestrcpy(&((Form_pg_trigger)GETSTRUCT(tuple))->tgname, stmt->newname);
simple_heap_update(tgrel, &tuple->t_self, tuple);
@ -1500,6 +1505,7 @@ void renametrig(RenameStmt* stmt)
RelationGetRelationName(targetrel))));
}
ObjectAddressSet(address, TriggerRelationId, tgoid);
systable_endscan(tgscan);
heap_close(tgrel, RowExclusiveLock);
@ -1508,6 +1514,7 @@ void renametrig(RenameStmt* stmt)
* Close rel, but keep exclusive lock!
*/
relation_close(targetrel, NoLock);
return address;
}
/*

View File

@ -38,6 +38,7 @@
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_func.h"
@ -122,7 +123,7 @@ static Datum get_ts_parser_func(DefElem* defel, int attnum)
/*
* make pg_depend entries for a new pg_ts_parser entry
*/
static void makeParserDependencies(HeapTuple tuple)
static ObjectAddress makeParserDependencies(HeapTuple tuple)
{
Form_pg_ts_parser prs = (Form_pg_ts_parser)GETSTRUCT(tuple);
ObjectAddress myself, referenced;
@ -160,12 +161,13 @@ static void makeParserDependencies(HeapTuple tuple)
referenced.objectId = prs->prsheadline;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
return myself;
}
/*
* CREATE TEXT SEARCH PARSER
*/
void DefineTSParser(List* names, List* parameters)
ObjectAddress DefineTSParser(List* names, List* parameters)
{
char* prsname = NULL;
ListCell* pl = NULL;
@ -176,6 +178,7 @@ void DefineTSParser(List* names, List* parameters)
NameData pname;
Oid prsOid;
Oid namespaceoid;
ObjectAddress address;
if (!superuser())
ereport(ERROR,
@ -246,7 +249,7 @@ void DefineTSParser(List* names, List* parameters)
CatalogUpdateIndexes(prsRel, tup);
makeParserDependencies(tup);
address = makeParserDependencies(tup);
/* Post creation hook for new text search parser */
InvokeObjectAccessHook(OAT_POST_CREATE, TSParserRelationId, prsOid, 0, NULL);
@ -254,6 +257,7 @@ void DefineTSParser(List* names, List* parameters)
tableam_tops_free_tuple(tup);
heap_close(prsRel, RowExclusiveLock);
return address;
}
/*
@ -279,47 +283,14 @@ void RemoveTSParserById(Oid prsId)
heap_close(relation, RowExclusiveLock);
}
/*
* ALTER TEXT SEARCH PARSER RENAME
*/
void RenameTSParser(List* oldname, const char* newname)
{
HeapTuple tup;
Relation rel;
Oid prsId;
Oid namespaceOid;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be system admin to rename text search parsers")));
rel = heap_open(TSParserRelationId, RowExclusiveLock);
prsId = get_ts_parser_oid(oldname, false);
tup = SearchSysCacheCopy1(TSPARSEROID, ObjectIdGetDatum(prsId));
if (!HeapTupleIsValid(tup)) /* should not happen */
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for text search parser %u", prsId)));
namespaceOid = ((Form_pg_ts_parser)GETSTRUCT(tup))->prsnamespace;
if (SearchSysCacheExists2(TSPARSERNAMENSP, PointerGetDatum(newname), ObjectIdGetDatum(namespaceOid)))
ereport(
ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("text search parser \"%s\" already exists", newname)));
(void)namestrcpy(&(((Form_pg_ts_parser)GETSTRUCT(tup))->prsname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
}
/*
* ALTER TEXT SEARCH PARSER any_name SET SCHEMA name
*/
void AlterTSParserNamespace(List* name, const char* newschema)
ObjectAddress AlterTSParserNamespace(List* name, const char* newschema)
{
Oid prsId, nspOid;
Relation rel;
ObjectAddress address;
rel = heap_open(TSParserRelationId, RowExclusiveLock);
@ -339,6 +310,8 @@ void AlterTSParserNamespace(List* name, const char* newschema)
(AclObjectKind)-1);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
return address;
}
Oid AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
@ -367,7 +340,7 @@ Oid AlterTSParserNamespace_oid(Oid prsId, Oid newNspOid)
/*
* make pg_depend entries for a new pg_ts_dict entry
*/
static void makeDictionaryDependencies(HeapTuple tuple, const char* dictPrefix)
static ObjectAddress makeDictionaryDependencies(HeapTuple tuple, const char* dictPrefix)
{
Form_pg_ts_dict dict = (Form_pg_ts_dict)GETSTRUCT(tuple);
ObjectAddress myself, referenced;
@ -403,6 +376,7 @@ static void makeDictionaryDependencies(HeapTuple tuple, const char* dictPrefix)
referenced.objectId = dict->dicttemplate;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
return myself;
}
/*
@ -489,7 +463,7 @@ void copy_tsfiles(List* userFiles, const char* dictPrefix)
/*
* CREATE TEXT SEARCH DICTIONARY
*/
void DefineTSDictionary(List* names, List* parameters)
ObjectAddress DefineTSDictionary(List* names, List* parameters)
{
ListCell* pl = NULL;
Relation dictRel;
@ -507,6 +481,7 @@ void DefineTSDictionary(List* names, List* parameters)
List* userfiles = NIL;
/* internal dictionary file name prefix */
char* dictprefix = NULL;
ObjectAddress address;
/* For now only user with sysadmin can create dictionary */
if (!superuser())
@ -577,7 +552,7 @@ void DefineTSDictionary(List* names, List* parameters)
dictOid = simple_heap_insert(dictRel, tup);
CatalogUpdateIndexes(dictRel, tup);
makeDictionaryDependencies(tup, dictprefix);
address = makeDictionaryDependencies(tup, dictprefix);
/* Post creation hook for new text search dictionary */
InvokeObjectAccessHook(OAT_POST_CREATE, TSDictionaryRelationId, dictOid, 0, NULL);
tableam_tops_free_tuple(tup);
@ -592,6 +567,8 @@ void DefineTSDictionary(List* names, List* parameters)
/* Clean up */
if (userfiles != NIL)
list_free_deep(userfiles);
return address;
}
/*
@ -646,10 +623,11 @@ void RenameTSDictionary(List* oldname, const char* newname)
/*
* ALTER TEXT SEARCH DICTIONARY any_name SET SCHEMA name
*/
void AlterTSDictionaryNamespace(List* name, const char* newschema)
ObjectAddress AlterTSDictionaryNamespace(List* name, const char* newschema)
{
Oid dictId, nspOid;
Relation rel;
ObjectAddress address;
rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
@ -673,6 +651,8 @@ void AlterTSDictionaryNamespace(List* name, const char* newschema)
ACL_KIND_TSDICTIONARY);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
return address;
}
Oid AlterTSDictionaryNamespace_oid(Oid dictId, Oid newNspOid)
@ -732,7 +712,7 @@ void RemoveTSDictionaryById(Oid dictId)
/*
* ALTER TEXT SEARCH DICTIONARY
*/
void AlterTSDictionary(AlterTSDictionaryStmt* stmt)
ObjectAddress AlterTSDictionary(AlterTSDictionaryStmt* stmt)
{
HeapTuple tup, newtup;
Relation rel;
@ -744,6 +724,7 @@ void AlterTSDictionary(AlterTSDictionaryStmt* stmt)
Datum repl_val[Natts_pg_ts_dict];
bool repl_null[Natts_pg_ts_dict];
bool repl_repl[Natts_pg_ts_dict];
ObjectAddress address;
/* record first N option old */
int oldnum = 0;
@ -860,6 +841,7 @@ void AlterTSDictionary(AlterTSDictionaryStmt* stmt)
} else
changeDependencyOnObjfile(dictId, dictowner, NULL);
ObjectAddressSet(address, TSDictionaryRelationId, dictId);
/*
* NOTE: because we only support altering the options, not the template,
* there is no need to update dependencies. This might have to change if
@ -878,6 +860,8 @@ void AlterTSDictionary(AlterTSDictionaryStmt* stmt)
/* Clean up */
if (userfiles != NIL)
list_free_deep(userfiles);
return address;
}
/*
@ -953,10 +937,11 @@ void AlterTSDictionaryOwner_oid(Oid dictId, Oid newOwnerId)
/*
* ALTER TEXT SEARCH DICTIONARY OWNER
*/
void AlterTSDictionaryOwner(List* name, Oid newOwnerId)
ObjectAddress AlterTSDictionaryOwner(List* name, Oid newOwnerId)
{
Relation rel;
Oid dictId;
ObjectAddress address;
rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);
dictId = get_ts_dict_oid(name, false);
@ -967,6 +952,8 @@ void AlterTSDictionaryOwner(List* name, Oid newOwnerId)
AlterTSDictionaryOwner_internal(rel, dictId, newOwnerId);
heap_close(rel, NoLock);
ObjectAddressSet(address, TSDictionaryRelationId, dictId);
return address;
}
/* ---------------------- TS Template commands ----------------------- */
@ -1017,7 +1004,7 @@ static Datum get_ts_template_func(DefElem* defel, int attnum)
/*
* make pg_depend entries for a new pg_ts_template entry
*/
static void makeTSTemplateDependencies(HeapTuple tuple)
static ObjectAddress makeTSTemplateDependencies(HeapTuple tuple)
{
Form_pg_ts_template tmpl = (Form_pg_ts_template)GETSTRUCT(tuple);
ObjectAddress myself, referenced;
@ -1045,12 +1032,13 @@ static void makeTSTemplateDependencies(HeapTuple tuple)
referenced.objectId = tmpl->tmplinit;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
return myself;
}
/*
* CREATE TEXT SEARCH TEMPLATE
*/
void DefineTSTemplate(List* names, List* parameters)
ObjectAddress DefineTSTemplate(List* names, List* parameters)
{
ListCell* pl = NULL;
Relation tmplRel;
@ -1062,6 +1050,7 @@ void DefineTSTemplate(List* names, List* parameters)
Oid dictOid;
Oid namespaceoid;
char* tmplname = NULL;
ObjectAddress address;
if (!superuser())
ereport(ERROR,
@ -1112,54 +1101,23 @@ void DefineTSTemplate(List* names, List* parameters)
dictOid = simple_heap_insert(tmplRel, tup);
CatalogUpdateIndexes(tmplRel, tup);
makeTSTemplateDependencies(tup);
address = makeTSTemplateDependencies(tup);
/* Post creation hook for new text search template */
InvokeObjectAccessHook(OAT_POST_CREATE, TSTemplateRelationId, dictOid, 0, NULL);
tableam_tops_free_tuple(tup);
heap_close(tmplRel, RowExclusiveLock);
}
/*
* ALTER TEXT SEARCH TEMPLATE RENAME
*/
void RenameTSTemplate(List* oldname, const char* newname)
{
HeapTuple tup;
Relation rel;
Oid tmplId;
Oid namespaceOid;
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be system admin to rename text search templates")));
rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
tmplId = get_ts_template_oid(oldname, false);
tup = SearchSysCacheCopy1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
if (!HeapTupleIsValid(tup)) /* should not happen */
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for text search template %u", tmplId)));
namespaceOid = ((Form_pg_ts_template)GETSTRUCT(tup))->tmplnamespace;
if (SearchSysCacheExists2(TSTEMPLATENAMENSP, PointerGetDatum(newname), ObjectIdGetDatum(namespaceOid)))
ereport(
ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("text search template \"%s\" already exists", newname)));
(void)namestrcpy(&(((Form_pg_ts_template)GETSTRUCT(tup))->tmplname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
return address;
}
/*
* ALTER TEXT SEARCH TEMPLATE any_name SET SCHEMA name
*/
void AlterTSTemplateNamespace(List* name, const char* newschema)
ObjectAddress AlterTSTemplateNamespace(List* name, const char* newschema)
{
Oid tmplId, nspOid;
Relation rel;
ObjectAddress address;
rel = heap_open(TSTemplateRelationId, RowExclusiveLock);
tmplId = get_ts_template_oid(name, false);
@ -1177,6 +1135,8 @@ void AlterTSTemplateNamespace(List* name, const char* newschema)
(AclObjectKind)-1);
heap_close(rel, RowExclusiveLock);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
return address;
}
Oid AlterTSTemplateNamespace_oid(Oid tmplId, Oid newNspOid)
@ -1249,7 +1209,7 @@ static HeapTuple GetTSConfigTuple(List* names)
* Pass opened pg_ts_config_map relation if there might be any config map
* entries for the config.
*/
static void makeConfigurationDependencies(HeapTuple tuple, bool removeOld, Relation mapRel)
static ObjectAddress makeConfigurationDependencies(HeapTuple tuple, bool removeOld, Relation mapRel)
{
Form_pg_ts_config cfg = (Form_pg_ts_config)GETSTRUCT(tuple);
ObjectAddresses* addrs = NULL;
@ -1312,12 +1272,13 @@ static void makeConfigurationDependencies(HeapTuple tuple, bool removeOld, Relat
/* Record 'em (this includes duplicate elimination) */
record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
return myself;
}
/*
* CREATE TEXT SEARCH CONFIGURATION
*/
void DefineTSConfiguration(List* names, List* parameters, List* cfoptions)
ObjectAddress DefineTSConfiguration(List* names, List* parameters, List* cfoptions)
{
Relation cfgRel;
Relation mapRel = NULL;
@ -1333,6 +1294,7 @@ void DefineTSConfiguration(List* names, List* parameters, List* cfoptions)
Oid cfgOid;
ListCell* pl = NULL;
Datum newOptions;
ObjectAddress address;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);
@ -1470,7 +1432,7 @@ void DefineTSConfiguration(List* names, List* parameters, List* cfoptions)
systable_endscan(scan);
}
makeConfigurationDependencies(tup, false, mapRel);
address = makeConfigurationDependencies(tup, false, mapRel);
/* Post creation hook for new text search configuration */
InvokeObjectAccessHook(OAT_POST_CREATE, TSConfigRelationId, cfgOid, 0, NULL);
@ -1480,57 +1442,18 @@ void DefineTSConfiguration(List* names, List* parameters, List* cfoptions)
if (mapRel)
heap_close(mapRel, RowExclusiveLock);
heap_close(cfgRel, RowExclusiveLock);
}
/*
* ALTER TEXT SEARCH CONFIGURATION RENAME
*/
void RenameTSConfiguration(List* oldname, const char* newname)
{
HeapTuple tup;
Relation rel;
Oid cfgId;
AclResult aclresult;
Oid namespaceOid;
rel = heap_open(TSConfigRelationId, RowExclusiveLock);
cfgId = get_ts_config_oid(oldname, false);
tup = SearchSysCacheCopy1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
if (!HeapTupleIsValid(tup)) /* should not happen */
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED),
errmsg("cache lookup failed for text search configuration %u", cfgId)));
namespaceOid = ((Form_pg_ts_config)GETSTRUCT(tup))->cfgnamespace;
if (SearchSysCacheExists2(TSCONFIGNAMENSP, PointerGetDatum(newname), ObjectIdGetDatum(namespaceOid)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("text search configuration \"%s\" already exists", newname)));
/* must be owner */
if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION, NameListToString(oldname));
/* must have CREATE privilege on namespace */
aclresult = pg_namespace_aclcheck(namespaceOid, GetUserId(), ACL_CREATE);
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceOid));
(void)namestrcpy(&(((Form_pg_ts_config)GETSTRUCT(tup))->cfgname), newname);
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
return address;
}
/*
* ALTER TEXT SEARCH CONFIGURATION any_name SET SCHEMA name
*/
void AlterTSConfigurationNamespace(List* name, const char* newschema)
ObjectAddress AlterTSConfigurationNamespace(List* name, const char* newschema)
{
Oid cfgId, nspOid;
Relation rel;
ObjectAddress address;
rel = heap_open(TSConfigRelationId, RowExclusiveLock);
cfgId = get_ts_config_oid(name, false);
@ -1547,7 +1470,9 @@ void AlterTSConfigurationNamespace(List* name, const char* newschema)
Anum_pg_ts_config_cfgowner,
ACL_KIND_TSCONFIGURATION);
ObjectAddressSet(address, NamespaceRelationId, nspOid);
heap_close(rel, RowExclusiveLock);
return address;
}
Oid AlterTSConfigurationNamespace_oid(Oid cfgId, Oid newNspOid)
@ -1611,7 +1536,7 @@ void RemoveTSConfigurationById(Oid cfgId)
/*
* ALTER TEXT SEARCH CONFIGURATION OWNER
*/
void AlterTSConfigurationOwner(List* name, Oid newOwnerId)
ObjectAddress AlterTSConfigurationOwner(List* name, Oid newOwnerId)
{
HeapTuple tup;
Relation rel;
@ -1619,6 +1544,7 @@ void AlterTSConfigurationOwner(List* name, Oid newOwnerId)
AclResult aclresult;
Oid namespaceOid;
Form_pg_ts_config form;
ObjectAddress address;
rel = heap_open(TSConfigRelationId, RowExclusiveLock);
cfgId = get_ts_config_oid(name, false);
@ -1657,15 +1583,19 @@ void AlterTSConfigurationOwner(List* name, Oid newOwnerId)
heap_close(rel, NoLock);
tableam_tops_free_tuple(tup);
ObjectAddressSet(address, TSConfigMapRelationId, cfgId);
return address;
}
/*
* ALTER TEXT SEARCH CONFIGURATION - main entry point
*/
void AlterTSConfiguration(AlterTSConfigurationStmt* stmt)
ObjectAddress AlterTSConfiguration(AlterTSConfigurationStmt* stmt)
{
HeapTuple tup;
Relation relMap;
Oid cfgId;
ObjectAddress address;
/* Find the configuration */
tup = GetTSConfigTuple(stmt->cfgname);
@ -1674,6 +1604,7 @@ void AlterTSConfiguration(AlterTSConfigurationStmt* stmt)
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("text search configuration \"%s\" does not exist", NameListToString(stmt->cfgname))));
cfgId = HeapTupleGetOid(tup);
if (TSConfigurationHasDependentObjects(HeapTupleGetOid(tup))) {
ReleaseSysCache(tup);
ereport(ERROR,
@ -1698,9 +1629,11 @@ void AlterTSConfiguration(AlterTSConfigurationStmt* stmt)
/* Update dependencies */
makeConfigurationDependencies(tup, true, relMap);
ObjectAddressSet(address, TSConfigRelationId, cfgId);
heap_close(relMap, RowExclusiveLock);
ReleaseSysCache(tup);
return address;
}
/*
@ -1940,6 +1873,7 @@ static void MakeConfigurationMapping(AlterTSConfigurationStmt* stmt, HeapTuple t
}
}
}
EventTriggerCollectAlterTSConfig(stmt, cfgId, dictIds, ndict);
}
/*
@ -1990,6 +1924,7 @@ static void DropConfigurationMapping(AlterTSConfigurationStmt* stmt, HeapTuple t
i++;
}
EventTriggerCollectAlterTSConfig(stmt, cfgId, NULL, 0);
}
/*

View File

@ -107,14 +107,14 @@ static void validateDomainConstraint(Oid domainoid, char* ccbin);
static List* get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
static void checkEnumAlterPrivilege(HeapTuple tup);
static char* domainAddConstraint(
Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint* constr, char* domainName);
Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint* constr, char* domainName, ObjectAddress *constrAddr);
static void CheckFuncParamType(Oid foid, Oid toid, bool isin);
/*
* DefineType
* Registers a new base type.
*/
void DefineType(List* names, List* parameters)
ObjectAddress DefineType(List* names, List* parameters)
{
char* typname = NULL;
Oid typeNamespace;
@ -167,6 +167,7 @@ void DefineType(List* names, List* parameters)
Oid resulttype;
ListCell* pl = NULL;
Oid typowner = InvalidOid;
ObjectAddress address;
/*
* isalter is true, change the owner of the objects as the owner of the
@ -228,7 +229,7 @@ void DefineType(List* names, List* parameters)
* use in the I/O function definitions.
*/
if (!OidIsValid(typoid)) {
typoid = TypeShellMake(typname, typeNamespace, typowner);
address = TypeShellMake(typname, typeNamespace, typowner);
/* Make new shell type visible for modification below */
CommandCounterIncrement();
@ -237,7 +238,7 @@ void DefineType(List* names, List* parameters)
* creating the shell type was all we're supposed to do.
*/
if (parameters == NIL)
return;
return address;
} else {
/* Complain if dummy CREATE TYPE and entry already exists */
if (parameters == NIL)
@ -546,7 +547,7 @@ void DefineType(List* names, List* parameters)
* types) in ArrayType and in composite types in DatumTupleFields. This
* oid must be preserved by binary upgrades.
*/
typoid = TypeCreate(InvalidOid, /* no predetermined type OID */
address = TypeCreate(InvalidOid, /* no predetermined type OID */
typname, /* type name */
typeNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
@ -626,6 +627,7 @@ void DefineType(List* names, List* parameters)
pfree_ext(array_type);
}
return address;
}
/*
@ -677,7 +679,7 @@ void RemoveTypeById(Oid typeOid)
* DefineDomain
* Registers a new domain.
*/
void DefineDomain(CreateDomainStmt* stmt)
ObjectAddress DefineDomain(CreateDomainStmt* stmt)
{
char* domainName = NULL;
Oid domainNamespace;
@ -706,7 +708,7 @@ void DefineDomain(CreateDomainStmt* stmt)
List* schema = stmt->constraints;
ListCell* listptr = NULL;
Oid basetypeoid;
Oid domainoid;
ObjectAddress address;
Oid old_type_oid;
Oid domaincoll;
Form_pg_type baseType;
@ -969,7 +971,7 @@ void DefineDomain(CreateDomainStmt* stmt)
/*
* Have TypeCreate do all the real work.
*/
domainoid = TypeCreate(InvalidOid, /* no predetermined type OID */
address = TypeCreate(InvalidOid, /* no predetermined type OID */
domainName, /* type name */
domainNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
@ -1010,7 +1012,7 @@ void DefineDomain(CreateDomainStmt* stmt)
/* it must be a Constraint, per check above */
switch (constr->contype) {
case CONSTR_CHECK:
domainAddConstraint(domainoid, domainNamespace, basetypeoid, basetypeMod, constr, domainName);
domainAddConstraint(address.objectId, domainNamespace, basetypeoid, basetypeMod, constr, domainName, NULL);
break;
/* Other constraint types were fully processed above */
@ -1026,22 +1028,25 @@ void DefineDomain(CreateDomainStmt* stmt)
* Now we can clean up.
*/
ReleaseSysCache(typeTup);
return address;
}
/*
* DefineEnum
* Registers a new enum.
*/
void DefineEnum(CreateEnumStmt* stmt)
ObjectAddress DefineEnum(CreateEnumStmt* stmt)
{
char* enumName = NULL;
char* enumArrayName = NULL;
Oid enumNamespace;
Oid enumTypeOid;
//Oid enumTypeOid;
AclResult aclresult;
Oid old_type_oid;
Oid enumArrayOid;
Oid typowner = InvalidOid;
ObjectAddress enumTypeAddr;
/*
* isalter is true, change the owner of the objects as the owner of the
* namespace, if the owner of the namespce has the same name as the namescpe
@ -1088,7 +1093,7 @@ void DefineEnum(CreateEnumStmt* stmt)
enumArrayOid = AssignTypeArrayOid();
/* Create the pg_type entry */
enumTypeOid = TypeCreate(InvalidOid, /* no predetermined type OID */
enumTypeAddr = TypeCreate(InvalidOid, /* no predetermined type OID */
enumName, /* type name */
enumNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
@ -1121,7 +1126,7 @@ void DefineEnum(CreateEnumStmt* stmt)
InvalidOid); /* type's collation */
/* Enter the enum's values into pg_enum */
EnumValuesCreate(enumTypeOid, stmt->vals);
EnumValuesCreate(enumTypeAddr.objectId, stmt->vals);
/*
* Create the array type that goes with it.
@ -1146,7 +1151,7 @@ void DefineEnum(CreateEnumStmt* stmt)
InvalidOid, /* typmodin procedure - none */
InvalidOid, /* typmodout procedure - none */
F_ARRAY_TYPANALYZE, /* analyze procedure */
enumTypeOid, /* element type ID */
enumTypeAddr.objectId, /* element type ID */
true, /* yes this is an array type */
InvalidOid, /* no further array type */
InvalidOid, /* base type ID */
@ -1161,17 +1166,19 @@ void DefineEnum(CreateEnumStmt* stmt)
InvalidOid); /* type's collation */
pfree_ext(enumArrayName);
return enumTypeAddr;
}
/*
* AlterEnum
* Adds a new label to an existing enum.
*/
void AlterEnum(AlterEnumStmt* stmt)
ObjectAddress AlterEnum(AlterEnumStmt* stmt)
{
Oid enum_type_oid;
TypeName* typname = NULL;
HeapTuple tup;
ObjectAddress address;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(stmt->typname);
@ -1194,7 +1201,9 @@ void AlterEnum(AlterEnumStmt* stmt)
AddEnumLabel(enum_type_oid, stmt->newVal, stmt->newValNeighbor, stmt->newValIsAfter, stmt->skipIfNewValExists);
}
ObjectAddressSet(address, TypeRelationId, enum_type_oid);
ReleaseSysCache(tup);
return address;
}
/*
@ -1219,7 +1228,7 @@ static void checkEnumAlterPrivilege(HeapTuple tup)
}
}
void DefineSet(CreateSetStmt *stmt)
ObjectAddress DefineSet(CreateSetStmt *stmt)
{
char* setName = NULL;
Oid setNamespace;
@ -1227,6 +1236,7 @@ void DefineSet(CreateSetStmt *stmt)
AclResult aclresult;
Oid old_type_oid;
Oid typowner = InvalidOid;
ObjectAddress address;
/*
* isalter is true, change the owner of the objects as the owner of the
* namespace, if the owner of the namespce has the same name as the namescpe
@ -1269,7 +1279,7 @@ void DefineSet(CreateSetStmt *stmt)
}
/* Create the pg_type entry */
setTypeOid = TypeCreate(InvalidOid, /* no predetermined type OID */
address = TypeCreate(InvalidOid, /* no predetermined type OID */
setName, /* type name */
setNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
@ -1302,16 +1312,18 @@ void DefineSet(CreateSetStmt *stmt)
InvalidOid); /* type's collation */
/* Enter the set's values into pg_set */
setTypeOid=address.objectId;
SetValuesCreate(setTypeOid, stmt->typname->typmods);
stmt->typname->typeOid = setTypeOid;
stmt->typname->typmods = NIL;
return address;
}
/*
* DefineRange
* Registers a new range type.
*/
void DefineRange(CreateRangeStmt* stmt)
ObjectAddress DefineRange(CreateRangeStmt* stmt)
{
char* typname = NULL;
Oid typeNamespace;
@ -1334,6 +1346,8 @@ void DefineRange(CreateRangeStmt* stmt)
AclResult aclresult;
ListCell* lc = NULL;
Oid typowner = InvalidOid;
ObjectAddress address;
/*
* isalter is true, change the owner of the objects as the owner of the
* namespace, if the owner of the namespce has the same name as the namescpe
@ -1390,9 +1404,10 @@ void DefineRange(CreateRangeStmt* stmt)
* use in the range function definitions.
*/
if (!OidIsValid(typoid)) {
typoid = TypeShellMake(typname, typeNamespace, typowner);
address = TypeShellMake(typname, typeNamespace, typowner);
/* Make new shell type visible for modification below */
CommandCounterIncrement();
typoid = address.objectId;
}
/* Extract the parameters from the parameter list */
@ -1470,7 +1485,7 @@ void DefineRange(CreateRangeStmt* stmt)
rangeArrayOid = AssignTypeArrayOid();
/* Create the pg_type entry */
typoid = TypeCreate(InvalidOid, /* no predetermined type OID */
address = TypeCreate(InvalidOid, /* no predetermined type OID */
typname, /* type name */
typeNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
@ -1502,6 +1517,7 @@ void DefineRange(CreateRangeStmt* stmt)
false, /* Type NOT NULL */
InvalidOid); /* type's collation (ranges never have one) */
typoid = address.objectId;
/* Create the entry in pg_range */
RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, rangeCanonical, rangeSubtypeDiff);
@ -1546,6 +1562,7 @@ void DefineRange(CreateRangeStmt* stmt)
/* And create the constructor functions for this range type */
makeRangeConstructors(typname, typeNamespace, typoid, rangeSubtype);
return address;
}
/*
@ -1576,7 +1593,6 @@ static void makeRangeConstructors(const char* name, Oid nmspace, Oid rangeOid, O
for (i = 0; i < lengthof(prosrc); i++) {
oidvector* constructorArgTypesVector = NULL;
Oid procOid;
constructorArgTypesVector = buildoidvector(constructorArgTypes, pronargs[i]);
@ -1584,7 +1600,7 @@ static void makeRangeConstructors(const char* name, Oid nmspace, Oid rangeOid, O
* add an argument to record the position of arguments with default value.
* it is null here since that there is no argument with default value.
*/
procOid = ProcedureCreate(name, /* name: same as range type */
myself = ProcedureCreate(name, /* name: same as range type */
nmspace, /* namespace */
InvalidOid, /* package oid default invalid oid*/
false, /* not A db compatible */
@ -1622,9 +1638,6 @@ static void makeRangeConstructors(const char* name, Oid nmspace, Oid rangeOid, O
* that they go away silently when the type is dropped. Note that
* pg_dump depends on this choice to avoid dumping the constructors.
*/
myself.classId = ProcedureRelationId;
myself.objectId = procOid;
myself.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
}
@ -2024,7 +2037,7 @@ Oid AssignTypeArrayOid(void)
* create typy A as table of B, there are B and _B in pg_type
* add oid of _B in element
*/
void DefineTableOfType(const TableOfTypeStmt* stmt)
ObjectAddress DefineTableOfType(const TableOfTypeStmt* stmt)
{
char* typname = NULL;
Oid typeNamespace;
@ -2111,7 +2124,7 @@ void DefineTableOfType(const TableOfTypeStmt* stmt)
ReleaseSysCache(type_tup);
/* Create the pg_type entry */
typoid = TypeCreate(InvalidOid, /* no predetermined type OID */
return TypeCreate(InvalidOid, /* no predetermined type OID */
typname, /* type name */
typeNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
@ -2158,13 +2171,12 @@ void DefineTableOfType(const TableOfTypeStmt* stmt)
* an implicit composite type during function creation
* -------------------------------------------------------------------
*/
Oid DefineCompositeType(RangeVar* typevar, List* coldeflist)
ObjectAddress DefineCompositeType(RangeVar* typevar, List* coldeflist)
{
CreateStmt* createStmt = makeNode(CreateStmt);
Oid old_type_oid;
Oid typeNamespace;
Oid relid;
ObjectAddress address;
/*
* now set the parameters for keys/inheritance etc. All of these are
* uninteresting for composite types...
@ -2199,9 +2211,9 @@ Oid DefineCompositeType(RangeVar* typevar, List* coldeflist)
/*
* Finally create the relation. This also creates the type.
*/
relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid);
Assert(relid != InvalidOid);
return relid;
DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address);
return address;
}
/*
@ -2209,7 +2221,7 @@ Oid DefineCompositeType(RangeVar* typevar, List* coldeflist)
*
* Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements.
*/
void AlterDomainDefault(List* names, Node* defaultRaw)
ObjectAddress AlterDomainDefault(List* names, Node* defaultRaw)
{
TypeName* typname = NULL;
Oid domainoid;
@ -2223,6 +2235,7 @@ void AlterDomainDefault(List* names, Node* defaultRaw)
bool new_record_repl[Natts_pg_type];
HeapTuple newtuple;
Form_pg_type typTup;
ObjectAddress address;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(names);
@ -2321,9 +2334,11 @@ void AlterDomainDefault(List* names, Node* defaultRaw)
defaultExpr,
true); /* Rebuild is true */
ObjectAddressSet(address, TypeRelationId, domainoid);
/* Clean up */
heap_close(rel, NoLock);
tableam_tops_free_tuple(newtuple);
return address;
}
/*
@ -2331,13 +2346,14 @@ void AlterDomainDefault(List* names, Node* defaultRaw)
*
* Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements.
*/
void AlterDomainNotNull(List* names, bool notNull)
ObjectAddress AlterDomainNotNull(List* names, bool notNull)
{
TypeName* typname = NULL;
Oid domainoid;
Relation typrel;
HeapTuple tup;
Form_pg_type typTup;
ObjectAddress address = InvalidObjectAddress;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(names);
@ -2358,7 +2374,7 @@ void AlterDomainNotNull(List* names, bool notNull)
if (typTup->typnotnull == notNull) {
heap_close(typrel, RowExclusiveLock);
tableam_tops_free_tuple(tup);
return;
return address;
}
/* Adding a NOT NULL constraint requires checking existing columns */
@ -2414,9 +2430,12 @@ void AlterDomainNotNull(List* names, bool notNull)
CatalogUpdateIndexes(typrel, tup);
ObjectAddressSet(address, TypeRelationId, domainoid);
/* Clean up */
tableam_tops_free_tuple(tup);
heap_close(typrel, RowExclusiveLock);
return address;
}
/*
@ -2424,7 +2443,7 @@ void AlterDomainNotNull(List* names, bool notNull)
*
* Implements the ALTER DOMAIN DROP CONSTRAINT statement
*/
void AlterDomainDropConstraint(List* names, const char* constrName, DropBehavior behavior, bool missing_ok)
ObjectAddress AlterDomainDropConstraint(List* names, const char* constrName, DropBehavior behavior, bool missing_ok)
{
TypeName* typname = NULL;
Oid domainoid;
@ -2435,6 +2454,7 @@ void AlterDomainDropConstraint(List* names, const char* constrName, DropBehavior
ScanKeyData key[1];
HeapTuple contup;
bool found = false;
ObjectAddress address = InvalidObjectAddress;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(names);
@ -2476,6 +2496,7 @@ void AlterDomainDropConstraint(List* names, const char* constrName, DropBehavior
found = true;
}
}
ObjectAddressSet(address, TypeRelationId, domainoid);
/* Clean up after the scan */
systable_endscan(conscan);
heap_close(conrel, RowExclusiveLock);
@ -2494,6 +2515,7 @@ void AlterDomainDropConstraint(List* names, const char* constrName, DropBehavior
constrName,
TypeNameToString(typname))));
}
return address;
}
/*
@ -2501,7 +2523,7 @@ void AlterDomainDropConstraint(List* names, const char* constrName, DropBehavior
*
* Implements the ALTER DOMAIN .. ADD CONSTRAINT statement.
*/
void AlterDomainAddConstraint(List* names, Node* newConstraint)
ObjectAddress AlterDomainAddConstraint(List* names, Node* newConstraint)
{
TypeName* typname = NULL;
Oid domainoid;
@ -2510,6 +2532,7 @@ void AlterDomainAddConstraint(List* names, Node* newConstraint)
Form_pg_type typTup;
Constraint* constr = NULL;
char* ccbin = NULL;
ObjectAddress address = InvalidObjectAddress;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(names);
@ -2580,7 +2603,8 @@ void AlterDomainAddConstraint(List* names, Node* newConstraint)
typTup->typbasetype,
typTup->typtypmod,
constr,
NameStr(typTup->typname));
NameStr(typTup->typname),
NULL);
/*
* If requested to validate the constraint, test all values stored in the
@ -2589,8 +2613,10 @@ void AlterDomainAddConstraint(List* names, Node* newConstraint)
if (!constr->skip_validation)
validateDomainConstraint(domainoid, ccbin);
ObjectAddressSet(address, TypeRelationId, domainoid);
/* Clean up */
heap_close(typrel, RowExclusiveLock);
return address;
}
/*
@ -2598,7 +2624,7 @@ void AlterDomainAddConstraint(List* names, Node* newConstraint)
*
* Implements the ALTER DOMAIN .. VALIDATE CONSTRAINT statement.
*/
void AlterDomainValidateConstraint(List* names, char* constrName)
ObjectAddress AlterDomainValidateConstraint(List* names, char* constrName)
{
TypeName* typname = NULL;
Oid domainoid;
@ -2615,6 +2641,7 @@ void AlterDomainValidateConstraint(List* names, char* constrName)
HeapTuple tuple;
HeapTuple copyTuple;
ScanKeyData key;
ObjectAddress address;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(names);
@ -2675,12 +2702,14 @@ void AlterDomainValidateConstraint(List* names, char* constrName)
CatalogUpdateIndexes(conrel, copyTuple);
tableam_tops_free_tuple(copyTuple);
ObjectAddressSet(address, TypeRelationId, domainoid);
systable_endscan(scan);
heap_close(typrel, AccessShareLock);
heap_close(conrel, RowExclusiveLock);
ReleaseSysCache(tup);
return address;
}
static void validateDomainConstraint(Oid domainoid, char* ccbin)
@ -2924,13 +2953,14 @@ void checkDomainOwner(HeapTuple tup)
* domainAddConstraint - code shared between CREATE and ALTER DOMAIN
*/
static char* domainAddConstraint(
Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint* constr, char* domainName)
Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint* constr, char* domainName, ObjectAddress *constrAddr)
{
Node* expr = NULL;
char* ccsrc = NULL;
char* ccbin = NULL;
ParseState* pstate = NULL;
CoerceToDomainValue* domVal = NULL;
Oid ccoid;
/*
* Assign or validate constraint name
@ -3018,7 +3048,7 @@ static char* domainAddConstraint(
/*
* Store the constraint in pg_constraint
*/
CreateConstraintEntry(constr->conname, /* Constraint Name */
ccoid = CreateConstraintEntry(constr->conname, /* Constraint Name */
domainNamespace, /* namespace */
CONSTRAINT_CHECK, /* Constraint Type */
false, /* Is Deferrable */
@ -3048,6 +3078,8 @@ static char* domainAddConstraint(
false, /* connoinherit */
constr->inforConstraint) /* @hdfs, informational constraint information */;
if (constrAddr)
ObjectAddressSet(*constrAddr, ConstraintRelationId, ccoid);
/*
* Return the compiled constraint expression so the calling routine can
* perform any additional required tests.
@ -3171,7 +3203,7 @@ List* GetDomainConstraints(Oid typeOid)
/*
* Execute ALTER TYPE RENAME
*/
void RenameType(RenameStmt* stmt)
ObjectAddress RenameType(RenameStmt* stmt)
{
List* names = stmt->object;
const char* newTypeName = stmt->newname;
@ -3180,6 +3212,7 @@ void RenameType(RenameStmt* stmt)
Relation rel;
HeapTuple tup;
Form_pg_type typTup;
ObjectAddress address;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(names);
@ -3246,14 +3279,16 @@ void RenameType(RenameStmt* stmt)
else
RenameTypeInternal(typeOid, newTypeName, typTup->typnamespace);
ObjectAddressSet(address, TypeRelationId, typeOid);
/* Clean up */
heap_close(rel, RowExclusiveLock);
return address;
}
/*
* Change the owner of a type.
*/
void AlterTypeOwner(List* names, Oid newOwnerId, ObjectType objecttype, bool altertype)
ObjectAddress AlterTypeOwner(List* names, Oid newOwnerId, ObjectType objecttype, bool altertype)
{
TypeName* typname = NULL;
Oid typeOid;
@ -3262,6 +3297,7 @@ void AlterTypeOwner(List* names, Oid newOwnerId, ObjectType objecttype, bool alt
HeapTuple newtup;
Form_pg_type typTup;
AclResult aclresult;
ObjectAddress address;
rel = heap_open(TypeRelationId, RowExclusiveLock);
@ -3372,8 +3408,10 @@ void AlterTypeOwner(List* names, Oid newOwnerId, ObjectType objecttype, bool alt
}
}
ObjectAddressSet(address, TypeRelationId, typeOid);
/* Clean up */
heap_close(rel, RowExclusiveLock);
return address;
}
/*
@ -3517,12 +3555,14 @@ void AlterTypeOwnerByFunc(Oid funcOid, Oid newOwnerId)
/*
* Execute ALTER TYPE SET SCHEMA
*/
void AlterTypeNamespace(List* names, const char* newschema, ObjectType objecttype)
ObjectAddress AlterTypeNamespace(List* names, const char* newschema, ObjectType objecttype)
{
TypeName* typname = NULL;
Oid typeOid;
Oid nspOid;
Oid oldNspOid;
ObjectAddresses* objsMoved = NULL;
ObjectAddress myself;
/* Make a TypeName so we can use standard type lookup machinery */
typname = makeTypeNameFromNameList(names);
@ -3556,8 +3596,12 @@ void AlterTypeNamespace(List* names, const char* newschema, ObjectType objecttyp
nspOid = LookupCreationNamespace(newschema);
objsMoved = new_object_addresses();
AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
oldNspOid = AlterTypeNamespace_oid(typeOid, nspOid, objsMoved);
free_object_addresses(objsMoved);
ObjectAddressSet(myself, TypeRelationId, typeOid);
return myself;
}
Oid AlterTypeNamespace_oid(Oid typeOid, Oid nspOid, ObjectAddresses* objsMoved)

Some files were not shown because too many files have changed in this diff Show More