#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
#include "nodes/makefuncs.h"
#include "parser/parser.h"
#include "parser/parse_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
Go to the source code of this file.
static void appendTypeNameToBuffer | ( | const TypeName * | typeName, | |
StringInfo | string | |||
) | [static] |
Definition at line 369 of file parse_type.c.
References appendStringInfoChar(), appendStringInfoString(), TypeName::arrayBounds, format_type_be(), lfirst, list_head(), TypeName::names, NIL, TypeName::pct_type, strVal, and TypeName::typeOid.
Referenced by TypeNameListToString(), and TypeNameToString().
{ if (typeName->names != NIL) { /* Emit possibly-qualified name as-is */ ListCell *l; foreach(l, typeName->names) { if (l != list_head(typeName->names)) appendStringInfoChar(string, '.'); appendStringInfoString(string, strVal(lfirst(l))); } } else { /* Look up internally-specified type */ appendStringInfoString(string, format_type_be(typeName->typeOid)); } /* * Add decoration as needed, but only for fields considered by * LookupTypeName */ if (typeName->pct_type) appendStringInfoString(string, "%TYPE"); if (typeName->arrayBounds != NIL) appendStringInfoString(string, "[]"); }
Oid GetColumnDefCollation | ( | ParseState * | pstate, | |
ColumnDef * | coldef, | |||
Oid | typeOid | |||
) |
Definition at line 471 of file parse_type.c.
References ColumnDef::collClause, CollateClause::collname, ColumnDef::collOid, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_typcollation(), CollateClause::location, LookupCollation(), OidIsValid, and parser_errposition().
Referenced by addRangeTableEntryForFunction(), ATExecAddColumn(), ATExecAlterColumnType(), ATPrepAlterColumnType(), BuildDescForRelation(), and MergeAttributes().
{ Oid result; Oid typcollation = get_typcollation(typeOid); int location = -1; if (coldef->collClause) { /* We have a raw COLLATE clause, so look up the collation */ location = coldef->collClause->location; result = LookupCollation(pstate, coldef->collClause->collname, location); } else if (OidIsValid(coldef->collOid)) { /* Precooked collation spec, use that */ result = coldef->collOid; } else { /* Use the type's default collation if any */ result = typcollation; } /* Complain if COLLATE is applied to an uncollatable type */ if (OidIsValid(result) && !OidIsValid(typcollation)) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("collations are not supported by type %s", format_type_be(typeOid)), parser_errposition(pstate, location))); return result; }
Oid LookupCollation | ( | ParseState * | pstate, | |
List * | collnames, | |||
int | location | |||
) |
Definition at line 446 of file parse_type.c.
References cancel_parser_errposition_callback(), get_collation_oid(), and setup_parser_errposition_callback().
Referenced by GetColumnDefCollation(), transformCollateClause(), and transformColumnType().
{ Oid colloid; ParseCallbackState pcbstate; if (pstate) setup_parser_errposition_callback(&pcbstate, pstate, location); colloid = get_collation_oid(collnames, false); if (pstate) cancel_parser_errposition_callback(&pcbstate); return colloid; }
Type LookupTypeName | ( | ParseState * | pstate, | |
const TypeName * | typeName, | |||
int32 * | typmod_p | |||
) |
Definition at line 58 of file parse_type.c.
References TypeName::arrayBounds, Assert, RangeVar::catalogname, DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_array_type(), get_attnum(), get_atttype(), GetSysCacheOid2, HeapTupleIsValid, InvalidAttrNumber, lfourth, linitial, list_length(), TypeName::location, LookupExplicitNamespace(), lsecond, lthird, makeRangeVar(), NameListToString(), TypeName::names, NIL, NoLock, NOTICE, NULL, ObjectIdGetDatum, OidIsValid, parser_errposition(), TypeName::pct_type, PointerGetDatum, RangeVarGetRelid, RangeVar::relname, RangeVar::schemaname, SearchSysCache1, strVal, TypenameGetTypid(), TYPENAMENSP, TypeNameToString(), typenameTypeMod(), TYPEOID, and TypeName::typeOid.
Referenced by AlterTypeOwner(), compute_return_type(), examine_parameter_list(), FuncNameAsType(), get_object_address_type(), LookupTypeNameOid(), plpgsql_parse_wordtype(), and typenameType().
{ Oid typoid; HeapTuple tup; int32 typmod; if (typeName->names == NIL) { /* We have the OID already if it's an internally generated TypeName */ typoid = typeName->typeOid; } else if (typeName->pct_type) { /* Handle %TYPE reference to type of an existing field */ RangeVar *rel = makeRangeVar(NULL, NULL, typeName->location); char *field = NULL; Oid relid; AttrNumber attnum; /* deconstruct the name list */ switch (list_length(typeName->names)) { case 1: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper %%TYPE reference (too few dotted names): %s", NameListToString(typeName->names)), parser_errposition(pstate, typeName->location))); break; case 2: rel->relname = strVal(linitial(typeName->names)); field = strVal(lsecond(typeName->names)); break; case 3: rel->schemaname = strVal(linitial(typeName->names)); rel->relname = strVal(lsecond(typeName->names)); field = strVal(lthird(typeName->names)); break; case 4: rel->catalogname = strVal(linitial(typeName->names)); rel->schemaname = strVal(lsecond(typeName->names)); rel->relname = strVal(lthird(typeName->names)); field = strVal(lfourth(typeName->names)); break; default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper %%TYPE reference (too many dotted names): %s", NameListToString(typeName->names)), parser_errposition(pstate, typeName->location))); break; } /* * Look up the field. * * XXX: As no lock is taken here, this might fail in the presence of * concurrent DDL. But taking a lock would carry a performance * penalty and would also require a permissions check. */ relid = RangeVarGetRelid(rel, NoLock, false); attnum = get_attnum(relid, field); if (attnum == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" of relation \"%s\" does not exist", field, rel->relname), parser_errposition(pstate, typeName->location))); typoid = get_atttype(relid, attnum); /* this construct should never have an array indicator */ Assert(typeName->arrayBounds == NIL); /* emit nuisance notice (intentionally not errposition'd) */ ereport(NOTICE, (errmsg("type reference %s converted to %s", TypeNameToString(typeName), format_type_be(typoid)))); } else { /* Normal reference to a type name */ char *schemaname; char *typname; /* deconstruct the name list */ DeconstructQualifiedName(typeName->names, &schemaname, &typname); if (schemaname) { /* Look in specific schema only */ Oid namespaceId; namespaceId = LookupExplicitNamespace(schemaname, false); typoid = GetSysCacheOid2(TYPENAMENSP, PointerGetDatum(typname), ObjectIdGetDatum(namespaceId)); } else { /* Unqualified type name, so search the search path */ typoid = TypenameGetTypid(typname); } /* If an array reference, return the array type instead */ if (typeName->arrayBounds != NIL) typoid = get_array_type(typoid); } if (!OidIsValid(typoid)) { if (typmod_p) *typmod_p = -1; return NULL; } tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid)); if (!HeapTupleIsValid(tup)) /* should not happen */ elog(ERROR, "cache lookup failed for type %u", typoid); typmod = typenameTypeMod(pstate, typeName, (Type) tup); if (typmod_p) *typmod_p = typmod; return (Type) tup; }
Definition at line 664 of file parse_type.c.
References appendStringInfo(), TypeCast::arg, ErrorContextCallback::arg, buf, ErrorContextCallback::callback, StringInfoData::data, SelectStmt::distinctClause, ereport, errcode(), errmsg(), ERROR, error_context_stack, SelectStmt::fromClause, SelectStmt::groupClause, SelectStmt::havingClause, ResTarget::indirection, initStringInfo(), SelectStmt::intoClause, IsA, SelectStmt::limitCount, SelectStmt::limitOffset, linitial, list_length(), SelectStmt::lockingClause, ResTarget::name, NIL, NULL, SelectStmt::op, pfree(), ErrorContextCallback::previous, raw_parser(), TypeName::setof, SelectStmt::sortClause, SelectStmt::targetList, TypeCast::typeName, typenameTypeIdAndMod(), ResTarget::val, SelectStmt::valuesLists, SelectStmt::whereClause, SelectStmt::windowClause, and SelectStmt::withClause.
Referenced by parseNameAndArgTypes(), plperl_spi_prepare(), pltcl_SPI_prepare(), PLy_spi_prepare(), and regtypein().
{ StringInfoData buf; List *raw_parsetree_list; SelectStmt *stmt; ResTarget *restarget; TypeCast *typecast; TypeName *typeName; ErrorContextCallback ptserrcontext; /* make sure we give useful error for empty input */ if (strspn(str, " \t\n\r\f") == strlen(str)) goto fail; initStringInfo(&buf); appendStringInfo(&buf, "SELECT NULL::%s", str); /* * Setup error traceback support in case of ereport() during parse */ ptserrcontext.callback = pts_error_callback; ptserrcontext.arg = (void *) str; ptserrcontext.previous = error_context_stack; error_context_stack = &ptserrcontext; raw_parsetree_list = raw_parser(buf.data); error_context_stack = ptserrcontext.previous; /* * Make sure we got back exactly what we expected and no more; paranoia is * justified since the string might contain anything. */ if (list_length(raw_parsetree_list) != 1) goto fail; stmt = (SelectStmt *) linitial(raw_parsetree_list); if (stmt == NULL || !IsA(stmt, SelectStmt) || stmt->distinctClause != NIL || stmt->intoClause != NULL || stmt->fromClause != NIL || stmt->whereClause != NULL || stmt->groupClause != NIL || stmt->havingClause != NULL || stmt->windowClause != NIL || stmt->valuesLists != NIL || stmt->sortClause != NIL || stmt->limitOffset != NULL || stmt->limitCount != NULL || stmt->lockingClause != NIL || stmt->withClause != NULL || stmt->op != SETOP_NONE) goto fail; if (list_length(stmt->targetList) != 1) goto fail; restarget = (ResTarget *) linitial(stmt->targetList); if (restarget == NULL || !IsA(restarget, ResTarget) || restarget->name != NULL || restarget->indirection != NIL) goto fail; typecast = (TypeCast *) restarget->val; if (typecast == NULL || !IsA(typecast, TypeCast) || typecast->arg == NULL || !IsA(typecast->arg, A_Const)) goto fail; typeName = typecast->typeName; if (typeName == NULL || !IsA(typeName, TypeName)) goto fail; if (typeName->setof) goto fail; typenameTypeIdAndMod(NULL, typeName, typeid_p, typmod_p); pfree(buf.data); return; fail: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("invalid type name \"%s\"", str))); }
static void pts_error_callback | ( | void * | arg | ) | [static] |
Definition at line 644 of file parse_type.c.
References errcontext, and errposition().
{ const char *str = (const char *) arg; errcontext("invalid type name \"%s\"", str); /* * Currently we just suppress any syntax error position report, rather * than transforming to an "internal query" error. It's unlikely that a * type name is complex enough to need positioning. */ errposition(0); }
Definition at line 585 of file parse_type.c.
References datumIsEqual(), elog, GETSTRUCT, getTypeIOParam(), NameStr, OidInputFunctionCall(), and WARNING.
Referenced by coerce_type().
{ Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp); Oid typinput = typform->typinput; Oid typioparam = getTypeIOParam(tp); Datum result; result = OidInputFunctionCall(typinput, string, typioparam, atttypmod); #ifdef RANDOMIZE_ALLOCATED_MEMORY /* * For pass-by-reference data types, repeat the conversion to see if the * input function leaves any uninitialized bytes in the result. We can * only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is enabled, so * we don't bother testing otherwise. The reason we don't want any * instability in the input function is that comparison of Const nodes * relies on bytewise comparison of the datums, so if the input function * leaves garbage then subexpressions that should be identical may not get * recognized as such. See pgsql-hackers discussion of 2008-04-04. */ if (string && !typform->typbyval) { Datum result2; result2 = OidInputFunctionCall(typinput, string, typioparam, atttypmod); if (!datumIsEqual(result, result2, typform->typbyval, typform->typlen)) elog(WARNING, "type %s has unstable input conversion for \"%s\"", NameStr(typform->typname), string); } #endif return result; }
Definition at line 540 of file parse_type.c.
References GETSTRUCT.
Referenced by coerce_type().
{ Form_pg_type typ; typ = (Form_pg_type) GETSTRUCT(t); return typ->typbyval; }
Definition at line 509 of file parse_type.c.
References elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, SearchSysCache1, and TYPEOID.
Referenced by coerce_type(), and find_typmod_coercion_function().
{ HeapTuple tup; tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id)); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for type %u", id); return (Type) tup; }
Definition at line 624 of file parse_type.c.
References elog, ERROR, GETSTRUCT, HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), SearchSysCache1, and TYPEOID.
Referenced by get_rte_attribute_is_dropped(), PLy_input_tuple_funcs(), PLy_output_tuple_funcs(), ProcedureCreate(), transformAssignmentIndirection(), typeInheritsFrom(), and typeIsOfTypedTable().
{ HeapTuple typeTuple; Form_pg_type type; Oid result; typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id)); if (!HeapTupleIsValid(typeTuple)) elog(ERROR, "cache lookup failed for type %u", type_id); type = (Form_pg_type) GETSTRUCT(typeTuple); result = type->typrelid; ReleaseSysCache(typeTuple); return result; }
Definition at line 530 of file parse_type.c.
References GETSTRUCT.
Referenced by coerce_type().
{ Form_pg_type typ; typ = (Form_pg_type) GETSTRUCT(t); return typ->typlen; }
char* TypeNameListToString | ( | List * | typenames | ) |
Definition at line 422 of file parse_type.c.
References appendStringInfoChar(), appendTypeNameToBuffer(), Assert, initStringInfo(), IsA, lfirst, and list_head().
Referenced by does_not_exist_skipping().
{ StringInfoData string; ListCell *l; initStringInfo(&string); foreach(l, typenames) { TypeName *typeName = (TypeName *) lfirst(l); Assert(IsA(typeName, TypeName)); if (l != list_head(typenames)) appendStringInfoChar(&string, ','); appendTypeNameToBuffer(typeName, &string); } return string.data; }
char* TypeNameToString | ( | const TypeName * | typeName | ) |
Definition at line 408 of file parse_type.c.
References appendTypeNameToBuffer(), and initStringInfo().
Referenced by AlterDomainDropConstraint(), AlterDomainValidateConstraint(), AlterTypeOwner(), compute_return_type(), CreateCast(), defGetString(), defGetTypeLength(), DefineAggregate(), DefineDomain(), DefineOpClass(), does_not_exist_skipping(), examine_parameter_list(), get_object_address_type(), LookupTypeName(), LookupTypeNameOid(), MergeAttributes(), typenameType(), and typenameTypeMod().
{ StringInfoData string; initStringInfo(&string); appendTypeNameToBuffer(typeName, &string); return string.data; }
Type typenameType | ( | ParseState * | pstate, | |
const TypeName * | typeName, | |||
int32 * | typmod_p | |||
) |
Definition at line 195 of file parse_type.c.
References ereport, errcode(), errmsg(), ERROR, GETSTRUCT, TypeName::location, LookupTypeName(), NULL, parser_errposition(), and TypeNameToString().
Referenced by ATExecAddColumn(), ATExecAddOf(), ATExecAlterColumnType(), DefineDomain(), DefineType(), transformColumnType(), transformOfType(), typenameTypeId(), and typenameTypeIdAndMod().
{ Type tup; tup = LookupTypeName(pstate, typeName, typmod_p); if (tup == NULL) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", TypeNameToString(typeName)), parser_errposition(pstate, typeName->location))); if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" is only a shell", TypeNameToString(typeName)), parser_errposition(pstate, typeName->location))); return tup; }
Oid typenameTypeId | ( | ParseState * | pstate, | |
const TypeName * | typeName | |||
) |
Definition at line 222 of file parse_type.c.
References HeapTupleGetOid, NULL, ReleaseSysCache(), and typenameType().
Referenced by AlterDomainAddConstraint(), AlterDomainDefault(), AlterDomainDropConstraint(), AlterDomainNotNull(), AlterDomainValidateConstraint(), AlterEnum(), AlterTypeNamespace(), check_object_ownership(), CreateCast(), DefineAggregate(), DefineOpClass(), DefineOperator(), DefineRange(), DefineRelation(), DefineType(), does_not_exist_skipping(), get_object_address(), LookupOperNameTypeNames(), objectNamesToOids(), PrepareQuery(), processTypesSpec(), RenameConstraint(), RenameType(), and transformAExprOf().
{ Oid typoid; Type tup; tup = typenameType(pstate, typeName, NULL); typoid = HeapTupleGetOid(tup); ReleaseSysCache(tup); return typoid; }
void typenameTypeIdAndMod | ( | ParseState * | pstate, | |
const TypeName * | typeName, | |||
Oid * | typeid_p, | |||
int32 * | typmod_p | |||
) |
Definition at line 241 of file parse_type.c.
References HeapTupleGetOid, ReleaseSysCache(), and typenameType().
Referenced by addRangeTableEntryForFunction(), ATExecAddColumn(), ATPrepAlterColumnType(), BuildDescForRelation(), flatten_set_variable_args(), MergeAttributes(), parseTypeString(), transformExprRecurse(), transformTypeCast(), and transformXmlSerialize().
{ Type tup; tup = typenameType(pstate, typeName, typmod_p); *typeid_p = HeapTupleGetOid(tup); ReleaseSysCache(tup); }
static int32 typenameTypeMod | ( | ParseState * | pstate, | |
const TypeName * | typeName, | |||
Type | typ | |||
) | [static] |
Definition at line 263 of file parse_type.c.
References cancel_parser_errposition_callback(), construct_array(), CStringGetDatum, CSTRINGOID, DatumGetInt32, ereport, errcode(), errmsg(), ERROR, ColumnRef::fields, GETSTRUCT, InvalidOid, IsA, Value::ValUnion::ival, lfirst, linitial, list_length(), TypeName::location, NIL, OidFunctionCall1, palloc(), parser_errposition(), pfree(), PointerGetDatum, setup_parser_errposition_callback(), snprintf(), Value::ValUnion::str, strVal, tm, TypeName::typemod, TypeNameToString(), TypeName::typmods, Value::val, and A_Const::val.
Referenced by LookupTypeName().
{ int32 result; Oid typmodin; Datum *datums; int n; ListCell *l; ArrayType *arrtypmod; ParseCallbackState pcbstate; /* Return prespecified typmod if no typmod expressions */ if (typeName->typmods == NIL) return typeName->typemod; /* * Else, type had better accept typmods. We give a special error message * for the shell-type case, since a shell couldn't possibly have a * typmodin function. */ if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type modifier cannot be specified for shell type \"%s\"", TypeNameToString(typeName)), parser_errposition(pstate, typeName->location))); typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin; if (typmodin == InvalidOid) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type modifier is not allowed for type \"%s\"", TypeNameToString(typeName)), parser_errposition(pstate, typeName->location))); /* * Convert the list of raw-grammar-output expressions to a cstring array. * Currently, we allow simple numeric constants, string literals, and * identifiers; possibly this list could be extended. */ datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum)); n = 0; foreach(l, typeName->typmods) { Node *tm = (Node *) lfirst(l); char *cstr = NULL; if (IsA(tm, A_Const)) { A_Const *ac = (A_Const *) tm; if (IsA(&ac->val, Integer)) { cstr = (char *) palloc(32); snprintf(cstr, 32, "%ld", (long) ac->val.val.ival); } else if (IsA(&ac->val, Float) || IsA(&ac->val, String)) { /* we can just use the str field directly. */ cstr = ac->val.val.str; } } else if (IsA(tm, ColumnRef)) { ColumnRef *cr = (ColumnRef *) tm; if (list_length(cr->fields) == 1 && IsA(linitial(cr->fields), String)) cstr = strVal(linitial(cr->fields)); } if (!cstr) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type modifiers must be simple constants or identifiers"), parser_errposition(pstate, typeName->location))); datums[n++] = CStringGetDatum(cstr); } /* hardwired knowledge about cstring's representation details here */ arrtypmod = construct_array(datums, n, CSTRINGOID, -2, false, 'c'); /* arrange to report location if type's typmodin function fails */ setup_parser_errposition_callback(&pcbstate, pstate, typeName->location); result = DatumGetInt32(OidFunctionCall1(typmodin, PointerGetDatum(arrtypmod))); cancel_parser_errposition_callback(&pcbstate); pfree(datums); pfree(arrtypmod); return result; }
Definition at line 571 of file parse_type.c.
References GETSTRUCT.
Referenced by coerce_type().
{ Form_pg_type typtup; typtup = (Form_pg_type) GETSTRUCT(typ); return typtup->typcollation; }
Definition at line 521 of file parse_type.c.
References elog, ERROR, HeapTupleGetOid, and NULL.
Referenced by AlterTypeOwner(), compute_return_type(), examine_parameter_list(), FuncNameAsType(), get_object_address_type(), and LookupTypeNameOid().
{ if (tp == NULL) /* probably useless */ elog(ERROR, "typeTypeId() called with NULL type struct"); return HeapTupleGetOid(tp); }
char* typeTypeName | ( | Type | t | ) |
Definition at line 550 of file parse_type.c.
References GETSTRUCT, NameStr, and pstrdup().
{ Form_pg_type typ; typ = (Form_pg_type) GETSTRUCT(t); /* pstrdup here because result may need to outlive the syscache entry */ return pstrdup(NameStr(typ->typname)); }
Definition at line 561 of file parse_type.c.
References GETSTRUCT.
Referenced by FuncNameAsType().
{ Form_pg_type typtup; typtup = (Form_pg_type) GETSTRUCT(typ); return typtup->typrelid; }