ruleutils.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,434 行 · 第 1/5 页

C
2,434
字号
	/*	 * Start the trigger definition. Note that the trigger's name should never	 * be schema-qualified, but the trigger rel's name may be.	 */	initStringInfo(&buf);	tgname = NameStr(trigrec->tgname);	appendStringInfo(&buf, "CREATE %sTRIGGER %s ",					 trigrec->tgisconstraint ? "CONSTRAINT " : "",					 quote_identifier(tgname));	if (TRIGGER_FOR_BEFORE(trigrec->tgtype))		appendStringInfo(&buf, "BEFORE");	else		appendStringInfo(&buf, "AFTER");	if (TRIGGER_FOR_INSERT(trigrec->tgtype))	{		appendStringInfo(&buf, " INSERT");		findx++;	}	if (TRIGGER_FOR_DELETE(trigrec->tgtype))	{		if (findx > 0)			appendStringInfo(&buf, " OR DELETE");		else			appendStringInfo(&buf, " DELETE");		findx++;	}	if (TRIGGER_FOR_UPDATE(trigrec->tgtype))	{		if (findx > 0)			appendStringInfo(&buf, " OR UPDATE");		else			appendStringInfo(&buf, " UPDATE");	}	appendStringInfo(&buf, " ON %s ",					 generate_relation_name(trigrec->tgrelid));	if (trigrec->tgisconstraint)	{		if (trigrec->tgconstrrelid != InvalidOid)			appendStringInfo(&buf, "FROM %s ",							 generate_relation_name(trigrec->tgconstrrelid));		if (!trigrec->tgdeferrable)			appendStringInfo(&buf, "NOT ");		appendStringInfo(&buf, "DEFERRABLE INITIALLY ");		if (trigrec->tginitdeferred)			appendStringInfo(&buf, "DEFERRED ");		else			appendStringInfo(&buf, "IMMEDIATE ");	}	if (TRIGGER_FOR_ROW(trigrec->tgtype))		appendStringInfo(&buf, "FOR EACH ROW ");	else		appendStringInfo(&buf, "FOR EACH STATEMENT ");	appendStringInfo(&buf, "EXECUTE PROCEDURE %s(",					 generate_function_name(trigrec->tgfoid, 0, NULL));	if (trigrec->tgnargs > 0)	{		bytea	   *val;		bool		isnull;		char	   *p;		int			i;		val = (bytea *)			DatumGetPointer(fastgetattr(ht_trig,										Anum_pg_trigger_tgargs,										tgrel->rd_att, &isnull));		if (isnull)			elog(ERROR, "tgargs is null for trigger %u", trigid);		p = (char *) VARDATA(val);		for (i = 0; i < trigrec->tgnargs; i++)		{			if (i > 0)				appendStringInfo(&buf, ", ");			if (strchr(p, '\\') != NULL)				appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX);			appendStringInfoChar(&buf, '\'');			while (*p)			{				if (SQL_STR_DOUBLE(*p))					appendStringInfoChar(&buf, *p);				appendStringInfoChar(&buf, *p++);			}			p++;			appendStringInfoChar(&buf, '\'');		}	}	/* We deliberately do not put semi-colon at end */	appendStringInfo(&buf, ")");	/* Clean up */	systable_endscan(tgscan);	heap_close(tgrel, AccessShareLock);	PG_RETURN_TEXT_P(string_to_text(buf.data));}/* ---------- * get_indexdef			- Get the definition of an index * * In the extended version, there is a colno argument as well as pretty bool. *	if colno == 0, we want a complete index definition. *	if colno > 0, we only want the Nth index key's variable or expression. * ---------- */Datumpg_get_indexdef(PG_FUNCTION_ARGS){	Oid			indexrelid = PG_GETARG_OID(0);	PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0, 0)));}Datumpg_get_indexdef_ext(PG_FUNCTION_ARGS){	Oid			indexrelid = PG_GETARG_OID(0);	int32		colno = PG_GETARG_INT32(1);	bool		pretty = PG_GETARG_BOOL(2);	int			prettyFlags;	prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;	PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno, prettyFlags)));}/* Internal version that returns a palloc'd C string */char *pg_get_indexdef_string(Oid indexrelid){	return pg_get_indexdef_worker(indexrelid, 0, 0);}static char *pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags){	HeapTuple	ht_idx;	HeapTuple	ht_idxrel;	HeapTuple	ht_am;	Form_pg_index idxrec;	Form_pg_class idxrelrec;	Form_pg_am	amrec;	List	   *indexprs;	ListCell   *indexpr_item;	List	   *context;	Oid			indrelid;	int			keyno;	Oid			keycoltype;	Datum		indclassDatum;	bool		isnull;	oidvector  *indclass;	StringInfoData buf;	char	   *str;	char	   *sep;	/*	 * Fetch the pg_index tuple by the Oid of the index	 */	ht_idx = SearchSysCache(INDEXRELID,							ObjectIdGetDatum(indexrelid),							0, 0, 0);	if (!HeapTupleIsValid(ht_idx))		elog(ERROR, "cache lookup failed for index %u", indexrelid);	idxrec = (Form_pg_index) GETSTRUCT(ht_idx);	indrelid = idxrec->indrelid;	Assert(indexrelid == idxrec->indexrelid);	/* Must get indclass the hard way */	indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx,									Anum_pg_index_indclass, &isnull);	Assert(!isnull);	indclass = (oidvector *) DatumGetPointer(indclassDatum);	/*	 * Fetch the pg_class tuple of the index relation	 */	ht_idxrel = SearchSysCache(RELOID,							   ObjectIdGetDatum(indexrelid),							   0, 0, 0);	if (!HeapTupleIsValid(ht_idxrel))		elog(ERROR, "cache lookup failed for relation %u", indexrelid);	idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);	/*	 * Fetch the pg_am tuple of the index' access method	 */	ht_am = SearchSysCache(AMOID,						   ObjectIdGetDatum(idxrelrec->relam),						   0, 0, 0);	if (!HeapTupleIsValid(ht_am))		elog(ERROR, "cache lookup failed for access method %u",			 idxrelrec->relam);	amrec = (Form_pg_am) GETSTRUCT(ht_am);	/*	 * Get the index expressions, if any.  (NOTE: we do not use the relcache	 * versions of the expressions and predicate, because we want to display	 * non-const-folded expressions.)	 */	if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs))	{		Datum		exprsDatum;		bool		isnull;		char	   *exprsString;		exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx,									 Anum_pg_index_indexprs, &isnull);		Assert(!isnull);		exprsString = DatumGetCString(DirectFunctionCall1(textout,														  exprsDatum));		indexprs = (List *) stringToNode(exprsString);		pfree(exprsString);	}	else		indexprs = NIL;	indexpr_item = list_head(indexprs);	context = deparse_context_for(get_rel_name(indrelid), indrelid);	/*	 * Start the index definition.	Note that the index's name should never be	 * schema-qualified, but the indexed rel's name may be.	 */	initStringInfo(&buf);	if (!colno)		appendStringInfo(&buf, "CREATE %sINDEX %s ON %s USING %s (",						 idxrec->indisunique ? "UNIQUE " : "",						 quote_identifier(NameStr(idxrelrec->relname)),						 generate_relation_name(indrelid),						 quote_identifier(NameStr(amrec->amname)));	/*	 * Report the indexed attributes	 */	sep = "";	for (keyno = 0; keyno < idxrec->indnatts; keyno++)	{		AttrNumber	attnum = idxrec->indkey.values[keyno];		if (!colno)			appendStringInfoString(&buf, sep);		sep = ", ";		if (attnum != 0)		{			/* Simple index column */			char	   *attname;			attname = get_relid_attribute_name(indrelid, attnum);			if (!colno || colno == keyno + 1)				appendStringInfoString(&buf, quote_identifier(attname));			keycoltype = get_atttype(indrelid, attnum);		}		else		{			/* expressional index */			Node	   *indexkey;			if (indexpr_item == NULL)				elog(ERROR, "too few entries in indexprs list");			indexkey = (Node *) lfirst(indexpr_item);			indexpr_item = lnext(indexpr_item);			/* Deparse */			str = deparse_expression_pretty(indexkey, context, false, false,											prettyFlags, 0);			if (!colno || colno == keyno + 1)			{				/* Need parens if it's not a bare function call */				if (indexkey && IsA(indexkey, FuncExpr) &&				 ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)					appendStringInfoString(&buf, str);				else					appendStringInfo(&buf, "(%s)", str);			}			keycoltype = exprType(indexkey);		}		/*		 * Add the operator class name		 */		if (!colno)			get_opclass_name(indclass->values[keyno], keycoltype,							 &buf);	}	if (!colno)	{		appendStringInfoChar(&buf, ')');		/*		 * If it's a partial index, decompile and append the predicate		 */		if (!heap_attisnull(ht_idx, Anum_pg_index_indpred))		{			Node	   *node;			Datum		predDatum;			bool		isnull;			char	   *predString;			/* Convert text string to node tree */			predDatum = SysCacheGetAttr(INDEXRELID, ht_idx,										Anum_pg_index_indpred, &isnull);			Assert(!isnull);			predString = DatumGetCString(DirectFunctionCall1(textout,															 predDatum));			node = (Node *) stringToNode(predString);			pfree(predString);			/* Deparse */			str = deparse_expression_pretty(node, context, false, false,											prettyFlags, 0);			appendStringInfo(&buf, " WHERE %s", str);		}	}	/* Clean up */	ReleaseSysCache(ht_idx);	ReleaseSysCache(ht_idxrel);	ReleaseSysCache(ht_am);	return buf.data;}/* * pg_get_constraintdef * * Returns the definition for the constraint, ie, everything that needs to * appear after "ALTER TABLE ... ADD CONSTRAINT <constraintname>". */Datumpg_get_constraintdef(PG_FUNCTION_ARGS){	Oid			constraintId = PG_GETARG_OID(0);	PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,																false, 0)));}Datumpg_get_constraintdef_ext(PG_FUNCTION_ARGS){	Oid			constraintId = PG_GETARG_OID(0);	bool		pretty = PG_GETARG_BOOL(1);	int			prettyFlags;	prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;	PG_RETURN_TEXT_P(string_to_text(pg_get_constraintdef_worker(constraintId,													   false, prettyFlags)));}/* Internal version that returns a palloc'd C string */char *pg_get_constraintdef_string(Oid constraintId){	return pg_get_constraintdef_worker(constraintId, true, 0);}static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,							int prettyFlags){	StringInfoData buf;	Relation	conDesc;	SysScanDesc conscan;	ScanKeyData skey[1];	HeapTuple	tup;	Form_pg_constraint conForm;	/*	 * Fetch the pg_constraint row.  There's no syscache for pg_constraint so	 * we must do it the hard way.	 */	conDesc = heap_open(ConstraintRelationId, AccessShareLock);	ScanKeyInit(&skey[0],				ObjectIdAttributeNumber,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(constraintId));	conscan = systable_beginscan(conDesc, ConstraintOidIndexId, true,								 SnapshotNow, 1, skey);	tup = systable_getnext(conscan);	if (!HeapTupleIsValid(tup))		elog(ERROR, "could not find tuple for constraint %u", constraintId);	conForm = (Form_pg_constraint) GETSTRUCT(tup);	initStringInfo(&buf);	if (fullCommand && OidIsValid(conForm->conrelid))	{		appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",						 generate_relation_name(conForm->conrelid),						 quote_identifier(NameStr(conForm->conname)));	}	switch (conForm->contype)	{		case CONSTRAINT_FOREIGN:			{				Datum		val;				bool		isnull;				const char *string;				/* Start off the constraint definition */				appendStringInfo(&buf, "FOREIGN KEY (");				/* Fetch and build referencing-column list */				val = heap_getattr(tup, Anum_pg_constraint_conkey,								   RelationGetDescr(conDesc), &isnull);				if (isnull)					elog(ERROR, "null conkey for constraint %u",						 constraintId);				decompile_column_index_array(val, conForm->conrelid, &buf);				/* add foreign relation name */				appendStringInfo(&buf, ") REFERENCES %s(",								 generate_relation_name(conForm->confrelid));				/* Fetch and build referenced-column list */				val = heap_getattr(tup, Anum_pg_constraint_confkey,								   RelationGetDescr(conDesc), &isnull);				if (isnull)					elog(ERROR, "null confkey for constraint %u",						 constraintId);				decompile_column_index_array(val, conForm->confrelid, &buf);				appendStringInfo(&buf, ")");				/* Add match type */				switch (conForm->confmatchtype)				{					case FKCONSTR_MATCH_FULL:						string = " MATCH FULL";						break;					case FKCONSTR_MATCH_PARTIAL:						string = " MATCH PARTIAL";						break;					case FKCONSTR_MATCH_UNSPECIFIED:						string = "";						break;					default:						elog(ERROR, "unrecognized confmatchtype: %d",							 conForm->confmatchtype);						string = "";	/* keep compiler quiet */						break;				}				appendStringInfoString(&buf, string);				/* Add ON UPDATE and ON DELETE clauses, if needed */				switch (conForm->confupdtype)				{					case FKCONSTR_ACTION_NOACTION:						string = NULL;	/* suppress default */						break;					case FKCONSTR_ACTION_RESTRICT:						string = "RESTRICT";						break;					case FKCONSTR_ACTION_CASCADE:						string = "CASCADE";						break;					case FKCONSTR_ACTION_SETNULL:						string = "SET NULL";						break;					case FKCONSTR_ACTION_SETDEFAULT:						string = "SET DEFAULT";						break;					default:						elog(ERROR, "unrecognized confupdtype: %d",							 conForm->confupdtype);						string = NULL;	/* keep compiler quiet */						break;				}				if (string)

⌨️ 快捷键说明

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