mirror of https://github.com/citusdata/citus.git
Implement infra to get foreign key connected relations (#4439)
On top of our foreign key graph, implement the infrastructure to get list of relations that are connected to input relation via a foreign key graph. We need this to support cascading create_citus_local_table & undistribute_table operations. Also add regression tests to see what our foreign key graph is able to capture currently.pull/4409/head
parent
0db21bbe14
commit
5ed9197041
|
@ -14,13 +14,20 @@
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
|
|
||||||
|
#include "distributed/foreign_key_relationship.h"
|
||||||
#include "distributed/listutils.h"
|
#include "distributed/listutils.h"
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/tuplestore.h"
|
||||||
#include "distributed/version_compat.h"
|
#include "distributed/version_compat.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define GET_FKEY_CONNECTED_RELATIONS_COLUMNS 1
|
||||||
|
|
||||||
|
|
||||||
/* these functions are only exported in the regression tests */
|
/* these functions are only exported in the regression tests */
|
||||||
PG_FUNCTION_INFO_V1(get_referencing_relation_id_list);
|
PG_FUNCTION_INFO_V1(get_referencing_relation_id_list);
|
||||||
PG_FUNCTION_INFO_V1(get_referenced_relation_id_list);
|
PG_FUNCTION_INFO_V1(get_referenced_relation_id_list);
|
||||||
|
PG_FUNCTION_INFO_V1(get_foreign_key_connected_relations);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_referencing_relation_id_list returns the list of table oids that is referencing
|
* get_referencing_relation_id_list returns the list of table oids that is referencing
|
||||||
|
@ -138,3 +145,38 @@ get_referenced_relation_id_list(PG_FUNCTION_ARGS)
|
||||||
SRF_RETURN_DONE(functionContext);
|
SRF_RETURN_DONE(functionContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_foreign_key_connected_relations takes a relation, and returns relations
|
||||||
|
* that are connected to input relation via a foreign key graph.
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
get_foreign_key_connected_relations(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
CheckCitusVersion(ERROR);
|
||||||
|
|
||||||
|
Oid relationId = PG_GETARG_OID(0);
|
||||||
|
|
||||||
|
TupleDesc tupleDescriptor = NULL;
|
||||||
|
Tuplestorestate *tupleStore = SetupTuplestore(fcinfo, &tupleDescriptor);
|
||||||
|
|
||||||
|
Oid connectedRelationId;
|
||||||
|
List *fkeyConnectedRelationIdList = GetForeignKeyConnectedRelationIdList(relationId);
|
||||||
|
foreach_oid(connectedRelationId, fkeyConnectedRelationIdList)
|
||||||
|
{
|
||||||
|
Datum values[GET_FKEY_CONNECTED_RELATIONS_COLUMNS];
|
||||||
|
bool nulls[GET_FKEY_CONNECTED_RELATIONS_COLUMNS];
|
||||||
|
|
||||||
|
memset(values, 0, sizeof(values));
|
||||||
|
memset(nulls, false, sizeof(nulls));
|
||||||
|
|
||||||
|
values[0] = ObjectIdGetDatum(connectedRelationId);
|
||||||
|
|
||||||
|
tuplestore_putvalues(tupleStore, tupleDescriptor, values, nulls);
|
||||||
|
}
|
||||||
|
|
||||||
|
tuplestore_donestoring(tupleStore);
|
||||||
|
|
||||||
|
PG_RETURN_VOID();
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
#include "common/hashfn.h"
|
#include "common/hashfn.h"
|
||||||
#endif
|
#endif
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
|
#if PG_VERSION_NUM < PG_VERSION_12
|
||||||
|
#include "utils/rel.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -77,6 +80,9 @@ typedef struct ForeignConstraintRelationshipEdge
|
||||||
|
|
||||||
static ForeignConstraintRelationshipGraph *fConstraintRelationshipGraph = NULL;
|
static ForeignConstraintRelationshipGraph *fConstraintRelationshipGraph = NULL;
|
||||||
|
|
||||||
|
static List * GetRelationshipNodesForFKeyConnectedRelations(
|
||||||
|
ForeignConstraintRelationshipNode *relationshipNode);
|
||||||
|
static List * GetAllNeighboursList(ForeignConstraintRelationshipNode *relationshipNode);
|
||||||
static ForeignConstraintRelationshipNode * GetRelationshipNodeForRelationId(Oid
|
static ForeignConstraintRelationshipNode * GetRelationshipNodeForRelationId(Oid
|
||||||
relationId,
|
relationId,
|
||||||
bool *isFound);
|
bool *isFound);
|
||||||
|
@ -98,6 +104,108 @@ static void VisitOid(HTAB *oidVisitedMap, Oid oid);
|
||||||
static List * GetForeignConstraintRelationshipHelper(Oid relationId, bool isReferencing);
|
static List * GetForeignConstraintRelationshipHelper(Oid relationId, bool isReferencing);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetForeignKeyConnectedRelationIdList returns a list of relation id's for
|
||||||
|
* relations that are connected to relation with relationId via a foreign
|
||||||
|
* key graph.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
GetForeignKeyConnectedRelationIdList(Oid relationId)
|
||||||
|
{
|
||||||
|
/* use ShareRowExclusiveLock to prevent concurent foreign key creation */
|
||||||
|
LOCKMODE lockMode = ShareRowExclusiveLock;
|
||||||
|
Relation relation = try_relation_open(relationId, lockMode);
|
||||||
|
if (!RelationIsValid(relation))
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("relation with OID %d does not exist",
|
||||||
|
relationId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
relation_close(relation, NoLock);
|
||||||
|
|
||||||
|
bool foundInFKeyGraph = false;
|
||||||
|
ForeignConstraintRelationshipNode *relationshipNode =
|
||||||
|
GetRelationshipNodeForRelationId(relationId, &foundInFKeyGraph);
|
||||||
|
if (!foundInFKeyGraph)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Relation could not be found in foreign key graph, then it has no
|
||||||
|
* foreign key relationships.
|
||||||
|
*/
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
List *fKeyConnectedRelationshipNodeList =
|
||||||
|
GetRelationshipNodesForFKeyConnectedRelations(relationshipNode);
|
||||||
|
List *fKeyConnectedRelationIdList =
|
||||||
|
GetRelationIdsFromRelationshipNodeList(fKeyConnectedRelationshipNodeList);
|
||||||
|
return fKeyConnectedRelationIdList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetRelationshipNodesForFKeyConnectedRelations performs breadth-first search
|
||||||
|
* starting from input ForeignConstraintRelationshipNode and returns a list
|
||||||
|
* of ForeignConstraintRelationshipNode objects for relations that are connected
|
||||||
|
* to given relation node via a foreign key relationhip graph.
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
GetRelationshipNodesForFKeyConnectedRelations(
|
||||||
|
ForeignConstraintRelationshipNode *relationshipNode)
|
||||||
|
{
|
||||||
|
HTAB *oidVisitedMap = CreateOidVisitedHashSet();
|
||||||
|
|
||||||
|
VisitOid(oidVisitedMap, relationshipNode->relationId);
|
||||||
|
List *relationshipNodeList = list_make1(relationshipNode);
|
||||||
|
|
||||||
|
ForeignConstraintRelationshipNode *currentNode = NULL;
|
||||||
|
foreach_ptr_append(currentNode, relationshipNodeList)
|
||||||
|
{
|
||||||
|
List *allNeighboursList = GetAllNeighboursList(currentNode);
|
||||||
|
ForeignConstraintRelationshipNode *neighbourNode = NULL;
|
||||||
|
foreach_ptr(neighbourNode, allNeighboursList)
|
||||||
|
{
|
||||||
|
Oid neighbourRelationId = neighbourNode->relationId;
|
||||||
|
if (OidVisited(oidVisitedMap, neighbourRelationId))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VisitOid(oidVisitedMap, neighbourRelationId);
|
||||||
|
relationshipNodeList = lappend(relationshipNodeList, neighbourNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return relationshipNodeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetAllNeighboursList returns a list of ForeignConstraintRelationshipNode
|
||||||
|
* objects by concatenating both (referencing & referenced) adjacency lists
|
||||||
|
* of given relationship node.
|
||||||
|
*/
|
||||||
|
static List *
|
||||||
|
GetAllNeighboursList(ForeignConstraintRelationshipNode *relationshipNode)
|
||||||
|
{
|
||||||
|
bool isReferencing = false;
|
||||||
|
List *referencedNeighboursList = GetNeighbourList(relationshipNode, isReferencing);
|
||||||
|
|
||||||
|
isReferencing = true;
|
||||||
|
List *referencingNeighboursList = GetNeighbourList(relationshipNode, isReferencing);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetNeighbourList returns list from graph as is, so first copy it as
|
||||||
|
* list_concat might invalidate it.
|
||||||
|
*/
|
||||||
|
List *allNeighboursList = list_copy(referencedNeighboursList);
|
||||||
|
allNeighboursList = list_concat_unique_ptr(allNeighboursList,
|
||||||
|
referencingNeighboursList);
|
||||||
|
return allNeighboursList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ReferencedRelationIdList is a wrapper function around GetForeignConstraintRelationshipHelper
|
* ReferencedRelationIdList is a wrapper function around GetForeignConstraintRelationshipHelper
|
||||||
* to get list of relation IDs which are referenced by the given relation id.
|
* to get list of relation IDs which are referenced by the given relation id.
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "utils/hsearch.h"
|
#include "utils/hsearch.h"
|
||||||
#include "nodes/primnodes.h"
|
#include "nodes/primnodes.h"
|
||||||
|
|
||||||
|
extern List * GetForeignKeyConnectedRelationIdList(Oid relationId);
|
||||||
extern List * ReferencedRelationIdList(Oid relationId);
|
extern List * ReferencedRelationIdList(Oid relationId);
|
||||||
extern List * ReferencingRelationIdList(Oid relationId);
|
extern List * ReferencingRelationIdList(Oid relationId);
|
||||||
extern void SetForeignConstraintRelationshipGraphInvalid(void);
|
extern void SetForeignConstraintRelationshipGraphInvalid(void);
|
||||||
|
|
|
@ -602,18 +602,133 @@ drop cascades to table test_8
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
CREATE OR REPLACE FUNCTION get_foreign_key_connected_relations(IN table_name regclass)
|
||||||
|
RETURNS SETOF RECORD
|
||||||
|
LANGUAGE C STRICT
|
||||||
|
AS 'citus', $$get_foreign_key_connected_relations$$;
|
||||||
|
COMMENT ON FUNCTION get_foreign_key_connected_relations(IN table_name regclass)
|
||||||
|
IS 'returns relations connected to input relation via a foreign key graph';
|
||||||
|
CREATE TABLE distributed_table_1(col int unique);
|
||||||
|
CREATE TABLE distributed_table_2(col int unique);
|
||||||
|
CREATE TABLE distributed_table_3(col int unique);
|
||||||
|
CREATE TABLE distributed_table_4(col int unique);
|
||||||
|
SELECT create_distributed_table('distributed_table_1', 'col');
|
||||||
|
create_distributed_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT create_distributed_table('distributed_table_2', 'col');
|
||||||
|
create_distributed_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT create_distributed_table('distributed_table_3', 'col');
|
||||||
|
create_distributed_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE TABLE reference_table_1(col int unique);
|
||||||
|
CREATE TABLE reference_table_2(col int unique);
|
||||||
|
SELECT create_reference_table('reference_table_1');
|
||||||
|
create_reference_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT create_reference_table('reference_table_2');
|
||||||
|
create_reference_table
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Now build below foreign key graph:
|
||||||
|
--
|
||||||
|
-- --------------------------------------------
|
||||||
|
-- ^ |
|
||||||
|
-- | v
|
||||||
|
-- distributed_table_1 <- distributed_table_2 -> reference_table_1 <- reference_table_2
|
||||||
|
-- | ^
|
||||||
|
-- | |
|
||||||
|
-- ----------> distributed_table_3
|
||||||
|
ALTER TABLE distributed_table_2 ADD CONSTRAINT fkey_1 FOREIGN KEY (col) REFERENCES distributed_table_1(col);
|
||||||
|
ALTER TABLE distributed_table_2 ADD CONSTRAINT fkey_2 FOREIGN KEY (col) REFERENCES reference_table_1(col);
|
||||||
|
ALTER TABLE reference_table_2 ADD CONSTRAINT fkey_3 FOREIGN KEY (col) REFERENCES reference_table_1(col);
|
||||||
|
ALTER TABLE distributed_table_3 ADD CONSTRAINT fkey_4 FOREIGN KEY (col) REFERENCES distributed_table_2(col);
|
||||||
|
ALTER TABLE distributed_table_2 ADD CONSTRAINT fkey_5 FOREIGN KEY (col) REFERENCES reference_table_2(col);
|
||||||
|
ALTER TABLE distributed_table_1 ADD CONSTRAINT fkey_6 FOREIGN KEY (col) REFERENCES distributed_table_3(col);
|
||||||
|
-- below queries should print all 5 tables mentioned in above graph
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('reference_table_1') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
tablename
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
distributed_table_1
|
||||||
|
distributed_table_2
|
||||||
|
distributed_table_3
|
||||||
|
reference_table_1
|
||||||
|
reference_table_2
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('distributed_table_1') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
tablename
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
distributed_table_1
|
||||||
|
distributed_table_2
|
||||||
|
distributed_table_3
|
||||||
|
reference_table_1
|
||||||
|
reference_table_2
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- show that this does not print anything as distributed_table_4
|
||||||
|
-- is not involved in any foreign key relationship
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('distributed_table_4') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
tablename
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
ALTER TABLE distributed_table_4 ADD CONSTRAINT fkey_1 FOREIGN KEY (col) REFERENCES distributed_table_4(col);
|
||||||
|
-- even if distributed_table_4 has a self referencing foreign key,
|
||||||
|
-- we don't print anything as we only consider foreign key relationships
|
||||||
|
-- with other tables
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('distributed_table_4') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
tablename
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
CREATE TABLE local_table_1 (col int unique);
|
||||||
|
CREATE TABLE local_table_2 (col int unique);
|
||||||
|
-- show that we do not trigger updating foreign key graph when
|
||||||
|
-- defining/dropping foreign keys between postgres tables
|
||||||
|
ALTER TABLE local_table_1 ADD CONSTRAINT fkey_1 FOREIGN KEY (col) REFERENCES local_table_2(col);
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('local_table_2') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
tablename
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
ALTER TABLE local_table_1 DROP CONSTRAINT fkey_1;
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('local_table_1') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
tablename
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
-- show that we error out for non-existent tables
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('non_existent_table') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
ERROR: relation "non_existent_table" does not exist
|
||||||
|
set client_min_messages to error;
|
||||||
SET search_path TO public;
|
SET search_path TO public;
|
||||||
DROP SCHEMA fkey_graph CASCADE;
|
DROP SCHEMA fkey_graph CASCADE;
|
||||||
NOTICE: drop cascades to 12 other objects
|
|
||||||
DETAIL: drop cascades to function fkey_graph.get_referencing_relation_id_list(oid)
|
|
||||||
drop cascades to function fkey_graph.get_referenced_relation_id_list(oid)
|
|
||||||
drop cascades to table fkey_graph.dtt1
|
|
||||||
drop cascades to table fkey_graph.dtt2
|
|
||||||
drop cascades to table fkey_graph.dtt3
|
|
||||||
drop cascades to table fkey_graph.dtt4
|
|
||||||
drop cascades to view fkey_graph.referential_integrity_summary
|
|
||||||
drop cascades to table fkey_graph.test_1
|
|
||||||
drop cascades to table fkey_graph.test_2
|
|
||||||
drop cascades to table fkey_graph.test_3
|
|
||||||
drop cascades to table fkey_graph.test_4
|
|
||||||
drop cascades to table fkey_graph.test_5
|
|
||||||
|
|
|
@ -220,5 +220,95 @@ BEGIN;
|
||||||
|
|
||||||
ROLLBACK;
|
ROLLBACK;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION get_foreign_key_connected_relations(IN table_name regclass)
|
||||||
|
RETURNS SETOF RECORD
|
||||||
|
LANGUAGE C STRICT
|
||||||
|
AS 'citus', $$get_foreign_key_connected_relations$$;
|
||||||
|
COMMENT ON FUNCTION get_foreign_key_connected_relations(IN table_name regclass)
|
||||||
|
IS 'returns relations connected to input relation via a foreign key graph';
|
||||||
|
|
||||||
|
CREATE TABLE distributed_table_1(col int unique);
|
||||||
|
CREATE TABLE distributed_table_2(col int unique);
|
||||||
|
CREATE TABLE distributed_table_3(col int unique);
|
||||||
|
CREATE TABLE distributed_table_4(col int unique);
|
||||||
|
|
||||||
|
SELECT create_distributed_table('distributed_table_1', 'col');
|
||||||
|
SELECT create_distributed_table('distributed_table_2', 'col');
|
||||||
|
SELECT create_distributed_table('distributed_table_3', 'col');
|
||||||
|
|
||||||
|
CREATE TABLE reference_table_1(col int unique);
|
||||||
|
CREATE TABLE reference_table_2(col int unique);
|
||||||
|
|
||||||
|
SELECT create_reference_table('reference_table_1');
|
||||||
|
SELECT create_reference_table('reference_table_2');
|
||||||
|
|
||||||
|
|
||||||
|
-- Now build below foreign key graph:
|
||||||
|
--
|
||||||
|
-- --------------------------------------------
|
||||||
|
-- ^ |
|
||||||
|
-- | v
|
||||||
|
-- distributed_table_1 <- distributed_table_2 -> reference_table_1 <- reference_table_2
|
||||||
|
-- | ^
|
||||||
|
-- | |
|
||||||
|
-- ----------> distributed_table_3
|
||||||
|
|
||||||
|
ALTER TABLE distributed_table_2 ADD CONSTRAINT fkey_1 FOREIGN KEY (col) REFERENCES distributed_table_1(col);
|
||||||
|
ALTER TABLE distributed_table_2 ADD CONSTRAINT fkey_2 FOREIGN KEY (col) REFERENCES reference_table_1(col);
|
||||||
|
ALTER TABLE reference_table_2 ADD CONSTRAINT fkey_3 FOREIGN KEY (col) REFERENCES reference_table_1(col);
|
||||||
|
ALTER TABLE distributed_table_3 ADD CONSTRAINT fkey_4 FOREIGN KEY (col) REFERENCES distributed_table_2(col);
|
||||||
|
ALTER TABLE distributed_table_2 ADD CONSTRAINT fkey_5 FOREIGN KEY (col) REFERENCES reference_table_2(col);
|
||||||
|
ALTER TABLE distributed_table_1 ADD CONSTRAINT fkey_6 FOREIGN KEY (col) REFERENCES distributed_table_3(col);
|
||||||
|
|
||||||
|
-- below queries should print all 5 tables mentioned in above graph
|
||||||
|
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('reference_table_1') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('distributed_table_1') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
|
||||||
|
-- show that this does not print anything as distributed_table_4
|
||||||
|
-- is not involved in any foreign key relationship
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('distributed_table_4') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
|
||||||
|
ALTER TABLE distributed_table_4 ADD CONSTRAINT fkey_1 FOREIGN KEY (col) REFERENCES distributed_table_4(col);
|
||||||
|
|
||||||
|
-- even if distributed_table_4 has a self referencing foreign key,
|
||||||
|
-- we don't print anything as we only consider foreign key relationships
|
||||||
|
-- with other tables
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('distributed_table_4') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
|
||||||
|
CREATE TABLE local_table_1 (col int unique);
|
||||||
|
CREATE TABLE local_table_2 (col int unique);
|
||||||
|
|
||||||
|
-- show that we do not trigger updating foreign key graph when
|
||||||
|
-- defining/dropping foreign keys between postgres tables
|
||||||
|
|
||||||
|
ALTER TABLE local_table_1 ADD CONSTRAINT fkey_1 FOREIGN KEY (col) REFERENCES local_table_2(col);
|
||||||
|
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('local_table_2') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
|
||||||
|
ALTER TABLE local_table_1 DROP CONSTRAINT fkey_1;
|
||||||
|
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('local_table_1') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
|
||||||
|
-- show that we error out for non-existent tables
|
||||||
|
SELECT oid::regclass::text AS tablename
|
||||||
|
FROM get_foreign_key_connected_relations('non_existent_table') AS f(oid oid)
|
||||||
|
ORDER BY tablename;
|
||||||
|
|
||||||
|
set client_min_messages to error;
|
||||||
|
|
||||||
SET search_path TO public;
|
SET search_path TO public;
|
||||||
DROP SCHEMA fkey_graph CASCADE;
|
DROP SCHEMA fkey_graph CASCADE;
|
||||||
|
|
Loading…
Reference in New Issue