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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * defind.c
  4.  *   POSTGRES define, extend and remove index code.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.4.2.1 1999/08/02 05:56:58 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include "postgres.h"
  15. #include "access/genam.h"
  16. #include "access/heapam.h"
  17. #include "catalog/heap.h"
  18. #include "catalog/index.h"
  19. #include "catalog/pg_index.h"
  20. #include "catalog/pg_opclass.h"
  21. #include "catalog/pg_proc.h"
  22. #include "catalog/pg_type.h"
  23. #include "commands/defrem.h"
  24. #include "optimizer/clauses.h"
  25. #include "optimizer/prep.h"
  26. #include "parser/parsetree.h"
  27. #include "utils/builtins.h"
  28. #include "utils/syscache.h"
  29. #define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args!=NULL)
  30. /* non-export function prototypes */
  31. static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
  32. static void CheckPredExpr(Node *predicate, List *rangeTable,
  33.   Oid baseRelOid);
  34. static void
  35. CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
  36. static void FuncIndexArgs(IndexElem *funcIndex, AttrNumber *attNumP,
  37.   Oid *argTypes, Oid *opOidP, Oid relId);
  38. static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
  39.    Oid *opOidP, Oid relId);
  40. static char *GetDefaultOpClass(Oid atttypid);
  41. /*
  42.  * DefineIndex
  43.  * Creates a new index.
  44.  *
  45.  * 'attributeList' is a list of IndexElem specifying either a functional
  46.  * index or a list of attributes to index on.
  47.  * 'parameterList' is a list of ParamString specified in the with clause.
  48.  * 'predicate' is the qual specified in the where clause.
  49.  * 'rangetable' is for the predicate
  50.  *
  51.  * Exceptions:
  52.  * XXX
  53.  */
  54. void
  55. DefineIndex(char *heapRelationName,
  56. char *indexRelationName,
  57. char *accessMethodName,
  58. List *attributeList,
  59. List *parameterList,
  60. bool unique,
  61. bool primary,
  62. Expr *predicate,
  63. List *rangetable)
  64. {
  65. Oid    *classObjectId;
  66. Oid accessMethodId;
  67. Oid relationId;
  68. int numberOfAttributes;
  69. AttrNumber *attributeNumberA;
  70. HeapTuple tuple;
  71. uint16 parameterCount = 0;
  72. Datum    *parameterA = NULL;
  73. FuncIndexInfo fInfo;
  74. List    *cnfPred = NULL;
  75. bool lossy = FALSE;
  76. List    *pl;
  77. /*
  78.  * Handle attributes
  79.  */
  80. numberOfAttributes = length(attributeList);
  81. if (numberOfAttributes <= 0)
  82. elog(ERROR, "DefineIndex: must specify at least one attribute");
  83. /*
  84.  * compute heap relation id
  85.  */
  86. if ((relationId = RelnameFindRelid(heapRelationName)) == InvalidOid)
  87. {
  88. elog(ERROR, "DefineIndex: %s relation not found",
  89.  heapRelationName);
  90. }
  91. if (unique && strcmp(accessMethodName, "btree") != 0)
  92. elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
  93. if (numberOfAttributes > 1 && strcmp(accessMethodName, "btree") != 0)
  94. elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
  95. /*
  96.  * compute access method id
  97.  */
  98. tuple = SearchSysCacheTuple(AMNAME,
  99. PointerGetDatum(accessMethodName),
  100. 0, 0, 0);
  101. if (!HeapTupleIsValid(tuple))
  102. {
  103. elog(ERROR, "DefineIndex: %s access method not found",
  104.  accessMethodName);
  105. }
  106. accessMethodId = tuple->t_data->t_oid;
  107. /*
  108.  * Handle parameters [param list is now different (NOT USED, really) -
  109.  * ay 10/94]
  110.  *
  111.  * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
  112.  */
  113. foreach(pl, parameterList)
  114. {
  115. ParamString *param = (ParamString *) lfirst(pl);
  116. if (!strcasecmp(param->name, "islossy"))
  117. lossy = TRUE;
  118. }
  119. /*
  120.  * Convert the partial-index predicate from parsetree form to plan
  121.  * form, so it can be readily evaluated during index creation. Note:
  122.  * "predicate" comes in as a list containing (1) the predicate itself
  123.  * (a where_clause), and (2) a corresponding range table.
  124.  *
  125.  * [(1) is 'predicate' and (2) is 'rangetable' now. - ay 10/94]
  126.  */
  127. if (predicate != NULL && rangetable != NIL)
  128. {
  129. cnfPred = cnfify((Expr *) copyObject(predicate), true);
  130. fix_opids(cnfPred);
  131. CheckPredicate(cnfPred, rangetable, relationId);
  132. }
  133. if (IsFuncIndex(attributeList))
  134. {
  135. IndexElem  *funcIndex = lfirst(attributeList);
  136. int nargs;
  137. nargs = length(funcIndex->args);
  138. if (nargs > INDEX_MAX_KEYS)
  139. {
  140. elog(ERROR,
  141.    "Too many args to function, limit of %d", INDEX_MAX_KEYS);
  142. }
  143. FIsetnArgs(&fInfo, nargs);
  144. strcpy(FIgetname(&fInfo), funcIndex->name);
  145. attributeNumberA = (AttrNumber *) palloc(nargs * sizeof attributeNumberA[0]);
  146. classObjectId = (Oid *) palloc(sizeof classObjectId[0]);
  147. FuncIndexArgs(funcIndex, attributeNumberA,
  148.   &(FIgetArg(&fInfo, 0)),
  149.   classObjectId, relationId);
  150. index_create(heapRelationName,
  151.  indexRelationName,
  152.  &fInfo, NULL, accessMethodId,
  153.  numberOfAttributes, attributeNumberA,
  154.  classObjectId, parameterCount, parameterA, (Node *) cnfPred,
  155.  lossy, unique, primary);
  156. }
  157. else
  158. {
  159. attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
  160.  sizeof attributeNumberA[0]);
  161. classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
  162. NormIndexAttrs(attributeList, attributeNumberA,
  163.    classObjectId, relationId);
  164. index_create(heapRelationName, indexRelationName, NULL,
  165.  attributeList,
  166.  accessMethodId, numberOfAttributes, attributeNumberA,
  167.  classObjectId, parameterCount, parameterA, (Node *) cnfPred,
  168.  lossy, unique, primary);
  169. }
  170. }
  171. /*
  172.  * ExtendIndex
  173.  * Extends a partial index.
  174.  *
  175.  * Exceptions:
  176.  * XXX
  177.  */
  178. void
  179. ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
  180. {
  181. Oid    *classObjectId;
  182. Oid accessMethodId;
  183. Oid indexId,
  184. relationId;
  185. Oid indproc;
  186. int numberOfAttributes;
  187. AttrNumber *attributeNumberA;
  188. HeapTuple tuple;
  189. FuncIndexInfo fInfo;
  190. FuncIndexInfo *funcInfo = NULL;
  191. Form_pg_index index;
  192. Node    *oldPred = NULL;
  193. List    *cnfPred = NULL;
  194. PredInfo   *predInfo;
  195. Relation heapRelation;
  196. Relation indexRelation;
  197. int i;
  198. /*
  199.  * compute index relation id and access method id
  200.  */
  201. tuple = SearchSysCacheTuple(RELNAME,
  202. PointerGetDatum(indexRelationName),
  203. 0, 0, 0);
  204. if (!HeapTupleIsValid(tuple))
  205. {
  206. elog(ERROR, "ExtendIndex: %s index not found",
  207.  indexRelationName);
  208. }
  209. indexId = tuple->t_data->t_oid;
  210. accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
  211. /*
  212.  * find pg_index tuple
  213.  */
  214. tuple = SearchSysCacheTuple(INDEXRELID,
  215. ObjectIdGetDatum(indexId),
  216. 0, 0, 0);
  217. if (!HeapTupleIsValid(tuple))
  218. {
  219. elog(ERROR, "ExtendIndex: %s is not an index",
  220.  indexRelationName);
  221. }
  222. /*
  223.  * Extract info from the pg_index tuple
  224.  */
  225. index = (Form_pg_index) GETSTRUCT(tuple);
  226. Assert(index->indexrelid == indexId);
  227. relationId = index->indrelid;
  228. indproc = index->indproc;
  229. for (i = 0; i < INDEX_MAX_KEYS; i++)
  230. if (index->indkey[i] == InvalidAttrNumber)
  231. break;
  232. numberOfAttributes = i;
  233. if (VARSIZE(&index->indpred) != 0)
  234. {
  235. char    *predString;
  236. predString = fmgr(F_TEXTOUT, &index->indpred);
  237. oldPred = stringToNode(predString);
  238. pfree(predString);
  239. }
  240. if (oldPred == NULL)
  241. elog(ERROR, "ExtendIndex: %s is not a partial index",
  242.  indexRelationName);
  243. /*
  244.  * Convert the extension predicate from parsetree form to plan form,
  245.  * so it can be readily evaluated during index creation. Note:
  246.  * "predicate" comes in as a list containing (1) the predicate itself
  247.  * (a where_clause), and (2) a corresponding range table.
  248.  */
  249. if (rangetable != NIL)
  250. {
  251. cnfPred = cnfify((Expr *) copyObject(predicate), true);
  252. fix_opids(cnfPred);
  253. CheckPredicate(cnfPred, rangetable, relationId);
  254. }
  255. /* make predInfo list to pass to index_build */
  256. predInfo = (PredInfo *) palloc(sizeof(PredInfo));
  257. predInfo->pred = (Node *) cnfPred;
  258. predInfo->oldPred = oldPred;
  259. attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
  260.  sizeof attributeNumberA[0]);
  261. classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
  262. for (i = 0; i < numberOfAttributes; i++)
  263. {
  264. attributeNumberA[i] = index->indkey[i];
  265. classObjectId[i] = index->indclass[i];
  266. }
  267. if (indproc != InvalidOid)
  268. {
  269. funcInfo = &fInfo;
  270. /* FIgetnArgs(funcInfo) = numberOfAttributes; */
  271. FIsetnArgs(funcInfo, numberOfAttributes);
  272. tuple = SearchSysCacheTuple(PROOID,
  273. ObjectIdGetDatum(indproc),
  274. 0, 0, 0);
  275. if (!HeapTupleIsValid(tuple))
  276. elog(ERROR, "ExtendIndex: index procedure not found");
  277. namecpy(&(funcInfo->funcName),
  278. &(((Form_pg_proc) GETSTRUCT(tuple))->proname));
  279. FIsetProcOid(funcInfo, tuple->t_data->t_oid);
  280. }
  281. heapRelation = heap_open(relationId);
  282. indexRelation = index_open(indexId);
  283. LockRelation(heapRelation, ShareLock);
  284. InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
  285. index_build(heapRelation, indexRelation, numberOfAttributes,
  286. attributeNumberA, 0, NULL, funcInfo, predInfo);
  287. }
  288. /*
  289.  * CheckPredicate
  290.  * Checks that the given list of partial-index predicates refer
  291.  * (via the given range table) only to the given base relation oid,
  292.  * and that they're in a form the planner can handle, i.e.,
  293.  * boolean combinations of "ATTR OP CONST" (yes, for now, the ATTR
  294.  * has to be on the left).
  295.  */
  296. static void
  297. CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
  298. {
  299. List    *item;
  300. foreach(item, predList)
  301. CheckPredExpr(lfirst(item), rangeTable, baseRelOid);
  302. }
  303. static void
  304. CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid)
  305. {
  306. List    *clauses = NIL,
  307.    *clause;
  308. if (is_opclause(predicate))
  309. {
  310. CheckPredClause((Expr *) predicate, rangeTable, baseRelOid);
  311. return;
  312. }
  313. else if (or_clause(predicate) || and_clause(predicate))
  314. clauses = ((Expr *) predicate)->args;
  315. else
  316. elog(ERROR, "Unsupported partial-index predicate expression type");
  317. foreach(clause, clauses)
  318. CheckPredExpr(lfirst(clause), rangeTable, baseRelOid);
  319. }
  320. static void
  321. CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
  322. {
  323. Var    *pred_var;
  324. Const    *pred_const;
  325. pred_var = (Var *) get_leftop(predicate);
  326. pred_const = (Const *) get_rightop(predicate);
  327. if (!IsA(predicate->oper, Oper) ||
  328. !IsA(pred_var, Var) ||
  329. !IsA(pred_const, Const))
  330. elog(ERROR, "Unsupported partial-index predicate clause type");
  331. if (getrelid(pred_var->varno, rangeTable) != baseRelOid)
  332. elog(ERROR,
  333.  "Partial-index predicates may refer only to the base relation");
  334. }
  335. static void
  336. FuncIndexArgs(IndexElem *funcIndex,
  337.   AttrNumber *attNumP,
  338.   Oid *argTypes,
  339.   Oid *opOidP,
  340.   Oid relId)
  341. {
  342. List    *rest;
  343. HeapTuple tuple;
  344. Form_pg_attribute att;
  345. tuple = SearchSysCacheTuple(CLANAME,
  346. PointerGetDatum(funcIndex->class),
  347. 0, 0, 0);
  348. if (!HeapTupleIsValid(tuple))
  349. {
  350. elog(ERROR, "DefineIndex: %s class not found",
  351.  funcIndex->class);
  352. }
  353. *opOidP = tuple->t_data->t_oid;
  354. MemSet(argTypes, 0, 8 * sizeof(Oid));
  355. /*
  356.  * process the function arguments
  357.  */
  358. for (rest = funcIndex->args; rest != NIL; rest = lnext(rest))
  359. {
  360. char    *arg;
  361. arg = strVal(lfirst(rest));
  362. tuple = SearchSysCacheTuple(ATTNAME,
  363. ObjectIdGetDatum(relId),
  364. PointerGetDatum(arg), 0, 0);
  365. if (!HeapTupleIsValid(tuple))
  366. {
  367. elog(ERROR,
  368.  "DefineIndex: attribute "%s" not found",
  369.  arg);
  370. }
  371. att = (Form_pg_attribute) GETSTRUCT(tuple);
  372. *attNumP++ = att->attnum;
  373. *argTypes++ = att->atttypid;
  374. }
  375. }
  376. static void
  377. NormIndexAttrs(List *attList, /* list of IndexElem's */
  378.    AttrNumber *attNumP,
  379.    Oid *classOidP,
  380.    Oid relId)
  381. {
  382. List    *rest;
  383. HeapTuple atttuple,
  384. tuple;
  385. /*
  386.  * process attributeList
  387.  */
  388. for (rest = attList; rest != NIL; rest = lnext(rest))
  389. {
  390. IndexElem  *attribute;
  391. Form_pg_attribute attform;
  392. attribute = lfirst(rest);
  393. if (attribute->name == NULL)
  394. elog(ERROR, "missing attribute for define index");
  395. atttuple = SearchSysCacheTupleCopy(ATTNAME,
  396.    ObjectIdGetDatum(relId),
  397. PointerGetDatum(attribute->name),
  398.    0, 0);
  399. if (!HeapTupleIsValid(atttuple))
  400. {
  401. elog(ERROR,
  402.  "DefineIndex: attribute "%s" not found",
  403.  attribute->name);
  404. }
  405. attform = (Form_pg_attribute) GETSTRUCT(atttuple);
  406. *attNumP++ = attform->attnum;
  407. /* we want the type so we can set the proper alignment, etc. */
  408. if (attribute->typename == NULL)
  409. {
  410. tuple = SearchSysCacheTuple(TYPOID,
  411.  ObjectIdGetDatum(attform->atttypid),
  412. 0, 0, 0);
  413. if (!HeapTupleIsValid(tuple))
  414. elog(ERROR, "create index: type for attribute '%s' undefined",
  415.  attribute->name);
  416. /* we just set the type name because that is all we need */
  417. attribute->typename = makeNode(TypeName);
  418. attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
  419. /* we all need the typmod for the char and varchar types. */
  420. attribute->typename->typmod = attform->atttypmod;
  421. }
  422. if (attribute->class == NULL)
  423. {
  424. /* no operator class specified, so find the default */
  425. attribute->class = GetDefaultOpClass(attform->atttypid);
  426. if (attribute->class == NULL)
  427. {
  428. elog(ERROR,
  429.  "Can't find a default operator class for type %u.",
  430.  attform->atttypid);
  431. }
  432. }
  433. tuple = SearchSysCacheTuple(CLANAME,
  434. PointerGetDatum(attribute->class),
  435. 0, 0, 0);
  436. if (!HeapTupleIsValid(tuple))
  437. {
  438. elog(ERROR, "DefineIndex: %s class not found",
  439.  attribute->class);
  440. }
  441. *classOidP++ = tuple->t_data->t_oid;
  442. pfree(atttuple);
  443. }
  444. }
  445. static char *
  446. GetDefaultOpClass(Oid atttypid)
  447. {
  448. HeapTuple tuple;
  449. tuple = SearchSysCacheTuple(CLADEFTYPE,
  450. ObjectIdGetDatum(atttypid),
  451. 0, 0, 0);
  452. if (!HeapTupleIsValid(tuple))
  453. return 0;
  454. return nameout(&(((Form_pg_opclass) GETSTRUCT(tuple))->opcname));
  455. }
  456. /*
  457.  * RemoveIndex
  458.  * Deletes an index.
  459.  *
  460.  * Exceptions:
  461.  * BadArg if name is invalid.
  462.  * "WARN" if index nonexistent.
  463.  * ...
  464.  */
  465. void
  466. RemoveIndex(char *name)
  467. {
  468. HeapTuple tuple;
  469. tuple = SearchSysCacheTuple(RELNAME,
  470. PointerGetDatum(name),
  471. 0, 0, 0);
  472. if (!HeapTupleIsValid(tuple))
  473. elog(ERROR, "index "%s" nonexistent", name);
  474. if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
  475. {
  476. elog(ERROR, "relation "%s" is of type "%c"",
  477.  name,
  478.  ((Form_pg_class) GETSTRUCT(tuple))->relkind);
  479. }
  480. index_destroy(tuple->t_data->t_oid);
  481. }