ruleutils.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,446 行 · 第 1/5 页

C
2,446
字号
						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";						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 confdeltype: %d",							 conForm->confdeltype);						string = NULL;	/* keep compiler quiet */						break;				}				if (string)					appendStringInfo(&buf, " ON DELETE %s", string);				if (conForm->condeferrable)					appendStringInfo(&buf, " DEFERRABLE");				if (conForm->condeferred)					appendStringInfo(&buf, " INITIALLY DEFERRED");				break;			}		case CONSTRAINT_PRIMARY:		case CONSTRAINT_UNIQUE:			{				Datum		val;				bool		isnull;				Oid			indexId;				/* Start off the constraint definition */				if (conForm->contype == CONSTRAINT_PRIMARY)					appendStringInfo(&buf, "PRIMARY KEY (");				else					appendStringInfo(&buf, "UNIQUE (");				/* Fetch and build target column list */				val = SysCacheGetAttr(CONSTROID, tup,									  Anum_pg_constraint_conkey, &isnull);				if (isnull)					elog(ERROR, "null conkey for constraint %u",						 constraintId);				decompile_column_index_array(val, conForm->conrelid, &buf);				appendStringInfo(&buf, ")");				indexId = get_constraint_index(constraintId);				/* XXX why do we only print these bits if fullCommand? */				if (fullCommand && OidIsValid(indexId))				{					char	   *options = flatten_reloptions(indexId);					Oid			tblspc;					if (options)					{						appendStringInfo(&buf, " WITH (%s)", options);						pfree(options);					}					tblspc = get_rel_tablespace(indexId);					if (OidIsValid(tblspc))						appendStringInfo(&buf, " USING INDEX TABLESPACE %s",							  quote_identifier(get_tablespace_name(tblspc)));				}				break;			}		case CONSTRAINT_CHECK:			{				Datum		val;				bool		isnull;				char	   *conbin;				char	   *consrc;				Node	   *expr;				List	   *context;				/* Fetch constraint expression in parsetree form */				val = SysCacheGetAttr(CONSTROID, tup,									  Anum_pg_constraint_conbin, &isnull);				if (isnull)					elog(ERROR, "null conbin for constraint %u",						 constraintId);				conbin = DatumGetCString(DirectFunctionCall1(textout, val));				expr = stringToNode(conbin);				/* Set up deparsing context for Var nodes in constraint */				if (conForm->conrelid != InvalidOid)				{					/* relation constraint */					context = deparse_context_for(get_rel_name(conForm->conrelid),												  conForm->conrelid);				}				else				{					/* domain constraint --- can't have Vars */					context = NIL;				}				consrc = deparse_expression_pretty(expr, context, false, false,												   prettyFlags, 0);				/*				 * Now emit the constraint definition.	There are cases where				 * the constraint expression will be fully parenthesized and				 * we don't need the outer parens ... but there are other				 * cases where we do need 'em.  Be conservative for now.				 *				 * Note that simply checking for leading '(' and trailing ')'				 * would NOT be good enough, consider "(x > 0) AND (y > 0)".				 */				appendStringInfo(&buf, "CHECK (%s)", consrc);				break;			}		default:			elog(ERROR, "invalid constraint type \"%c\"", conForm->contype);			break;	}	/* Cleanup */	ReleaseSysCache(tup);	return buf.data;}/* * Convert an int16[] Datum into a comma-separated list of column names * for the indicated relation; append the list to buf. */static voiddecompile_column_index_array(Datum column_index_array, Oid relId,							 StringInfo buf){	Datum	   *keys;	int			nKeys;	int			j;	/* Extract data from array of int16 */	deconstruct_array(DatumGetArrayTypeP(column_index_array),					  INT2OID, 2, true, 's',					  &keys, NULL, &nKeys);	for (j = 0; j < nKeys; j++)	{		char	   *colName;		colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j]));		if (j == 0)			appendStringInfoString(buf, quote_identifier(colName));		else			appendStringInfo(buf, ", %s", quote_identifier(colName));	}}/* ---------- * get_expr			- Decompile an expression tree * * Input: an expression tree in nodeToString form, and a relation OID * * Output: reverse-listed expression * * Currently, the expression can only refer to a single relation, namely * the one specified by the second parameter.  This is sufficient for * partial indexes, column default expressions, etc. * ---------- */Datumpg_get_expr(PG_FUNCTION_ARGS){	text	   *expr = PG_GETARG_TEXT_P(0);	Oid			relid = PG_GETARG_OID(1);	char	   *relname;	/* Get the name for the relation */	relname = get_rel_name(relid);	if (relname == NULL)		PG_RETURN_NULL();		/* should we raise an error? */	PG_RETURN_TEXT_P(string_to_text(pg_get_expr_worker(expr, relid, relname, 0)));}Datumpg_get_expr_ext(PG_FUNCTION_ARGS){	text	   *expr = PG_GETARG_TEXT_P(0);	Oid			relid = PG_GETARG_OID(1);	bool		pretty = PG_GETARG_BOOL(2);	int			prettyFlags;	char	   *relname;	prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;	/* Get the name for the relation */	relname = get_rel_name(relid);	if (relname == NULL)		PG_RETURN_NULL();		/* should we raise an error? */	PG_RETURN_TEXT_P(string_to_text(pg_get_expr_worker(expr, relid, relname, prettyFlags)));}static char *pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags){	Node	   *node;	List	   *context;	char	   *exprstr;	char	   *str;	/* Convert input TEXT object to C string */	exprstr = DatumGetCString(DirectFunctionCall1(textout,												  PointerGetDatum(expr)));	/* Convert expression to node tree */	node = (Node *) stringToNode(exprstr);	/* Deparse */	context = deparse_context_for(relname, relid);	str = deparse_expression_pretty(node, context, false, false,									prettyFlags, 0);	return str;}/* ---------- * get_userbyid			- Get a user name by roleid and *				  fallback to 'unknown (OID=n)' * ---------- */Datumpg_get_userbyid(PG_FUNCTION_ARGS){	Oid			roleid = PG_GETARG_OID(0);	Name		result;	HeapTuple	roletup;	Form_pg_authid role_rec;	/*	 * Allocate space for the result	 */	result = (Name) palloc(NAMEDATALEN);	memset(NameStr(*result), 0, NAMEDATALEN);	/*	 * Get the pg_authid entry and print the result	 */	roletup = SearchSysCache(AUTHOID,							 ObjectIdGetDatum(roleid),							 0, 0, 0);	if (HeapTupleIsValid(roletup))	{		role_rec = (Form_pg_authid) GETSTRUCT(roletup);		StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN);		ReleaseSysCache(roletup);	}	else		sprintf(NameStr(*result), "unknown (OID=%u)", roleid);	PG_RETURN_NAME(result);}/* * pg_get_serial_sequence *		Get the name of the sequence used by a serial column, *		formatted suitably for passing to setval, nextval or currval. *		First parameter is not treated as double-quoted, second parameter *		is --- see documentation for reason. */Datumpg_get_serial_sequence(PG_FUNCTION_ARGS){	text	   *tablename = PG_GETARG_TEXT_P(0);	text	   *columnname = PG_GETARG_TEXT_P(1);	RangeVar   *tablerv;	Oid			tableOid;	char	   *column;	AttrNumber	attnum;	Oid			sequenceId = InvalidOid;	Relation	depRel;	ScanKeyData key[3];	SysScanDesc scan;	HeapTuple	tup;	/* Get the OID of the table */	tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));	tableOid = RangeVarGetRelid(tablerv, false);	/* Get the number of the column */	column = DatumGetCString(DirectFunctionCall1(textout,											   PointerGetDatum(columnname)));	attnum = get_attnum(tableOid, column);	if (attnum == InvalidAttrNumber)		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_COLUMN),				 errmsg("column \"%s\" of relation \"%s\" does not exist",						column, tablerv->relname)));	/* Search the dependency table for the dependent sequence */	depRel = heap_open(DependRelationId, AccessShareLock);	ScanKeyInit(&key[0],				Anum_pg_depend_refclassid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(RelationRelationId));	ScanKeyInit(&key[1],				Anum_pg_depend_refobjid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(tableOid));	ScanKeyInit(&key[2],				Anum_pg_depend_refobjsubid,				BTEqualStrategyNumber, F_INT4EQ,				Int32GetDatum(attnum));	scan = systable_beginscan(depRel, DependReferenceIndexId, true,							  SnapshotNow, 3, key);	while (HeapTupleIsValid(tup = systable_getnext(scan)))	{		Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);		/*		 * We assume any auto dependency of a sequence on a column must be		 * what we are looking for.  (We need the relkind test because indexes		 * can also have auto dependencies on columns.)		 */		if (deprec->classid == RelationRelationId &&			deprec->objsubid == 0 &&			deprec->deptype == DEPENDENCY_AUTO &&			get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)		{			sequenceId = deprec->objid;			break;		}	}	systable_endscan(scan);	heap_close(depRel, AccessShareLock);	if (OidIsValid(sequenceId))	{		HeapTuple	classtup;		Form_pg_class classtuple;		char	   *nspname;		char	   *result;		/* Get the sequence's pg_class entry */		classtup = SearchSysCache(RELOID,								  ObjectIdGetDatum(sequenceId),								  0, 0, 0);		if (!HeapTupleIsValid(classtup))			elog(ERROR, "cache lookup failed for relation %u", sequenceId);		classtuple = (Form_pg_class) GETSTRUCT(classtup);		/* Get the namespace */		nspname = get_namespace_name(classtuple->relnamespace);		if (!nspname)			elog(ERROR, "cache lookup failed for namespace %u",				 classtuple->relnamespace);		/* And construct the result string */		result = quote_qualified_identifier(nspname,											NameStr(classtuple->relname));		ReleaseSysCache(classtup);		PG_RETURN_TEXT_P(string_to_text(result));	}	PG_RETURN_NULL();}/* * deparse_expression			- General utility for deparsing expressions * * calls deparse_expression_pretty with all prettyPrinting disabled */char *deparse_expression(Node *expr, List *dpcontext,				   bool forceprefix, bool showimplicit){	return deparse_expression_pretty(expr, dpcontext, forceprefix,									 showimplicit, 0, 0);}/* ---------- * deparse_expression_pretty	- General utility for deparsing expressions * * expr is the node tree to be deparsed.  It must be a transformed expression * tree (ie, not the raw output of gram.y). * * dpcontext is a list of deparse_namespace nodes representing the context * for interpreting Vars in the node tree. * * forceprefix is TRUE to force all Vars to be prefixed with their table names. * * showimplicit is TRUE to force all implicit casts to be shown explicitly. * * tries to pretty up the output according to prettyFlags and startIndent. * * The result is a palloc'd string. * ---------- */static char *deparse_expression_pretty(Node *expr, List *dpcontext,						  bool forceprefix, bool showimplicit,						  int prettyFlags, int startIndent){	StringInfoData buf;	deparse_context context;	initStringInfo(&buf);	context.buf = &buf;	context.namespaces = dpcontext;	context.varprefix = forceprefix;	context.prettyFlags = prettyFlags;	context.indentLevel = startIndent;	get_rule_expr(expr, &context, showimplicit);	return buf.data;}/* ---------- * deparse_context_for			- Build deparse context for a single relation * * Given the reference name (alias) and OID of a relation, build deparsing * context for an expression referencing only that relation (as varno 1, * varlevelsup 0).	This is sufficient for many uses of deparse_expression. * ---------- */List *deparse_context_for(const char *aliasname, Oid relid){	deparse_namespace *dpns;	RangeTblEntry *rte;	dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace));	/* Build a minimal RTE for the rel */	rte = makeNode(RangeTblEntry);	rte->rtekind = RTE_RELATION;	rte->relid = relid;	rte->eref = makeAlias(aliasname, NIL);	rte->inh = false;	rte->inFromCl = true;	/* Build one-element rtable */	dpns->rtable = list_make1(rte);	dpns->outer_plan = dpns->inner_plan = NULL;	/* Return a one-deep namespace stack */	return list_make1(dpns);

⌨️ 快捷键说明

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