ruleutils.c

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

C
2,475
字号
								SnapshotNow, 1, skey);	ht_trig = systable_getnext(tgscan);	if (!HeapTupleIsValid(ht_trig))		elog(ERROR, "could not find tuple for trigger %u", trigid);	trigrec = (Form_pg_trigger) GETSTRUCT(ht_trig);	/*	 * 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 *) 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, ", ");			appendStringInfoChar(&buf, '\'');			while (*p)			{				/* escape quotes and backslashes */				if (*p == '\'' || *p == '\\')					appendStringInfoChar(&buf, '\\');				appendStringInfoChar(&buf, *p++);			}			p++;			appendStringInfoChar(&buf, '\'');		}	}	/* We deliberately do not put semi-colon at end */	appendStringInfo(&buf, ")");	/*	 * Create the result as a TEXT datum, and free working data	 */	len = buf.len + VARHDRSZ;	trigdef = (text *) palloc(len);	VARATT_SIZEP(trigdef) = len;	memcpy(VARDATA(trigdef), buf.data, buf.len);	pfree(buf.data);	systable_endscan(tgscan);	heap_close(tgrel, AccessShareLock);	PG_RETURN_TEXT_P(trigdef);}/* ---------- * 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);	return 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;	return pg_get_indexdef_worker(indexrelid, colno, prettyFlags);}static Datumpg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags){	text	   *indexdef;	HeapTuple	ht_idx;	HeapTuple	ht_idxrel;	HeapTuple	ht_am;	Form_pg_index idxrec;	Form_pg_class idxrelrec;	Form_pg_am	amrec;	List	   *indexprs;	List	   *context;	Oid			indrelid;	int			len;	int			keyno;	Oid			keycoltype;	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);	/*	 * 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;	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[keyno];		if (!colno)			appendStringInfo(&buf, sep);		sep = ", ";		if (attnum != 0)		{			/* Simple index column */			char	   *attname;			attname = get_relid_attribute_name(indrelid, attnum);			if (!colno || colno == keyno + 1)				appendStringInfo(&buf, "%s", quote_identifier(attname));			keycoltype = get_atttype(indrelid, attnum);		}		else		{			/* expressional index */			Node	   *indexkey;			if (indexprs == NIL)				elog(ERROR, "too few entries in indexprs list");			indexkey = (Node *) lfirst(indexprs);			indexprs = lnext(indexprs);			/* 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)					appendStringInfo(&buf, "%s", str);				else					appendStringInfo(&buf, "(%s)", str);			}			keycoltype = exprType(indexkey);		}		/*		 * Add the operator class name		 */		if (!colno)			get_opclass_name(idxrec->indclass[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);			/*			 * If top level is a List, assume it is an implicit-AND			 * structure, and convert to explicit AND.	This is needed for			 * partial index predicates.			 */			if (node && IsA(node, List))				node = (Node *) make_ands_explicit((List *) node);			/* Deparse */			str = deparse_expression_pretty(node, context, false, false,											prettyFlags, 0);			appendStringInfo(&buf, " WHERE %s", str);		}	}	/*	 * Create the result as a TEXT datum, and free working data	 */	len = buf.len + VARHDRSZ;	indexdef = (text *) palloc(len);	VARATT_SIZEP(indexdef) = len;	memcpy(VARDATA(indexdef), buf.data, buf.len);	pfree(buf.data);	ReleaseSysCache(ht_idx);	ReleaseSysCache(ht_idxrel);	ReleaseSysCache(ht_am);	PG_RETURN_TEXT_P(indexdef);}/* * 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);	return pg_get_constraintdef_worker(constraintId, 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;	return pg_get_constraintdef_worker(constraintId, prettyFlags);}static Datumpg_get_constraintdef_worker(Oid constraintId, int prettyFlags){	text	   *result;	StringInfoData buf;	int			len;	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_openr(ConstraintRelationName, AccessShareLock);	ScanKeyEntryInitialize(&skey[0], 0x0,						   ObjectIdAttributeNumber, F_OIDEQ,						   ObjectIdGetDatum(constraintId));	conscan = systable_beginscan(conDesc, ConstraintOidIndex, 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);	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;				}				appendStringInfo(&buf, "%s", 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)					appendStringInfo(&buf, " ON UPDATE %s", string);				switch (conForm->confdeltype)				{					case FKCONSTR_ACTION_NOACTION:						string = NULL;	/* suppress default */						break;					case FKCONSTR_ACTION_RESTRICT:						string = "RESTRICT";

⌨️ 快捷键说明

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