Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

brin_inclusion.c 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. * brin_inclusion.c
  3. * Implementation of inclusion opclasses for BRIN
  4. *
  5. * This module provides framework BRIN support functions for the "inclusion"
  6. * operator classes. A few SQL-level support functions are also required for
  7. * each opclass.
  8. *
  9. * The "inclusion" BRIN strategy is useful for types that support R-Tree
  10. * operations. This implementation is a straight mapping of those operations
  11. * to the block-range nature of BRIN, with two exceptions: (a) we explicitly
  12. * support "empty" elements: at least with range types, we need to consider
  13. * emptiness separately from regular R-Tree strategies; and (b) we need to
  14. * consider "unmergeable" elements, that is, a set of elements for whose union
  15. * no representation exists. The only case where that happens as of this
  16. * writing is the INET type, where IPv6 values cannot be merged with IPv4
  17. * values.
  18. *
  19. * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  20. * Portions Copyright (c) 1994, Regents of the University of California
  21. *
  22. * IDENTIFICATION
  23. * src/backend/access/brin/brin_inclusion.c
  24. */
  25. #include "postgres.h"
  26. #include "access/brin_internal.h"
  27. #include "access/brin_tuple.h"
  28. #include "access/genam.h"
  29. #include "access/skey.h"
  30. #include "catalog/pg_amop.h"
  31. #include "catalog/pg_type.h"
  32. #include "utils/builtins.h"
  33. #include "utils/datum.h"
  34. #include "utils/lsyscache.h"
  35. #include "utils/rel.h"
  36. #include "utils/syscache.h"
  37. /*
  38. * Additional SQL level support functions
  39. *
  40. * Procedure numbers must not use values reserved for BRIN itself; see
  41. * brin_internal.h.
  42. */
  43. #define INCLUSION_MAX_PROCNUMS 4 /* maximum support procs we need */
  44. #define PROCNUM_MERGE 11 /* required */
  45. #define PROCNUM_MERGEABLE 12 /* optional */
  46. #define PROCNUM_CONTAINS 13 /* optional */
  47. #define PROCNUM_EMPTY 14 /* optional */
  48. /*
  49. * Subtract this from procnum to obtain index in InclusionOpaque arrays
  50. * (Must be equal to minimum of private procnums).
  51. */
  52. #define PROCNUM_BASE 11
  53. /*-
  54. * The values stored in the bv_values arrays correspond to:
  55. *
  56. * INCLUSION_UNION
  57. * the union of the values in the block range
  58. * INCLUSION_UNMERGEABLE
  59. * whether the values in the block range cannot be merged
  60. * (e.g. an IPv6 address amidst IPv4 addresses)
  61. * INCLUSION_CONTAINS_EMPTY
  62. * whether an empty value is present in any tuple
  63. * in the block range
  64. */
  65. #define INCLUSION_UNION 0
  66. #define INCLUSION_UNMERGEABLE 1
  67. #define INCLUSION_CONTAINS_EMPTY 2
  68. typedef struct InclusionOpaque
  69. {
  70. FmgrInfo extra_procinfos[INCLUSION_MAX_PROCNUMS];
  71. bool extra_proc_missing[INCLUSION_MAX_PROCNUMS];
  72. Oid cached_subtype;
  73. FmgrInfo strategy_procinfos[RTMaxStrategyNumber];
  74. } InclusionOpaque;
  75. static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno,
  76. uint16 procnum);
  77. static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
  78. Oid subtype, uint16 strategynum);
  79. /*
  80. * BRIN inclusion OpcInfo function
  81. */
  82. Datum
  83. brin_inclusion_opcinfo(PG_FUNCTION_ARGS)
  84. {
  85. Oid typoid = PG_GETARG_OID(0);
  86. BrinOpcInfo *result;
  87. TypeCacheEntry *bool_typcache = lookup_type_cache(BOOLOID, 0);
  88. /*
  89. * All members of opaque are initialized lazily; both procinfo arrays
  90. * start out as non-initialized by having fn_oid be InvalidOid, and
  91. * "missing" to false, by zeroing here. strategy_procinfos elements can
  92. * be invalidated when cached_subtype changes by zeroing fn_oid.
  93. * extra_procinfo entries are never invalidated, but if a lookup fails
  94. * (which is expected), extra_proc_missing is set to true, indicating not
  95. * to look it up again.
  96. */
  97. result = palloc0(MAXALIGN(SizeofBrinOpcInfo(3)) + sizeof(InclusionOpaque));
  98. result->oi_nstored = 3;
  99. result->oi_opaque = (InclusionOpaque *)
  100. MAXALIGN((char *) result + SizeofBrinOpcInfo(3));
  101. /* the union */
  102. result->oi_typcache[INCLUSION_UNION] =
  103. lookup_type_cache(typoid, 0);
  104. /* includes elements that are not mergeable */
  105. result->oi_typcache[INCLUSION_UNMERGEABLE] = bool_typcache;
  106. /* includes the empty element */
  107. result->oi_typcache[INCLUSION_CONTAINS_EMPTY] = bool_typcache;
  108. PG_RETURN_POINTER(result);
  109. }
  110. /*
  111. * BRIN inclusion add value function
  112. *
  113. * Examine the given index tuple (which contains partial status of a certain
  114. * page range) by comparing it to the given value that comes from another heap
  115. * tuple. If the new value is outside the union specified by the existing
  116. * tuple values, update the index tuple and return true. Otherwise, return
  117. * false and do not modify in this case.
  118. */
  119. Datum
  120. brin_inclusion_add_value(PG_FUNCTION_ARGS)
  121. {
  122. BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
  123. BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
  124. Datum newval = PG_GETARG_DATUM(2);
  125. bool isnull = PG_GETARG_BOOL(3);
  126. Oid colloid = PG_GET_COLLATION();
  127. FmgrInfo *finfo;
  128. Datum result;
  129. bool new = false;
  130. AttrNumber attno;
  131. Form_pg_attribute attr;
  132. /*
  133. * If the new value is null, we record that we saw it if it's the first
  134. * one; otherwise, there's nothing to do.
  135. */
  136. if (isnull)
  137. {
  138. if (column->bv_hasnulls)
  139. PG_RETURN_BOOL(false);
  140. column->bv_hasnulls = true;
  141. PG_RETURN_BOOL(true);
  142. }
  143. attno = column->bv_attno;
  144. attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
  145. /*
  146. * If the recorded value is null, copy the new value (which we know to be
  147. * not null), and we're almost done.
  148. */
  149. if (column->bv_allnulls)
  150. {
  151. column->bv_values[INCLUSION_UNION] =
  152. datumCopy(newval, attr->attbyval, attr->attlen);
  153. column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false);
  154. column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false);
  155. column->bv_allnulls = false;
  156. new = true;
  157. }
  158. /*
  159. * No need for further processing if the block range is marked as
  160. * containing unmergeable values.
  161. */
  162. if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE]))
  163. PG_RETURN_BOOL(false);
  164. /*
  165. * If the opclass supports the concept of empty values, test the passed
  166. * new value for emptiness; if it returns true, we need to set the
  167. * "contains empty" flag in the element (unless already set).
  168. */
  169. finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY);
  170. if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, colloid, newval)))
  171. {
  172. if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
  173. {
  174. column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
  175. PG_RETURN_BOOL(true);
  176. }
  177. PG_RETURN_BOOL(false);
  178. }
  179. if (new)
  180. PG_RETURN_BOOL(true);
  181. /* Check if the new value is already contained. */
  182. finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS);
  183. if (finfo != NULL &&
  184. DatumGetBool(FunctionCall2Coll(finfo, colloid,
  185. column->bv_values[INCLUSION_UNION],
  186. newval)))
  187. PG_RETURN_BOOL(false);
  188. /*
  189. * Check if the new value is mergeable to the existing union. If it is
  190. * not, mark the value as containing unmergeable elements and get out.
  191. *
  192. * Note: at this point we could remove the value from the union, since
  193. * it's not going to be used any longer. However, the BRIN framework
  194. * doesn't allow for the value not being present. Improve someday.
  195. */
  196. finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
  197. if (finfo != NULL &&
  198. !DatumGetBool(FunctionCall2Coll(finfo, colloid,
  199. column->bv_values[INCLUSION_UNION],
  200. newval)))
  201. {
  202. column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
  203. PG_RETURN_BOOL(true);
  204. }
  205. /* Finally, merge the new value to the existing union. */
  206. finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
  207. Assert(finfo != NULL);
  208. result = FunctionCall2Coll(finfo, colloid,
  209. column->bv_values[INCLUSION_UNION], newval);
  210. if (!attr->attbyval)
  211. pfree(DatumGetPointer(column->bv_values[INCLUSION_UNION]));
  212. column->bv_values[INCLUSION_UNION] = result;
  213. PG_RETURN_BOOL(true);
  214. }
  215. /*
  216. * BRIN inclusion consistent function
  217. *
  218. * All of the strategies are optional.
  219. */
  220. Datum
  221. brin_inclusion_consistent(PG_FUNCTION_ARGS)
  222. {
  223. BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
  224. BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
  225. ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
  226. Oid colloid = PG_GET_COLLATION(),
  227. subtype;
  228. Datum unionval;
  229. AttrNumber attno;
  230. Datum query;
  231. FmgrInfo *finfo;
  232. Datum result;
  233. Assert(key->sk_attno == column->bv_attno);
  234. /* Handle IS NULL/IS NOT NULL tests. */
  235. if (key->sk_flags & SK_ISNULL)
  236. {
  237. if (key->sk_flags & SK_SEARCHNULL)
  238. {
  239. if (column->bv_allnulls || column->bv_hasnulls)
  240. PG_RETURN_BOOL(true);
  241. PG_RETURN_BOOL(false);
  242. }
  243. /*
  244. * For IS NOT NULL, we can only skip ranges that are known to have
  245. * only nulls.
  246. */
  247. if (key->sk_flags & SK_SEARCHNOTNULL)
  248. PG_RETURN_BOOL(!column->bv_allnulls);
  249. /*
  250. * Neither IS NULL nor IS NOT NULL was used; assume all indexable
  251. * operators are strict and return false.
  252. */
  253. PG_RETURN_BOOL(false);
  254. }
  255. /* If it is all nulls, it cannot possibly be consistent. */
  256. if (column->bv_allnulls)
  257. PG_RETURN_BOOL(false);
  258. /* It has to be checked, if it contains elements that are not mergeable. */
  259. if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE]))
  260. PG_RETURN_BOOL(true);
  261. attno = key->sk_attno;
  262. subtype = key->sk_subtype;
  263. query = key->sk_argument;
  264. unionval = column->bv_values[INCLUSION_UNION];
  265. switch (key->sk_strategy)
  266. {
  267. /*
  268. * Placement strategies
  269. *
  270. * These are implemented by logically negating the result of the
  271. * converse placement operator; for this to work, the converse
  272. * operator must be part of the opclass. An error will be thrown
  273. * by inclusion_get_strategy_procinfo() if the required strategy
  274. * is not part of the opclass.
  275. *
  276. * These all return false if either argument is empty, so there is
  277. * no need to check for empty elements.
  278. */
  279. case RTLeftStrategyNumber:
  280. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  281. RTOverRightStrategyNumber);
  282. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  283. PG_RETURN_BOOL(!DatumGetBool(result));
  284. case RTOverLeftStrategyNumber:
  285. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  286. RTRightStrategyNumber);
  287. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  288. PG_RETURN_BOOL(!DatumGetBool(result));
  289. case RTOverRightStrategyNumber:
  290. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  291. RTLeftStrategyNumber);
  292. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  293. PG_RETURN_BOOL(!DatumGetBool(result));
  294. case RTRightStrategyNumber:
  295. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  296. RTOverLeftStrategyNumber);
  297. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  298. PG_RETURN_BOOL(!DatumGetBool(result));
  299. case RTBelowStrategyNumber:
  300. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  301. RTOverAboveStrategyNumber);
  302. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  303. PG_RETURN_BOOL(!DatumGetBool(result));
  304. case RTOverBelowStrategyNumber:
  305. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  306. RTAboveStrategyNumber);
  307. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  308. PG_RETURN_BOOL(!DatumGetBool(result));
  309. case RTOverAboveStrategyNumber:
  310. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  311. RTBelowStrategyNumber);
  312. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  313. PG_RETURN_BOOL(!DatumGetBool(result));
  314. case RTAboveStrategyNumber:
  315. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  316. RTOverBelowStrategyNumber);
  317. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  318. PG_RETURN_BOOL(!DatumGetBool(result));
  319. /*
  320. * Overlap and contains strategies
  321. *
  322. * These strategies are simple enough that we can simply call the
  323. * operator and return its result. Empty elements don't change
  324. * the result.
  325. */
  326. case RTOverlapStrategyNumber:
  327. case RTContainsStrategyNumber:
  328. case RTOldContainsStrategyNumber:
  329. case RTContainsElemStrategyNumber:
  330. case RTSubStrategyNumber:
  331. case RTSubEqualStrategyNumber:
  332. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  333. key->sk_strategy);
  334. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  335. PG_RETURN_DATUM(result);
  336. /*
  337. * Contained by strategies
  338. *
  339. * We cannot just call the original operator for the contained by
  340. * strategies because some elements can be contained even though
  341. * the union is not; instead we use the overlap operator.
  342. *
  343. * We check for empty elements separately as they are not merged
  344. * to the union but contained by everything.
  345. */
  346. case RTContainedByStrategyNumber:
  347. case RTOldContainedByStrategyNumber:
  348. case RTSuperStrategyNumber:
  349. case RTSuperEqualStrategyNumber:
  350. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  351. RTOverlapStrategyNumber);
  352. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  353. if (DatumGetBool(result))
  354. PG_RETURN_BOOL(true);
  355. PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
  356. /*
  357. * Adjacent strategy
  358. *
  359. * We test for overlap first but to be safe we need to call the
  360. * actual adjacent operator also.
  361. *
  362. * An empty element cannot be adjacent to any other, so there is
  363. * no need to check for it.
  364. */
  365. case RTAdjacentStrategyNumber:
  366. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  367. RTOverlapStrategyNumber);
  368. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  369. if (DatumGetBool(result))
  370. PG_RETURN_BOOL(true);
  371. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  372. RTAdjacentStrategyNumber);
  373. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  374. PG_RETURN_DATUM(result);
  375. /*
  376. * Basic comparison strategies
  377. *
  378. * It is straightforward to support the equality strategies with
  379. * the contains operator. Generally, inequality strategies do not
  380. * make much sense for the types which will be used with the
  381. * inclusion BRIN family of opclasses, but is possible to
  382. * implement them with logical negation of the left-of and
  383. * right-of operators.
  384. *
  385. * NB: These strategies cannot be used with geometric datatypes
  386. * that use comparison of areas! The only exception is the "same"
  387. * strategy.
  388. *
  389. * Empty elements are considered to be less than the others. We
  390. * cannot use the empty support function to check the query is an
  391. * empty element, because the query can be another data type than
  392. * the empty support function argument. So we will return true,
  393. * if there is a possibility that empty elements will change the
  394. * result.
  395. */
  396. case RTLessStrategyNumber:
  397. case RTLessEqualStrategyNumber:
  398. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  399. RTRightStrategyNumber);
  400. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  401. if (!DatumGetBool(result))
  402. PG_RETURN_BOOL(true);
  403. PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
  404. case RTSameStrategyNumber:
  405. case RTEqualStrategyNumber:
  406. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  407. RTContainsStrategyNumber);
  408. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  409. if (DatumGetBool(result))
  410. PG_RETURN_BOOL(true);
  411. PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
  412. case RTGreaterEqualStrategyNumber:
  413. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  414. RTLeftStrategyNumber);
  415. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  416. if (!DatumGetBool(result))
  417. PG_RETURN_BOOL(true);
  418. PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]);
  419. case RTGreaterStrategyNumber:
  420. /* no need to check for empty elements */
  421. finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype,
  422. RTLeftStrategyNumber);
  423. result = FunctionCall2Coll(finfo, colloid, unionval, query);
  424. PG_RETURN_BOOL(!DatumGetBool(result));
  425. default:
  426. /* shouldn't happen */
  427. elog(ERROR, "invalid strategy number %d", key->sk_strategy);
  428. PG_RETURN_BOOL(false);
  429. }
  430. }
  431. /*
  432. * BRIN inclusion union function
  433. *
  434. * Given two BrinValues, update the first of them as a union of the summary
  435. * values contained in both. The second one is untouched.
  436. */
  437. Datum
  438. brin_inclusion_union(PG_FUNCTION_ARGS)
  439. {
  440. BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
  441. BrinValues *col_a = (BrinValues *) PG_GETARG_POINTER(1);
  442. BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2);
  443. Oid colloid = PG_GET_COLLATION();
  444. AttrNumber attno;
  445. Form_pg_attribute attr;
  446. FmgrInfo *finfo;
  447. Datum result;
  448. Assert(col_a->bv_attno == col_b->bv_attno);
  449. /* Adjust "hasnulls". */
  450. if (!col_a->bv_hasnulls && col_b->bv_hasnulls)
  451. col_a->bv_hasnulls = true;
  452. /* If there are no values in B, there's nothing left to do. */
  453. if (col_b->bv_allnulls)
  454. PG_RETURN_VOID();
  455. attno = col_a->bv_attno;
  456. attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
  457. /*
  458. * Adjust "allnulls". If A doesn't have values, just copy the values from
  459. * B into A, and we're done. We cannot run the operators in this case,
  460. * because values in A might contain garbage. Note we already established
  461. * that B contains values.
  462. */
  463. if (col_a->bv_allnulls)
  464. {
  465. col_a->bv_allnulls = false;
  466. col_a->bv_values[INCLUSION_UNION] =
  467. datumCopy(col_b->bv_values[INCLUSION_UNION],
  468. attr->attbyval, attr->attlen);
  469. col_a->bv_values[INCLUSION_UNMERGEABLE] =
  470. col_b->bv_values[INCLUSION_UNMERGEABLE];
  471. col_a->bv_values[INCLUSION_CONTAINS_EMPTY] =
  472. col_b->bv_values[INCLUSION_CONTAINS_EMPTY];
  473. PG_RETURN_VOID();
  474. }
  475. /* If B includes empty elements, mark A similarly, if needed. */
  476. if (!DatumGetBool(col_a->bv_values[INCLUSION_CONTAINS_EMPTY]) &&
  477. DatumGetBool(col_b->bv_values[INCLUSION_CONTAINS_EMPTY]))
  478. col_a->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
  479. /* Check if A includes elements that are not mergeable. */
  480. if (DatumGetBool(col_a->bv_values[INCLUSION_UNMERGEABLE]))
  481. PG_RETURN_VOID();
  482. /* If B includes elements that are not mergeable, mark A similarly. */
  483. if (DatumGetBool(col_b->bv_values[INCLUSION_UNMERGEABLE]))
  484. {
  485. col_a->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
  486. PG_RETURN_VOID();
  487. }
  488. /* Check if A and B are mergeable; if not, mark A unmergeable. */
  489. finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
  490. if (finfo != NULL &&
  491. !DatumGetBool(FunctionCall2Coll(finfo, colloid,
  492. col_a->bv_values[INCLUSION_UNION],
  493. col_b->bv_values[INCLUSION_UNION])))
  494. {
  495. col_a->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
  496. PG_RETURN_VOID();
  497. }
  498. /* Finally, merge B to A. */
  499. finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
  500. Assert(finfo != NULL);
  501. result = FunctionCall2Coll(finfo, colloid,
  502. col_a->bv_values[INCLUSION_UNION],
  503. col_b->bv_values[INCLUSION_UNION]);
  504. if (!attr->attbyval)
  505. pfree(DatumGetPointer(col_a->bv_values[INCLUSION_UNION]));
  506. col_a->bv_values[INCLUSION_UNION] = result;
  507. PG_RETURN_VOID();
  508. }
  509. /*
  510. * Cache and return inclusion opclass support procedure
  511. *
  512. * Return the procedure corresponding to the given function support number
  513. * or null if it is not exists.
  514. */
  515. static FmgrInfo *
  516. inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
  517. {
  518. InclusionOpaque *opaque;
  519. uint16 basenum = procnum - PROCNUM_BASE;
  520. /*
  521. * We cache these in the opaque struct, to avoid repetitive syscache
  522. * lookups.
  523. */
  524. opaque = (InclusionOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
  525. /*
  526. * If we already searched for this proc and didn't find it, don't bother
  527. * searching again.
  528. */
  529. if (opaque->extra_proc_missing[basenum])
  530. return NULL;
  531. if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
  532. {
  533. if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
  534. procnum)))
  535. {
  536. fmgr_info_copy(&opaque->extra_procinfos[basenum],
  537. index_getprocinfo(bdesc->bd_index, attno, procnum),
  538. bdesc->bd_context);
  539. }
  540. else
  541. {
  542. opaque->extra_proc_missing[basenum] = true;
  543. return NULL;
  544. }
  545. }
  546. return &opaque->extra_procinfos[basenum];
  547. }
  548. /*
  549. * Cache and return the procedure of the given strategy
  550. *
  551. * Return the procedure corresponding to the given sub-type and strategy
  552. * number. The data type of the index will be used as the left hand side of
  553. * the operator and the given sub-type will be used as the right hand side.
  554. * Throws an error if the pg_amop row does not exist, but that should not
  555. * happen with a properly configured opclass.
  556. *
  557. * It always throws an error when the data type of the opclass is different
  558. * from the data type of the column or the expression. That happens when the
  559. * column data type has implicit cast to the opclass data type. We don't
  560. * bother casting types, because this situation can easily be avoided by
  561. * setting storage data type to that of the opclass. The same problem does not
  562. * apply to the data type of the right hand side, because the type in the
  563. * ScanKey always matches the opclass' one.
  564. *
  565. * Note: this function mirrors minmax_get_strategy_procinfo; if changes are
  566. * made here, see that function too.
  567. */
  568. static FmgrInfo *
  569. inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype,
  570. uint16 strategynum)
  571. {
  572. InclusionOpaque *opaque;
  573. Assert(strategynum >= 1 &&
  574. strategynum <= RTMaxStrategyNumber);
  575. opaque = (InclusionOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
  576. /*
  577. * We cache the procedures for the last sub-type in the opaque struct, to
  578. * avoid repetitive syscache lookups. If the sub-type is changed,
  579. * invalidate all the cached entries.
  580. */
  581. if (opaque->cached_subtype != subtype)
  582. {
  583. uint16 i;
  584. for (i = 1; i <= RTMaxStrategyNumber; i++)
  585. opaque->strategy_procinfos[i - 1].fn_oid = InvalidOid;
  586. opaque->cached_subtype = subtype;
  587. }
  588. if (opaque->strategy_procinfos[strategynum - 1].fn_oid == InvalidOid)
  589. {
  590. Form_pg_attribute attr;
  591. HeapTuple tuple;
  592. Oid opfamily,
  593. oprid;
  594. bool isNull;
  595. opfamily = bdesc->bd_index->rd_opfamily[attno - 1];
  596. attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1);
  597. tuple = SearchSysCache4(AMOPSTRATEGY, ObjectIdGetDatum(opfamily),
  598. ObjectIdGetDatum(attr->atttypid),
  599. ObjectIdGetDatum(subtype),
  600. Int16GetDatum(strategynum));
  601. if (!HeapTupleIsValid(tuple))
  602. elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
  603. strategynum, attr->atttypid, subtype, opfamily);
  604. oprid = DatumGetObjectId(SysCacheGetAttr(AMOPSTRATEGY, tuple,
  605. Anum_pg_amop_amopopr, &isNull));
  606. ReleaseSysCache(tuple);
  607. Assert(!isNull && RegProcedureIsValid(oprid));
  608. fmgr_info_cxt(get_opcode(oprid),
  609. &opaque->strategy_procinfos[strategynum - 1],
  610. bdesc->bd_context);
  611. }
  612. return &opaque->strategy_procinfos[strategynum - 1];
  613. }