pg_type.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:15k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * pg_type.c
  4.  *   routines to support manipulation of the pg_type relation
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.37.2.1 1999/08/02 05:56:55 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/heapam.h"
  16. #include "catalog/catname.h"
  17. #include "catalog/indexing.h"
  18. #include "catalog/pg_type.h"
  19. #include "miscadmin.h"
  20. #include "parser/parse_func.h"
  21. #include "utils/builtins.h"
  22. #include "utils/syscache.h"
  23. static Oid TypeShellMakeWithOpenRelation(Relation pg_type_desc,
  24.   char *typeName);
  25. /* ----------------------------------------------------------------
  26.  * TypeGetWithOpenRelation
  27.  *
  28.  * preforms a scan on pg_type for a type tuple with the
  29.  * given type name.
  30.  * ----------------------------------------------------------------
  31.  * pg_type_desc  -- reldesc for pg_type
  32.  * typeName  -- name of type to be fetched
  33.  * defined  -- has the type been defined?
  34.  */
  35. static Oid
  36. TypeGetWithOpenRelation(Relation pg_type_desc,
  37. char *typeName,
  38. bool *defined)
  39. {
  40. HeapScanDesc scan;
  41. HeapTuple tup;
  42. Oid typoid;
  43. static ScanKeyData typeKey[1] = {
  44. {0, Anum_pg_type_typname, F_NAMEEQ}
  45. };
  46. /* ----------------
  47.  * initialize the scan key and begin a scan of pg_type
  48.  * ----------------
  49.  */
  50. fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
  51. typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
  52. typeKey[0].sk_argument = PointerGetDatum(typeName);
  53. scan = heap_beginscan(pg_type_desc,
  54.   0,
  55.   SnapshotSelf, /* cache? */
  56.   1,
  57.   typeKey);
  58. /* ----------------
  59.  * get the type tuple, if it exists.
  60.  * ----------------
  61.  */
  62. tup = heap_getnext(scan, 0);
  63. /* ----------------
  64.  * if no type tuple exists for the given type name, then
  65.  * end the scan and return appropriate information.
  66.  * ----------------
  67.  */
  68. if (!HeapTupleIsValid(tup))
  69. {
  70. heap_endscan(scan);
  71. *defined = false;
  72. return InvalidOid;
  73. }
  74. /* ----------------
  75.  * here, the type tuple does exist so we pull information from
  76.  * the typisdefined field of the tuple and return the tuple's
  77.  * oid, which is the oid of the type.
  78.  * ----------------
  79.  */
  80. *defined = (bool) ((Form_pg_type) GETSTRUCT(tup))->typisdefined;
  81. typoid = tup->t_data->t_oid;
  82. heap_endscan(scan);
  83. return typoid;
  84. }
  85. /* ----------------------------------------------------------------
  86.  * TypeGet
  87.  *
  88.  * Finds the ObjectId of a type, even if uncommitted; "defined"
  89.  * is only set if the type has actually been defined, i.e., if
  90.  * the type tuple is not a shell.
  91.  *
  92.  * Note: the meat of this function is now in the function
  93.  *   TypeGetWithOpenRelation().  -cim 6/15/90
  94.  *
  95.  * Also called from util/remove.c
  96.  * ----------------------------------------------------------------
  97.  */
  98. Oid
  99. TypeGet(char *typeName, /* name of type to be fetched */
  100. bool *defined) /* has the type been defined? */
  101. {
  102. Relation pg_type_desc;
  103. Oid typeoid;
  104. /* ----------------
  105.  * open the pg_type relation
  106.  * ----------------
  107.  */
  108. pg_type_desc = heap_openr(TypeRelationName);
  109. /* ----------------
  110.  * scan the type relation for the information we want
  111.  * ----------------
  112.  */
  113. typeoid = TypeGetWithOpenRelation(pg_type_desc,
  114.   typeName,
  115.   defined);
  116. /* ----------------
  117.  * close the type relation and return the type oid.
  118.  * ----------------
  119.  */
  120. heap_close(pg_type_desc);
  121. return typeoid;
  122. }
  123. /* ----------------------------------------------------------------
  124.  * TypeShellMakeWithOpenRelation
  125.  *
  126.  * ----------------------------------------------------------------
  127.  */
  128. static Oid
  129. TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
  130. {
  131. int i;
  132. HeapTuple tup;
  133. Datum values[Natts_pg_type];
  134. char nulls[Natts_pg_type];
  135. Oid typoid;
  136. NameData name;
  137. TupleDesc tupDesc;
  138. /* ----------------
  139.  * initialize our *nulls and *values arrays
  140.  * ----------------
  141.  */
  142. for (i = 0; i < Natts_pg_type; ++i)
  143. {
  144. nulls[i] = ' ';
  145. values[i] = (Datum) NULL; /* redundant, but safe */
  146. }
  147. /* ----------------
  148.  * initialize *values with the type name and
  149.  * ----------------
  150.  */
  151. i = 0;
  152. namestrcpy(&name, typeName);
  153. values[i++] = NameGetDatum(&name); /* 1 */
  154. values[i++] = (Datum) InvalidOid; /* 2 */
  155. values[i++] = (Datum) (int16) 0; /* 3 */
  156. values[i++] = (Datum) (int16) 0; /* 4 */
  157. values[i++] = (Datum) (bool) 0; /* 5 */
  158. values[i++] = (Datum) (bool) 0; /* 6 */
  159. values[i++] = (Datum) (bool) 0; /* 7 */
  160. values[i++] = (Datum) (bool) 0; /* 8 */
  161. values[i++] = (Datum) InvalidOid; /* 9 */
  162. values[i++] = (Datum) InvalidOid; /* 10 */
  163. values[i++] = (Datum) InvalidOid; /* 11 */
  164. values[i++] = (Datum) InvalidOid; /* 12 */
  165. values[i++] = (Datum) InvalidOid; /* 13 */
  166. values[i++] = (Datum) InvalidOid; /* 14 */
  167. values[i++] = (Datum) 'i'; /* 15 */
  168. /*
  169.  * ... and fill typdefault with a bogus value
  170.  */
  171. values[i++] = (Datum) fmgr(F_TEXTIN, typeName); /* 15 */
  172. /* ----------------
  173.  * create a new type tuple with FormHeapTuple
  174.  * ----------------
  175.  */
  176. tupDesc = pg_type_desc->rd_att;
  177. tup = heap_formtuple(tupDesc, values, nulls);
  178. /* ----------------
  179.  * insert the tuple in the relation and get the tuple's oid.
  180.  * ----------------
  181.  */
  182. heap_insert(pg_type_desc, tup);
  183. typoid = tup->t_data->t_oid;
  184. if (RelationGetForm(pg_type_desc)->relhasindex)
  185. {
  186. Relation idescs[Num_pg_type_indices];
  187. CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
  188. CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
  189. CatalogCloseIndices(Num_pg_type_indices, idescs);
  190. }
  191. /* ----------------
  192.  * free the tuple and return the type-oid
  193.  * ----------------
  194.  */
  195. pfree(tup);
  196. return typoid;
  197. }
  198. /* ----------------------------------------------------------------
  199.  * TypeShellMake
  200.  *
  201.  * This procedure inserts a "shell" tuple into the type
  202.  * relation.  The type tuple inserted has invalid values
  203.  * and in particular, the "typisdefined" field is false.
  204.  *
  205.  * This is used so that a tuple exists in the catalogs.
  206.  * The invalid fields should be fixed up sometime after
  207.  * this routine is called, and then the "typeisdefined"
  208.  * field is set to true. -cim 6/15/90
  209.  * ----------------------------------------------------------------
  210.  */
  211. Oid
  212. TypeShellMake(char *typeName)
  213. {
  214. Relation pg_type_desc;
  215. Oid typoid;
  216. Assert(PointerIsValid(typeName));
  217. /* ----------------
  218.  * open pg_type
  219.  * ----------------
  220.  */
  221. pg_type_desc = heap_openr(TypeRelationName);
  222. /* ----------------
  223.  * insert the shell tuple
  224.  * ----------------
  225.  */
  226. typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
  227. /* ----------------
  228.  * close pg_type and return the tuple's oid.
  229.  * ----------------
  230.  */
  231. heap_close(pg_type_desc);
  232. return typoid;
  233. }
  234. /* ----------------------------------------------------------------
  235.  * TypeCreate
  236.  *
  237.  * This does all the necessary work needed to define a new type.
  238.  * ----------------------------------------------------------------
  239.  */
  240. Oid
  241. TypeCreate(char *typeName,
  242.    Oid relationOid, /* only for 'c'atalog typeTypes */
  243.    int16 internalSize,
  244.    int16 externalSize,
  245.    char typeType,
  246.    char typDelim,
  247.    char *inputProcedure,
  248.    char *outputProcedure,
  249.    char *receiveProcedure,
  250.    char *sendProcedure,
  251.    char *elementTypeName,
  252.    char *defaultTypeValue, /* internal rep */
  253.    bool passedByValue,
  254.    char alignment)
  255. {
  256. int i,
  257. j;
  258. Relation pg_type_desc;
  259. HeapScanDesc pg_type_scan;
  260. Oid typeObjectId;
  261. Oid elementObjectId = InvalidOid;
  262. HeapTuple tup;
  263. char nulls[Natts_pg_type];
  264. char replaces[Natts_pg_type];
  265. Datum values[Natts_pg_type];
  266. char    *procname;
  267. char    *procs[4];
  268. bool defined;
  269. NameData name;
  270. TupleDesc tupDesc;
  271. Oid argList[8];
  272. static ScanKeyData typeKey[1] = {
  273. {0, Anum_pg_type_typname, F_NAMEEQ}
  274. };
  275. fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
  276. typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
  277. /* ----------------
  278.  * check that the type is not already defined.
  279.  * ----------------
  280.  */
  281. typeObjectId = TypeGet(typeName, &defined);
  282. if (OidIsValid(typeObjectId) && defined)
  283. elog(ERROR, "TypeCreate: type %s already defined", typeName);
  284. /* ----------------
  285.  * if this type has an associated elementType, then we check that
  286.  * it is defined.
  287.  * ----------------
  288.  */
  289. if (elementTypeName)
  290. {
  291. elementObjectId = TypeGet(elementTypeName, &defined);
  292. if (!defined)
  293. elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
  294. }
  295. /* ----------------
  296.  * XXX comment me
  297.  * ----------------
  298.  */
  299. if (externalSize == 0)
  300. externalSize = -1; /* variable length */
  301. /* ----------------
  302.  * initialize arrays needed by FormHeapTuple
  303.  * ----------------
  304.  */
  305. for (i = 0; i < Natts_pg_type; ++i)
  306. {
  307. nulls[i] = ' ';
  308. replaces[i] = 'r';
  309. values[i] = (Datum) NULL; /* redundant, but nice */
  310. }
  311. /*
  312.  * XXX
  313.  *
  314.  * Do this so that user-defined types have size -1 instead of zero if
  315.  * they are variable-length - this is so that everything else in the
  316.  * backend works.
  317.  */
  318. if (internalSize == 0)
  319. internalSize = -1;
  320. /* ----------------
  321.  * initialize the *values information
  322.  * ----------------
  323.  */
  324. i = 0;
  325. namestrcpy(&name, typeName);
  326. values[i++] = NameGetDatum(&name); /* 1 */
  327. values[i++] = (Datum) GetUserId(); /* 2 */
  328. values[i++] = (Datum) internalSize; /* 3 */
  329. values[i++] = (Datum) externalSize; /* 4 */
  330. values[i++] = (Datum) passedByValue; /* 5 */
  331. values[i++] = (Datum) typeType; /* 6 */
  332. values[i++] = (Datum) (bool) 1; /* 7 */
  333. values[i++] = (Datum) typDelim; /* 8 */
  334. values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
  335. values[i++] = (Datum) elementObjectId; /* 10 */
  336. procs[0] = inputProcedure;
  337. procs[1] = outputProcedure;
  338. procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
  339. procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
  340. for (j = 0; j < 4; ++j)
  341. {
  342. procname = procs[j];
  343. /*
  344.  * First look for a 1-argument func with all argtypes 0. This is
  345.  * valid for all four kinds of procedure.
  346.  */
  347. MemSet(argList, 0, 8 * sizeof(Oid));
  348. tup = SearchSysCacheTuple(PRONAME,
  349.   PointerGetDatum(procname),
  350.   Int32GetDatum(1),
  351.   PointerGetDatum(argList),
  352.   0);
  353. if (!HeapTupleIsValid(tup))
  354. {
  355. /*
  356.  * For array types, the input procedures may take 3 args (data
  357.  * value, element OID, atttypmod); the pg_proc argtype
  358.  * signature is 0,0,INT4OID.  The output procedures may take 2
  359.  * args (data value, element OID).
  360.  */
  361. if (OidIsValid(elementObjectId))
  362. {
  363. int nargs;
  364. if (j % 2)
  365. {
  366. /* output proc */
  367. nargs = 2;
  368. }
  369. else
  370. {
  371. /* input proc */
  372. nargs = 3;
  373. argList[2] = INT4OID;
  374. }
  375. tup = SearchSysCacheTuple(PRONAME,
  376.   PointerGetDatum(procname),
  377.   Int32GetDatum(nargs),
  378.   PointerGetDatum(argList),
  379.   0);
  380. }
  381. if (!HeapTupleIsValid(tup))
  382. func_error("TypeCreate", procname, 1, argList, NULL);
  383. }
  384. values[i++] = (Datum) tup->t_data->t_oid; /* 11 - 14 */
  385. }
  386. /* ----------------
  387.  * set default alignment
  388.  * ----------------
  389.  */
  390. values[i++] = (Datum) alignment; /* 15 */
  391. /* ----------------
  392.  * initialize the default value for this type.
  393.  * ----------------
  394.  */
  395. values[i] = (Datum) fmgr(F_TEXTIN, /* 16 */
  396.  PointerIsValid(defaultTypeValue)
  397.  ? defaultTypeValue : "-"); /* XXX default
  398.  * typdefault */
  399. /* ----------------
  400.  * open pg_type and begin a scan for the type name.
  401.  * ----------------
  402.  */
  403. pg_type_desc = heap_openr(TypeRelationName);
  404. /* -----------------
  405.  * Set a write lock initially so as not upgrade a read to a write
  406.  * when the heap_insert() or heap_replace() is called.
  407.  * -----------------
  408.  */
  409. LockRelation(pg_type_desc, AccessExclusiveLock);
  410. typeKey[0].sk_argument = PointerGetDatum(typeName);
  411. pg_type_scan = heap_beginscan(pg_type_desc,
  412.   0,
  413.   SnapshotSelf, /* cache? */
  414.   1,
  415.   typeKey);
  416. /* ----------------
  417.  * define the type either by adding a tuple to the type
  418.  * relation, or by updating the fields of the "shell" tuple
  419.  * already there.
  420.  * ----------------
  421.  */
  422. tup = heap_getnext(pg_type_scan, 0);
  423. if (HeapTupleIsValid(tup))
  424. {
  425. tup = heap_modifytuple(tup,
  426.    pg_type_desc,
  427.    values,
  428.    nulls,
  429.    replaces);
  430. setheapoverride(true);
  431. heap_replace(pg_type_desc, &tup->t_self, tup, NULL);
  432. setheapoverride(false);
  433. typeObjectId = tup->t_data->t_oid;
  434. }
  435. else
  436. {
  437. tupDesc = pg_type_desc->rd_att;
  438. tup = heap_formtuple(tupDesc,
  439.  values,
  440.  nulls);
  441. heap_insert(pg_type_desc, tup);
  442. typeObjectId = tup->t_data->t_oid;
  443. }
  444. /* ----------------
  445.  * finish up
  446.  * ----------------
  447.  */
  448. heap_endscan(pg_type_scan);
  449. if (RelationGetForm(pg_type_desc)->relhasindex)
  450. {
  451. Relation idescs[Num_pg_type_indices];
  452. CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
  453. CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
  454. CatalogCloseIndices(Num_pg_type_indices, idescs);
  455. }
  456. UnlockRelation(pg_type_desc, AccessExclusiveLock);
  457. heap_close(pg_type_desc);
  458. return typeObjectId;
  459. }
  460. /* ----------------------------------------------------------------
  461.  * TypeRename
  462.  *
  463.  * This renames a type
  464.  * ----------------------------------------------------------------
  465.  */
  466. void
  467. TypeRename(char *oldTypeName, char *newTypeName)
  468. {
  469. Relation pg_type_desc;
  470. Relation idescs[Num_pg_type_indices];
  471. HeapTuple oldtup,
  472. newtup;
  473. pg_type_desc = heap_openr(TypeRelationName);
  474. oldtup = SearchSysCacheTupleCopy(TYPNAME,
  475.  PointerGetDatum(oldTypeName),
  476.  0, 0, 0);
  477. if (!HeapTupleIsValid(oldtup))
  478. {
  479. heap_close(pg_type_desc);
  480. elog(ERROR, "TypeRename: type %s not defined", oldTypeName);
  481. }
  482. newtup = SearchSysCacheTuple(TYPNAME,
  483.  PointerGetDatum(newTypeName),
  484.  0, 0, 0);
  485. if (HeapTupleIsValid(newtup))
  486. {
  487. pfree(oldtup);
  488. heap_close(pg_type_desc);
  489. elog(ERROR, "TypeRename: type %s already defined", newTypeName);
  490. }
  491. namestrcpy(&(((Form_pg_type) GETSTRUCT(oldtup))->typname), newTypeName);
  492. setheapoverride(true);
  493. heap_replace(pg_type_desc, &oldtup->t_self, oldtup, NULL);
  494. setheapoverride(false);
  495. /* update the system catalog indices */
  496. CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
  497. CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, oldtup);
  498. CatalogCloseIndices(Num_pg_type_indices, idescs);
  499. pfree(oldtup);
  500. heap_close(pg_type_desc);
  501. }
  502. /*
  503.  * makeArrayTypeName(typeName);
  504.  *   - given a base type name, make an array of type name out of it
  505.  *
  506.  * the CALLER is responsible for pfreeing the
  507.  */
  508. char *
  509. makeArrayTypeName(char *typeName)
  510. {
  511. char    *arr;
  512. if (!typeName)
  513. return NULL;
  514. arr = palloc(strlen(typeName) + 2);
  515. arr[0] = '_';
  516. strcpy(arr + 1, typeName);
  517. return arr;
  518. }