typecmds.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,044 行 · 第 1/4 页
C
2,044 行
procOid = LookupFuncName(procname, 2, argList, true); if (OidIsValid(procOid)) return procOid; ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(procname, 1, argList)))); return InvalidOid; /* keep compiler quiet */}/*------------------------------------------------------------------- * DefineCompositeType * * Create a Composite Type relation. * `DefineRelation' does all the work, we just provide the correct * arguments! * * If the relation already exists, then 'DefineRelation' will abort * the xact... * * DefineCompositeType returns relid for use when creating * an implicit composite type during function creation *------------------------------------------------------------------- */OidDefineCompositeType(const RangeVar *typevar, List *coldeflist){ CreateStmt *createStmt = makeNode(CreateStmt); if (coldeflist == NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("composite type must have at least one attribute"))); /* * now create the parameters for keys/inheritance etc. All of them are * nil... */ createStmt->relation = (RangeVar *) typevar; createStmt->tableElts = coldeflist; createStmt->inhRelations = NIL; createStmt->constraints = NIL; createStmt->hasoids = false; createStmt->oncommit = ONCOMMIT_NOOP; /* * finally create the relation... */ return DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE);}/* * AlterDomainDefault * * Routine implementing ALTER DOMAIN SET/DROP DEFAULT statements. */voidAlterDomainDefault(List *names, Node *defaultRaw){ TypeName *typename; Oid domainoid; HeapTuple tup; ParseState *pstate; Relation rel; char *defaultValue; Node *defaultExpr = NULL; /* NULL if no default specified */ Datum new_record[Natts_pg_type]; char new_record_nulls[Natts_pg_type]; char new_record_repl[Natts_pg_type]; HeapTuple newtuple; Form_pg_type typTup; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); typename->names = names; typename->typmod = -1; typename->arrayBounds = NIL; /* Lock the domain in the type table */ rel = heap_openr(TypeRelationName, RowExclusiveLock); /* Use LookupTypeName here so that shell types can be removed. */ domainoid = LookupTypeName(typename); if (!OidIsValid(domainoid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); /* Doesn't return if user isn't allowed to alter the domain */ domainOwnerCheck(tup, typename); /* Setup new tuple */ MemSet(new_record, (Datum) 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', sizeof(new_record_repl)); /* Useful later */ typTup = (Form_pg_type) GETSTRUCT(tup); /* Store the new default, if null then skip this step */ if (defaultRaw) { /* Create a dummy ParseState for transformExpr */ pstate = make_parsestate(NULL); /* * Cook the colDef->raw_expr into an expression. Note: Name is * strictly for error message */ defaultExpr = cookDefault(pstate, defaultRaw, typTup->typbasetype, typTup->typtypmod, NameStr(typTup->typname)); /* * Expression must be stored as a nodeToString result, but we also * require a valid textual representation (mainly to make life * easier for pg_dump). */ defaultValue = deparse_expression(defaultExpr, deparse_context_for(NameStr(typTup->typname), InvalidOid), false, false); /* * Form an updated tuple with the new default and write it back. */ new_record[Anum_pg_type_typdefaultbin - 1] = DirectFunctionCall1(textin, CStringGetDatum( nodeToString(defaultExpr))); new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r'; new_record[Anum_pg_type_typdefault - 1] = DirectFunctionCall1(textin, CStringGetDatum(defaultValue)); new_record_repl[Anum_pg_type_typdefault - 1] = 'r'; } else/* Default is NULL, drop it */ { new_record_nulls[Anum_pg_type_typdefaultbin - 1] = 'n'; new_record_repl[Anum_pg_type_typdefaultbin - 1] = 'r'; new_record_nulls[Anum_pg_type_typdefault - 1] = 'n'; new_record_repl[Anum_pg_type_typdefault - 1] = 'r'; } newtuple = heap_modifytuple(tup, rel, new_record, new_record_nulls, new_record_repl); simple_heap_update(rel, &tup->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); /* Rebuild dependencies */ GenerateTypeDependencies(typTup->typnamespace, domainoid, typTup->typrelid, 0, /* relation kind is n/a */ typTup->typinput, typTup->typoutput, typTup->typreceive, typTup->typsend, typTup->typelem, typTup->typbasetype, defaultExpr, true); /* Rebuild is true */ /* Clean up */ heap_close(rel, NoLock); heap_freetuple(newtuple);}/* * AlterDomainNotNull * * Routine implementing ALTER DOMAIN SET/DROP NOT NULL statements. */voidAlterDomainNotNull(List *names, bool notNull){ TypeName *typename; Oid domainoid; Relation typrel; HeapTuple tup; Form_pg_type typTup; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); typename->names = names; typename->typmod = -1; typename->arrayBounds = NIL; /* Lock the type table */ typrel = heap_openr(TypeRelationName, RowExclusiveLock); /* Use LookupTypeName here so that shell types can be found (why?). */ domainoid = LookupTypeName(typename); if (!OidIsValid(domainoid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); typTup = (Form_pg_type) GETSTRUCT(tup); /* Doesn't return if user isn't allowed to alter the domain */ domainOwnerCheck(tup, typename); /* Is the domain already set to the desired constraint? */ if (typTup->typnotnull == notNull) { heap_close(typrel, RowExclusiveLock); return; } /* Adding a NOT NULL constraint requires checking existing columns */ if (notNull) { List *rels; List *rt; /* Fetch relation list with attributes based on this domain */ /* ShareLock is sufficient to prevent concurrent data changes */ rels = get_rels_with_domain(domainoid, ShareLock); foreach(rt, rels) { RelToCheck *rtc = (RelToCheck *) lfirst(rt); Relation testrel = rtc->rel; TupleDesc tupdesc = RelationGetDescr(testrel); HeapScanDesc scan; HeapTuple tuple; /* Scan all tuples in this relation */ scan = heap_beginscan(testrel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { int i; /* Test attributes that are of the domain */ for (i = 0; i < rtc->natts; i++) { int attnum = rtc->atts[i]; Datum d; bool isNull; d = heap_getattr(tuple, attnum, tupdesc, &isNull); if (isNull) ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), errmsg("column \"%s\" of table \"%s\" contains null values", NameStr(tupdesc->attrs[attnum - 1]->attname), RelationGetRelationName(testrel)))); } } heap_endscan(scan); /* Close each rel after processing, but keep lock */ heap_close(testrel, NoLock); } } /* * Okay to update pg_type row. We can scribble on typTup because it's * a copy. */ typTup->typnotnull = notNull; simple_heap_update(typrel, &tup->t_self, tup); CatalogUpdateIndexes(typrel, tup); /* Clean up */ heap_freetuple(tup); heap_close(typrel, RowExclusiveLock);}/* * AlterDomainDropConstraint * * Implements the ALTER DOMAIN DROP CONSTRAINT statement */voidAlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior){ TypeName *typename; Oid domainoid; HeapTuple tup; Relation rel; Form_pg_type typTup; Relation conrel; SysScanDesc conscan; ScanKeyData key[1]; HeapTuple contup; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); typename->names = names; typename->typmod = -1; typename->arrayBounds = NIL; /* Lock the type table */ rel = heap_openr(TypeRelationName, RowExclusiveLock); /* Use LookupTypeName here so that shell types can be removed. */ domainoid = LookupTypeName(typename); if (!OidIsValid(domainoid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); /* Doesn't return if user isn't allowed to alter the domain */ domainOwnerCheck(tup, typename); /* Grab an appropriate lock on the pg_constraint relation */ conrel = heap_openr(ConstraintRelationName, RowExclusiveLock); /* Use the index to scan only constraints of the target relation */ ScanKeyEntryInitialize(&key[0], 0x0, Anum_pg_constraint_contypid, F_OIDEQ, ObjectIdGetDatum(HeapTupleGetOid(tup))); conscan = systable_beginscan(conrel, ConstraintTypidIndex, true, SnapshotNow, 1, key); typTup = (Form_pg_type) GETSTRUCT(tup); /* * Scan over the result set, removing any matching entries. */ while ((contup = systable_getnext(conscan)) != NULL) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup); if (strcmp(NameStr(con->conname), constrName) == 0) { ObjectAddress conobj; conobj.classId = RelationGetRelid(conrel); conobj.objectId = HeapTupleGetOid(contup); conobj.objectSubId = 0; performDeletion(&conobj, behavior); } } /* Clean up after the scan */ systable_endscan(conscan); heap_close(conrel, RowExclusiveLock); heap_close(rel, NoLock);}/* * AlterDomainAddConstraint * * Implements the ALTER DOMAIN .. ADD CONSTRAINT statement. */voidAlterDomainAddConstraint(List *names, Node *newConstraint){ TypeName *typename; Oid domainoid; Relation typrel; HeapTuple tup; Form_pg_type typTup; List *rels; List *rt; EState *estate; ExprContext *econtext; char *ccbin; Expr *expr; ExprState *exprstate; int counter = 0; Constraint *constr; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); typename->names = names; typename->typmod = -1; typename->arrayBounds = NIL; /* Lock the type table */ typrel = heap_openr(TypeRelationName, RowExclusiveLock); /* Use LookupTypeName here so that shell types can be found (why?). */ domainoid = LookupTypeName(typename); if (!OidIsValid(domainoid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); tup = SearchSysCacheCopy(TYPEOID, ObjectIdGetDatum(domainoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", domainoid); typTup = (Form_pg_type) GETSTRUCT(tup); /* Doesn't return if user isn't allowed to alter the domain */ domainOwnerCheck(tup, typename); /* Check for unsupported constraint types */ if (IsA(newConstraint, FkConstraint)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("foreign key constraints not possible for domains"))); /* otherwise it should be a plain Constraint */ if (!IsA(newConstraint, Constraint)) elog(ERROR, "unrecognized node type: %d", (int) nodeTag(newConstraint)); constr = (Constraint *) newConstraint; switch (constr->contype) { case CONSTR_CHECK: /* processed below */ break; case CONSTR_UNIQUE: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unique constraints not possible for domains"))); break; case CONSTR_PRIMARY: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("primary key constraints not possible for domains"))); break; case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: case CONSTR_ATTR_IMMEDIATE: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("specifying constraint deferrability not supported for domains"))); break; default: elog(ERROR, "unrecognized constraint subtype: %d", (int) constr->contype); break; } /* * Since all other constraint types throw errors, this must be a check * constraint. First, process the constraint expression and add an * entry to pg_constraint. */ ccbin = domainAddConstraint(HeapTupleGetOid(tup), typTup->typnamespace, typTup->typbasetype, typTup->typtypmod, constr, &counter, NameStr(typTup->typname)); /* * Test all values stored in the attributes based on the domain the * constraint is being added to. */ expr = (Expr *) stringToNode(ccbin); /* Need an EState to run ExecEvalExpr */ estate = CreateExecutorState(); econtext = GetPerTupleExprContext(estate); /* build execution state for expr */ exprstate = ExecPrepareExpr(expr, estate); /* Fetch relation list with attributes based on this domain */ /* ShareLock is sufficient to prevent concurrent data changes */ rels = get_rels_with_domain(domainoid, ShareLock); foreach(rt, rels) { RelToCheck *rtc = (RelToCheck *) lfirst(rt); Relation testrel = rtc->rel; TupleDesc tupdesc = RelationGetDescr(testrel); HeapScanDesc scan; HeapTuple tuple; /* Scan all tuples in this relation */ scan = heap_beginscan(testrel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?