mirror of https://github.com/citusdata/citus.git
703 lines
20 KiB
C
703 lines
20 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* domain.c
|
|
* Hooks to handle the creation, altering and removal of domains.
|
|
* These hooks are responsible for duplicating the changes to the
|
|
* workers nodes.
|
|
*
|
|
* Copyright (c) Citus Data, Inc.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "access/genam.h"
|
|
#include "catalog/pg_collation.h"
|
|
#include "catalog/pg_constraint.h"
|
|
#include "catalog/pg_type.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_type.h"
|
|
#include "tcop/utility.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/fmgroids.h"
|
|
#include "utils/regproc.h"
|
|
#include "utils/syscache.h"
|
|
|
|
#include "distributed/commands.h"
|
|
#include "distributed/commands/utility_hook.h"
|
|
#include "distributed/deparser.h"
|
|
#include "distributed/listutils.h"
|
|
#include "distributed/metadata/distobject.h"
|
|
#include "distributed/metadata_sync.h"
|
|
#include "distributed/metadata_utility.h"
|
|
#include "distributed/multi_executor.h"
|
|
#include "distributed/worker_create_or_replace.h"
|
|
#include "distributed/worker_transaction.h"
|
|
|
|
|
|
static CollateClause * MakeCollateClauseFromOid(Oid collationOid);
|
|
static List * FilterNameListForDistributedDomains(List *domainNames, bool missing_ok,
|
|
List **distributedDomainAddresses);
|
|
static ObjectAddress GetDomainAddressByName(TypeName *domainName, bool missing_ok);
|
|
|
|
/*
|
|
* PreprocessCreateDomainStmt handles the propagation of the create domain statements.
|
|
*/
|
|
List *
|
|
PreprocessCreateDomainStmt(Node *node, const char *queryString,
|
|
ProcessUtilityContext processUtilityContext)
|
|
{
|
|
if (!ShouldPropagate())
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
/* check creation against multi-statement transaction policy */
|
|
if (!ShouldPropagateCreateInCoordinatedTransction())
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureCoordinator();
|
|
EnsureSequentialMode(OBJECT_DOMAIN);
|
|
|
|
QualifyTreeNode(node);
|
|
const char *sql = DeparseTreeNode(node);
|
|
sql = WrapCreateOrReplace(sql);
|
|
|
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
|
(void *) sql,
|
|
ENABLE_DDL_PROPAGATION);
|
|
|
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
|
}
|
|
|
|
|
|
/*
|
|
* PostprocessCreateDomainStmt gets called after the domain has been created locally. When
|
|
* the domain is decided to be propagated we make sure all the domains dependencies exist
|
|
* on all workers.
|
|
*/
|
|
List *
|
|
PostprocessCreateDomainStmt(Node *node, const char *queryString)
|
|
{
|
|
if (!ShouldPropagate())
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
/* check creation against multi-statement transaction policy */
|
|
if (!ShouldPropagateCreateInCoordinatedTransction())
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
/*
|
|
* find object address of the just created object, because the domain has been created
|
|
* locally it can't be missing
|
|
*/
|
|
ObjectAddress typeAddress = GetObjectAddressFromParseTree(node, false);
|
|
EnsureDependenciesExistOnAllNodes(&typeAddress);
|
|
|
|
return NIL;
|
|
}
|
|
|
|
|
|
/*
|
|
* PreprocessDropDomainStmt gets called before dropping the domain locally. For
|
|
* distributed domains it will make sure the fully qualified statement is forwarded to all
|
|
* the workers reflecting the drop of the domain.
|
|
*/
|
|
List *
|
|
PreprocessDropDomainStmt(Node *node, const char *queryString,
|
|
ProcessUtilityContext processUtilityContext)
|
|
{
|
|
DropStmt *stmt = castNode(DropStmt, node);
|
|
|
|
|
|
if (!ShouldPropagate())
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
QualifyTreeNode((Node *) stmt);
|
|
|
|
List *oldDomains = stmt->objects;
|
|
List *distributedDomainAddresses = NIL;
|
|
List *distributedDomains = FilterNameListForDistributedDomains(
|
|
oldDomains,
|
|
stmt->missing_ok,
|
|
&distributedDomainAddresses);
|
|
if (list_length(distributedDomains) <= 0)
|
|
{
|
|
/* no distributed domains to drop */
|
|
return NIL;
|
|
}
|
|
|
|
EnsureCoordinator();
|
|
EnsureSequentialMode(OBJECT_DOMAIN);
|
|
|
|
ObjectAddress *addressItem = NULL;
|
|
foreach_ptr(addressItem, distributedDomainAddresses)
|
|
{
|
|
UnmarkObjectDistributed(addressItem);
|
|
}
|
|
|
|
/*
|
|
* temporary swap the lists of objects to delete with the distributed objects and
|
|
* deparse to an executable sql statement for the workers
|
|
*/
|
|
stmt->objects = distributedDomains;
|
|
char *dropStmtSql = DeparseTreeNode((Node *) stmt);
|
|
stmt->objects = oldDomains;
|
|
|
|
/* to prevent recursion with mx we disable ddl propagation */
|
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
|
(void *) dropStmtSql,
|
|
ENABLE_DDL_PROPAGATION);
|
|
|
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
|
}
|
|
|
|
|
|
/*
|
|
* PreprocessAlterDomainStmt gets called for all domain specific alter statements. When
|
|
* the change happens on a distributed domain we reflect the changes on the workers.
|
|
*/
|
|
List *
|
|
PreprocessAlterDomainStmt(Node *node, const char *queryString,
|
|
ProcessUtilityContext processUtilityContext)
|
|
{
|
|
AlterDomainStmt *stmt = castNode(AlterDomainStmt, node);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureCoordinator();
|
|
EnsureSequentialMode(OBJECT_DOMAIN);
|
|
|
|
QualifyTreeNode((Node *) stmt);
|
|
char *sqlStmt = DeparseTreeNode((Node *) stmt);
|
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
|
(void *) sqlStmt,
|
|
ENABLE_DDL_PROPAGATION);
|
|
|
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
|
}
|
|
|
|
|
|
/*
|
|
* PostprocessAlterDomainStmt gets called after the domain has been altered locally. A
|
|
* change on the constraints could cause new (undistributed) objects to be dependencies of
|
|
* the domain. Here we recreate any new dependencies on the workers before we forward the
|
|
* alter statement to the workers.
|
|
*/
|
|
List *
|
|
PostprocessAlterDomainStmt(Node *node, const char *queryString)
|
|
{
|
|
AlterDomainStmt *stmt = castNode(AlterDomainStmt, node);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureDependenciesExistOnAllNodes(&domainAddress);
|
|
return NIL;
|
|
}
|
|
|
|
|
|
/*
|
|
* PreprocessDomainRenameConstraintStmt gets called locally when a constraint on a domain
|
|
* is renamed. When the constraint is on a distributed domain we forward the statement
|
|
* appropriately.
|
|
*/
|
|
List *
|
|
PreprocessDomainRenameConstraintStmt(Node *node, const char *queryString,
|
|
ProcessUtilityContext processUtilityContext)
|
|
{
|
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
|
Assert(stmt->renameType == OBJECT_DOMCONSTRAINT);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureCoordinator();
|
|
EnsureSequentialMode(OBJECT_DOMAIN);
|
|
|
|
QualifyTreeNode((Node *) stmt);
|
|
char *sqlStmt = DeparseTreeNode((Node *) stmt);
|
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
|
(void *) sqlStmt,
|
|
ENABLE_DDL_PROPAGATION);
|
|
|
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
|
}
|
|
|
|
|
|
/*
|
|
* PreprocessAlterDomainOwnerStmt called locally when the owner of a constraint is
|
|
* changed. For distributed domains the statement is forwarded to all the workers.
|
|
*/
|
|
List *
|
|
PreprocessAlterDomainOwnerStmt(Node *node, const char *queryString,
|
|
ProcessUtilityContext processUtilityContext)
|
|
{
|
|
AlterOwnerStmt *stmt = castNode(AlterOwnerStmt, node);
|
|
Assert(stmt->objectType == OBJECT_DOMAIN);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureCoordinator();
|
|
EnsureSequentialMode(OBJECT_DOMAIN);
|
|
|
|
QualifyTreeNode((Node *) stmt);
|
|
char *sqlStmt = DeparseTreeNode((Node *) stmt);
|
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
|
(void *) sqlStmt,
|
|
ENABLE_DDL_PROPAGATION);
|
|
|
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
|
}
|
|
|
|
|
|
/*
|
|
* PostprocessAlterDomainOwnerStmt given the change of ownership could cause new
|
|
* dependencies to exist for the domain we make sure all dependencies for the domain are
|
|
* created before we forward the statement to the workers.
|
|
*/
|
|
List *
|
|
PostprocessAlterDomainOwnerStmt(Node *node, const char *queryString)
|
|
{
|
|
AlterOwnerStmt *stmt = castNode(AlterOwnerStmt, node);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureDependenciesExistOnAllNodes(&domainAddress);
|
|
return NIL;
|
|
}
|
|
|
|
|
|
/*
|
|
* PreprocessRenameDomainStmt creates the statements to execute on the workers when the
|
|
* domain being renamed is distributed.
|
|
*/
|
|
List *
|
|
PreprocessRenameDomainStmt(Node *node, const char *queryString,
|
|
ProcessUtilityContext processUtilityContext)
|
|
{
|
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
|
Assert(stmt->renameType == OBJECT_DOMAIN);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureCoordinator();
|
|
EnsureSequentialMode(OBJECT_DOMAIN);
|
|
|
|
QualifyTreeNode((Node *) stmt);
|
|
char *sqlStmt = DeparseTreeNode((Node *) stmt);
|
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
|
(void *) sqlStmt,
|
|
ENABLE_DDL_PROPAGATION);
|
|
|
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
|
}
|
|
|
|
|
|
/*
|
|
* PreprocessAlterDomainSchemaStmt cretes the statements to execute on the workers when
|
|
* the domain being moved to a new schema has been distributed.
|
|
*/
|
|
List *
|
|
PreprocessAlterDomainSchemaStmt(Node *node, const char *queryString,
|
|
ProcessUtilityContext processUtilityContext)
|
|
{
|
|
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
|
|
Assert(stmt->objectType == OBJECT_DOMAIN);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureCoordinator();
|
|
EnsureSequentialMode(OBJECT_DOMAIN);
|
|
|
|
QualifyTreeNode((Node *) stmt);
|
|
char *sqlStmt = DeparseTreeNode((Node *) stmt);
|
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
|
(void *) sqlStmt,
|
|
ENABLE_DDL_PROPAGATION);
|
|
|
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
|
}
|
|
|
|
|
|
/*
|
|
* PostprocessAlterDomainSchemaStmt makes sure any new dependencies (as result of the
|
|
* schema move) are created on the workers before we forward the statement.
|
|
*/
|
|
List *
|
|
PostprocessAlterDomainSchemaStmt(Node *node, const char *queryString)
|
|
{
|
|
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
|
|
|
|
ObjectAddress domainAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
|
|
if (!ShouldPropagateObject(&domainAddress))
|
|
{
|
|
return NIL;
|
|
}
|
|
|
|
EnsureDependenciesExistOnAllNodes(&domainAddress);
|
|
return NIL;
|
|
}
|
|
|
|
|
|
/*
|
|
* FilterNameListForDistributedDomains given a liost of domain names we will return a list
|
|
* filtered with only the names of distributed domains remaining. The pointer to the list
|
|
* distributedDomainAddresses is populated with a list of ObjectAddresses of the domains
|
|
* that are distributed. Indices between the returned list and the object addresses are
|
|
* synchronizes.
|
|
* Note: the pointer in distributedDomainAddresses should not be omitted
|
|
*
|
|
* When missing_ok is false this function will raise an error if a domain identified by a
|
|
* domain name cannot be found.
|
|
*/
|
|
static List *
|
|
FilterNameListForDistributedDomains(List *domainNames, bool missing_ok,
|
|
List **distributedDomainAddresses)
|
|
{
|
|
Assert(distributedDomainAddresses != NULL);
|
|
|
|
List *distributedDomainNames = NIL;
|
|
TypeName *domainName = NULL;
|
|
foreach_ptr(domainName, domainNames)
|
|
{
|
|
ObjectAddress objectAddress = GetDomainAddressByName(domainName, missing_ok);
|
|
if (IsObjectDistributed(&objectAddress))
|
|
{
|
|
distributedDomainNames = lappend(distributedDomainNames, domainName);
|
|
if (distributedDomainAddresses)
|
|
{
|
|
ObjectAddress *allocatedAddress = palloc0(sizeof(ObjectAddress));
|
|
*allocatedAddress = objectAddress;
|
|
*distributedDomainAddresses = lappend(*distributedDomainAddresses,
|
|
allocatedAddress);
|
|
}
|
|
}
|
|
}
|
|
|
|
return distributedDomainNames;
|
|
}
|
|
|
|
|
|
/*
|
|
* GetDomainAddressByName returns the ObjectAddress of the domain identified by
|
|
* domainName. When missing_ok is true the object id part of the ObjectAddress can be
|
|
* InvalidOid. When missing_ok is false this function will raise an error instead when the
|
|
* domain can't be found.
|
|
*/
|
|
static ObjectAddress
|
|
GetDomainAddressByName(TypeName *domainName, bool missing_ok)
|
|
{
|
|
ObjectAddress address = { 0 };
|
|
Oid domainOid = LookupTypeNameOid(NULL, domainName, missing_ok);
|
|
ObjectAddressSet(address, TypeRelationId, domainOid);
|
|
return address;
|
|
}
|
|
|
|
|
|
/*
|
|
* RecreateDomainStmt returns a CreateDomainStmt pointer where the statement represents
|
|
* the creation of the domain to recreate the domain on a different postgres node based on
|
|
* the current representation in the local catalog.
|
|
*/
|
|
CreateDomainStmt *
|
|
RecreateDomainStmt(Oid domainOid)
|
|
{
|
|
CreateDomainStmt *stmt = makeNode(CreateDomainStmt);
|
|
stmt->domainname = stringToQualifiedNameList(format_type_be_qualified(domainOid));
|
|
|
|
HeapTuple tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(domainOid));
|
|
if (!HeapTupleIsValid(tup))
|
|
{
|
|
elog(ERROR, "cache lookup failed for type %u", domainOid);
|
|
}
|
|
|
|
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
|
|
if (typTup->typtype != TYPTYPE_DOMAIN)
|
|
{
|
|
elog(ERROR, "type is not a domain type");
|
|
}
|
|
|
|
stmt->typeName = makeTypeNameFromOid(typTup->typbasetype, typTup->typtypmod);
|
|
|
|
if (OidIsValid(typTup->typcollation))
|
|
{
|
|
stmt->collClause = MakeCollateClauseFromOid(typTup->typcollation);
|
|
}
|
|
|
|
/*
|
|
* typdefault and typdefaultbin are potentially null, so don't try to
|
|
* access 'em as struct fields. Must do it the hard way with
|
|
* SysCacheGetAttr.
|
|
*/
|
|
bool isNull = false;
|
|
Datum typeDefaultDatum = SysCacheGetAttr(TYPEOID,
|
|
tup,
|
|
Anum_pg_type_typdefaultbin,
|
|
&isNull);
|
|
if (!isNull)
|
|
{
|
|
/* when not null there is default value which we should add as a constraint */
|
|
Constraint *constraint = makeNode(Constraint);
|
|
constraint->contype = CONSTR_DEFAULT;
|
|
constraint->cooked_expr = TextDatumGetCString(typeDefaultDatum);
|
|
|
|
stmt->constraints = lappend(stmt->constraints, constraint);
|
|
}
|
|
|
|
/* NOT NULL constraints are non-named on the actual type */
|
|
if (typTup->typnotnull)
|
|
{
|
|
Constraint *constraint = makeNode(Constraint);
|
|
constraint->contype = CONSTR_NOTNULL;
|
|
|
|
stmt->constraints = lappend(stmt->constraints, constraint);
|
|
}
|
|
|
|
/* lookup and look all constraints to add them to the CreateDomainStmt */
|
|
Relation conRel = table_open(ConstraintRelationId, AccessShareLock);
|
|
|
|
/* Look for CHECK Constraints on this domain */
|
|
ScanKeyData key[1];
|
|
ScanKeyInit(&key[0],
|
|
Anum_pg_constraint_contypid,
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
ObjectIdGetDatum(domainOid));
|
|
|
|
SysScanDesc scan = systable_beginscan(conRel, ConstraintTypidIndexId, true, NULL, 1,
|
|
key);
|
|
|
|
HeapTuple conTup = NULL;
|
|
while (HeapTupleIsValid(conTup = systable_getnext(scan)))
|
|
{
|
|
Form_pg_constraint c = (Form_pg_constraint) GETSTRUCT(conTup);
|
|
|
|
if (c->contype != CONSTRAINT_CHECK)
|
|
{
|
|
/* Ignore non-CHECK constraints, shouldn't be any */
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* We create a constraint, completely ignoring c->convalidated because we can't
|
|
* create a domain with an invalidated constraint. Once a constraint is added to
|
|
* a domain -even non valid-, all new data is validated. Meaning, creating a
|
|
* domain with a non-valid constraint doesn't make any sense.
|
|
*
|
|
* Given it will be too hard to defer the creation of a constraint till we
|
|
* validate the constraint on the coordinator we will simply create the
|
|
* non-validated constraint to ad hear to validating all new data.
|
|
*
|
|
* An edgecase here would be when moving existing data, that hasn't been validated
|
|
* before to an other node. This behaviour is consistent with sending it to an
|
|
* already existing node (that has the constraint created but not validated) and a
|
|
* new node.
|
|
*/
|
|
|
|
Constraint *constraint = makeNode(Constraint);
|
|
|
|
constraint->conname = pstrdup(NameStr(c->conname));
|
|
constraint->contype = CONSTR_CHECK; /* we only come here with check constraints */
|
|
|
|
/* Not expecting conbin to be NULL, but we'll test for it anyway */
|
|
Datum conbin = heap_getattr(conTup, Anum_pg_constraint_conbin, conRel->rd_att,
|
|
&isNull);
|
|
if (isNull)
|
|
{
|
|
elog(ERROR, "domain \"%s\" constraint \"%s\" has NULL conbin",
|
|
NameStr(typTup->typname), NameStr(c->conname));
|
|
}
|
|
|
|
/*
|
|
* The conbin containes the cooked expression from when the constraint was
|
|
* inserted into the catalog. We store it here for the deparser to distinguish
|
|
* between cooked expressions and raw expressions.
|
|
*
|
|
* There is no supported way to go from a cooked expression to a raw expression.
|
|
*/
|
|
constraint->cooked_expr = TextDatumGetCString(conbin);
|
|
|
|
stmt->constraints = lappend(stmt->constraints, constraint);
|
|
}
|
|
|
|
systable_endscan(scan);
|
|
table_close(conRel, NoLock);
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
QualifyTreeNode((Node *) stmt);
|
|
|
|
return stmt;
|
|
}
|
|
|
|
|
|
/*
|
|
* MakeCollateClauseFromOid returns a CollateClause describing the COLLATE segment of a
|
|
* CREATE DOMAIN statement based on the Oid of the collation used for the domain.
|
|
*/
|
|
static CollateClause *
|
|
MakeCollateClauseFromOid(Oid collationOid)
|
|
{
|
|
CollateClause *collateClause = makeNode(CollateClause);
|
|
|
|
ObjectAddress collateAddress = { 0 };
|
|
ObjectAddressSet(collateAddress, CollationRelationId, collationOid);
|
|
|
|
List *objName = NIL;
|
|
List *objArgs = NIL;
|
|
|
|
#if PG_VERSION_NUM >= PG_VERSION_14
|
|
getObjectIdentityParts(&collateAddress, &objName, &objArgs, false);
|
|
#else
|
|
getObjectIdentityParts(&collateAddress, &objName, &objArgs);
|
|
#endif
|
|
|
|
char *name = NULL;
|
|
foreach_ptr(name, objName)
|
|
{
|
|
collateClause->collname = lappend(collateClause->collname, makeString(name));
|
|
}
|
|
|
|
collateClause->location = -1;
|
|
|
|
return collateClause;
|
|
}
|
|
|
|
|
|
/*
|
|
* CreateDomainStmtObjectAddress returns the ObjectAddress of the domain that would be
|
|
* created by the statement. When missing_ok is false the function will raise an error if
|
|
* the domain cannot be found in the local catalog.
|
|
*/
|
|
ObjectAddress
|
|
CreateDomainStmtObjectAddress(Node *node, bool missing_ok)
|
|
{
|
|
CreateDomainStmt *stmt = castNode(CreateDomainStmt, node);
|
|
|
|
TypeName *typeName = makeTypeNameFromNameList(stmt->domainname);
|
|
Oid typeOid = LookupTypeNameOid(NULL, typeName, missing_ok);
|
|
ObjectAddress address = { 0 };
|
|
ObjectAddressSet(address, TypeRelationId, typeOid);
|
|
|
|
return address;
|
|
}
|
|
|
|
|
|
/*
|
|
* AlterDomainStmtObjectAddress returns the ObjectAddress of the domain being altered.
|
|
* When missing_ok is false this function will raise an error when the domain is not
|
|
* found.
|
|
*/
|
|
ObjectAddress
|
|
AlterDomainStmtObjectAddress(Node *node, bool missing_ok)
|
|
{
|
|
AlterDomainStmt *stmt = castNode(AlterDomainStmt, node);
|
|
|
|
TypeName *domainName = makeTypeNameFromNameList(stmt->typeName);
|
|
return GetDomainAddressByName(domainName, missing_ok);
|
|
}
|
|
|
|
|
|
/*
|
|
* DomainRenameConstraintStmtObjectAddress returns the ObjectAddress of the domain for
|
|
* which the constraint is being renamed. When missing_ok this function will raise an
|
|
* error if the domain cannot be found.
|
|
*/
|
|
ObjectAddress
|
|
DomainRenameConstraintStmtObjectAddress(Node *node, bool missing_ok)
|
|
{
|
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
|
|
|
TypeName *domainName = makeTypeNameFromNameList(castNode(List, stmt->object));
|
|
return GetDomainAddressByName(domainName, missing_ok);
|
|
}
|
|
|
|
|
|
/*
|
|
* AlterDomainOwnerStmtObjectAddress returns the ObjectAddress for which the owner is
|
|
* being changed. When missing_ok is false this function will raise an error if the domain
|
|
* cannot be found.
|
|
*/
|
|
ObjectAddress
|
|
AlterDomainOwnerStmtObjectAddress(Node *node, bool missing_ok)
|
|
{
|
|
AlterOwnerStmt *stmt = castNode(AlterOwnerStmt, node);
|
|
Assert(stmt->objectType == OBJECT_DOMAIN);
|
|
|
|
TypeName *domainName = makeTypeNameFromNameList(castNode(List, stmt->object));
|
|
return GetDomainAddressByName(domainName, missing_ok);
|
|
}
|
|
|
|
|
|
/*
|
|
* RenameDomainStmtObjectAddress returns the ObjectAddress of the domain being renamed.
|
|
* When missing_ok is false this function will raise an error when the domain cannot be
|
|
* found.
|
|
*/
|
|
ObjectAddress
|
|
RenameDomainStmtObjectAddress(Node *node, bool missing_ok)
|
|
{
|
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
|
Assert(stmt->renameType == OBJECT_DOMAIN);
|
|
|
|
TypeName *domainName = makeTypeNameFromNameList(castNode(List, stmt->object));
|
|
return GetDomainAddressByName(domainName, missing_ok);
|
|
}
|
|
|
|
|
|
/*
|
|
* get_constraint_typid returns the contypid of a constraint. This field is only set for
|
|
* constraints on domain types. Returns InvalidOid if conoid is an invalid constraint, as
|
|
* well as for constraints that are not on domain types.
|
|
*/
|
|
Oid
|
|
get_constraint_typid(Oid conoid)
|
|
{
|
|
HeapTuple tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
|
|
if (HeapTupleIsValid(tp))
|
|
{
|
|
Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
|
|
Oid result = contup->contypid;
|
|
ReleaseSysCache(tp);
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return InvalidOid;
|
|
}
|
|
}
|