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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * index.c
  4.  *   code to create and destroy POSTGRES index relations
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/catalog/index.c,v 1.81.2.1 1999/08/02 05:56:54 scrappy Exp $
  11.  *
  12.  *
  13.  * INTERFACE ROUTINES
  14.  * index_create() - Create a cataloged index relation
  15.  * index_destroy() - Removes index relation from catalogs
  16.  *
  17.  *
  18.  *-------------------------------------------------------------------------
  19.  */
  20. #include "postgres.h"
  21. #include "access/genam.h"
  22. #include "access/heapam.h"
  23. #include "access/istrat.h"
  24. #include "bootstrap/bootstrap.h"
  25. #include "catalog/catname.h"
  26. #include "catalog/heap.h"
  27. #include "catalog/index.h"
  28. #include "catalog/indexing.h"
  29. #include "catalog/pg_index.h"
  30. #include "catalog/pg_proc.h"
  31. #include "catalog/pg_type.h"
  32. #include "executor/executor.h"
  33. #include "miscadmin.h"
  34. #include "optimizer/clauses.h"
  35. #include "optimizer/prep.h"
  36. #include "parser/parse_func.h"
  37. #include "storage/smgr.h"
  38. #include "utils/builtins.h"
  39. #include "utils/relcache.h"
  40. #include "utils/syscache.h"
  41. #include "utils/temprel.h"
  42. /*
  43.  * macros used in guessing how many tuples are on a page.
  44.  */
  45. #define AVG_ATTR_SIZE 8
  46. #define NTUPLES_PER_PAGE(natts) 
  47. ((BLCKSZ - MAXALIGN(sizeof (PageHeaderData))) / 
  48. ((natts) * AVG_ATTR_SIZE + MAXALIGN(sizeof(HeapTupleHeaderData))))
  49. /* non-export function prototypes */
  50. static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
  51.    bool istemp);
  52. static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
  53. static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
  54.  List *attributeList,
  55.  int numatts, AttrNumber *attNums);
  56. static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
  57. static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname);
  58. static void InitializeAttributeOids(Relation indexRelation,
  59. int numatts,
  60. Oid indexoid);
  61. static void
  62. AppendAttributeTuples(Relation indexRelation, int numatts);
  63. static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
  64. FuncIndexInfo *funcInfo, int natts,
  65. AttrNumber *attNums, Oid *classOids, Node *predicate,
  66.    List *attributeList, bool islossy, bool unique, bool primary);
  67. static void DefaultBuild(Relation heapRelation, Relation indexRelation,
  68.  int numberOfAttributes, AttrNumber *attributeNumber,
  69.  IndexStrategy indexStrategy, uint16 parameterCount,
  70. Datum *parameter, FuncIndexInfoPtr funcInfo, PredInfo *predInfo);
  71. /* ----------------------------------------------------------------
  72.  *   sysatts is a structure containing attribute tuple forms
  73.  *   for system attributes (numbered -1, -2, ...).  This really
  74.  *   should be generated or eliminated or moved elsewhere. -cim 1/19/91
  75.  *
  76.  * typedef struct FormData_pg_attribute {
  77.  * Oid attrelid;
  78.  * NameData attname;
  79.  * Oid atttypid;
  80.  * uint32 attnvals;
  81.  * int16 attlen;
  82.  * AttrNumber attnum;
  83.  * uint32 attnelems;
  84.  * int32 attcacheoff;
  85.  * int32 atttypmod;
  86.  * bool attbyval;
  87.  * bool attisset;
  88.  * char attalign;
  89.  * bool attnotnull;
  90.  * bool atthasdef;
  91.  * } FormData_pg_attribute;
  92.  *
  93.  * ----------------------------------------------------------------
  94.  */
  95. static FormData_pg_attribute sysatts[] = {
  96. {0, {"ctid"}, TIDOID, 0, 6, -1, 0, -1, -1, '', '', 'i', '', ''},
  97. {0, {"oid"}, OIDOID, 0, 4, -2, 0, -1, -1, '01', '', 'i', '', ''},
  98. {0, {"xmin"}, XIDOID, 0, 4, -3, 0, -1, -1, '01', '', 'i', '', ''},
  99. {0, {"cmin"}, CIDOID, 0, 4, -4, 0, -1, -1, '01', '', 'i', '', ''},
  100. {0, {"xmax"}, XIDOID, 0, 4, -5, 0, -1, -1, '01', '', 'i', '', ''},
  101. {0, {"cmax"}, CIDOID, 0, 4, -6, 0, -1, -1, '01', '', 'i', '', ''},
  102. };
  103. /* ----------------------------------------------------------------
  104.  * GetHeapRelationOid
  105.  * ----------------------------------------------------------------
  106.  */
  107. static Oid
  108. GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
  109. {
  110. Oid indoid;
  111. Oid heapoid;
  112. indoid = RelnameFindRelid(indexRelationName);
  113. if ((!istemp && OidIsValid(indoid)) ||
  114. (istemp && get_temp_rel_by_name(indexRelationName) != NULL))
  115. elog(ERROR, "Cannot create index: '%s' already exists",
  116.  indexRelationName);
  117. heapoid = RelnameFindRelid(heapRelationName);
  118. if (!OidIsValid(heapoid))
  119. elog(ERROR, "Cannot create index on '%s': relation does not exist",
  120.  heapRelationName);
  121. return heapoid;
  122. }
  123. static TupleDesc
  124. BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
  125. {
  126. HeapTuple tuple;
  127. TupleDesc funcTupDesc;
  128. Oid retType;
  129. char    *funcname;
  130. int4 nargs;
  131. Oid    *argtypes;
  132. /*
  133.  * Allocate and zero a tuple descriptor.
  134.  */
  135. funcTupDesc = CreateTemplateTupleDesc(1);
  136. funcTupDesc->attrs[0] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
  137. MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
  138. /*
  139.  * Lookup the function for the return type.
  140.  */
  141. funcname = FIgetname(funcInfo);
  142. nargs = FIgetnArgs(funcInfo);
  143. argtypes = FIgetArglist(funcInfo);
  144. tuple = SearchSysCacheTuple(PRONAME,
  145. PointerGetDatum(funcname),
  146. Int32GetDatum(nargs),
  147. PointerGetDatum(argtypes),
  148. 0);
  149. if (!HeapTupleIsValid(tuple))
  150. func_error("BuildFuncTupleDesc", funcname, nargs, argtypes, NULL);
  151. retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
  152. /*
  153.  * Look up the return type in pg_type for the type length.
  154.  */
  155. tuple = SearchSysCacheTuple(TYPOID,
  156. ObjectIdGetDatum(retType),
  157. 0, 0, 0);
  158. if (!HeapTupleIsValid(tuple))
  159. elog(ERROR, "Function %s return type does not exist", FIgetname(funcInfo));
  160. /*
  161.  * Assign some of the attributes values. Leave the rest as 0.
  162.  */
  163. funcTupDesc->attrs[0]->attlen = ((Form_pg_type) GETSTRUCT(tuple))->typlen;
  164. funcTupDesc->attrs[0]->atttypid = retType;
  165. funcTupDesc->attrs[0]->attnum = 1;
  166. funcTupDesc->attrs[0]->attbyval = ((Form_pg_type) GETSTRUCT(tuple))->typbyval;
  167. funcTupDesc->attrs[0]->attcacheoff = -1;
  168. funcTupDesc->attrs[0]->atttypmod = -1;
  169. funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
  170. /*
  171.  * make the attributes name the same as the functions
  172.  */
  173. namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
  174. return funcTupDesc;
  175. }
  176. /* ----------------------------------------------------------------
  177.  * ConstructTupleDescriptor
  178.  * ----------------------------------------------------------------
  179.  */
  180. static TupleDesc
  181. ConstructTupleDescriptor(Oid heapoid,
  182.  Relation heapRelation,
  183.  List *attributeList,
  184.  int numatts,
  185.  AttrNumber *attNums)
  186. {
  187. TupleDesc heapTupDesc;
  188. TupleDesc indexTupDesc;
  189. IndexElem  *IndexKey;
  190. TypeName   *IndexKeyType;
  191. AttrNumber atnum; /* attributeNumber[attributeOffset] */
  192. AttrNumber atind;
  193. int natts; /* Form_pg_class->relnatts */
  194. char    *from; /* used to simplify memcpy below */
  195. char    *to; /* used to simplify memcpy below */
  196. int i;
  197. /* ----------------
  198.  * allocate the new tuple descriptor
  199.  * ----------------
  200.  */
  201. natts = RelationGetForm(heapRelation)->relnatts;
  202. indexTupDesc = CreateTemplateTupleDesc(numatts);
  203. /* ----------------
  204.  *
  205.  * ----------------
  206.  */
  207. /* ----------------
  208.  *   for each attribute we are indexing, obtain its attribute
  209.  *   tuple form from either the static table of system attribute
  210.  *   tuple forms or the relation tuple descriptor
  211.  * ----------------
  212.  */
  213. for (i = 0; i < numatts; i += 1)
  214. {
  215. /* ----------------
  216.  *  get the attribute number and make sure it's valid
  217.  * ----------------
  218.  */
  219. atnum = attNums[i];
  220. if (atnum > natts)
  221. elog(ERROR, "Cannot create index: attribute %d does not exist",
  222.  atnum);
  223. if (attributeList)
  224. {
  225. IndexKey = (IndexElem *) lfirst(attributeList);
  226. IndexKeyType = IndexKey->typename;
  227. attributeList = lnext(attributeList);
  228. }
  229. else
  230. IndexKeyType = NULL;
  231. indexTupDesc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
  232. /* ----------------
  233.  *  determine which tuple descriptor to copy
  234.  * ----------------
  235.  */
  236. if (!AttrNumberIsForUserDefinedAttr(atnum))
  237. {
  238. /* ----------------
  239.  *   here we are indexing on a system attribute (-1...-12)
  240.  *   so we convert atnum into a usable index 0...11 so we can
  241.  *   use it to dereference the array sysatts[] which stores
  242.  *   tuple descriptor information for system attributes.
  243.  * ----------------
  244.  */
  245. if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
  246. elog(ERROR, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
  247. atind = (-atnum) - 1;
  248. from = (char *) (&sysatts[atind]);
  249. }
  250. else
  251. {
  252. /* ----------------
  253.  *   here we are indexing on a normal attribute (1...n)
  254.  * ----------------
  255.  */
  256. heapTupDesc = RelationGetDescr(heapRelation);
  257. atind = AttrNumberGetAttrOffset(atnum);
  258. from = (char *) (heapTupDesc->attrs[atind]);
  259. }
  260. /* ----------------
  261.  *  now that we've determined the "from", let's copy
  262.  *  the tuple desc data...
  263.  * ----------------
  264.  */
  265. to = (char *) (indexTupDesc->attrs[i]);
  266. memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
  267. ((Form_pg_attribute) to)->attnum = i + 1;
  268. ((Form_pg_attribute) to)->attnotnull = false;
  269. ((Form_pg_attribute) to)->atthasdef = false;
  270. ((Form_pg_attribute) to)->attcacheoff = -1;
  271. ((Form_pg_attribute) to)->atttypmod = -1;
  272. ((Form_pg_attribute) to)->attalign = 'i';
  273. /*
  274.  * if the keytype is defined, we need to change the tuple form's
  275.  * atttypid & attlen field to match that of the key's type
  276.  */
  277. if (IndexKeyType != NULL)
  278. {
  279. HeapTuple tup;
  280. tup = SearchSysCacheTuple(TYPNAME,
  281.   PointerGetDatum(IndexKeyType->name),
  282.   0, 0, 0);
  283. if (!HeapTupleIsValid(tup))
  284. elog(ERROR, "create index: type '%s' undefined",
  285.  IndexKeyType->name);
  286. ((Form_pg_attribute) to)->atttypid = tup->t_data->t_oid;
  287. ((Form_pg_attribute) to)->attbyval =
  288. ((Form_pg_type) GETSTRUCT(tup))->typbyval;
  289. ((Form_pg_attribute) to)->attlen =
  290. ((Form_pg_type) GETSTRUCT(tup))->typlen;
  291. ((Form_pg_attribute) to)->attalign =
  292. ((Form_pg_type) GETSTRUCT(tup))->typalign;
  293. ((Form_pg_attribute) to)->atttypmod = IndexKeyType->typmod;
  294. }
  295. /* ----------------
  296.  *   now we have to drop in the proper relation descriptor
  297.  *   into the copied tuple form's attrelid and we should be
  298.  *   all set.
  299.  * ----------------
  300.  */
  301. ((Form_pg_attribute) to)->attrelid = heapoid;
  302. }
  303. return indexTupDesc;
  304. }
  305. /* ----------------------------------------------------------------
  306.  * AccessMethodObjectIdGetForm
  307.  * Returns the formated access method tuple given its object identifier.
  308.  *
  309.  * XXX ADD INDEXING
  310.  *
  311.  * Note:
  312.  * Assumes object identifier is valid.
  313.  * ----------------------------------------------------------------
  314.  */
  315. Form_pg_am
  316. AccessMethodObjectIdGetForm(Oid accessMethodObjectId)
  317. {
  318. Relation pg_am_desc;
  319. HeapScanDesc pg_am_scan;
  320. HeapTuple pg_am_tuple;
  321. ScanKeyData key;
  322. Form_pg_am aform;
  323. /* ----------------
  324.  * form a scan key for the pg_am relation
  325.  * ----------------
  326.  */
  327. ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
  328.    F_OIDEQ,
  329.    ObjectIdGetDatum(accessMethodObjectId));
  330. /* ----------------
  331.  * fetch the desired access method tuple
  332.  * ----------------
  333.  */
  334. pg_am_desc = heap_openr(AccessMethodRelationName);
  335. pg_am_scan = heap_beginscan(pg_am_desc, 0, SnapshotNow, 1, &key);
  336. pg_am_tuple = heap_getnext(pg_am_scan, 0);
  337. /* ----------------
  338.  * return NULL if not found
  339.  * ----------------
  340.  */
  341. if (!HeapTupleIsValid(pg_am_tuple))
  342. {
  343. heap_endscan(pg_am_scan);
  344. heap_close(pg_am_desc);
  345. return NULL;
  346. }
  347. /* ----------------
  348.  * if found am tuple, then copy the form and return the copy
  349.  * ----------------
  350.  */
  351. aform = (Form_pg_am) palloc(sizeof *aform);
  352. memcpy(aform, GETSTRUCT(pg_am_tuple), sizeof *aform);
  353. heap_endscan(pg_am_scan);
  354. heap_close(pg_am_desc);
  355. return aform;
  356. }
  357. /* ----------------------------------------------------------------
  358.  * ConstructIndexReldesc
  359.  * ----------------------------------------------------------------
  360.  */
  361. static void
  362. ConstructIndexReldesc(Relation indexRelation, Oid amoid)
  363. {
  364. extern GlobalMemory CacheCxt;
  365. MemoryContext oldcxt;
  366. /* ----------------
  367.  *   here we make certain to allocate the access method
  368.  *   tuple within the cache context lest it vanish when the
  369.  *   context changes
  370.  * ----------------
  371.  */
  372. if (!CacheCxt)
  373. CacheCxt = CreateGlobalMemory("Cache");
  374. oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
  375. indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
  376. MemoryContextSwitchTo(oldcxt);
  377. /* ----------------
  378.  *  XXX missing the initialization of some other fields
  379.  * ----------------
  380.  */
  381. indexRelation->rd_rel->relowner = GetUserId();
  382. indexRelation->rd_rel->relam = amoid;
  383. indexRelation->rd_rel->reltuples = 1; /* XXX */
  384. indexRelation->rd_rel->relkind = RELKIND_INDEX;
  385. }
  386. /* ----------------------------------------------------------------
  387.  * UpdateRelationRelation
  388.  * ----------------------------------------------------------------
  389.  */
  390. static Oid
  391. UpdateRelationRelation(Relation indexRelation, char *temp_relname)
  392. {
  393. Relation pg_class;
  394. HeapTuple tuple;
  395. Oid tupleOid;
  396. Relation idescs[Num_pg_class_indices];
  397. pg_class = heap_openr(RelationRelationName);
  398. /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
  399. tuple = heap_addheader(Natts_pg_class_fixed,
  400.    sizeof(*indexRelation->rd_rel),
  401.    (char *) indexRelation->rd_rel);
  402. /* ----------------
  403.  * the new tuple must have the same oid as the relcache entry for the
  404.  * index. sure would be embarassing to do this sort of thing in polite
  405.  * company.
  406.  * ----------------
  407.  */
  408. tuple->t_data->t_oid = RelationGetRelid(indexRelation);
  409. heap_insert(pg_class, tuple);
  410. if (temp_relname)
  411. create_temp_relation(temp_relname, tuple);
  412. /*
  413.  * During normal processing, we need to make sure that the system
  414.  * catalog indices are correct.  Bootstrap (initdb) time doesn't
  415.  * require this, because we make sure that the indices are correct
  416.  * just before exiting.
  417.  */
  418. if (!IsBootstrapProcessingMode())
  419. {
  420. CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
  421. CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
  422. CatalogCloseIndices(Num_pg_class_indices, idescs);
  423. }
  424. tupleOid = tuple->t_data->t_oid;
  425. pfree(tuple);
  426. heap_close(pg_class);
  427. return tupleOid;
  428. }
  429. /* ----------------------------------------------------------------
  430.  * InitializeAttributeOids
  431.  * ----------------------------------------------------------------
  432.  */
  433. static void
  434. InitializeAttributeOids(Relation indexRelation,
  435. int numatts,
  436. Oid indexoid)
  437. {
  438. TupleDesc tupleDescriptor;
  439. int i;
  440. tupleDescriptor = RelationGetDescr(indexRelation);
  441. for (i = 0; i < numatts; i += 1)
  442. tupleDescriptor->attrs[i]->attrelid = indexoid;
  443. }
  444. /* ----------------------------------------------------------------
  445.  * AppendAttributeTuples
  446.  *
  447.  * XXX For now, only change the ATTNUM attribute value
  448.  * ----------------------------------------------------------------
  449.  */
  450. static void
  451. AppendAttributeTuples(Relation indexRelation, int numatts)
  452. {
  453. Relation pg_attribute;
  454. HeapTuple init_tuple,
  455. cur_tuple = NULL,
  456. new_tuple;
  457. bool hasind;
  458. Relation idescs[Num_pg_attr_indices];
  459. Datum value[Natts_pg_attribute];
  460. char nullv[Natts_pg_attribute];
  461. char replace[Natts_pg_attribute];
  462. TupleDesc indexTupDesc;
  463. int i;
  464. /* ----------------
  465.  * open the attribute relation
  466.  * XXX ADD INDEXING
  467.  * ----------------
  468.  */
  469. pg_attribute = heap_openr(AttributeRelationName);
  470. /* ----------------
  471.  * initialize *null, *replace and *value
  472.  * ----------------
  473.  */
  474. MemSet(nullv, ' ', Natts_pg_attribute);
  475. MemSet(replace, ' ', Natts_pg_attribute);
  476. /* ----------------
  477.  * create the first attribute tuple.
  478.  * XXX For now, only change the ATTNUM attribute value
  479.  * ----------------
  480.  */
  481. replace[Anum_pg_attribute_attnum - 1] = 'r';
  482. replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
  483. value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
  484. value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
  485. init_tuple = heap_addheader(Natts_pg_attribute,
  486. ATTRIBUTE_TUPLE_SIZE,
  487.  (char *) (indexRelation->rd_att->attrs[0]));
  488. hasind = false;
  489. if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex)
  490. {
  491. hasind = true;
  492. CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
  493. }
  494. /* ----------------
  495.  * insert the first attribute tuple.
  496.  * ----------------
  497.  */
  498. cur_tuple = heap_modifytuple(init_tuple,
  499.  pg_attribute,
  500.  value,
  501.  nullv,
  502.  replace);
  503. pfree(init_tuple);
  504. heap_insert(pg_attribute, cur_tuple);
  505. if (hasind)
  506. CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, cur_tuple);
  507. /* ----------------
  508.  * now we use the information in the index cur_tuple
  509.  * descriptor to form the remaining attribute tuples.
  510.  * ----------------
  511.  */
  512. indexTupDesc = RelationGetDescr(indexRelation);
  513. for (i = 1; i < numatts; i += 1)
  514. {
  515. /* ----------------
  516.  * process the remaining attributes...
  517.  * ----------------
  518.  */
  519. memmove(GETSTRUCT(cur_tuple),
  520. (char *) indexTupDesc->attrs[i],
  521. ATTRIBUTE_TUPLE_SIZE);
  522. value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
  523. new_tuple = heap_modifytuple(cur_tuple,
  524.  pg_attribute,
  525.  value,
  526.  nullv,
  527.  replace);
  528. pfree(cur_tuple);
  529. heap_insert(pg_attribute, new_tuple);
  530. if (hasind)
  531. CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, new_tuple);
  532. /* ----------------
  533.  * ModifyHeapTuple returns a new copy of a cur_tuple
  534.  * so we free the original and use the copy..
  535.  * ----------------
  536.  */
  537. cur_tuple = new_tuple;
  538. }
  539. if (cur_tuple)
  540. pfree(cur_tuple);
  541. heap_close(pg_attribute);
  542. if (hasind)
  543. CatalogCloseIndices(Num_pg_attr_indices, idescs);
  544. }
  545. /* ----------------------------------------------------------------
  546.  * UpdateIndexRelation
  547.  * ----------------------------------------------------------------
  548.  */
  549. static void
  550. UpdateIndexRelation(Oid indexoid,
  551. Oid heapoid,
  552. FuncIndexInfo *funcInfo,
  553. int natts,
  554. AttrNumber *attNums,
  555. Oid *classOids,
  556. Node *predicate,
  557. List *attributeList,
  558. bool islossy,
  559. bool unique,
  560. bool primary)
  561. {
  562. Form_pg_index indexForm;
  563. IndexElem  *IndexKey;
  564. char    *predString;
  565. text    *predText;
  566. int predLen,
  567. itupLen;
  568. Relation pg_index;
  569. HeapTuple tuple;
  570. int i;
  571. /* ----------------
  572.  * allocate an Form_pg_index big enough to hold the
  573.  * index-predicate (if any) in string form
  574.  * ----------------
  575.  */
  576. if (predicate != NULL)
  577. {
  578. predString = nodeToString(predicate);
  579. predText = (text *) fmgr(F_TEXTIN, predString);
  580. pfree(predString);
  581. }
  582. else
  583. predText = (text *) fmgr(F_TEXTIN, "");
  584. predLen = VARSIZE(predText);
  585. itupLen = predLen + sizeof(FormData_pg_index);
  586. indexForm = (Form_pg_index) palloc(itupLen);
  587. memset(indexForm, 0, sizeof(FormData_pg_index));
  588. memmove((char *) &indexForm->indpred, (char *) predText, predLen);
  589. /* ----------------
  590.  * store the oid information into the index tuple form
  591.  * ----------------
  592.  */
  593. indexForm->indrelid = heapoid;
  594. indexForm->indexrelid = indexoid;
  595. indexForm->indproc = (PointerIsValid(funcInfo)) ?
  596. FIgetProcOid(funcInfo) : InvalidOid;
  597. indexForm->indislossy = islossy;
  598. indexForm->indisprimary = primary;
  599. indexForm->indisunique = unique;
  600. indexForm->indhaskeytype = 0;
  601. while (attributeList != NIL)
  602. {
  603. IndexKey = (IndexElem *) lfirst(attributeList);
  604. if (IndexKey->typename != NULL)
  605. {
  606. indexForm->indhaskeytype = 1;
  607. break;
  608. }
  609. attributeList = lnext(attributeList);
  610. }
  611. MemSet((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
  612. MemSet((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
  613. /* ----------------
  614.  * copy index key and op class information
  615.  * ----------------
  616.  */
  617. for (i = 0; i < natts; i += 1)
  618. {
  619. indexForm->indkey[i] = attNums[i];
  620. indexForm->indclass[i] = classOids[i];
  621. }
  622. /*
  623.  * If we have a functional index, add all attribute arguments
  624.  */
  625. if (PointerIsValid(funcInfo))
  626. {
  627. for (i = 1; i < FIgetnArgs(funcInfo); i++)
  628. indexForm->indkey[i] = attNums[i];
  629. }
  630. indexForm->indisclustered = ''; /* XXX constant */
  631. /* ----------------
  632.  * open the system catalog index relation
  633.  * ----------------
  634.  */
  635. pg_index = heap_openr(IndexRelationName);
  636. /* ----------------
  637.  * form a tuple to insert into pg_index
  638.  * ----------------
  639.  */
  640. tuple = heap_addheader(Natts_pg_index,
  641.    itupLen,
  642.    (char *) indexForm);
  643. /* ----------------
  644.  * insert the tuple into the pg_index
  645.  * XXX ADD INDEX TUPLES TOO
  646.  * ----------------
  647.  */
  648. heap_insert(pg_index, tuple);
  649. /* ----------------
  650.  * close the relation and free the tuple
  651.  * ----------------
  652.  */
  653. heap_close(pg_index);
  654. pfree(predText);
  655. pfree(indexForm);
  656. pfree(tuple);
  657. }
  658. /* ----------------------------------------------------------------
  659.  * UpdateIndexPredicate
  660.  * ----------------------------------------------------------------
  661.  */
  662. void
  663. UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
  664. {
  665. Node    *newPred;
  666. char    *predString;
  667. text    *predText;
  668. Relation pg_index;
  669. HeapTuple tuple;
  670. HeapTuple newtup;
  671. int i;
  672. Datum values[Natts_pg_index];
  673. char nulls[Natts_pg_index];
  674. char replace[Natts_pg_index];
  675. /*
  676.  * Construct newPred as a CNF expression equivalent to the OR of the
  677.  * original partial-index predicate ("oldPred") and the extension
  678.  * predicate ("predicate").
  679.  *
  680.  * This should really try to process the result to change things like
  681.  * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
  682.  * that if the extension predicate is NULL (i.e., it is being extended
  683.  * to be a complete index), then newPred will be NULL - in effect,
  684.  * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
  685.  */
  686. newPred = NULL;
  687. if (predicate != NULL)
  688. {
  689. newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
  690.   lcons(make_andclause((List *) oldPred),
  691. NIL)));
  692. newPred = (Node *) cnfify((Expr *) newPred, true);
  693. }
  694. /* translate the index-predicate to string form */
  695. if (newPred != NULL)
  696. {
  697. predString = nodeToString(newPred);
  698. predText = (text *) fmgr(F_TEXTIN, predString);
  699. pfree(predString);
  700. }
  701. else
  702. predText = (text *) fmgr(F_TEXTIN, "");
  703. /* open the index system catalog relation */
  704. pg_index = heap_openr(IndexRelationName);
  705. tuple = SearchSysCacheTuple(INDEXRELID,
  706. ObjectIdGetDatum(indexoid),
  707. 0, 0, 0);
  708. Assert(HeapTupleIsValid(tuple));
  709. for (i = 0; i < Natts_pg_index; i++)
  710. {
  711. nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
  712. replace[i] = ' ';
  713. values[i] = (Datum) NULL;
  714. }
  715. replace[Anum_pg_index_indpred - 1] = 'r';
  716. values[Anum_pg_index_indpred - 1] = (Datum) predText;
  717. newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
  718. heap_replace(pg_index, &newtup->t_self, newtup, NULL);
  719. pfree(newtup);
  720. heap_close(pg_index);
  721. pfree(predText);
  722. }
  723. /* ----------------------------------------------------------------
  724.  * InitIndexStrategy
  725.  * ----------------------------------------------------------------
  726.  */
  727. void
  728. InitIndexStrategy(int numatts,
  729.   Relation indexRelation,
  730.   Oid accessMethodObjectId)
  731. {
  732. IndexStrategy strategy;
  733. RegProcedure *support;
  734. uint16 amstrategies;
  735. uint16 amsupport;
  736. Oid attrelid;
  737. Size strsize;
  738. extern GlobalMemory CacheCxt;
  739. /* ----------------
  740.  * get information from the index relation descriptor
  741.  * ----------------
  742.  */
  743. attrelid = indexRelation->rd_att->attrs[0]->attrelid;
  744. amstrategies = indexRelation->rd_am->amstrategies;
  745. amsupport = indexRelation->rd_am->amsupport;
  746. /* ----------------
  747.  * get the size of the strategy
  748.  * ----------------
  749.  */
  750. strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
  751. /* ----------------
  752.  * allocate the new index strategy structure
  753.  *
  754.  * the index strategy has to be allocated in the same
  755.  * context as the relation descriptor cache or else
  756.  * it will be lost at the end of the transaction.
  757.  * ----------------
  758.  */
  759. if (!CacheCxt)
  760. CacheCxt = CreateGlobalMemory("Cache");
  761. strategy = (IndexStrategy)
  762. MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
  763. if (amsupport > 0)
  764. {
  765. strsize = numatts * (amsupport * sizeof(RegProcedure));
  766. support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
  767.   strsize);
  768. }
  769. else
  770. support = (RegProcedure *) NULL;
  771. /* ----------------
  772.  * fill in the index strategy structure with information
  773.  * from the catalogs. Note: we use heap override mode
  774.  * in order to be allowed to see the correct information in the
  775.  * catalogs, even though our transaction has not yet committed.
  776.  * ----------------
  777.  */
  778. setheapoverride(true);
  779. IndexSupportInitialize(strategy, support,
  780.    attrelid, accessMethodObjectId,
  781.    amstrategies, amsupport, numatts);
  782. setheapoverride(false);
  783. /* ----------------
  784.  * store the strategy information in the index reldesc
  785.  * ----------------
  786.  */
  787. RelationSetIndexSupport(indexRelation, strategy, support);
  788. }
  789. /* ----------------------------------------------------------------
  790.  * index_create
  791.  * ----------------------------------------------------------------
  792.  */
  793. void
  794. index_create(char *heapRelationName,
  795.  char *indexRelationName,
  796.  FuncIndexInfo *funcInfo,
  797.  List *attributeList,
  798.  Oid accessMethodObjectId,
  799.  int numatts,
  800.  AttrNumber *attNums,
  801.  Oid *classObjectId,
  802.  uint16 parameterCount,
  803.  Datum *parameter,
  804.  Node *predicate,
  805.  bool islossy,
  806.  bool unique,
  807.  bool primary)
  808. {
  809. Relation heapRelation;
  810. Relation indexRelation;
  811. TupleDesc indexTupDesc;
  812. Oid heapoid;
  813. Oid indexoid;
  814. PredInfo   *predInfo;
  815. bool istemp = (get_temp_rel_by_name(heapRelationName) != NULL);
  816. char    *temp_relname = NULL;
  817. /* ----------------
  818.  * check parameters
  819.  * ----------------
  820.  */
  821. if (numatts < 1)
  822. elog(ERROR, "must index at least one attribute");
  823. /* ----------------
  824.  *   get heap relation oid and open the heap relation
  825.  *   XXX ADD INDEXING
  826.  * ----------------
  827.  */
  828. heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
  829. heapRelation = heap_open(heapoid);
  830. /*
  831.  * Only SELECT ... FOR UPDATE are allowed
  832.  */
  833. LockRelation(heapRelation, ShareLock);
  834. /* ----------------
  835.  *   construct new tuple descriptor
  836.  * ----------------
  837.  */
  838. if (PointerIsValid(funcInfo))
  839. indexTupDesc = BuildFuncTupleDesc(funcInfo);
  840. else
  841. indexTupDesc = ConstructTupleDescriptor(heapoid,
  842. heapRelation,
  843. attributeList,
  844. numatts,
  845. attNums);
  846. /* invalidate cache so possible non-temp index is masked by temp */
  847. if (istemp)
  848. {
  849. Oid relid = RelnameFindRelid(indexRelationName);
  850. if (relid != InvalidOid)
  851. RelationForgetRelation(relid);
  852. }
  853. /* save user relation name because heap_create changes it */
  854. if (istemp)
  855. {
  856. temp_relname = pstrdup(indexRelationName); /* save original value */
  857. indexRelationName = palloc(NAMEDATALEN);
  858. strcpy(indexRelationName, temp_relname); /* heap_create will
  859.  * change this */
  860. }
  861. /* ----------------
  862.  * create the index relation
  863.  * ----------------
  864.  */
  865. indexRelation = heap_create(indexRelationName,
  866. indexTupDesc, false, istemp);
  867. /* ----------------
  868.  *   construct the index relation descriptor
  869.  *
  870.  *   XXX should have a proper way to create cataloged relations
  871.  * ----------------
  872.  */
  873. ConstructIndexReldesc(indexRelation, accessMethodObjectId);
  874. /* ----------------
  875.  *   add index to catalogs
  876.  *   (append RELATION tuple)
  877.  * ----------------
  878.  */
  879. indexoid = UpdateRelationRelation(indexRelation, temp_relname);
  880. /* ----------------
  881.  * Now get the index procedure (only relevant for functional indices).
  882.  * ----------------
  883.  */
  884. if (PointerIsValid(funcInfo))
  885. {
  886. HeapTuple proc_tup;
  887. proc_tup = SearchSysCacheTuple(PRONAME,
  888. PointerGetDatum(FIgetname(funcInfo)),
  889.  Int32GetDatum(FIgetnArgs(funcInfo)),
  890.  PointerGetDatum(FIgetArglist(funcInfo)),
  891.    0);
  892. if (!HeapTupleIsValid(proc_tup))
  893. {
  894. func_error("index_create", FIgetname(funcInfo),
  895.  FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL);
  896. }
  897. FIgetProcOid(funcInfo) = proc_tup->t_data->t_oid;
  898. }
  899. /* ----------------
  900.  * now update the object id's of all the attribute
  901.  * tuple forms in the index relation's tuple descriptor
  902.  * ----------------
  903.  */
  904. InitializeAttributeOids(indexRelation, numatts, indexoid);
  905. /* ----------------
  906.  *   append ATTRIBUTE tuples
  907.  * ----------------
  908.  */
  909. AppendAttributeTuples(indexRelation, numatts);
  910. /* ----------------
  911.  *   update pg_index
  912.  *   (append INDEX tuple)
  913.  *
  914.  *   Note that this stows away a representation of "predicate".
  915.  *   (Or, could define a rule to maintain the predicate) --Nels, Feb '92
  916.  * ----------------
  917.  */
  918. UpdateIndexRelation(indexoid, heapoid, funcInfo,
  919. numatts, attNums, classObjectId, predicate,
  920. attributeList, islossy, unique, primary);
  921. predInfo = (PredInfo *) palloc(sizeof(PredInfo));
  922. predInfo->pred = predicate;
  923. predInfo->oldPred = NULL;
  924. /* ----------------
  925.  *   initialize the index strategy
  926.  * ----------------
  927.  */
  928. InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
  929. /*
  930.  * If this is bootstrap (initdb) time, then we don't actually fill in
  931.  * the index yet.  We'll be creating more indices and classes later,
  932.  * so we delay filling them in until just before we're done with
  933.  * bootstrapping.  Otherwise, we call the routine that constructs the
  934.  * index.  The heap and index relations are closed by index_build().
  935.  */
  936. if (IsBootstrapProcessingMode())
  937. {
  938. index_register(heapRelationName, indexRelationName, numatts, attNums,
  939.    parameterCount, parameter, funcInfo, predInfo);
  940. }
  941. else
  942. {
  943. heapRelation = heap_openr(heapRelationName);
  944. index_build(heapRelation, indexRelation, numatts, attNums,
  945. parameterCount, parameter, funcInfo, predInfo);
  946. }
  947. }
  948. /* ----------------------------------------------------------------
  949.  *
  950.  * index_destroy
  951.  *
  952.  * ----------------------------------------------------------------
  953.  */
  954. void
  955. index_destroy(Oid indexId)
  956. {
  957. Relation userindexRelation;
  958. Relation indexRelation;
  959. Relation relationRelation;
  960. Relation attributeRelation;
  961. HeapTuple tuple;
  962. int16 attnum;
  963. Assert(OidIsValid(indexId));
  964. /* Open now to obtain lock by referencing table?  bjm */
  965. userindexRelation = index_open(indexId);
  966. /* ----------------
  967.  * fix RELATION relation
  968.  * ----------------
  969.  */
  970. relationRelation = heap_openr(RelationRelationName);
  971. tuple = SearchSysCacheTupleCopy(RELOID,
  972. ObjectIdGetDatum(indexId),
  973. 0, 0, 0);
  974. Assert(HeapTupleIsValid(tuple));
  975. heap_delete(relationRelation, &tuple->t_self, NULL);
  976. pfree(tuple);
  977. heap_close(relationRelation);
  978. /* ----------------
  979.  * fix ATTRIBUTE relation
  980.  * ----------------
  981.  */
  982. attributeRelation = heap_openr(AttributeRelationName);
  983. attnum = 1; /* indexes start at 1 */
  984. while (HeapTupleIsValid(tuple = SearchSysCacheTupleCopy(ATTNUM,
  985.    ObjectIdGetDatum(indexId),
  986.    Int16GetDatum(attnum),
  987. 0, 0)))
  988. {
  989. heap_delete(attributeRelation, &tuple->t_self, NULL);
  990. pfree(tuple);
  991. attnum++;
  992. }
  993. heap_close(attributeRelation);
  994. /* does something only if it is a temp index */
  995. remove_temp_relation(indexId);
  996. /* ----------------
  997.  * fix INDEX relation
  998.  * ----------------
  999.  */
  1000. tuple = SearchSysCacheTupleCopy(INDEXRELID,
  1001. ObjectIdGetDatum(indexId),
  1002. 0, 0, 0);
  1003. Assert(HeapTupleIsValid(tuple));
  1004. indexRelation = heap_openr(IndexRelationName);
  1005. heap_delete(indexRelation, &tuple->t_self, NULL);
  1006. pfree(tuple);
  1007. heap_close(indexRelation);
  1008. /*
  1009.  * flush cache and physically remove the file
  1010.  */
  1011. ReleaseRelationBuffers(userindexRelation);
  1012. if (smgrunlink(DEFAULT_SMGR, userindexRelation) != SM_SUCCESS)
  1013. elog(ERROR, "amdestroyr: unlink: %m");
  1014. index_close(userindexRelation);
  1015. RelationForgetRelation(RelationGetRelid(userindexRelation));
  1016. }
  1017. /* ----------------------------------------------------------------
  1018.  * index_build support
  1019.  * ----------------------------------------------------------------
  1020.  */
  1021. /* ----------------
  1022.  * FormIndexDatum
  1023.  * ----------------
  1024.  */
  1025. void
  1026. FormIndexDatum(int numberOfAttributes,
  1027.    AttrNumber *attributeNumber,
  1028.    HeapTuple heapTuple,
  1029.    TupleDesc heapDescriptor,
  1030.    Datum *datum,
  1031.    char *nullv,
  1032.    FuncIndexInfoPtr fInfo)
  1033. {
  1034. AttrNumber i;
  1035. int offset;
  1036. bool isNull;
  1037. /* ----------------
  1038.  * for each attribute we need from the heap tuple,
  1039.  * get the attribute and stick it into the datum and
  1040.  * null arrays.
  1041.  * ----------------
  1042.  */
  1043. for (i = 1; i <= numberOfAttributes; i++)
  1044. {
  1045. offset = AttrNumberGetAttrOffset(i);
  1046. datum[offset] = PointerGetDatum(GetIndexValue(heapTuple,
  1047.   heapDescriptor,
  1048.   offset,
  1049.   attributeNumber,
  1050.   fInfo,
  1051.   &isNull));
  1052. nullv[offset] = (isNull) ? 'n' : ' ';
  1053. }
  1054. }
  1055. /* ----------------
  1056.  * UpdateStats
  1057.  * ----------------
  1058.  */
  1059. void
  1060. UpdateStats(Oid relid, long reltuples, bool hasindex)
  1061. {
  1062. Relation whichRel;
  1063. Relation pg_class;
  1064. HeapTuple tuple;
  1065. HeapTuple newtup;
  1066. long relpages;
  1067. int i;
  1068. Form_pg_class rd_rel;
  1069. Relation idescs[Num_pg_class_indices];
  1070. Datum values[Natts_pg_class];
  1071. char nulls[Natts_pg_class];
  1072. char replace[Natts_pg_class];
  1073. HeapScanDesc pg_class_scan = NULL;
  1074. /* ----------------
  1075.  * This routine handles updates for both the heap and index relation
  1076.  * statistics. In order to guarantee that we're able to *see* the index
  1077.  * relation tuple, we bump the command counter id here.  The index
  1078.  * relation tuple was created in the current transaction.
  1079.  * ----------------
  1080.  */
  1081. CommandCounterIncrement();
  1082. /* ----------------
  1083.  * CommandCounterIncrement() flushes invalid cache entries, including
  1084.  * those for the heap and index relations for which we're updating
  1085.  * statistics. Now that the cache is flushed, it's safe to open the
  1086.  * relation again. We need the relation open in order to figure out
  1087.  * how many blocks it contains.
  1088.  * ----------------
  1089.  */
  1090. whichRel = RelationIdGetRelation(relid);
  1091. if (!RelationIsValid(whichRel))
  1092. elog(ERROR, "UpdateStats: cannot open relation id %u", relid);
  1093. /* ----------------
  1094.  * Find the RELATION relation tuple for the given relation.
  1095.  * ----------------
  1096.  */
  1097. pg_class = heap_openr(RelationRelationName);
  1098. if (!RelationIsValid(pg_class))
  1099. elog(ERROR, "UpdateStats: could not open RELATION relation");
  1100. if (!IsBootstrapProcessingMode())
  1101. {
  1102. tuple = SearchSysCacheTupleCopy(RELOID,
  1103. ObjectIdGetDatum(relid),
  1104. 0, 0, 0);
  1105. }
  1106. else
  1107. {
  1108. ScanKeyData key[1];
  1109. ScanKeyEntryInitialize(&key[0], 0,
  1110.    ObjectIdAttributeNumber,
  1111.    F_OIDEQ,
  1112.    ObjectIdGetDatum(relid));
  1113. pg_class_scan = heap_beginscan(pg_class, 0, SnapshotNow, 1, key);
  1114. tuple = heap_getnext(pg_class_scan, 0);
  1115. }
  1116. if (!HeapTupleIsValid(tuple))
  1117. {
  1118. if (IsBootstrapProcessingMode())
  1119. heap_endscan(pg_class_scan);
  1120. heap_close(pg_class);
  1121. elog(ERROR, "UpdateStats: cannot scan RELATION relation");
  1122. }
  1123. /* ----------------
  1124.  * Figure values to insert.
  1125.  *
  1126.  * If we found zero tuples in the scan, do NOT believe it; instead put
  1127.  * a bogus estimate into the statistics fields.  Otherwise, the common
  1128.  * pattern "CREATE TABLE; CREATE INDEX; insert data" leaves the table
  1129.  * with zero size statistics until a VACUUM is done.  The optimizer will
  1130.  * generate very bad plans if the stats claim the table is empty when
  1131.  * it is actually sizable.  See also CREATE TABLE in heap.c.
  1132.  * ----------------
  1133.  */
  1134. relpages = RelationGetNumberOfBlocks(whichRel);
  1135. if (reltuples == 0)
  1136. {
  1137. if (relpages == 0)
  1138. {
  1139. /* Bogus defaults for a virgin table, same as heap.c */
  1140. reltuples = 1000;
  1141. relpages = 10;
  1142. }
  1143. else if (whichRel->rd_rel->relkind == RELKIND_INDEX && relpages <= 2)
  1144. {
  1145. /* Empty index, leave bogus defaults in place */
  1146. reltuples = 1000;
  1147. }
  1148. else
  1149. reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
  1150. }
  1151. /*
  1152.  * We shouldn't have to do this, but we do...  Modify the reldesc in
  1153.  * place with the new values so that the cache contains the latest
  1154.  * copy.
  1155.  */
  1156. whichRel->rd_rel->relhasindex = hasindex;
  1157. whichRel->rd_rel->relpages = relpages;
  1158. whichRel->rd_rel->reltuples = reltuples;
  1159. /* ----------------
  1160.  * Update statistics in pg_class.
  1161.  * ----------------
  1162.  */
  1163. if (IsBootstrapProcessingMode())
  1164. {
  1165. /*
  1166.  * At bootstrap time, we don't need to worry about concurrency or
  1167.  * visibility of changes, so we cheat.
  1168.  */
  1169. rd_rel = (Form_pg_class) GETSTRUCT(tuple);
  1170. rd_rel->relpages = relpages;
  1171. rd_rel->reltuples = reltuples;
  1172. rd_rel->relhasindex = hasindex;
  1173. WriteBuffer(pg_class_scan->rs_cbuf);
  1174. }
  1175. else
  1176. {
  1177. /* During normal processing, must work harder. */
  1178. for (i = 0; i < Natts_pg_class; i++)
  1179. {
  1180. nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
  1181. replace[i] = ' ';
  1182. values[i] = (Datum) NULL;
  1183. }
  1184. replace[Anum_pg_class_relpages - 1] = 'r';
  1185. values[Anum_pg_class_relpages - 1] = (Datum) relpages;
  1186. replace[Anum_pg_class_reltuples - 1] = 'r';
  1187. values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
  1188. replace[Anum_pg_class_relhasindex - 1] = 'r';
  1189. values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex);
  1190. newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace);
  1191. heap_replace(pg_class, &tuple->t_self, newtup, NULL);
  1192. CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
  1193. CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
  1194. CatalogCloseIndices(Num_pg_class_indices, idescs);
  1195. pfree(newtup);
  1196. }
  1197. if (!IsBootstrapProcessingMode())
  1198. pfree(tuple);
  1199. else
  1200. heap_endscan(pg_class_scan);
  1201. heap_close(pg_class);
  1202. heap_close(whichRel);
  1203. }
  1204. /* -------------------------
  1205.  * FillDummyExprContext
  1206.  * Sets up dummy ExprContext and TupleTableSlot objects for use
  1207.  * with ExecQual.
  1208.  * -------------------------
  1209.  */
  1210. void
  1211. FillDummyExprContext(ExprContext *econtext,
  1212.  TupleTableSlot *slot,
  1213.  TupleDesc tupdesc,
  1214.  Buffer buffer)
  1215. {
  1216. econtext->ecxt_scantuple = slot;
  1217. econtext->ecxt_innertuple = NULL;
  1218. econtext->ecxt_outertuple = NULL;
  1219. econtext->ecxt_param_list_info = NULL;
  1220. econtext->ecxt_range_table = NULL;
  1221. slot->ttc_tupleDescriptor = tupdesc;
  1222. slot->ttc_buffer = buffer;
  1223. slot->ttc_shouldFree = false;
  1224. }
  1225. /* ----------------
  1226.  * DefaultBuild
  1227.  * ----------------
  1228.  */
  1229. static void
  1230. DefaultBuild(Relation heapRelation,
  1231.  Relation indexRelation,
  1232.  int numberOfAttributes,
  1233.  AttrNumber *attributeNumber,
  1234.  IndexStrategy indexStrategy, /* not used */
  1235.  uint16 parameterCount, /* not used */
  1236.  Datum *parameter, /* not used */
  1237.  FuncIndexInfoPtr funcInfo,
  1238.  PredInfo *predInfo)
  1239. {
  1240. HeapScanDesc scan;
  1241. HeapTuple heapTuple;
  1242. IndexTuple indexTuple;
  1243. TupleDesc heapDescriptor;
  1244. TupleDesc indexDescriptor;
  1245. Datum    *datum;
  1246. char    *nullv;
  1247. long reltuples,
  1248. indtuples;
  1249. #ifndef OMIT_PARTIAL_INDEX
  1250. ExprContext *econtext;
  1251. TupleTable tupleTable;
  1252. TupleTableSlot *slot;
  1253. #endif
  1254. Node    *predicate;
  1255. Node    *oldPred;
  1256. InsertIndexResult insertResult;
  1257. /* ----------------
  1258.  * more & better checking is needed
  1259.  * ----------------
  1260.  */
  1261. Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
  1262. /* ----------------
  1263.  * get the tuple descriptors from the relations so we know
  1264.  * how to form the index tuples..
  1265.  * ----------------
  1266.  */
  1267. heapDescriptor = RelationGetDescr(heapRelation);
  1268. indexDescriptor = RelationGetDescr(indexRelation);
  1269. /* ----------------
  1270.  * datum and null are arrays in which we collect the index attributes
  1271.  * when forming a new index tuple.
  1272.  * ----------------
  1273.  */
  1274. datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
  1275. nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
  1276. /*
  1277.  * If this is a predicate (partial) index, we will need to evaluate
  1278.  * the predicate using ExecQual, which requires the current tuple to
  1279.  * be in a slot of a TupleTable.  In addition, ExecQual must have an
  1280.  * ExprContext referring to that slot. Here, we initialize dummy
  1281.  * TupleTable and ExprContext objects for this purpose. --Nels, Feb
  1282.  * '92
  1283.  */
  1284. predicate = predInfo->pred;
  1285. oldPred = predInfo->oldPred;
  1286. #ifndef OMIT_PARTIAL_INDEX
  1287. if (predicate != NULL || oldPred != NULL)
  1288. {
  1289. tupleTable = ExecCreateTupleTable(1);
  1290. slot = ExecAllocTableSlot(tupleTable);
  1291. econtext = makeNode(ExprContext);
  1292. /* last parameter was junk being sent bjm 1998/08/17 */
  1293. FillDummyExprContext(econtext, slot, heapDescriptor, InvalidBuffer);
  1294. }
  1295. else
  1296. {
  1297. econtext = NULL;
  1298. tupleTable = 0;
  1299. slot = NULL;
  1300. }
  1301. #endif  /* OMIT_PARTIAL_INDEX */
  1302. /* ----------------
  1303.  * Ok, begin our scan of the base relation.
  1304.  * ----------------
  1305.  */
  1306. scan = heap_beginscan(heapRelation, /* relation */
  1307.   0, /* start at end */
  1308.   SnapshotNow, /* seeself */
  1309.   0, /* number of keys */
  1310.   (ScanKey) NULL); /* scan key */
  1311. reltuples = indtuples = 0;
  1312. /* ----------------
  1313.  * for each tuple in the base relation, we create an index
  1314.  * tuple and add it to the index relation.  We keep a running
  1315.  * count of the number of tuples so that we can update pg_class
  1316.  * with correct statistics when we're done building the index.
  1317.  * ----------------
  1318.  */
  1319. while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
  1320. {
  1321. reltuples++;
  1322. #ifndef OMIT_PARTIAL_INDEX
  1323. /*
  1324.  * If oldPred != NULL, this is an EXTEND INDEX command, so skip
  1325.  * this tuple if it was already in the existing partial index
  1326.  */
  1327. if (oldPred != NULL)
  1328. {
  1329. /* SetSlotContents(slot, heapTuple); */
  1330. slot->val = heapTuple;
  1331. if (ExecQual((List *) oldPred, econtext) == true)
  1332. {
  1333. indtuples++;
  1334. continue;
  1335. }
  1336. }
  1337. /*
  1338.  * Skip this tuple if it doesn't satisfy the partial-index
  1339.  * predicate
  1340.  */
  1341. if (predicate != NULL)
  1342. {
  1343. /* SetSlotContents(slot, heapTuple); */
  1344. slot->val = heapTuple;
  1345. if (ExecQual((List *) predicate, econtext) == false)
  1346. continue;
  1347. }
  1348. #endif  /* OMIT_PARTIAL_INDEX */
  1349. indtuples++;
  1350. /* ----------------
  1351.  * FormIndexDatum fills in its datum and null parameters
  1352.  * with attribute information taken from the given heap tuple.
  1353.  * ----------------
  1354.  */
  1355. FormIndexDatum(numberOfAttributes, /* num attributes */
  1356.    attributeNumber, /* array of att nums to extract */
  1357.    heapTuple, /* tuple from base relation */
  1358.    heapDescriptor, /* heap tuple's descriptor */
  1359.    datum, /* return: array of attributes */
  1360.    nullv, /* return: array of char's */
  1361.    funcInfo);
  1362. indexTuple = index_formtuple(indexDescriptor,
  1363.  datum,
  1364.  nullv);
  1365. indexTuple->t_tid = heapTuple->t_self;
  1366. insertResult = index_insert(indexRelation, datum, nullv,
  1367. &(heapTuple->t_self), heapRelation);
  1368. if (insertResult)
  1369. pfree(insertResult);
  1370. pfree(indexTuple);
  1371. }
  1372. heap_endscan(scan);
  1373. #ifndef OMIT_PARTIAL_INDEX
  1374. if (predicate != NULL || oldPred != NULL)
  1375. {
  1376. ExecDestroyTupleTable(tupleTable, false);
  1377. }
  1378. #endif  /* OMIT_PARTIAL_INDEX */
  1379. pfree(nullv);
  1380. pfree(datum);
  1381. /*
  1382.  * Okay, now update the reltuples and relpages statistics for both the
  1383.  * heap relation and the index.  These statistics are used by the
  1384.  * planner to choose a scan type.  They are maintained generally by
  1385.  * the vacuum daemon, but we update them here to make the index useful
  1386.  * as soon as possible.
  1387.  */
  1388. UpdateStats(RelationGetRelid(heapRelation), reltuples, true);
  1389. UpdateStats(RelationGetRelid(indexRelation), indtuples, false);
  1390. if (oldPred != NULL)
  1391. {
  1392. if (indtuples == reltuples)
  1393. predicate = NULL;
  1394. UpdateIndexPredicate(RelationGetRelid(indexRelation),
  1395.  oldPred, predicate);
  1396. }
  1397. }
  1398. /* ----------------
  1399.  * index_build
  1400.  * ----------------
  1401.  */
  1402. void
  1403. index_build(Relation heapRelation,
  1404. Relation indexRelation,
  1405. int numberOfAttributes,
  1406. AttrNumber *attributeNumber,
  1407. uint16 parameterCount,
  1408. Datum *parameter,
  1409. FuncIndexInfo *funcInfo,
  1410. PredInfo *predInfo)
  1411. {
  1412. RegProcedure procedure;
  1413. /* ----------------
  1414.  * sanity checks
  1415.  * ----------------
  1416.  */
  1417. Assert(RelationIsValid(indexRelation));
  1418. Assert(PointerIsValid(indexRelation->rd_am));
  1419. procedure = indexRelation->rd_am->ambuild;
  1420. /* ----------------
  1421.  * use the access method build procedure if supplied..
  1422.  * ----------------
  1423.  */
  1424. if (RegProcedureIsValid(procedure))
  1425. fmgr(procedure,
  1426.  heapRelation,
  1427.  indexRelation,
  1428.  numberOfAttributes,
  1429.  attributeNumber,
  1430.  RelationGetIndexStrategy(indexRelation),
  1431.  parameterCount,
  1432.  parameter,
  1433.  funcInfo,
  1434.  predInfo);
  1435. else
  1436. DefaultBuild(heapRelation,
  1437.  indexRelation,
  1438.  numberOfAttributes,
  1439.  attributeNumber,
  1440.  RelationGetIndexStrategy(indexRelation),
  1441.  parameterCount,
  1442.  parameter,
  1443.  funcInfo,
  1444.  predInfo);
  1445. }
  1446. /*
  1447.  * IndexIsUnique: given an index's relation OID, see if it
  1448.  * is unique using the system cache.
  1449.  */
  1450. bool
  1451. IndexIsUnique(Oid indexId)
  1452. {
  1453. HeapTuple tuple;
  1454. Form_pg_index index;
  1455. tuple = SearchSysCacheTuple(INDEXRELID,
  1456. ObjectIdGetDatum(indexId),
  1457. 0, 0, 0);
  1458. if (!HeapTupleIsValid(tuple))
  1459. {
  1460. elog(ERROR, "IndexIsUnique: can't find index id %u",
  1461.  indexId);
  1462. }
  1463. index = (Form_pg_index) GETSTRUCT(tuple);
  1464. Assert(index->indexrelid == indexId);
  1465. return index->indisunique;
  1466. }
  1467. /*
  1468.  * IndexIsUniqueNoCache: same as above function, but don't use the
  1469.  * system cache.  if we are called from btbuild, the transaction
  1470.  * that is adding the entry to pg_index has not been committed yet.
  1471.  * the system cache functions will do a heap scan, but only with
  1472.  * NowTimeQual, not SelfTimeQual, so it won't find tuples added
  1473.  * by the current transaction (which is good, because if the transaction
  1474.  * is aborted, you don't want the tuples sitting around in the cache).
  1475.  * so anyway, we have to do our own scan with SelfTimeQual.
  1476.  * this is only called when a new index is created, so it's OK
  1477.  * if it's slow.
  1478.  */
  1479. bool
  1480. IndexIsUniqueNoCache(Oid indexId)
  1481. {
  1482. Relation pg_index;
  1483. ScanKeyData skey[1];
  1484. HeapScanDesc scandesc;
  1485. HeapTuple tuple;
  1486. Form_pg_index index;
  1487. bool isunique;
  1488. pg_index = heap_openr(IndexRelationName);
  1489. ScanKeyEntryInitialize(&skey[0], (bits16) 0x0,
  1490.    Anum_pg_index_indexrelid,
  1491.    (RegProcedure) F_OIDEQ,
  1492.    ObjectIdGetDatum(indexId));
  1493. scandesc = heap_beginscan(pg_index, 0, SnapshotSelf, 1, skey);
  1494. /* NO CACHE */
  1495. tuple = heap_getnext(scandesc, 0);
  1496. if (!HeapTupleIsValid(tuple))
  1497. elog(ERROR, "IndexIsUniqueNoCache: can't find index id %u", indexId);
  1498. index = (Form_pg_index) GETSTRUCT(tuple);
  1499. Assert(index->indexrelid == indexId);
  1500. isunique = index->indisunique;
  1501. heap_endscan(scandesc);
  1502. heap_close(pg_index);
  1503. return isunique;
  1504. }