forked from openGauss-Ecosystem/openGauss-server
实现事件触发器
This commit is contained in:
parent
5a69c46920
commit
9f8064bb24
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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).
|
||||
*/
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -891,6 +891,7 @@ static int lexescape(struct vars* v)
|
|||
break;
|
||||
}
|
||||
Assert(NOTREACHED);
|
||||
FAILW(REG_EESCAPE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 ---------- */
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -276,6 +276,7 @@ Boot_CreateStmt:
|
|||
NULL, // partTableState add by data partition
|
||||
REL_CMPRS_NOT_SUPPORT,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
if (id == DescriptionRelationId) {
|
||||
InsertBuiltinFuncDescInBootstrap();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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))));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue