typecmds.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,044 行 · 第 1/4 页

C
2,044
字号
	procOid = LookupFuncName(procname, 2, argList, true);	if (OidIsValid(procOid))		return procOid;	ereport(ERROR,			(errcode(ERRCODE_UNDEFINED_FUNCTION),			 errmsg("function %s does not exist",					func_signature_string(procname, 1, argList))));	return InvalidOid;			/* keep compiler quiet */}/*------------------------------------------------------------------- * DefineCompositeType * * Create a Composite Type relation. * `DefineRelation' does all the work, we just provide the correct * arguments! * * If the relation already exists, then 'DefineRelation' will abort * the xact... * * DefineCompositeType returns relid for use when creating * an implicit composite type during function creation *------------------------------------------------------------------- */OidDefineCompositeType(const RangeVar *typevar, List *coldeflist){	CreateStmt *createStmt = makeNode(CreateStmt);	if (coldeflist == NIL)		ereport(ERROR,				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),			 errmsg("composite type must have at least one attribute")));	/*	 * now create the parameters for keys/inheritance etc. All of them are	 * nil...	 */	createStmt->relation = (RangeVar *) typevar;	createStmt->tableElts = coldeflist;	createStmt->inhRelations = NIL;	createStmt->constraints = NIL;	createStmt->hasoids = false;	createStmt->oncommit = ONCOMMIT_NOOP;	/*	 * finally create the relation...	 */	return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);}/* * AlterDomainDefault * * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements. */voidAlterDomainDefault(List *names, Node *defaultRaw){	TypeName   *typename;	Oid			domainoid;	HeapTuple	tup;	ParseState *pstate;	Relation	rel;	char	   *defaultValue;	Node	   *defaultExpr = NULL;		/* NULL if no default specified */	Datum		new_record[Natts_pg_type];	char		new_record_nulls[Natts_pg_type];	char		new_record_repl[Natts_pg_type];	HeapTuple	newtuple;	Form_pg_type typTup;	/* Make a TypeName so we can use standard type lookup machinery */	typename = makeNode(TypeName);	typename->names = names;	typename->typmod = -1;	typename->arrayBounds = NIL;	/* Lock the domain in the type table */	rel = heap_openr(TypeRelationName, RowExclusiveLock);	/* Use LookupTypeName here so that shell types can be removed. */	domainoid = LookupTypeName(typename);	if (!OidIsValid(domainoid))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("type \"%s\" does not exist",						TypeNameToString(typename))));	tup = SearchSysCacheCopy(TYPEOID,							 ObjectIdGetDatum(domainoid),							 0, 0, 0);	if (!HeapTupleIsValid(tup))		elog(ERROR, "cache lookup failed for type %u", domainoid);	/* Doesn't return if user isn't allowed to alter the domain */	domainOwnerCheck(tup, typename);	/* Setup new tuple */	MemSet(new_record, (Datum) 0, sizeof(new_record));	MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));	MemSet(new_record_repl, ' ', sizeof(new_record_repl));	/* Useful later */	typTup = (Form_pg_type) GETSTRUCT(tup);	/* Store the new default, if null then skip this step */	if (defaultRaw)	{		/* Create a dummy ParseState for transformExpr */		pstate = make_parsestate(NULL);		/*		 * Cook the colDef->raw_expr into an expression. Note: Name is		 * strictly for error message		 */		defaultExpr = cookDefault(pstate, defaultRaw,								  typTup->typbasetype,								  typTup->typtypmod,								  NameStr(typTup->typname));		/*		 * Expression must be stored as a nodeToString result, but we also		 * require a valid textual representation (mainly to make life		 * easier for pg_dump).		 */		defaultValue = deparse_expression(defaultExpr,							deparse_context_for(NameStr(typTup->typname),												InvalidOid),										  false, false);		/*		 * Form an updated tuple with the new default and write it back.		 */		new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin,														 CStringGetDatum(											 nodeToString(defaultExpr)));		new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';		new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin,										  CStringGetDatum(defaultValue));		new_record_repl[Anum_pg_type_typdefault - 1] = 'r';	}	else/* Default is NULL, drop it */	{		new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n';		new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r';		new_record_nulls[Anum_pg_type_typdefault - 1] = 'n';		new_record_repl[Anum_pg_type_typdefault - 1] = 'r';	}	newtuple = heap_modifytuple(tup, rel,						  new_record, new_record_nulls, new_record_repl);	simple_heap_update(rel, &tup->t_self, newtuple);	CatalogUpdateIndexes(rel, newtuple);	/* Rebuild dependencies */	GenerateTypeDependencies(typTup->typnamespace,							 domainoid,							 typTup->typrelid,							 0, /* relation kind is n/a */							 typTup->typinput,							 typTup->typoutput,							 typTup->typreceive,							 typTup->typsend,							 typTup->typelem,							 typTup->typbasetype,							 defaultExpr,							 true);		/* Rebuild is true */	/* Clean up */	heap_close(rel, NoLock);	heap_freetuple(newtuple);}/* * AlterDomainNotNull * * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements. */voidAlterDomainNotNull(List *names, bool notNull){	TypeName   *typename;	Oid			domainoid;	Relation	typrel;	HeapTuple	tup;	Form_pg_type typTup;	/* Make a TypeName so we can use standard type lookup machinery */	typename = makeNode(TypeName);	typename->names = names;	typename->typmod = -1;	typename->arrayBounds = NIL;	/* Lock the type table */	typrel = heap_openr(TypeRelationName, RowExclusiveLock);	/* Use LookupTypeName here so that shell types can be found (why?). */	domainoid = LookupTypeName(typename);	if (!OidIsValid(domainoid))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("type \"%s\" does not exist",						TypeNameToString(typename))));	tup = SearchSysCacheCopy(TYPEOID,							 ObjectIdGetDatum(domainoid),							 0, 0, 0);	if (!HeapTupleIsValid(tup))		elog(ERROR, "cache lookup failed for type %u", domainoid);	typTup = (Form_pg_type) GETSTRUCT(tup);	/* Doesn't return if user isn't allowed to alter the domain */	domainOwnerCheck(tup, typename);	/* Is the domain already set to the desired constraint? */	if (typTup->typnotnull == notNull)	{		heap_close(typrel, RowExclusiveLock);		return;	}	/* Adding a NOT NULL constraint requires checking existing columns */	if (notNull)	{		List	   *rels;		List	   *rt;		/* Fetch relation list with attributes based on this domain */		/* ShareLock is sufficient to prevent concurrent data changes */		rels = get_rels_with_domain(domainoid, ShareLock);		foreach(rt, rels)		{			RelToCheck *rtc = (RelToCheck *) lfirst(rt);			Relation	testrel = rtc->rel;			TupleDesc	tupdesc = RelationGetDescr(testrel);			HeapScanDesc scan;			HeapTuple	tuple;			/* Scan all tuples in this relation */			scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);			while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)			{				int			i;				/* Test attributes that are of the domain */				for (i = 0; i < rtc->natts; i++)				{					int			attnum = rtc->atts[i];					Datum		d;					bool		isNull;					d = heap_getattr(tuple, attnum, tupdesc, &isNull);					if (isNull)						ereport(ERROR,								(errcode(ERRCODE_NOT_NULL_VIOLATION),								 errmsg("column \"%s\" of table \"%s\" contains null values",										NameStr(tupdesc->attrs[attnum - 1]->attname),										RelationGetRelationName(testrel))));				}			}			heap_endscan(scan);			/* Close each rel after processing, but keep lock */			heap_close(testrel, NoLock);		}	}	/*	 * Okay to update pg_type row.	We can scribble on typTup because it's	 * a copy.	 */	typTup->typnotnull = notNull;	simple_heap_update(typrel, &tup->t_self, tup);	CatalogUpdateIndexes(typrel, tup);	/* Clean up */	heap_freetuple(tup);	heap_close(typrel, RowExclusiveLock);}/* * AlterDomainDropConstraint * * Implements the ALTER DOMAIN DROP CONSTRAINT statement */voidAlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior){	TypeName   *typename;	Oid			domainoid;	HeapTuple	tup;	Relation	rel;	Form_pg_type typTup;	Relation	conrel;	SysScanDesc conscan;	ScanKeyData key[1];	HeapTuple	contup;	/* Make a TypeName so we can use standard type lookup machinery */	typename = makeNode(TypeName);	typename->names = names;	typename->typmod = -1;	typename->arrayBounds = NIL;	/* Lock the type table */	rel = heap_openr(TypeRelationName, RowExclusiveLock);	/* Use LookupTypeName here so that shell types can be removed. */	domainoid = LookupTypeName(typename);	if (!OidIsValid(domainoid))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("type \"%s\" does not exist",						TypeNameToString(typename))));	tup = SearchSysCacheCopy(TYPEOID,							 ObjectIdGetDatum(domainoid),							 0, 0, 0);	if (!HeapTupleIsValid(tup))		elog(ERROR, "cache lookup failed for type %u", domainoid);	/* Doesn't return if user isn't allowed to alter the domain */	domainOwnerCheck(tup, typename);	/* Grab an appropriate lock on the pg_constraint relation */	conrel = heap_openr(ConstraintRelationName, RowExclusiveLock);	/* Use the index to scan only constraints of the target relation */	ScanKeyEntryInitialize(&key[0], 0x0,						   Anum_pg_constraint_contypid, F_OIDEQ,						   ObjectIdGetDatum(HeapTupleGetOid(tup)));	conscan = systable_beginscan(conrel, ConstraintTypidIndex, true,								 SnapshotNow, 1, key);	typTup = (Form_pg_type) GETSTRUCT(tup);	/*	 * Scan over the result set, removing any matching entries.	 */	while ((contup = systable_getnext(conscan)) != NULL)	{		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);		if (strcmp(NameStr(con->conname), constrName) == 0)		{			ObjectAddress conobj;			conobj.classId = RelationGetRelid(conrel);			conobj.objectId = HeapTupleGetOid(contup);			conobj.objectSubId = 0;			performDeletion(&conobj, behavior);		}	}	/* Clean up after the scan */	systable_endscan(conscan);	heap_close(conrel, RowExclusiveLock);	heap_close(rel, NoLock);}/* * AlterDomainAddConstraint * * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement. */voidAlterDomainAddConstraint(List *names, Node *newConstraint){	TypeName   *typename;	Oid			domainoid;	Relation	typrel;	HeapTuple	tup;	Form_pg_type typTup;	List	   *rels;	List	   *rt;	EState	   *estate;	ExprContext *econtext;	char	   *ccbin;	Expr	   *expr;	ExprState  *exprstate;	int			counter = 0;	Constraint *constr;	/* Make a TypeName so we can use standard type lookup machinery */	typename = makeNode(TypeName);	typename->names = names;	typename->typmod = -1;	typename->arrayBounds = NIL;	/* Lock the type table */	typrel = heap_openr(TypeRelationName, RowExclusiveLock);	/* Use LookupTypeName here so that shell types can be found (why?). */	domainoid = LookupTypeName(typename);	if (!OidIsValid(domainoid))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("type \"%s\" does not exist",						TypeNameToString(typename))));	tup = SearchSysCacheCopy(TYPEOID,							 ObjectIdGetDatum(domainoid),							 0, 0, 0);	if (!HeapTupleIsValid(tup))		elog(ERROR, "cache lookup failed for type %u", domainoid);	typTup = (Form_pg_type) GETSTRUCT(tup);	/* Doesn't return if user isn't allowed to alter the domain */	domainOwnerCheck(tup, typename);	/* Check for unsupported constraint types */	if (IsA(newConstraint, FkConstraint))		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),		   errmsg("foreign key constraints not possible for domains")));	/* otherwise it should be a plain Constraint */	if (!IsA(newConstraint, Constraint))		elog(ERROR, "unrecognized node type: %d",			 (int) nodeTag(newConstraint));	constr = (Constraint *) newConstraint;	switch (constr->contype)	{		case CONSTR_CHECK:			/* processed below */			break;		case CONSTR_UNIQUE:			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),					 errmsg("unique constraints not possible for domains")));			break;		case CONSTR_PRIMARY:			ereport(ERROR,					(errcode(ERRCODE_SYNTAX_ERROR),					 errmsg("primary key constraints not possible for domains")));			break;		case CONSTR_ATTR_DEFERRABLE:		case CONSTR_ATTR_NOT_DEFERRABLE:		case CONSTR_ATTR_DEFERRED:		case CONSTR_ATTR_IMMEDIATE:			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("specifying constraint deferrability not supported for domains")));			break;		default:			elog(ERROR, "unrecognized constraint subtype: %d",				 (int) constr->contype);			break;	}	/*	 * Since all other constraint types throw errors, this must be a check	 * constraint.	First, process the constraint expression and add an	 * entry to pg_constraint.	 */	ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace,								typTup->typbasetype, typTup->typtypmod,							 constr, &counter, NameStr(typTup->typname));	/*	 * Test all values stored in the attributes based on the domain the	 * constraint is being added to.	 */	expr = (Expr *) stringToNode(ccbin);	/* Need an EState to run ExecEvalExpr */	estate = CreateExecutorState();	econtext = GetPerTupleExprContext(estate);	/* build execution state for expr */	exprstate = ExecPrepareExpr(expr, estate);	/* Fetch relation list with attributes based on this domain */	/* ShareLock is sufficient to prevent concurrent data changes */	rels = get_rels_with_domain(domainoid, ShareLock);	foreach(rt, rels)	{		RelToCheck *rtc = (RelToCheck *) lfirst(rt);		Relation	testrel = rtc->rel;		TupleDesc	tupdesc = RelationGetDescr(testrel);		HeapScanDesc scan;		HeapTuple	tuple;		/* Scan all tuples in this relation */		scan = heap_beginscan(testrel, SnapshotNow, 0, NULL);		while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?