📄 typecmds.c
字号:
0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeOid); simple_heap_delete(relation, &tup->t_self); ReleaseSysCache(tup); heap_close(relation, RowExclusiveLock);}/* * DefineDomain * Registers a new domain. */voidDefineDomain(CreateDomainStmt *stmt){ char *domainName; Oid domainNamespace; AclResult aclresult; int16 internalLength; Oid inputProcedure; Oid outputProcedure; Oid receiveProcedure; Oid sendProcedure; Oid analyzeProcedure; bool byValue; char delimiter; char alignment; char storage; char typtype; Datum datum; bool isnull; Node *defaultExpr = NULL; char *defaultValue = NULL; char *defaultValueBin = NULL; bool typNotNull = false; bool nullDefined = false; Oid basetypelem; int32 typNDims = list_length(stmt->typename->arrayBounds); HeapTuple typeTup; List *schema = stmt->constraints; ListCell *listptr; Oid basetypeoid; Oid domainoid; Form_pg_type baseType; /* Convert list of names to a name and namespace */ domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname, &domainName); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(domainNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(domainNamespace)); /* * Domainnames, unlike typenames don't need to account for the '_' prefix. * So they can be one character longer. (This test is presently useless * since the parser will have truncated the name to fit. But leave it * here since we may someday support arrays of domains, in which case * we'll be back to needing to enforce NAMEDATALEN-2.) */ if (strlen(domainName) > (NAMEDATALEN - 1)) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("domain names must be %d characters or less", NAMEDATALEN - 1))); /* * Look up the base type. */ typeTup = typenameType(stmt->typename); baseType = (Form_pg_type) GETSTRUCT(typeTup); basetypeoid = HeapTupleGetOid(typeTup); /* * Base type must be a plain base type. Domains over pseudo types would * create a security hole. Domains of domains might be made to work in * the future, but not today. Ditto for domains over complex types. */ typtype = baseType->typtype; if (typtype != 'b') ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("\"%s\" is not a valid base type for a domain", TypeNameToString(stmt->typename)))); /* passed by value */ byValue = baseType->typbyval; /* Required Alignment */ alignment = baseType->typalign; /* TOAST Strategy */ storage = baseType->typstorage; /* Storage Length */ internalLength = baseType->typlen; /* Array element Delimiter */ delimiter = baseType->typdelim; /* I/O Functions */ inputProcedure = baseType->typinput; outputProcedure = baseType->typoutput; receiveProcedure = baseType->typreceive; sendProcedure = baseType->typsend; /* Analysis function */ analyzeProcedure = baseType->typanalyze; /* Inherited default value */ datum = SysCacheGetAttr(TYPEOID, typeTup, Anum_pg_type_typdefault, &isnull); if (!isnull) defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum)); /* Inherited default binary value */ datum = SysCacheGetAttr(TYPEOID, typeTup, Anum_pg_type_typdefaultbin, &isnull); if (!isnull) defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum)); /* * Pull out the typelem name of the parent OID. * * This is what enables us to make a domain of an array */ basetypelem = baseType->typelem; /* * Run through constraints manually to avoid the additional processing * conducted by DefineRelation() and friends. */ foreach(listptr, schema) { Node *newConstraint = lfirst(listptr); Constraint *constr; ParseState *pstate; /* 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_DEFAULT: /* * The inherited default value may be overridden by the user * with the DEFAULT <expr> statement. */ if (defaultExpr) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple default expressions"))); /* Create a dummy ParseState for transformExpr */ pstate = make_parsestate(NULL); /* * Cook the constr->raw_expr into an expression. Note: Name is * strictly for error message */ defaultExpr = cookDefault(pstate, constr->raw_expr, basetypeoid, stmt->typename->typmod, domainName); /* * 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(domainName, InvalidOid), false, false); defaultValueBin = nodeToString(defaultExpr); break; case CONSTR_NOTNULL: if (nullDefined && !typNotNull) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL constraints"))); typNotNull = true; nullDefined = true; break; case CONSTR_NULL: if (nullDefined && typNotNull) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting NULL/NOT NULL constraints"))); typNotNull = false; nullDefined = true; break; case CONSTR_CHECK: /* * Check constraints are handled after domain creation, as * they require the Oid of the domain */ break; /* * All else are error cases */ 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; } } /* * Have TypeCreate do all the real work. */ domainoid = TypeCreate(domainName, /* type name */ domainNamespace, /* namespace */ InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ internalLength, /* internal size */ 'd', /* type-type (domain type) */ delimiter, /* array element delimiter */ inputProcedure, /* input procedure */ outputProcedure, /* output procedure */ receiveProcedure, /* receive procedure */ sendProcedure, /* send procedure */ analyzeProcedure, /* analyze procedure */ basetypelem, /* element type ID */ basetypeoid, /* base type ID */ defaultValue, /* default type value (text) */ defaultValueBin, /* default type value (binary) */ byValue, /* passed by value */ alignment, /* required alignment */ storage, /* TOAST strategy */ stmt->typename->typmod, /* typeMod value */ typNDims, /* Array dimensions for base type */ typNotNull); /* Type NOT NULL */ /* * Process constraints which refer to the domain ID returned by TypeCreate */ foreach(listptr, schema) { Constraint *constr = lfirst(listptr); /* it must be a Constraint, per check above */ switch (constr->contype) { case CONSTR_CHECK: domainAddConstraint(domainoid, domainNamespace, basetypeoid, stmt->typename->typmod, constr, domainName); break; /* Other constraint types were fully processed above */ default: break; } /* CCI so we can detect duplicate constraint names */ CommandCounterIncrement(); } /* * Now we can clean up. */ ReleaseSysCache(typeTup);}/* * RemoveDomain * Removes a domain. * * This is identical to RemoveType except we insist it be a domain. */voidRemoveDomain(List *names, DropBehavior behavior){ TypeName *typename; Oid typeoid; HeapTuple tup; char typtype; ObjectAddress object; /* Make a TypeName so we can use standard type lookup machinery */ typename = makeNode(TypeName); typename->names = names; typename->typmod = -1; typename->arrayBounds = NIL; /* Use LookupTypeName here so that shell types can be removed. */ typeoid = LookupTypeName(typename); if (!OidIsValid(typeoid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typename)))); tup = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", typeoid); /* Permission check: must own type or its namespace */ if (!pg_type_ownercheck(typeoid, GetUserId()) && !pg_namespace_ownercheck(((Form_pg_type) GETSTRUCT(tup))->typnamespace, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, TypeNameToString(typename)); /* Check that this is actually a domain */ typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype; if (typtype != 'd') ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a domain", TypeNameToString(typename)))); ReleaseSysCache(tup); /* * Do the deletion */ object.classId = TypeRelationId; object.objectId = typeoid; object.objectSubId = 0; performDeletion(&object, behavior);}/* * Find suitable I/O functions for a type. * * typeOid is the type's OID (which will already exist, if only as a shell * type). */static OidfindTypeInputFunction(List *procname, Oid typeOid){ Oid argList[3]; Oid procOid; /* * Input functions can take a single argument of type CSTRING, or three * arguments (string, typioparam OID, typmod). * * For backwards compatibility we allow OPAQUE in place of CSTRING; if we * see this, we issue a warning and fix up the pg_proc entry. */ argList[0] = CSTRINGOID; 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; /* No luck, try it with OPAQUE */ argList[0] = OPAQUEOID; procOid = LookupFuncName(procname, 1, argList, true); if (!OidIsValid(procOid)) { argList[1] = OIDOID; argList[2] = INT4OID; procOid = LookupFuncName(procname, 3, 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 \"cstring\"", NameListToString(procname)))); SetFunctionArgType(procOid, 0, CSTRINGOID); /* * Need CommandCounterIncrement since DefineType will likely try to * alter the pg_proc tuple again. */ CommandCounterIncrement(); return procOid; } /* Use CSTRING (preferred) in the error message */ argList[0] = CSTRINGOID; ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function %s does not exist", func_signature_string(procname, 1, argList)))); return InvalidOid; /* keep compiler quiet */}static OidfindTypeOutputFunction(List *procname, Oid typeOid){ Oid argList[1]; Oid procOid; /* * Output functions can take a single argument of the type.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -