📄 typecmds.c
字号:
* * For backwards compatibility we allow OPAQUE in place of the actual type * name; if we see this, we issue a warning and fix up the pg_proc entry. */ argList[0] = typeOid; procOid = LookupFuncName(procname, 1, argList, true); if (OidIsValid(procOid)) return procOid; /* No luck, try it with OPAQUE */ argList[0] = OPAQUEOID; procOid = LookupFuncName(procname, 1, argList, true); if (OidIsValid(procOid)) { /* Found, but must complain and fix the pg_proc entry */ ereport(WARNING, (errmsg("changing argument type of function %s from \"opaque\" to %s", NameListToString(procname), format_type_be(typeOid)))); SetFunctionArgType(procOid, 0, typeOid); /* * Need CommandCounterIncrement since DefineType will likely try to * alter the pg_proc tuple again. */ CommandCounterIncrement(); return procOid; } /* Use type name, not OPAQUE, in the failure message. */ argList[0] = typeOid; ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(procname, 1, argList)))); return InvalidOid; /* keep compiler quiet */}static OidfindTypeReceiveFunction(List *procname, Oid typeOid){ Oid argList[3]; Oid procOid; /* * Receive functions can take a single argument of type INTERNAL, or three * arguments (internal, typioparam OID, typmod). */ argList[0] = INTERNALOID; procOid = LookupFuncName(procname, 1, argList, true); if (OidIsValid(procOid)) return procOid; argList[1] = OIDOID; argList[2] = INT4OID; procOid = LookupFuncName(procname, 3, 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 */}static OidfindTypeSendFunction(List *procname, Oid typeOid){ Oid argList[1]; Oid procOid; /* * Send functions can take a single argument of the type. */ argList[0] = typeOid; procOid = LookupFuncName(procname, 1, 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 */}static OidfindTypeAnalyzeFunction(List *procname, Oid typeOid){ Oid argList[1]; Oid procOid; /* * Analyze functions always take one INTERNAL argument and return bool. */ argList[0] = INTERNALOID; procOid = LookupFuncName(procname, 1, argList, true); if (!OidIsValid(procOid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(procname, 1, argList)))); if (get_func_rettype(procOid) != BOOLOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("type analyze function %s must return type \"boolean\"", NameListToString(procname)))); return procOid;}/*------------------------------------------------------------------- * 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 set the parameters for keys/inheritance etc. All of these are * uninteresting for composite types... */ createStmt->relation = (RangeVar *) typevar; createStmt->tableElts = coldeflist; createStmt->inhRelations = NIL; createStmt->constraints = NIL; createStmt->hasoids = MUST_NOT_HAVE_OIDS; createStmt->oncommit = ONCOMMIT_NOOP; createStmt->tablespacename = NULL; /* * 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_open(TypeRelationId, 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, RelationGetDescr(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->typowner, typTup->typinput, typTup->typoutput, typTup->typreceive, typTup->typsend, typTup->typanalyze, 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_open(TypeRelationId, 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; ListCell *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]; if (heap_attisnull(tuple, attnum)) 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; 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_open(TypeRelationId, 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_open(ConstraintRelationId, RowExclusiveLock); /* Use the index to scan only constraints of the target relation */ ScanKeyInit(&key[0], Anum_pg_constraint_contypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(HeapTupleGetOid(tup))); conscan = systable_beginscan(conrel, ConstraintTypidIndexId, true, SnapshotNow, 1, key);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -