/contrib/hstore/hstore_gin.c

https://gitlab.com/kajan-rezg/postgres · C · 212 lines · 156 code · 31 blank · 25 comment · 37 complexity · d8f0a1c9959970269b09988416a30839 MD5 · raw file

  1. /*
  2. * contrib/hstore/hstore_gin.c
  3. */
  4. #include "postgres.h"
  5. #include "access/gin.h"
  6. #include "access/stratnum.h"
  7. #include "catalog/pg_type.h"
  8. #include "hstore.h"
  9. /*
  10. * When using a GIN index for hstore, we choose to index both keys and values.
  11. * The storage format is "text" values, with K, V, or N prepended to the string
  12. * to indicate key, value, or null values. (As of 9.1 it might be better to
  13. * store null values as nulls, but we'll keep it this way for on-disk
  14. * compatibility.)
  15. */
  16. #define KEYFLAG 'K'
  17. #define VALFLAG 'V'
  18. #define NULLFLAG 'N'
  19. PG_FUNCTION_INFO_V1(gin_extract_hstore);
  20. /* Build an indexable text value */
  21. static text *
  22. makeitem(char *str, int len, char flag)
  23. {
  24. text *item;
  25. item = (text *) palloc(VARHDRSZ + len + 1);
  26. SET_VARSIZE(item, VARHDRSZ + len + 1);
  27. *VARDATA(item) = flag;
  28. if (str && len > 0)
  29. memcpy(VARDATA(item) + 1, str, len);
  30. return item;
  31. }
  32. Datum
  33. gin_extract_hstore(PG_FUNCTION_ARGS)
  34. {
  35. HStore *hs = PG_GETARG_HS(0);
  36. int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
  37. Datum *entries = NULL;
  38. HEntry *hsent = ARRPTR(hs);
  39. char *ptr = STRPTR(hs);
  40. int count = HS_COUNT(hs);
  41. int i;
  42. *nentries = 2 * count;
  43. if (count)
  44. entries = (Datum *) palloc(sizeof(Datum) * 2 * count);
  45. for (i = 0; i < count; ++i)
  46. {
  47. text *item;
  48. item = makeitem(HSTORE_KEY(hsent, ptr, i),
  49. HSTORE_KEYLEN(hsent, i),
  50. KEYFLAG);
  51. entries[2 * i] = PointerGetDatum(item);
  52. if (HSTORE_VALISNULL(hsent, i))
  53. item = makeitem(NULL, 0, NULLFLAG);
  54. else
  55. item = makeitem(HSTORE_VAL(hsent, ptr, i),
  56. HSTORE_VALLEN(hsent, i),
  57. VALFLAG);
  58. entries[2 * i + 1] = PointerGetDatum(item);
  59. }
  60. PG_RETURN_POINTER(entries);
  61. }
  62. PG_FUNCTION_INFO_V1(gin_extract_hstore_query);
  63. Datum
  64. gin_extract_hstore_query(PG_FUNCTION_ARGS)
  65. {
  66. int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
  67. StrategyNumber strategy = PG_GETARG_UINT16(2);
  68. int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
  69. Datum *entries;
  70. if (strategy == HStoreContainsStrategyNumber)
  71. {
  72. /* Query is an hstore, so just apply gin_extract_hstore... */
  73. entries = (Datum *)
  74. DatumGetPointer(DirectFunctionCall2(gin_extract_hstore,
  75. PG_GETARG_DATUM(0),
  76. PointerGetDatum(nentries)));
  77. /* ... except that "contains {}" requires a full index scan */
  78. if (entries == NULL)
  79. *searchMode = GIN_SEARCH_MODE_ALL;
  80. }
  81. else if (strategy == HStoreExistsStrategyNumber)
  82. {
  83. text *query = PG_GETARG_TEXT_PP(0);
  84. text *item;
  85. *nentries = 1;
  86. entries = (Datum *) palloc(sizeof(Datum));
  87. item = makeitem(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), KEYFLAG);
  88. entries[0] = PointerGetDatum(item);
  89. }
  90. else if (strategy == HStoreExistsAnyStrategyNumber ||
  91. strategy == HStoreExistsAllStrategyNumber)
  92. {
  93. ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
  94. Datum *key_datums;
  95. bool *key_nulls;
  96. int key_count;
  97. int i,
  98. j;
  99. text *item;
  100. deconstruct_array(query,
  101. TEXTOID, -1, false, 'i',
  102. &key_datums, &key_nulls, &key_count);
  103. entries = (Datum *) palloc(sizeof(Datum) * key_count);
  104. for (i = 0, j = 0; i < key_count; ++i)
  105. {
  106. /* Nulls in the array are ignored, cf hstoreArrayToPairs */
  107. if (key_nulls[i])
  108. continue;
  109. item = makeitem(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, KEYFLAG);
  110. entries[j++] = PointerGetDatum(item);
  111. }
  112. *nentries = j;
  113. /* ExistsAll with no keys should match everything */
  114. if (j == 0 && strategy == HStoreExistsAllStrategyNumber)
  115. *searchMode = GIN_SEARCH_MODE_ALL;
  116. }
  117. else
  118. {
  119. elog(ERROR, "unrecognized strategy number: %d", strategy);
  120. entries = NULL; /* keep compiler quiet */
  121. }
  122. PG_RETURN_POINTER(entries);
  123. }
  124. PG_FUNCTION_INFO_V1(gin_consistent_hstore);
  125. Datum
  126. gin_consistent_hstore(PG_FUNCTION_ARGS)
  127. {
  128. bool *check = (bool *) PG_GETARG_POINTER(0);
  129. StrategyNumber strategy = PG_GETARG_UINT16(1);
  130. /* HStore *query = PG_GETARG_HS(2); */
  131. int32 nkeys = PG_GETARG_INT32(3);
  132. /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
  133. bool *recheck = (bool *) PG_GETARG_POINTER(5);
  134. bool res = true;
  135. int32 i;
  136. if (strategy == HStoreContainsStrategyNumber)
  137. {
  138. /*
  139. * Index doesn't have information about correspondence of keys and
  140. * values, so we need recheck. However, if not all the keys are
  141. * present, we can fail at once.
  142. */
  143. *recheck = true;
  144. for (i = 0; i < nkeys; i++)
  145. {
  146. if (!check[i])
  147. {
  148. res = false;
  149. break;
  150. }
  151. }
  152. }
  153. else if (strategy == HStoreExistsStrategyNumber)
  154. {
  155. /* Existence of key is guaranteed in default search mode */
  156. *recheck = false;
  157. res = true;
  158. }
  159. else if (strategy == HStoreExistsAnyStrategyNumber)
  160. {
  161. /* Existence of key is guaranteed in default search mode */
  162. *recheck = false;
  163. res = true;
  164. }
  165. else if (strategy == HStoreExistsAllStrategyNumber)
  166. {
  167. /* Testing for all the keys being present gives an exact result */
  168. *recheck = false;
  169. for (i = 0; i < nkeys; i++)
  170. {
  171. if (!check[i])
  172. {
  173. res = false;
  174. break;
  175. }
  176. }
  177. }
  178. else
  179. elog(ERROR, "unrecognized strategy number: %d", strategy);
  180. PG_RETURN_BOOL(res);
  181. }