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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * istrat.c
  4.  *   index scan strategy manipulation code and index strategy manipulation
  5.  *   operator code.
  6.  *
  7.  * Copyright (c) 1994, Regents of the University of California
  8.  *
  9.  *
  10.  * IDENTIFICATION
  11.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/access/index/istrat.c,v 1.33.2.2 1999/08/02 05:56:39 scrappy Exp $
  12.  *
  13.  *-------------------------------------------------------------------------
  14.  */
  15. #include "postgres.h"
  16. #include "access/heapam.h"
  17. #include "access/istrat.h"
  18. #include "catalog/catname.h"
  19. #include "catalog/pg_amop.h"
  20. #include "catalog/pg_amproc.h"
  21. #include "catalog/pg_index.h"
  22. #include "catalog/pg_operator.h"
  23. #include "miscadmin.h"
  24. #include "utils/syscache.h"
  25. #ifdef USE_ASSERT_CHECKING
  26. static bool StrategyEvaluationIsValid(StrategyEvaluation evaluation);
  27. static bool StrategyExpressionIsValid(StrategyExpression expression,
  28.   StrategyNumber maxStrategy);
  29. static ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
  30.    StrategyNumber strategyNumber);
  31. static bool StrategyOperatorIsValid(StrategyOperator operator,
  32. StrategyNumber maxStrategy);
  33. static bool StrategyTermIsValid(StrategyTerm term,
  34. StrategyNumber maxStrategy);
  35. #endif
  36. /* ----------------------------------------------------------------
  37.  *    misc strategy support routines
  38.  * ----------------------------------------------------------------
  39.  */
  40. /*
  41.  * StrategyNumberIsValid
  42.  * StrategyNumberIsInBounds
  43.  * StrategyMapIsValid
  44.  * StrategyTransformMapIsValid
  45.  * IndexStrategyIsValid
  46.  *
  47.  * ... are now macros in istrat.h -cim 4/27/91
  48.  */
  49. /*
  50.  * StrategyMapGetScanKeyEntry
  51.  * Returns a scan key entry of a index strategy mapping member.
  52.  *
  53.  * Note:
  54.  * Assumes that the index strategy mapping is valid.
  55.  * Assumes that the index strategy number is valid.
  56.  * Bounds checking should be done outside this routine.
  57.  */
  58. static ScanKey
  59. StrategyMapGetScanKeyEntry(StrategyMap map,
  60.    StrategyNumber strategyNumber)
  61. {
  62. Assert(StrategyMapIsValid(map));
  63. Assert(StrategyNumberIsValid(strategyNumber));
  64. return &map->entry[strategyNumber - 1];
  65. }
  66. /*
  67.  * IndexStrategyGetStrategyMap
  68.  * Returns an index strategy mapping of an index strategy.
  69.  *
  70.  * Note:
  71.  * Assumes that the index strategy is valid.
  72.  * Assumes that the number of index strategies is valid.
  73.  * Bounds checking should be done outside this routine.
  74.  */
  75. StrategyMap
  76. IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
  77. StrategyNumber maxStrategyNum,
  78. AttrNumber attrNum)
  79. {
  80. Assert(IndexStrategyIsValid(indexStrategy));
  81. Assert(StrategyNumberIsValid(maxStrategyNum));
  82. Assert(AttributeNumberIsValid(attrNum));
  83. maxStrategyNum = AMStrategies(maxStrategyNum); /* XXX */
  84. return &indexStrategy->strategyMapData[maxStrategyNum * (attrNum - 1)];
  85. }
  86. /*
  87.  * AttributeNumberGetIndexStrategySize
  88.  * Computes the size of an index strategy.
  89.  */
  90. Size
  91. AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber,
  92. StrategyNumber maxStrategyNumber)
  93. {
  94. maxStrategyNumber = AMStrategies(maxStrategyNumber); /* XXX */
  95. return maxAttributeNumber * maxStrategyNumber * sizeof(ScanKeyData);
  96. }
  97. #ifdef USE_ASSERT_CHECKING
  98. /*
  99.  * StrategyTransformMapIsValid is now a macro in istrat.h -cim 4/27/91
  100.  */
  101. /* ----------------
  102.  * StrategyOperatorIsValid
  103.  * ----------------
  104.  */
  105. static bool
  106. StrategyOperatorIsValid(StrategyOperator operator,
  107. StrategyNumber maxStrategy)
  108. {
  109. return (bool)
  110. (PointerIsValid(operator) &&
  111.  StrategyNumberIsInBounds(operator->strategy, maxStrategy) &&
  112.  !(operator->flags & ~(SK_NEGATE | SK_COMMUTE)));
  113. }
  114. /* ----------------
  115.  * StrategyTermIsValid
  116.  * ----------------
  117.  */
  118. static bool
  119. StrategyTermIsValid(StrategyTerm term,
  120. StrategyNumber maxStrategy)
  121. {
  122. Index index;
  123. if (!PointerIsValid(term) || term->degree == 0)
  124. return false;
  125. for (index = 0; index < term->degree; index += 1)
  126. {
  127. if (!StrategyOperatorIsValid(&term->operatorData[index],
  128.  maxStrategy))
  129. return false;
  130. }
  131. return true;
  132. }
  133. /* ----------------
  134.  * StrategyExpressionIsValid
  135.  * ----------------
  136.  */
  137. static bool
  138. StrategyExpressionIsValid(StrategyExpression expression,
  139.   StrategyNumber maxStrategy)
  140. {
  141. StrategyTerm *termP;
  142. if (!PointerIsValid(expression))
  143. return true;
  144. if (!StrategyTermIsValid(expression->term[0], maxStrategy))
  145. return false;
  146. termP = &expression->term[1];
  147. while (StrategyTermIsValid(*termP, maxStrategy))
  148. termP += 1;
  149. return (bool)
  150. (!PointerIsValid(*termP));
  151. }
  152. /* ----------------
  153.  * StrategyEvaluationIsValid
  154.  * ----------------
  155.  */
  156. static bool
  157. StrategyEvaluationIsValid(StrategyEvaluation evaluation)
  158. {
  159. Index index;
  160. if (!PointerIsValid(evaluation) ||
  161. !StrategyNumberIsValid(evaluation->maxStrategy) ||
  162. !StrategyTransformMapIsValid(evaluation->negateTransform) ||
  163. !StrategyTransformMapIsValid(evaluation->commuteTransform) ||
  164. !StrategyTransformMapIsValid(evaluation->negateCommuteTransform))
  165. {
  166. return false;
  167. }
  168. for (index = 0; index < evaluation->maxStrategy; index += 1)
  169. {
  170. if (!StrategyExpressionIsValid(evaluation->expression[index],
  171.    evaluation->maxStrategy))
  172. {
  173. return false;
  174. }
  175. }
  176. return true;
  177. }
  178. #endif
  179. /* ----------------
  180.  * StrategyTermEvaluate
  181.  * ----------------
  182.  */
  183. static bool
  184. StrategyTermEvaluate(StrategyTerm term,
  185.  StrategyMap map,
  186.  Datum left,
  187.  Datum right)
  188. {
  189. Index index;
  190. long tmpres = 0;
  191. bool result = 0;
  192. StrategyOperator operator;
  193. ScanKey entry;
  194. for (index = 0, operator = &term->operatorData[0];
  195.  index < term->degree; index += 1, operator += 1)
  196. {
  197. entry = &map->entry[operator->strategy - 1];
  198. Assert(RegProcedureIsValid(entry->sk_procedure));
  199. switch (operator->flags ^ entry->sk_flags)
  200. {
  201. case 0x0:
  202. tmpres = (long) FMGR_PTR2(&entry->sk_func,
  203.   left, right);
  204. break;
  205. case SK_NEGATE:
  206. tmpres = (long) !FMGR_PTR2(&entry->sk_func,
  207.    left, right);
  208. break;
  209. case SK_COMMUTE:
  210. tmpres = (long) FMGR_PTR2(&entry->sk_func,
  211.   right, left);
  212. break;
  213. case SK_NEGATE | SK_COMMUTE:
  214. tmpres = (long) !FMGR_PTR2(&entry->sk_func,
  215.    right, left);
  216. break;
  217. default:
  218. elog(FATAL, "StrategyTermEvaluate: impossible case %d",
  219.  operator->flags ^ entry->sk_flags);
  220. }
  221. result = (bool) tmpres;
  222. if (!result)
  223. return result;
  224. }
  225. return result;
  226. }
  227. /* ----------------
  228.  * RelationGetStrategy
  229.  * ----------------
  230.  */
  231. StrategyNumber
  232. RelationGetStrategy(Relation relation,
  233. AttrNumber attributeNumber,
  234. StrategyEvaluation evaluation,
  235. RegProcedure procedure)
  236. {
  237. StrategyNumber strategy;
  238. StrategyMap strategyMap;
  239. ScanKey entry;
  240. Index index;
  241. int numattrs;
  242. Assert(RelationIsValid(relation));
  243. numattrs = RelationGetNumberOfAttributes(relation);
  244. Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
  245. Assert(AttributeNumberIsValid(attributeNumber));
  246. Assert((attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
  247. Assert(StrategyEvaluationIsValid(evaluation));
  248. Assert(RegProcedureIsValid(procedure));
  249. strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
  250.   evaluation->maxStrategy,
  251.   attributeNumber);
  252. /* get a strategy number for the procedure ignoring flags for now */
  253. for (index = 0; index < evaluation->maxStrategy; index += 1)
  254. {
  255. if (strategyMap->entry[index].sk_procedure == procedure)
  256. break;
  257. }
  258. if (index == evaluation->maxStrategy)
  259. return InvalidStrategy;
  260. strategy = 1 + index;
  261. entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
  262. Assert(!(entry->sk_flags & ~(SK_NEGATE | SK_COMMUTE)));
  263. switch (entry->sk_flags & (SK_NEGATE | SK_COMMUTE))
  264. {
  265. case 0x0:
  266. return strategy;
  267. case SK_NEGATE:
  268. strategy = evaluation->negateTransform->strategy[strategy - 1];
  269. break;
  270. case SK_COMMUTE:
  271. strategy = evaluation->commuteTransform->strategy[strategy - 1];
  272. break;
  273. case SK_NEGATE | SK_COMMUTE:
  274. strategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
  275. break;
  276. default:
  277. elog(FATAL, "RelationGetStrategy: impossible case %d", entry->sk_flags);
  278. }
  279. if (!StrategyNumberIsInBounds(strategy, evaluation->maxStrategy))
  280. {
  281. if (!StrategyNumberIsValid(strategy))
  282. elog(ERROR, "RelationGetStrategy: corrupted evaluation");
  283. }
  284. return strategy;
  285. }
  286. /* ----------------
  287.  * RelationInvokeStrategy
  288.  * ----------------
  289.  */
  290. bool /* XXX someday, this may return Datum */
  291. RelationInvokeStrategy(Relation relation,
  292.    StrategyEvaluation evaluation,
  293.    AttrNumber attributeNumber,
  294.    StrategyNumber strategy,
  295.    Datum left,
  296.    Datum right)
  297. {
  298. StrategyNumber newStrategy;
  299. StrategyMap strategyMap;
  300. ScanKey entry;
  301. StrategyTermData termData;
  302. int numattrs;
  303. Assert(RelationIsValid(relation));
  304. Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
  305. numattrs = RelationGetNumberOfAttributes(relation);
  306. Assert(StrategyEvaluationIsValid(evaluation));
  307. Assert(AttributeNumberIsValid(attributeNumber));
  308. Assert((attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
  309. Assert(StrategyNumberIsInBounds(strategy, evaluation->maxStrategy));
  310. termData.degree = 1;
  311. strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
  312.   evaluation->maxStrategy,
  313.   attributeNumber);
  314. entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
  315. if (RegProcedureIsValid(entry->sk_procedure))
  316. {
  317. termData.operatorData[0].strategy = strategy;
  318. termData.operatorData[0].flags = 0x0;
  319. return StrategyTermEvaluate(&termData, strategyMap, left, right);
  320. }
  321. newStrategy = evaluation->negateTransform->strategy[strategy - 1];
  322. if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
  323. {
  324. entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
  325. if (RegProcedureIsValid(entry->sk_procedure))
  326. {
  327. termData.operatorData[0].strategy = newStrategy;
  328. termData.operatorData[0].flags = SK_NEGATE;
  329. return StrategyTermEvaluate(&termData, strategyMap, left, right);
  330. }
  331. }
  332. newStrategy = evaluation->commuteTransform->strategy[strategy - 1];
  333. if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
  334. {
  335. entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
  336. if (RegProcedureIsValid(entry->sk_procedure))
  337. {
  338. termData.operatorData[0].strategy = newStrategy;
  339. termData.operatorData[0].flags = SK_COMMUTE;
  340. return StrategyTermEvaluate(&termData, strategyMap, left, right);
  341. }
  342. }
  343. newStrategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
  344. if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
  345. {
  346. entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
  347. if (RegProcedureIsValid(entry->sk_procedure))
  348. {
  349. termData.operatorData[0].strategy = newStrategy;
  350. termData.operatorData[0].flags = SK_NEGATE | SK_COMMUTE;
  351. return StrategyTermEvaluate(&termData, strategyMap, left, right);
  352. }
  353. }
  354. if (PointerIsValid(evaluation->expression[strategy - 1]))
  355. {
  356. StrategyTerm *termP;
  357. termP = &evaluation->expression[strategy - 1]->term[0];
  358. while (PointerIsValid(*termP))
  359. {
  360. Index index;
  361. for (index = 0; index < (*termP)->degree; index += 1)
  362. {
  363. entry = StrategyMapGetScanKeyEntry(strategyMap,
  364.  (*termP)->operatorData[index].strategy);
  365. if (!RegProcedureIsValid(entry->sk_procedure))
  366. break;
  367. }
  368. if (index == (*termP)->degree)
  369. return StrategyTermEvaluate(*termP, strategyMap, left, right);
  370. termP += 1;
  371. }
  372. }
  373. elog(ERROR, "RelationInvokeStrategy: cannot evaluate strategy %d",
  374.  strategy);
  375. /* not reached, just to make compiler happy */
  376. return FALSE;
  377. }
  378. /* ----------------
  379.  * OperatorRelationFillScanKeyEntry
  380.  * ----------------
  381.  */
  382. static void
  383. OperatorRelationFillScanKeyEntry(Relation operatorRelation,
  384.  Oid operatorObjectId,
  385.  ScanKey entry)
  386. {
  387. HeapTuple tuple;
  388. HeapScanDesc scan = NULL;
  389. if (!IsBootstrapProcessingMode())
  390. {
  391. tuple = SearchSysCacheTuple(OPROID,
  392. ObjectIdGetDatum(operatorObjectId),
  393. 0, 0, 0);
  394. }
  395. else
  396. {
  397. ScanKeyData scanKeyData;
  398. ScanKeyEntryInitialize(&scanKeyData, 0,
  399.    ObjectIdAttributeNumber,
  400.    F_OIDEQ,
  401.    ObjectIdGetDatum(operatorObjectId));
  402. scan = heap_beginscan(operatorRelation, false, SnapshotNow,
  403.   1, &scanKeyData);
  404. tuple = heap_getnext(scan, 0);
  405. }
  406. if (!HeapTupleIsValid(tuple))
  407. {
  408. if (IsBootstrapProcessingMode())
  409. heap_endscan(scan);
  410. elog(ERROR, "OperatorObjectIdFillScanKeyEntry: unknown operator %lu",
  411.  (uint32) operatorObjectId);
  412. }
  413. entry->sk_flags = 0;
  414. entry->sk_procedure = ((Form_pg_operator) GETSTRUCT(tuple))->oprcode;
  415. fmgr_info(entry->sk_procedure, &entry->sk_func);
  416. entry->sk_nargs = entry->sk_func.fn_nargs;
  417. if (IsBootstrapProcessingMode())
  418. heap_endscan(scan);
  419. if (!RegProcedureIsValid(entry->sk_procedure))
  420. {
  421. elog(ERROR,
  422. "OperatorObjectIdFillScanKeyEntry: no procedure for operator %lu",
  423.  (uint32) operatorObjectId);
  424. }
  425. }
  426. /*
  427.  * IndexSupportInitialize
  428.  * Initializes an index strategy and associated support procedures.
  429.  */
  430. void
  431. IndexSupportInitialize(IndexStrategy indexStrategy,
  432.    RegProcedure *indexSupport,
  433.    Oid indexObjectId,
  434.    Oid accessMethodObjectId,
  435.    StrategyNumber maxStrategyNumber,
  436.    StrategyNumber maxSupportNumber,
  437.    AttrNumber maxAttributeNumber)
  438. {
  439. Relation relation = NULL;
  440. HeapScanDesc scan = NULL;
  441. ScanKeyData entry[2];
  442. Relation operatorRelation;
  443. HeapTuple tuple;
  444. StrategyMap map;
  445. AttrNumber attributeNumber;
  446. int attributeIndex;
  447. Oid operatorClassObjectId[MaxIndexAttributeNumber];
  448. if (!IsBootstrapProcessingMode())
  449. {
  450. tuple = SearchSysCacheTuple(INDEXRELID,
  451. ObjectIdGetDatum(indexObjectId),
  452. 0, 0, 0);
  453. }
  454. else
  455. {
  456. ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
  457.    F_OIDEQ,
  458.    ObjectIdGetDatum(indexObjectId));
  459. relation = heap_openr(IndexRelationName);
  460. scan = heap_beginscan(relation, false, SnapshotNow, 1, entry);
  461. tuple = heap_getnext(scan, 0);
  462. }
  463. if (!HeapTupleIsValid(tuple))
  464. elog(ERROR, "IndexSupportInitialize: corrupted catalogs");
  465. maxStrategyNumber = AMStrategies(maxStrategyNumber);
  466. /*
  467.  * XXX note that the following assumes the INDEX tuple is well formed
  468.  * and that the *key and *class are 0 terminated.
  469.  */
  470. for (attributeIndex = 0; attributeIndex < maxAttributeNumber; attributeIndex++)
  471. {
  472. Form_pg_index iform;
  473. iform = (Form_pg_index) GETSTRUCT(tuple);
  474. if (!OidIsValid(iform->indkey[attributeIndex]))
  475. {
  476. if (attributeIndex == InvalidAttrNumber)
  477. elog(ERROR, "IndexSupportInitialize: no pg_index tuple");
  478. break;
  479. }
  480. operatorClassObjectId[attributeIndex] = iform->indclass[attributeIndex];
  481. }
  482. if (IsBootstrapProcessingMode())
  483. {
  484. heap_endscan(scan);
  485. heap_close(relation);
  486. }
  487. /* if support routines exist for this access method, load them */
  488. if (maxSupportNumber > 0)
  489. {
  490. ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_amproc_amid,
  491.    F_OIDEQ,
  492.    ObjectIdGetDatum(accessMethodObjectId));
  493. ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
  494.    F_OIDEQ, 0);
  495. relation = heap_openr(AccessMethodProcedureRelationName);
  496. for (attributeNumber = 1; attributeNumber <= maxAttributeNumber;
  497.  attributeNumber++)
  498. {
  499. int16 support;
  500. Form_pg_amproc aform;
  501. RegProcedure *loc;
  502. loc = &indexSupport[((attributeNumber - 1) * maxSupportNumber)];
  503. for (support = 0; support < maxSupportNumber; ++support)
  504. loc[support] = InvalidOid;
  505. entry[1].sk_argument =
  506. ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
  507. scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
  508. while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
  509. {
  510. aform = (Form_pg_amproc) GETSTRUCT(tuple);
  511. loc[(aform->amprocnum - 1)] = aform->amproc;
  512. }
  513. heap_endscan(scan);
  514. }
  515. heap_close(relation);
  516. }
  517. ScanKeyEntryInitialize(&entry[0], 0,
  518.    Anum_pg_amop_amopid,
  519.    F_OIDEQ,
  520.    ObjectIdGetDatum(accessMethodObjectId));
  521. ScanKeyEntryInitialize(&entry[1], 0,
  522.    Anum_pg_amop_amopclaid,
  523.    F_OIDEQ, 0);
  524. relation = heap_openr(AccessMethodOperatorRelationName);
  525. operatorRelation = heap_openr(OperatorRelationName);
  526. for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
  527.  attributeNumber--)
  528. {
  529. StrategyNumber strategy;
  530. entry[1].sk_argument =
  531. ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
  532. map = IndexStrategyGetStrategyMap(indexStrategy,
  533.   maxStrategyNumber,
  534.   attributeNumber);
  535. for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
  536. ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));
  537. scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
  538. while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
  539. {
  540. Form_pg_amop aform;
  541. aform = (Form_pg_amop) GETSTRUCT(tuple);
  542. OperatorRelationFillScanKeyEntry(operatorRelation,
  543.  aform->amopopr,
  544. StrategyMapGetScanKeyEntry(map, aform->amopstrategy));
  545. }
  546. heap_endscan(scan);
  547. }
  548. heap_close(operatorRelation);
  549. heap_close(relation);
  550. }
  551. /* ----------------
  552.  * IndexStrategyDisplay
  553.  * ----------------
  554.  */
  555. #ifdef ISTRATDEBUG
  556. int
  557. IndexStrategyDisplay(IndexStrategy indexStrategy,
  558.  StrategyNumber numberOfStrategies,
  559.  int numberOfAttributes)
  560. {
  561. StrategyMap strategyMap;
  562. AttrNumber attributeNumber;
  563. StrategyNumber strategyNumber;
  564. for (attributeNumber = 1; attributeNumber <= numberOfAttributes;
  565.  attributeNumber += 1)
  566. {
  567. strategyMap = IndexStrategyGetStrategyMap(indexStrategy,
  568.   numberOfStrategies,
  569.   attributeNumber);
  570. for (strategyNumber = 1;
  571.  strategyNumber <= AMStrategies(numberOfStrategies);
  572.  strategyNumber += 1)
  573. {
  574. printf(":att %dt:str %dt:opr 0x%x(%d)n",
  575.    attributeNumber, strategyNumber,
  576.    strategyMap->entry[strategyNumber - 1].sk_procedure,
  577.    strategyMap->entry[strategyNumber - 1].sk_procedure);
  578. }
  579. }
  580. }
  581. #endif  /* defined(ISTRATDEBUG) */