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.

ginfuncs.c 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * ginfuncs.c
  3. * Functions to investigate the content of GIN indexes
  4. *
  5. * Copyright (c) 2014-2019, PostgreSQL Global Development Group
  6. *
  7. * IDENTIFICATION
  8. * contrib/pageinspect/ginfuncs.c
  9. */
  10. #include "postgres.h"
  11. #include "pageinspect.h"
  12. #include "access/gin.h"
  13. #include "access/gin_private.h"
  14. #include "access/htup_details.h"
  15. #include "catalog/namespace.h"
  16. #include "catalog/pg_type.h"
  17. #include "funcapi.h"
  18. #include "miscadmin.h"
  19. #include "utils/array.h"
  20. #include "utils/builtins.h"
  21. #include "utils/rel.h"
  22. #define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
  23. #define ItemPointerGetDatum(X) PointerGetDatum(X)
  24. PG_FUNCTION_INFO_V1(gin_metapage_info);
  25. PG_FUNCTION_INFO_V1(gin_page_opaque_info);
  26. PG_FUNCTION_INFO_V1(gin_leafpage_items);
  27. Datum
  28. gin_metapage_info(PG_FUNCTION_ARGS)
  29. {
  30. bytea *raw_page = PG_GETARG_BYTEA_P(0);
  31. TupleDesc tupdesc;
  32. Page page;
  33. GinPageOpaque opaq;
  34. GinMetaPageData *metadata;
  35. HeapTuple resultTuple;
  36. Datum values[10];
  37. bool nulls[10];
  38. if (!superuser())
  39. ereport(ERROR,
  40. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  41. (errmsg("must be superuser to use raw page functions"))));
  42. page = get_page_from_raw(raw_page);
  43. opaq = (GinPageOpaque) PageGetSpecialPointer(page);
  44. if (opaq->flags != GIN_META)
  45. ereport(ERROR,
  46. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  47. errmsg("input page is not a GIN metapage"),
  48. errdetail("Flags %04X, expected %04X",
  49. opaq->flags, GIN_META)));
  50. /* Build a tuple descriptor for our result type */
  51. if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  52. elog(ERROR, "return type must be a row type");
  53. metadata = GinPageGetMeta(page);
  54. memset(nulls, 0, sizeof(nulls));
  55. values[0] = Int64GetDatum(metadata->head);
  56. values[1] = Int64GetDatum(metadata->tail);
  57. values[2] = Int32GetDatum(metadata->tailFreeSize);
  58. values[3] = Int64GetDatum(metadata->nPendingPages);
  59. values[4] = Int64GetDatum(metadata->nPendingHeapTuples);
  60. /* statistics, updated by VACUUM */
  61. values[5] = Int64GetDatum(metadata->nTotalPages);
  62. values[6] = Int64GetDatum(metadata->nEntryPages);
  63. values[7] = Int64GetDatum(metadata->nDataPages);
  64. values[8] = Int64GetDatum(metadata->nEntries);
  65. values[9] = Int32GetDatum(metadata->ginVersion);
  66. /* Build and return the result tuple. */
  67. resultTuple = heap_form_tuple(tupdesc, values, nulls);
  68. return HeapTupleGetDatum(resultTuple);
  69. }
  70. Datum
  71. gin_page_opaque_info(PG_FUNCTION_ARGS)
  72. {
  73. bytea *raw_page = PG_GETARG_BYTEA_P(0);
  74. TupleDesc tupdesc;
  75. Page page;
  76. GinPageOpaque opaq;
  77. HeapTuple resultTuple;
  78. Datum values[3];
  79. bool nulls[3];
  80. Datum flags[16];
  81. int nflags = 0;
  82. uint16 flagbits;
  83. if (!superuser())
  84. ereport(ERROR,
  85. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  86. (errmsg("must be superuser to use raw page functions"))));
  87. page = get_page_from_raw(raw_page);
  88. opaq = (GinPageOpaque) PageGetSpecialPointer(page);
  89. /* Build a tuple descriptor for our result type */
  90. if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  91. elog(ERROR, "return type must be a row type");
  92. /* Convert the flags bitmask to an array of human-readable names */
  93. flagbits = opaq->flags;
  94. if (flagbits & GIN_DATA)
  95. flags[nflags++] = CStringGetTextDatum("data");
  96. if (flagbits & GIN_LEAF)
  97. flags[nflags++] = CStringGetTextDatum("leaf");
  98. if (flagbits & GIN_DELETED)
  99. flags[nflags++] = CStringGetTextDatum("deleted");
  100. if (flagbits & GIN_META)
  101. flags[nflags++] = CStringGetTextDatum("meta");
  102. if (flagbits & GIN_LIST)
  103. flags[nflags++] = CStringGetTextDatum("list");
  104. if (flagbits & GIN_LIST_FULLROW)
  105. flags[nflags++] = CStringGetTextDatum("list_fullrow");
  106. if (flagbits & GIN_INCOMPLETE_SPLIT)
  107. flags[nflags++] = CStringGetTextDatum("incomplete_split");
  108. if (flagbits & GIN_COMPRESSED)
  109. flags[nflags++] = CStringGetTextDatum("compressed");
  110. flagbits &= ~(GIN_DATA | GIN_LEAF | GIN_DELETED | GIN_META | GIN_LIST |
  111. GIN_LIST_FULLROW | GIN_INCOMPLETE_SPLIT | GIN_COMPRESSED);
  112. if (flagbits)
  113. {
  114. /* any flags we don't recognize are printed in hex */
  115. flags[nflags++] = DirectFunctionCall1(to_hex32, Int32GetDatum(flagbits));
  116. }
  117. memset(nulls, 0, sizeof(nulls));
  118. values[0] = Int64GetDatum(opaq->rightlink);
  119. values[1] = Int32GetDatum(opaq->maxoff);
  120. values[2] = PointerGetDatum(construct_array(flags, nflags,
  121. TEXTOID, -1, false, 'i'));
  122. /* Build and return the result tuple. */
  123. resultTuple = heap_form_tuple(tupdesc, values, nulls);
  124. return HeapTupleGetDatum(resultTuple);
  125. }
  126. typedef struct gin_leafpage_items_state
  127. {
  128. TupleDesc tupd;
  129. GinPostingList *seg;
  130. GinPostingList *lastseg;
  131. } gin_leafpage_items_state;
  132. Datum
  133. gin_leafpage_items(PG_FUNCTION_ARGS)
  134. {
  135. bytea *raw_page = PG_GETARG_BYTEA_P(0);
  136. FuncCallContext *fctx;
  137. gin_leafpage_items_state *inter_call_data;
  138. if (!superuser())
  139. ereport(ERROR,
  140. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  141. (errmsg("must be superuser to use raw page functions"))));
  142. if (SRF_IS_FIRSTCALL())
  143. {
  144. TupleDesc tupdesc;
  145. MemoryContext mctx;
  146. Page page;
  147. GinPageOpaque opaq;
  148. fctx = SRF_FIRSTCALL_INIT();
  149. mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
  150. page = get_page_from_raw(raw_page);
  151. if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData)))
  152. ereport(ERROR,
  153. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  154. errmsg("input page is not a valid GIN data leaf page"),
  155. errdetail("Special size %d, expected %d",
  156. (int) PageGetSpecialSize(page),
  157. (int) MAXALIGN(sizeof(GinPageOpaqueData)))));
  158. opaq = (GinPageOpaque) PageGetSpecialPointer(page);
  159. if (opaq->flags != (GIN_DATA | GIN_LEAF | GIN_COMPRESSED))
  160. ereport(ERROR,
  161. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  162. errmsg("input page is not a compressed GIN data leaf page"),
  163. errdetail("Flags %04X, expected %04X",
  164. opaq->flags,
  165. (GIN_DATA | GIN_LEAF | GIN_COMPRESSED))));
  166. inter_call_data = palloc(sizeof(gin_leafpage_items_state));
  167. /* Build a tuple descriptor for our result type */
  168. if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
  169. elog(ERROR, "return type must be a row type");
  170. inter_call_data->tupd = tupdesc;
  171. inter_call_data->seg = GinDataLeafPageGetPostingList(page);
  172. inter_call_data->lastseg = (GinPostingList *)
  173. (((char *) inter_call_data->seg) +
  174. GinDataLeafPageGetPostingListSize(page));
  175. fctx->user_fctx = inter_call_data;
  176. MemoryContextSwitchTo(mctx);
  177. }
  178. fctx = SRF_PERCALL_SETUP();
  179. inter_call_data = fctx->user_fctx;
  180. if (inter_call_data->seg != inter_call_data->lastseg)
  181. {
  182. GinPostingList *cur = inter_call_data->seg;
  183. HeapTuple resultTuple;
  184. Datum result;
  185. Datum values[3];
  186. bool nulls[3];
  187. int ndecoded,
  188. i;
  189. ItemPointer tids;
  190. Datum *tids_datum;
  191. memset(nulls, 0, sizeof(nulls));
  192. values[0] = ItemPointerGetDatum(&cur->first);
  193. values[1] = UInt16GetDatum(cur->nbytes);
  194. /* build an array of decoded item pointers */
  195. tids = ginPostingListDecode(cur, &ndecoded);
  196. tids_datum = (Datum *) palloc(ndecoded * sizeof(Datum));
  197. for (i = 0; i < ndecoded; i++)
  198. tids_datum[i] = ItemPointerGetDatum(&tids[i]);
  199. values[2] = PointerGetDatum(construct_array(tids_datum,
  200. ndecoded,
  201. TIDOID,
  202. sizeof(ItemPointerData),
  203. false, 's'));
  204. pfree(tids_datum);
  205. pfree(tids);
  206. /* Build and return the result tuple. */
  207. resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
  208. result = HeapTupleGetDatum(resultTuple);
  209. inter_call_data->seg = GinNextPostingListSegment(cur);
  210. SRF_RETURN_NEXT(fctx, result);
  211. }
  212. else
  213. SRF_RETURN_DONE(fctx);
  214. }