00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/htup_details.h"
00018 #include "catalog/namespace.h"
00019 #include "catalog/pg_type.h"
00020 #include "lib/stringinfo.h"
00021 #include "nodes/makefuncs.h"
00022 #include "parser/parser.h"
00023 #include "parser/parse_type.h"
00024 #include "utils/array.h"
00025 #include "utils/builtins.h"
00026 #include "utils/datum.h"
00027 #include "utils/lsyscache.h"
00028 #include "utils/syscache.h"
00029
00030
00031 static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
00032 Type typ);
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 Type
00058 LookupTypeName(ParseState *pstate, const TypeName *typeName,
00059 int32 *typmod_p)
00060 {
00061 Oid typoid;
00062 HeapTuple tup;
00063 int32 typmod;
00064
00065 if (typeName->names == NIL)
00066 {
00067
00068 typoid = typeName->typeOid;
00069 }
00070 else if (typeName->pct_type)
00071 {
00072
00073 RangeVar *rel = makeRangeVar(NULL, NULL, typeName->location);
00074 char *field = NULL;
00075 Oid relid;
00076 AttrNumber attnum;
00077
00078
00079 switch (list_length(typeName->names))
00080 {
00081 case 1:
00082 ereport(ERROR,
00083 (errcode(ERRCODE_SYNTAX_ERROR),
00084 errmsg("improper %%TYPE reference (too few dotted names): %s",
00085 NameListToString(typeName->names)),
00086 parser_errposition(pstate, typeName->location)));
00087 break;
00088 case 2:
00089 rel->relname = strVal(linitial(typeName->names));
00090 field = strVal(lsecond(typeName->names));
00091 break;
00092 case 3:
00093 rel->schemaname = strVal(linitial(typeName->names));
00094 rel->relname = strVal(lsecond(typeName->names));
00095 field = strVal(lthird(typeName->names));
00096 break;
00097 case 4:
00098 rel->catalogname = strVal(linitial(typeName->names));
00099 rel->schemaname = strVal(lsecond(typeName->names));
00100 rel->relname = strVal(lthird(typeName->names));
00101 field = strVal(lfourth(typeName->names));
00102 break;
00103 default:
00104 ereport(ERROR,
00105 (errcode(ERRCODE_SYNTAX_ERROR),
00106 errmsg("improper %%TYPE reference (too many dotted names): %s",
00107 NameListToString(typeName->names)),
00108 parser_errposition(pstate, typeName->location)));
00109 break;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119 relid = RangeVarGetRelid(rel, NoLock, false);
00120 attnum = get_attnum(relid, field);
00121 if (attnum == InvalidAttrNumber)
00122 ereport(ERROR,
00123 (errcode(ERRCODE_UNDEFINED_COLUMN),
00124 errmsg("column \"%s\" of relation \"%s\" does not exist",
00125 field, rel->relname),
00126 parser_errposition(pstate, typeName->location)));
00127 typoid = get_atttype(relid, attnum);
00128
00129
00130 Assert(typeName->arrayBounds == NIL);
00131
00132
00133 ereport(NOTICE,
00134 (errmsg("type reference %s converted to %s",
00135 TypeNameToString(typeName),
00136 format_type_be(typoid))));
00137 }
00138 else
00139 {
00140
00141 char *schemaname;
00142 char *typname;
00143
00144
00145 DeconstructQualifiedName(typeName->names, &schemaname, &typname);
00146
00147 if (schemaname)
00148 {
00149
00150 Oid namespaceId;
00151
00152 namespaceId = LookupExplicitNamespace(schemaname, false);
00153 typoid = GetSysCacheOid2(TYPENAMENSP,
00154 PointerGetDatum(typname),
00155 ObjectIdGetDatum(namespaceId));
00156 }
00157 else
00158 {
00159
00160 typoid = TypenameGetTypid(typname);
00161 }
00162
00163
00164 if (typeName->arrayBounds != NIL)
00165 typoid = get_array_type(typoid);
00166 }
00167
00168 if (!OidIsValid(typoid))
00169 {
00170 if (typmod_p)
00171 *typmod_p = -1;
00172 return NULL;
00173 }
00174
00175 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
00176 if (!HeapTupleIsValid(tup))
00177 elog(ERROR, "cache lookup failed for type %u", typoid);
00178
00179 typmod = typenameTypeMod(pstate, typeName, (Type) tup);
00180
00181 if (typmod_p)
00182 *typmod_p = typmod;
00183
00184 return (Type) tup;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194 Type
00195 typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
00196 {
00197 Type tup;
00198
00199 tup = LookupTypeName(pstate, typeName, typmod_p);
00200 if (tup == NULL)
00201 ereport(ERROR,
00202 (errcode(ERRCODE_UNDEFINED_OBJECT),
00203 errmsg("type \"%s\" does not exist",
00204 TypeNameToString(typeName)),
00205 parser_errposition(pstate, typeName->location)));
00206 if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
00207 ereport(ERROR,
00208 (errcode(ERRCODE_UNDEFINED_OBJECT),
00209 errmsg("type \"%s\" is only a shell",
00210 TypeNameToString(typeName)),
00211 parser_errposition(pstate, typeName->location)));
00212 return tup;
00213 }
00214
00215
00216
00217
00218
00219
00220
00221 Oid
00222 typenameTypeId(ParseState *pstate, const TypeName *typeName)
00223 {
00224 Oid typoid;
00225 Type tup;
00226
00227 tup = typenameType(pstate, typeName, NULL);
00228 typoid = HeapTupleGetOid(tup);
00229 ReleaseSysCache(tup);
00230
00231 return typoid;
00232 }
00233
00234
00235
00236
00237
00238
00239
00240 void
00241 typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
00242 Oid *typeid_p, int32 *typmod_p)
00243 {
00244 Type tup;
00245
00246 tup = typenameType(pstate, typeName, typmod_p);
00247 *typeid_p = HeapTupleGetOid(tup);
00248 ReleaseSysCache(tup);
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 static int32
00263 typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
00264 {
00265 int32 result;
00266 Oid typmodin;
00267 Datum *datums;
00268 int n;
00269 ListCell *l;
00270 ArrayType *arrtypmod;
00271 ParseCallbackState pcbstate;
00272
00273
00274 if (typeName->typmods == NIL)
00275 return typeName->typemod;
00276
00277
00278
00279
00280
00281
00282 if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined)
00283 ereport(ERROR,
00284 (errcode(ERRCODE_SYNTAX_ERROR),
00285 errmsg("type modifier cannot be specified for shell type \"%s\"",
00286 TypeNameToString(typeName)),
00287 parser_errposition(pstate, typeName->location)));
00288
00289 typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
00290
00291 if (typmodin == InvalidOid)
00292 ereport(ERROR,
00293 (errcode(ERRCODE_SYNTAX_ERROR),
00294 errmsg("type modifier is not allowed for type \"%s\"",
00295 TypeNameToString(typeName)),
00296 parser_errposition(pstate, typeName->location)));
00297
00298
00299
00300
00301
00302
00303 datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
00304 n = 0;
00305 foreach(l, typeName->typmods)
00306 {
00307 Node *tm = (Node *) lfirst(l);
00308 char *cstr = NULL;
00309
00310 if (IsA(tm, A_Const))
00311 {
00312 A_Const *ac = (A_Const *) tm;
00313
00314 if (IsA(&ac->val, Integer))
00315 {
00316 cstr = (char *) palloc(32);
00317 snprintf(cstr, 32, "%ld", (long) ac->val.val.ival);
00318 }
00319 else if (IsA(&ac->val, Float) ||
00320 IsA(&ac->val, String))
00321 {
00322
00323 cstr = ac->val.val.str;
00324 }
00325 }
00326 else if (IsA(tm, ColumnRef))
00327 {
00328 ColumnRef *cr = (ColumnRef *) tm;
00329
00330 if (list_length(cr->fields) == 1 &&
00331 IsA(linitial(cr->fields), String))
00332 cstr = strVal(linitial(cr->fields));
00333 }
00334 if (!cstr)
00335 ereport(ERROR,
00336 (errcode(ERRCODE_SYNTAX_ERROR),
00337 errmsg("type modifiers must be simple constants or identifiers"),
00338 parser_errposition(pstate, typeName->location)));
00339 datums[n++] = CStringGetDatum(cstr);
00340 }
00341
00342
00343 arrtypmod = construct_array(datums, n, CSTRINGOID,
00344 -2, false, 'c');
00345
00346
00347 setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
00348
00349 result = DatumGetInt32(OidFunctionCall1(typmodin,
00350 PointerGetDatum(arrtypmod)));
00351
00352 cancel_parser_errposition_callback(&pcbstate);
00353
00354 pfree(datums);
00355 pfree(arrtypmod);
00356
00357 return result;
00358 }
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368 static void
00369 appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
00370 {
00371 if (typeName->names != NIL)
00372 {
00373
00374 ListCell *l;
00375
00376 foreach(l, typeName->names)
00377 {
00378 if (l != list_head(typeName->names))
00379 appendStringInfoChar(string, '.');
00380 appendStringInfoString(string, strVal(lfirst(l)));
00381 }
00382 }
00383 else
00384 {
00385
00386 appendStringInfoString(string, format_type_be(typeName->typeOid));
00387 }
00388
00389
00390
00391
00392
00393 if (typeName->pct_type)
00394 appendStringInfoString(string, "%TYPE");
00395
00396 if (typeName->arrayBounds != NIL)
00397 appendStringInfoString(string, "[]");
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407 char *
00408 TypeNameToString(const TypeName *typeName)
00409 {
00410 StringInfoData string;
00411
00412 initStringInfo(&string);
00413 appendTypeNameToBuffer(typeName, &string);
00414 return string.data;
00415 }
00416
00417
00418
00419
00420
00421 char *
00422 TypeNameListToString(List *typenames)
00423 {
00424 StringInfoData string;
00425 ListCell *l;
00426
00427 initStringInfo(&string);
00428 foreach(l, typenames)
00429 {
00430 TypeName *typeName = (TypeName *) lfirst(l);
00431
00432 Assert(IsA(typeName, TypeName));
00433 if (l != list_head(typenames))
00434 appendStringInfoChar(&string, ',');
00435 appendTypeNameToBuffer(typeName, &string);
00436 }
00437 return string.data;
00438 }
00439
00440
00441
00442
00443
00444
00445 Oid
00446 LookupCollation(ParseState *pstate, List *collnames, int location)
00447 {
00448 Oid colloid;
00449 ParseCallbackState pcbstate;
00450
00451 if (pstate)
00452 setup_parser_errposition_callback(&pcbstate, pstate, location);
00453
00454 colloid = get_collation_oid(collnames, false);
00455
00456 if (pstate)
00457 cancel_parser_errposition_callback(&pcbstate);
00458
00459 return colloid;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470 Oid
00471 GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
00472 {
00473 Oid result;
00474 Oid typcollation = get_typcollation(typeOid);
00475 int location = -1;
00476
00477 if (coldef->collClause)
00478 {
00479
00480 location = coldef->collClause->location;
00481 result = LookupCollation(pstate, coldef->collClause->collname,
00482 location);
00483 }
00484 else if (OidIsValid(coldef->collOid))
00485 {
00486
00487 result = coldef->collOid;
00488 }
00489 else
00490 {
00491
00492 result = typcollation;
00493 }
00494
00495
00496 if (OidIsValid(result) && !OidIsValid(typcollation))
00497 ereport(ERROR,
00498 (errcode(ERRCODE_DATATYPE_MISMATCH),
00499 errmsg("collations are not supported by type %s",
00500 format_type_be(typeOid)),
00501 parser_errposition(pstate, location)));
00502
00503 return result;
00504 }
00505
00506
00507
00508 Type
00509 typeidType(Oid id)
00510 {
00511 HeapTuple tup;
00512
00513 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
00514 if (!HeapTupleIsValid(tup))
00515 elog(ERROR, "cache lookup failed for type %u", id);
00516 return (Type) tup;
00517 }
00518
00519
00520 Oid
00521 typeTypeId(Type tp)
00522 {
00523 if (tp == NULL)
00524 elog(ERROR, "typeTypeId() called with NULL type struct");
00525 return HeapTupleGetOid(tp);
00526 }
00527
00528
00529 int16
00530 typeLen(Type t)
00531 {
00532 Form_pg_type typ;
00533
00534 typ = (Form_pg_type) GETSTRUCT(t);
00535 return typ->typlen;
00536 }
00537
00538
00539 bool
00540 typeByVal(Type t)
00541 {
00542 Form_pg_type typ;
00543
00544 typ = (Form_pg_type) GETSTRUCT(t);
00545 return typ->typbyval;
00546 }
00547
00548
00549 char *
00550 typeTypeName(Type t)
00551 {
00552 Form_pg_type typ;
00553
00554 typ = (Form_pg_type) GETSTRUCT(t);
00555
00556 return pstrdup(NameStr(typ->typname));
00557 }
00558
00559
00560 Oid
00561 typeTypeRelid(Type typ)
00562 {
00563 Form_pg_type typtup;
00564
00565 typtup = (Form_pg_type) GETSTRUCT(typ);
00566 return typtup->typrelid;
00567 }
00568
00569
00570 Oid
00571 typeTypeCollation(Type typ)
00572 {
00573 Form_pg_type typtup;
00574
00575 typtup = (Form_pg_type) GETSTRUCT(typ);
00576 return typtup->typcollation;
00577 }
00578
00579
00580
00581
00582
00583
00584 Datum
00585 stringTypeDatum(Type tp, char *string, int32 atttypmod)
00586 {
00587 Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
00588 Oid typinput = typform->typinput;
00589 Oid typioparam = getTypeIOParam(tp);
00590 Datum result;
00591
00592 result = OidInputFunctionCall(typinput, string,
00593 typioparam, atttypmod);
00594
00595 #ifdef RANDOMIZE_ALLOCATED_MEMORY
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 if (string && !typform->typbyval)
00608 {
00609 Datum result2;
00610
00611 result2 = OidInputFunctionCall(typinput, string,
00612 typioparam, atttypmod);
00613 if (!datumIsEqual(result, result2, typform->typbyval, typform->typlen))
00614 elog(WARNING, "type %s has unstable input conversion for \"%s\"",
00615 NameStr(typform->typname), string);
00616 }
00617 #endif
00618
00619 return result;
00620 }
00621
00622
00623 Oid
00624 typeidTypeRelid(Oid type_id)
00625 {
00626 HeapTuple typeTuple;
00627 Form_pg_type type;
00628 Oid result;
00629
00630 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
00631 if (!HeapTupleIsValid(typeTuple))
00632 elog(ERROR, "cache lookup failed for type %u", type_id);
00633
00634 type = (Form_pg_type) GETSTRUCT(typeTuple);
00635 result = type->typrelid;
00636 ReleaseSysCache(typeTuple);
00637 return result;
00638 }
00639
00640
00641
00642
00643 static void
00644 pts_error_callback(void *arg)
00645 {
00646 const char *str = (const char *) arg;
00647
00648 errcontext("invalid type name \"%s\"", str);
00649
00650
00651
00652
00653
00654
00655 errposition(0);
00656 }
00657
00658
00659
00660
00661
00662
00663 void
00664 parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p)
00665 {
00666 StringInfoData buf;
00667 List *raw_parsetree_list;
00668 SelectStmt *stmt;
00669 ResTarget *restarget;
00670 TypeCast *typecast;
00671 TypeName *typeName;
00672 ErrorContextCallback ptserrcontext;
00673
00674
00675 if (strspn(str, " \t\n\r\f") == strlen(str))
00676 goto fail;
00677
00678 initStringInfo(&buf);
00679 appendStringInfo(&buf, "SELECT NULL::%s", str);
00680
00681
00682
00683
00684 ptserrcontext.callback = pts_error_callback;
00685 ptserrcontext.arg = (void *) str;
00686 ptserrcontext.previous = error_context_stack;
00687 error_context_stack = &ptserrcontext;
00688
00689 raw_parsetree_list = raw_parser(buf.data);
00690
00691 error_context_stack = ptserrcontext.previous;
00692
00693
00694
00695
00696
00697 if (list_length(raw_parsetree_list) != 1)
00698 goto fail;
00699 stmt = (SelectStmt *) linitial(raw_parsetree_list);
00700 if (stmt == NULL ||
00701 !IsA(stmt, SelectStmt) ||
00702 stmt->distinctClause != NIL ||
00703 stmt->intoClause != NULL ||
00704 stmt->fromClause != NIL ||
00705 stmt->whereClause != NULL ||
00706 stmt->groupClause != NIL ||
00707 stmt->havingClause != NULL ||
00708 stmt->windowClause != NIL ||
00709 stmt->valuesLists != NIL ||
00710 stmt->sortClause != NIL ||
00711 stmt->limitOffset != NULL ||
00712 stmt->limitCount != NULL ||
00713 stmt->lockingClause != NIL ||
00714 stmt->withClause != NULL ||
00715 stmt->op != SETOP_NONE)
00716 goto fail;
00717 if (list_length(stmt->targetList) != 1)
00718 goto fail;
00719 restarget = (ResTarget *) linitial(stmt->targetList);
00720 if (restarget == NULL ||
00721 !IsA(restarget, ResTarget) ||
00722 restarget->name != NULL ||
00723 restarget->indirection != NIL)
00724 goto fail;
00725 typecast = (TypeCast *) restarget->val;
00726 if (typecast == NULL ||
00727 !IsA(typecast, TypeCast) ||
00728 typecast->arg == NULL ||
00729 !IsA(typecast->arg, A_Const))
00730 goto fail;
00731 typeName = typecast->typeName;
00732 if (typeName == NULL ||
00733 !IsA(typeName, TypeName))
00734 goto fail;
00735 if (typeName->setof)
00736 goto fail;
00737
00738 typenameTypeIdAndMod(NULL, typeName, typeid_p, typmod_p);
00739
00740 pfree(buf.data);
00741
00742 return;
00743
00744 fail:
00745 ereport(ERROR,
00746 (errcode(ERRCODE_SYNTAX_ERROR),
00747 errmsg("invalid type name \"%s\"", str)));
00748 }