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 + -
显示快捷键?