You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ginarrayproc.c 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*-------------------------------------------------------------------------
  2. *
  3. * ginarrayproc.c
  4. * support functions for GIN's indexing of any array
  5. *
  6. *
  7. * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
  8. * Portions Copyright (c) 1994, Regents of the University of California
  9. *
  10. * IDENTIFICATION
  11. * src/backend/access/gin/ginarrayproc.c
  12. *-------------------------------------------------------------------------
  13. */
  14. #include "postgres.h"
  15. #include "access/gin.h"
  16. #include "access/stratnum.h"
  17. #include "utils/array.h"
  18. #include "utils/builtins.h"
  19. #include "utils/lsyscache.h"
  20. #define GinOverlapStrategy 1
  21. #define GinContainsStrategy 2
  22. #define GinContainedStrategy 3
  23. #define GinEqualStrategy 4
  24. /*
  25. * extractValue support function
  26. */
  27. Datum
  28. ginarrayextract(PG_FUNCTION_ARGS)
  29. {
  30. /* Make copy of array input to ensure it doesn't disappear while in use */
  31. ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
  32. int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
  33. bool **nullFlags = (bool **) PG_GETARG_POINTER(2);
  34. int16 elmlen;
  35. bool elmbyval;
  36. char elmalign;
  37. Datum *elems;
  38. bool *nulls;
  39. int nelems;
  40. get_typlenbyvalalign(ARR_ELEMTYPE(array),
  41. &elmlen, &elmbyval, &elmalign);
  42. deconstruct_array(array,
  43. ARR_ELEMTYPE(array),
  44. elmlen, elmbyval, elmalign,
  45. &elems, &nulls, &nelems);
  46. *nkeys = nelems;
  47. *nullFlags = nulls;
  48. /* we should not free array, elems[i] points into it */
  49. PG_RETURN_POINTER(elems);
  50. }
  51. /*
  52. * Formerly, ginarrayextract had only two arguments. Now it has three,
  53. * but we still need a pg_proc entry with two args to support reloading
  54. * pre-9.1 contrib/intarray opclass declarations. This compatibility
  55. * function should go away eventually.
  56. */
  57. Datum
  58. ginarrayextract_2args(PG_FUNCTION_ARGS)
  59. {
  60. if (PG_NARGS() < 3) /* should not happen */
  61. elog(ERROR, "ginarrayextract requires three arguments");
  62. return ginarrayextract(fcinfo);
  63. }
  64. /*
  65. * extractQuery support function
  66. */
  67. Datum
  68. ginqueryarrayextract(PG_FUNCTION_ARGS)
  69. {
  70. /* Make copy of array input to ensure it doesn't disappear while in use */
  71. ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
  72. int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
  73. StrategyNumber strategy = PG_GETARG_UINT16(2);
  74. /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
  75. /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
  76. bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
  77. int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
  78. int16 elmlen;
  79. bool elmbyval;
  80. char elmalign;
  81. Datum *elems;
  82. bool *nulls;
  83. int nelems;
  84. get_typlenbyvalalign(ARR_ELEMTYPE(array),
  85. &elmlen, &elmbyval, &elmalign);
  86. deconstruct_array(array,
  87. ARR_ELEMTYPE(array),
  88. elmlen, elmbyval, elmalign,
  89. &elems, &nulls, &nelems);
  90. *nkeys = nelems;
  91. *nullFlags = nulls;
  92. switch (strategy)
  93. {
  94. case GinOverlapStrategy:
  95. *searchMode = GIN_SEARCH_MODE_DEFAULT;
  96. break;
  97. case GinContainsStrategy:
  98. if (nelems > 0)
  99. *searchMode = GIN_SEARCH_MODE_DEFAULT;
  100. else /* everything contains the empty set */
  101. *searchMode = GIN_SEARCH_MODE_ALL;
  102. break;
  103. case GinContainedStrategy:
  104. /* empty set is contained in everything */
  105. *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
  106. break;
  107. case GinEqualStrategy:
  108. if (nelems > 0)
  109. *searchMode = GIN_SEARCH_MODE_DEFAULT;
  110. else
  111. *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
  112. break;
  113. default:
  114. elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
  115. strategy);
  116. }
  117. /* we should not free array, elems[i] points into it */
  118. PG_RETURN_POINTER(elems);
  119. }
  120. /*
  121. * consistent support function
  122. */
  123. Datum
  124. ginarrayconsistent(PG_FUNCTION_ARGS)
  125. {
  126. bool *check = (bool *) PG_GETARG_POINTER(0);
  127. StrategyNumber strategy = PG_GETARG_UINT16(1);
  128. /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
  129. int32 nkeys = PG_GETARG_INT32(3);
  130. /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
  131. bool *recheck = (bool *) PG_GETARG_POINTER(5);
  132. /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
  133. bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
  134. bool res;
  135. int32 i;
  136. switch (strategy)
  137. {
  138. case GinOverlapStrategy:
  139. /* result is not lossy */
  140. *recheck = false;
  141. /* must have a match for at least one non-null element */
  142. res = false;
  143. for (i = 0; i < nkeys; i++)
  144. {
  145. if (check[i] && !nullFlags[i])
  146. {
  147. res = true;
  148. break;
  149. }
  150. }
  151. break;
  152. case GinContainsStrategy:
  153. /* result is not lossy */
  154. *recheck = false;
  155. /* must have all elements in check[] true, and no nulls */
  156. res = true;
  157. for (i = 0; i < nkeys; i++)
  158. {
  159. if (!check[i] || nullFlags[i])
  160. {
  161. res = false;
  162. break;
  163. }
  164. }
  165. break;
  166. case GinContainedStrategy:
  167. /* we will need recheck */
  168. *recheck = true;
  169. /* can't do anything else useful here */
  170. res = true;
  171. break;
  172. case GinEqualStrategy:
  173. /* we will need recheck */
  174. *recheck = true;
  175. /*
  176. * Must have all elements in check[] true; no discrimination
  177. * against nulls here. This is because array_contain_compare and
  178. * array_eq handle nulls differently ...
  179. */
  180. res = true;
  181. for (i = 0; i < nkeys; i++)
  182. {
  183. if (!check[i])
  184. {
  185. res = false;
  186. break;
  187. }
  188. }
  189. break;
  190. default:
  191. elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
  192. strategy);
  193. res = false;
  194. }
  195. PG_RETURN_BOOL(res);
  196. }
  197. /*
  198. * triconsistent support function
  199. */
  200. Datum
  201. ginarraytriconsistent(PG_FUNCTION_ARGS)
  202. {
  203. GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
  204. StrategyNumber strategy = PG_GETARG_UINT16(1);
  205. /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
  206. int32 nkeys = PG_GETARG_INT32(3);
  207. /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
  208. /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5); */
  209. bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
  210. GinTernaryValue res;
  211. int32 i;
  212. switch (strategy)
  213. {
  214. case GinOverlapStrategy:
  215. /* must have a match for at least one non-null element */
  216. res = GIN_FALSE;
  217. for (i = 0; i < nkeys; i++)
  218. {
  219. if (!nullFlags[i])
  220. {
  221. if (check[i] == GIN_TRUE)
  222. {
  223. res = GIN_TRUE;
  224. break;
  225. }
  226. else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
  227. {
  228. res = GIN_MAYBE;
  229. }
  230. }
  231. }
  232. break;
  233. case GinContainsStrategy:
  234. /* must have all elements in check[] true, and no nulls */
  235. res = GIN_TRUE;
  236. for (i = 0; i < nkeys; i++)
  237. {
  238. if (check[i] == GIN_FALSE || nullFlags[i])
  239. {
  240. res = GIN_FALSE;
  241. break;
  242. }
  243. if (check[i] == GIN_MAYBE)
  244. {
  245. res = GIN_MAYBE;
  246. }
  247. }
  248. break;
  249. case GinContainedStrategy:
  250. /* can't do anything else useful here */
  251. res = GIN_MAYBE;
  252. break;
  253. case GinEqualStrategy:
  254. /*
  255. * Must have all elements in check[] true; no discrimination
  256. * against nulls here. This is because array_contain_compare and
  257. * array_eq handle nulls differently ...
  258. */
  259. res = GIN_MAYBE;
  260. for (i = 0; i < nkeys; i++)
  261. {
  262. if (check[i] == GIN_FALSE)
  263. {
  264. res = GIN_FALSE;
  265. break;
  266. }
  267. }
  268. break;
  269. default:
  270. elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
  271. strategy);
  272. res = false;
  273. }
  274. PG_RETURN_GIN_TERNARY_VALUE(res);
  275. }