ruleutils.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,475 行 · 第 1/5 页
C
2,475 行
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; /* 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 = 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); appendStringInfo(&buf, ")"); break; } case CONSTRAINT_CHECK: { Datum val; bool isnull; char *conbin; char *consrc; Node *expr; List *context; /* Fetch constraint expression in parsetree form */ val = heap_getattr(tup, Anum_pg_constraint_conbin, RelationGetDescr(conDesc), &isnull); if (isnull) elog(ERROR, "null conbin for constraint %u", constraintId); conbin = DatumGetCString(DirectFunctionCall1(textout, val)); expr = stringToNode(conbin); /* * 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 (expr && IsA(expr, List)) expr = (Node *) make_ands_explicit((List *) expr); /* 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; } /* Record the results */ len = buf.len + VARHDRSZ; result = (text *) palloc(len); VARATT_SIZEP(result) = len; memcpy(VARDATA(result), buf.data, buf.len); /* Cleanup */ pfree(buf.data); systable_endscan(conscan); heap_close(conDesc, AccessShareLock); PG_RETURN_TEXT_P(result);}/* * 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, &nKeys); for (j = 0; j < nKeys; j++) { char *colName; colName = get_relid_attribute_name(relId, DatumGetInt16(keys[j])); if (j == 0) appendStringInfo(buf, "%s", 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? */ return 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? */ return pg_get_expr_worker(expr, relid, relname, prettyFlags);}static Datumpg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags){ text *result; 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); /* * 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 */ context = deparse_context_for(relname, relid); str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0); /* Pass the result back as TEXT */ result = DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(str))); PG_RETURN_TEXT_P(result);}/* ---------- * get_userbyid - Get a user name by usesysid and * fallback to 'unknown (UID=n)' * ---------- */Datumpg_get_userbyid(PG_FUNCTION_ARGS){ int32 uid = PG_GETARG_INT32(0); Name result; HeapTuple usertup; Form_pg_shadow user_rec; /* * Allocate space for the result */ result = (Name) palloc(NAMEDATALEN); memset(NameStr(*result), 0, NAMEDATALEN); /* * Get the pg_shadow entry and print the result */ usertup = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(uid), 0, 0, 0); if (HeapTupleIsValid(usertup)) { user_rec = (Form_pg_shadow) GETSTRUCT(usertup); StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN); ReleaseSysCache(usertup); } else sprintf(NameStr(*result), "unknown (UID=%d)", uid); PG_RETURN_NAME(result);}/* ---------- * 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 = makeList1(rte); dpns->outer_varno = dpns->inner_varno = 0; dpns->outer_rte = dpns->inner_rte = NULL; /* Return a one-deep namespace stack */ return makeList1(dpns);}/* * deparse_context_for_plan - Build deparse context for a plan node * * We assume we are dealing with an upper-level plan node having either * one or two referenceable children (pass innercontext = NULL if only one). * The passed-in Nodes should be made using deparse_context_for_subplan * and/or deparse_context_for_relation. The resulting context will work * for deparsing quals, tlists, etc of the plan node. * * An rtable list can also be passed in case plain Vars might be seen. * This is not needed for true upper-level expressions, but is helpful for * Sort nodes and similar cases with slightly bogus targetlists. */List *deparse_context_for_plan(int outer_varno, Node *outercontext, int inner_varno, Node *innercontext, List *rtable){ deparse_namespace *dpns; dpns = (deparse_namespace *) palloc(sizeof(deparse_namespace)); dpns->rtable = rtable; dpns->outer_varno = outer_varno; dpns->outer_rte = (RangeTblEntry *) outercontext; dpns->inner_varno = inner_varno; dpns->inner_rte = (RangeTblEntry *) innercontext; /* Return a one-deep namespace stack */ return makeList1(dpns);}/* * deparse_context_for_rte - Build deparse context for 1 relation * * Helper routine to build one of the inputs for deparse_context_for_plan. * * The returned node is actually the given RangeTblEntry, but we declare it * as just Node to discourage callers from assuming anything. */Node *deparse_context_for_rte(RangeTblEntry *rte){ return (Node *) rte;}/* * deparse_context_for_subplan - Build deparse context for a plan node * * Helper routine to build one of the inputs for deparse_context_for_plan. * Pass the tlist of the subplan node, plus the query rangetable. * * The returned node is actually a RangeTblEntry, but we declare it as just * Node to discourage callers from assuming anything. */Node *deparse_context_for_subplan(const char *name, List *tlist, List *rtable){ RangeTblEntry *rte = makeNode(RangeTblEntry); List *attrs = NIL; int nattrs = 0; int rtablelength = length(rtable); List *tl; char buf[32]; foreach(tl, tlist) { TargetEntry *tle = lfirst(tl); Resdom *resdom = tle->resdom; nattrs++; Assert(resdom->resno == nattrs); if (resdom->resname) { attrs = lappend(attrs, makeString(resdom->resname)); continue; } if (tle->expr && IsA(tle->expr, Var)) { Var *var = (Var *) tle->expr; /* varno/varattno won't be any good, but varnoold might be */ if (var->varnoold > 0 && var->varnoold <= rtablelength) { RangeTblEntry *varrte = rt_fetch(var->varnoold, rtable); char *varname; varname = get_rte_attribute_name(varrte, var->varoattno); attrs = lappend(attrs, makeString(varname)); continue; } } /* Fallback if can't get name */ snprintf(buf, sizeof(buf), "?column%d?", resdom->resno); attrs = lappend(attrs, makeString(pstrdup(buf))); } rte->rtekind = RTE_SPECIAL; /* XXX */ rte->relid = InvalidOid; rte->eref = makeAlias(name, attrs); rte->inh = false; rte->inFromCl = true; return (Node *) rte;}/* ---------- * make_ruledef - reconstruct the CREATE RULE command * for a given pg_rewrite tuple * ---------- */static voidmake_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, int prettyFlags){ char *rulename; char ev_type; Oid ev_class; int2 ev_attr; bool is_instead; char *ev_qual; char *ev_action; List *actions = NIL; int fno; Datum dat; bool isnull; /* * Get the attribute values from the rules tuple */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?