gitlab-pg_query 1.3.1 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +217 -99
  3. data/README.md +92 -69
  4. data/Rakefile +85 -5
  5. data/ext/pg_query/extconf.rb +3 -40
  6. data/ext/pg_query/guc-file.c +0 -0
  7. data/ext/pg_query/include/access/amapi.h +246 -0
  8. data/ext/pg_query/include/access/attmap.h +52 -0
  9. data/ext/pg_query/include/access/attnum.h +64 -0
  10. data/ext/pg_query/include/access/clog.h +61 -0
  11. data/ext/pg_query/include/access/commit_ts.h +77 -0
  12. data/ext/pg_query/include/access/detoast.h +92 -0
  13. data/ext/pg_query/include/access/genam.h +228 -0
  14. data/ext/pg_query/include/access/gin.h +78 -0
  15. data/ext/pg_query/include/access/htup.h +89 -0
  16. data/ext/pg_query/include/access/htup_details.h +819 -0
  17. data/ext/pg_query/include/access/itup.h +161 -0
  18. data/ext/pg_query/include/access/parallel.h +82 -0
  19. data/ext/pg_query/include/access/printtup.h +35 -0
  20. data/ext/pg_query/include/access/relation.h +28 -0
  21. data/ext/pg_query/include/access/relscan.h +176 -0
  22. data/ext/pg_query/include/access/rmgr.h +35 -0
  23. data/ext/pg_query/include/access/rmgrlist.h +49 -0
  24. data/ext/pg_query/include/access/sdir.h +58 -0
  25. data/ext/pg_query/include/access/skey.h +151 -0
  26. data/ext/pg_query/include/access/stratnum.h +83 -0
  27. data/ext/pg_query/include/access/sysattr.h +29 -0
  28. data/ext/pg_query/include/access/table.h +27 -0
  29. data/ext/pg_query/include/access/tableam.h +1825 -0
  30. data/ext/pg_query/include/access/transam.h +265 -0
  31. data/ext/pg_query/include/access/tupconvert.h +51 -0
  32. data/ext/pg_query/include/access/tupdesc.h +154 -0
  33. data/ext/pg_query/include/access/tupmacs.h +247 -0
  34. data/ext/pg_query/include/access/twophase.h +61 -0
  35. data/ext/pg_query/include/access/xact.h +463 -0
  36. data/ext/pg_query/include/access/xlog.h +398 -0
  37. data/ext/pg_query/include/access/xlog_internal.h +330 -0
  38. data/ext/pg_query/include/access/xlogdefs.h +109 -0
  39. data/ext/pg_query/include/access/xloginsert.h +64 -0
  40. data/ext/pg_query/include/access/xlogreader.h +327 -0
  41. data/ext/pg_query/include/access/xlogrecord.h +227 -0
  42. data/ext/pg_query/include/bootstrap/bootstrap.h +62 -0
  43. data/ext/pg_query/include/c.h +1322 -0
  44. data/ext/pg_query/include/catalog/catalog.h +42 -0
  45. data/ext/pg_query/include/catalog/catversion.h +58 -0
  46. data/ext/pg_query/include/catalog/dependency.h +275 -0
  47. data/ext/pg_query/include/catalog/genbki.h +64 -0
  48. data/ext/pg_query/include/catalog/index.h +199 -0
  49. data/ext/pg_query/include/catalog/indexing.h +366 -0
  50. data/ext/pg_query/include/catalog/namespace.h +188 -0
  51. data/ext/pg_query/include/catalog/objectaccess.h +197 -0
  52. data/ext/pg_query/include/catalog/objectaddress.h +84 -0
  53. data/ext/pg_query/include/catalog/pg_aggregate.h +176 -0
  54. data/ext/pg_query/include/catalog/pg_aggregate_d.h +77 -0
  55. data/ext/pg_query/include/catalog/pg_am.h +60 -0
  56. data/ext/pg_query/include/catalog/pg_am_d.h +45 -0
  57. data/ext/pg_query/include/catalog/pg_attribute.h +204 -0
  58. data/ext/pg_query/include/catalog/pg_attribute_d.h +59 -0
  59. data/ext/pg_query/include/catalog/pg_authid.h +58 -0
  60. data/ext/pg_query/include/catalog/pg_authid_d.h +49 -0
  61. data/ext/pg_query/include/catalog/pg_class.h +200 -0
  62. data/ext/pg_query/include/catalog/pg_class_d.h +103 -0
  63. data/ext/pg_query/include/catalog/pg_collation.h +73 -0
  64. data/ext/pg_query/include/catalog/pg_collation_d.h +45 -0
  65. data/ext/pg_query/include/catalog/pg_constraint.h +247 -0
  66. data/ext/pg_query/include/catalog/pg_constraint_d.h +67 -0
  67. data/ext/pg_query/include/catalog/pg_control.h +250 -0
  68. data/ext/pg_query/include/catalog/pg_conversion.h +72 -0
  69. data/ext/pg_query/include/catalog/pg_conversion_d.h +35 -0
  70. data/ext/pg_query/include/catalog/pg_depend.h +73 -0
  71. data/ext/pg_query/include/catalog/pg_depend_d.h +34 -0
  72. data/ext/pg_query/include/catalog/pg_event_trigger.h +51 -0
  73. data/ext/pg_query/include/catalog/pg_event_trigger_d.h +34 -0
  74. data/ext/pg_query/include/catalog/pg_index.h +80 -0
  75. data/ext/pg_query/include/catalog/pg_index_d.h +56 -0
  76. data/ext/pg_query/include/catalog/pg_language.h +67 -0
  77. data/ext/pg_query/include/catalog/pg_language_d.h +39 -0
  78. data/ext/pg_query/include/catalog/pg_namespace.h +59 -0
  79. data/ext/pg_query/include/catalog/pg_namespace_d.h +34 -0
  80. data/ext/pg_query/include/catalog/pg_opclass.h +85 -0
  81. data/ext/pg_query/include/catalog/pg_opclass_d.h +49 -0
  82. data/ext/pg_query/include/catalog/pg_operator.h +102 -0
  83. data/ext/pg_query/include/catalog/pg_operator_d.h +106 -0
  84. data/ext/pg_query/include/catalog/pg_opfamily.h +60 -0
  85. data/ext/pg_query/include/catalog/pg_opfamily_d.h +47 -0
  86. data/ext/pg_query/include/catalog/pg_partitioned_table.h +63 -0
  87. data/ext/pg_query/include/catalog/pg_partitioned_table_d.h +35 -0
  88. data/ext/pg_query/include/catalog/pg_proc.h +211 -0
  89. data/ext/pg_query/include/catalog/pg_proc_d.h +99 -0
  90. data/ext/pg_query/include/catalog/pg_publication.h +115 -0
  91. data/ext/pg_query/include/catalog/pg_publication_d.h +36 -0
  92. data/ext/pg_query/include/catalog/pg_replication_origin.h +57 -0
  93. data/ext/pg_query/include/catalog/pg_replication_origin_d.h +29 -0
  94. data/ext/pg_query/include/catalog/pg_statistic.h +275 -0
  95. data/ext/pg_query/include/catalog/pg_statistic_d.h +194 -0
  96. data/ext/pg_query/include/catalog/pg_statistic_ext.h +74 -0
  97. data/ext/pg_query/include/catalog/pg_statistic_ext_d.h +40 -0
  98. data/ext/pg_query/include/catalog/pg_transform.h +45 -0
  99. data/ext/pg_query/include/catalog/pg_transform_d.h +32 -0
  100. data/ext/pg_query/include/catalog/pg_trigger.h +137 -0
  101. data/ext/pg_query/include/catalog/pg_trigger_d.h +106 -0
  102. data/ext/pg_query/include/catalog/pg_ts_config.h +50 -0
  103. data/ext/pg_query/include/catalog/pg_ts_config_d.h +32 -0
  104. data/ext/pg_query/include/catalog/pg_ts_dict.h +54 -0
  105. data/ext/pg_query/include/catalog/pg_ts_dict_d.h +33 -0
  106. data/ext/pg_query/include/catalog/pg_ts_parser.h +57 -0
  107. data/ext/pg_query/include/catalog/pg_ts_parser_d.h +35 -0
  108. data/ext/pg_query/include/catalog/pg_ts_template.h +48 -0
  109. data/ext/pg_query/include/catalog/pg_ts_template_d.h +32 -0
  110. data/ext/pg_query/include/catalog/pg_type.h +372 -0
  111. data/ext/pg_query/include/catalog/pg_type_d.h +285 -0
  112. data/ext/pg_query/include/catalog/storage.h +48 -0
  113. data/ext/pg_query/include/commands/async.h +54 -0
  114. data/ext/pg_query/include/commands/dbcommands.h +35 -0
  115. data/ext/pg_query/include/commands/defrem.h +173 -0
  116. data/ext/pg_query/include/commands/event_trigger.h +88 -0
  117. data/ext/pg_query/include/commands/explain.h +127 -0
  118. data/ext/pg_query/include/commands/prepare.h +61 -0
  119. data/ext/pg_query/include/commands/tablespace.h +67 -0
  120. data/ext/pg_query/include/commands/trigger.h +277 -0
  121. data/ext/pg_query/include/commands/user.h +37 -0
  122. data/ext/pg_query/include/commands/vacuum.h +293 -0
  123. data/ext/pg_query/include/commands/variable.h +38 -0
  124. data/ext/pg_query/include/common/file_perm.h +56 -0
  125. data/ext/pg_query/include/common/hashfn.h +104 -0
  126. data/ext/pg_query/include/common/ip.h +37 -0
  127. data/ext/pg_query/include/common/keywords.h +33 -0
  128. data/ext/pg_query/include/common/kwlookup.h +44 -0
  129. data/ext/pg_query/include/common/relpath.h +90 -0
  130. data/ext/pg_query/include/common/string.h +19 -0
  131. data/ext/pg_query/include/common/unicode_combining_table.h +196 -0
  132. data/ext/pg_query/include/datatype/timestamp.h +197 -0
  133. data/ext/pg_query/include/executor/execdesc.h +70 -0
  134. data/ext/pg_query/include/executor/executor.h +614 -0
  135. data/ext/pg_query/include/executor/functions.h +41 -0
  136. data/ext/pg_query/include/executor/instrument.h +101 -0
  137. data/ext/pg_query/include/executor/spi.h +175 -0
  138. data/ext/pg_query/include/executor/tablefunc.h +67 -0
  139. data/ext/pg_query/include/executor/tuptable.h +487 -0
  140. data/ext/pg_query/include/fmgr.h +775 -0
  141. data/ext/pg_query/include/funcapi.h +348 -0
  142. data/ext/pg_query/include/getaddrinfo.h +162 -0
  143. data/ext/pg_query/include/jit/jit.h +105 -0
  144. data/ext/pg_query/include/kwlist_d.h +1072 -0
  145. data/ext/pg_query/include/lib/ilist.h +727 -0
  146. data/ext/pg_query/include/lib/pairingheap.h +102 -0
  147. data/ext/pg_query/include/lib/simplehash.h +1059 -0
  148. data/ext/pg_query/include/lib/stringinfo.h +161 -0
  149. data/ext/pg_query/include/libpq/auth.h +29 -0
  150. data/ext/pg_query/include/libpq/crypt.h +46 -0
  151. data/ext/pg_query/include/libpq/hba.h +140 -0
  152. data/ext/pg_query/include/libpq/libpq-be.h +326 -0
  153. data/ext/pg_query/include/libpq/libpq.h +133 -0
  154. data/ext/pg_query/include/libpq/pqcomm.h +208 -0
  155. data/ext/pg_query/include/libpq/pqformat.h +210 -0
  156. data/ext/pg_query/include/libpq/pqsignal.h +42 -0
  157. data/ext/pg_query/include/mb/pg_wchar.h +672 -0
  158. data/ext/pg_query/include/mb/stringinfo_mb.h +24 -0
  159. data/ext/pg_query/include/miscadmin.h +476 -0
  160. data/ext/pg_query/include/nodes/bitmapset.h +122 -0
  161. data/ext/pg_query/include/nodes/execnodes.h +2520 -0
  162. data/ext/pg_query/include/nodes/extensible.h +160 -0
  163. data/ext/pg_query/include/nodes/lockoptions.h +61 -0
  164. data/ext/pg_query/include/nodes/makefuncs.h +108 -0
  165. data/ext/pg_query/include/nodes/memnodes.h +108 -0
  166. data/ext/pg_query/include/nodes/nodeFuncs.h +162 -0
  167. data/ext/pg_query/include/nodes/nodes.h +842 -0
  168. data/ext/pg_query/include/nodes/params.h +170 -0
  169. data/ext/pg_query/include/nodes/parsenodes.h +3579 -0
  170. data/ext/pg_query/include/nodes/pathnodes.h +2556 -0
  171. data/ext/pg_query/include/nodes/pg_list.h +605 -0
  172. data/ext/pg_query/include/nodes/plannodes.h +1251 -0
  173. data/ext/pg_query/include/nodes/primnodes.h +1541 -0
  174. data/ext/pg_query/include/nodes/print.h +34 -0
  175. data/ext/pg_query/include/nodes/tidbitmap.h +75 -0
  176. data/ext/pg_query/include/nodes/value.h +61 -0
  177. data/ext/pg_query/include/optimizer/cost.h +206 -0
  178. data/ext/pg_query/include/optimizer/geqo.h +88 -0
  179. data/ext/pg_query/include/optimizer/geqo_gene.h +45 -0
  180. data/ext/pg_query/include/optimizer/optimizer.h +199 -0
  181. data/ext/pg_query/include/optimizer/paths.h +249 -0
  182. data/ext/pg_query/include/optimizer/planmain.h +119 -0
  183. data/ext/pg_query/include/parser/analyze.h +49 -0
  184. data/ext/pg_query/include/parser/gram.h +1067 -0
  185. data/ext/pg_query/include/parser/gramparse.h +75 -0
  186. data/ext/pg_query/include/parser/kwlist.h +477 -0
  187. data/ext/pg_query/include/parser/parse_agg.h +68 -0
  188. data/ext/pg_query/include/parser/parse_clause.h +54 -0
  189. data/ext/pg_query/include/parser/parse_coerce.h +97 -0
  190. data/ext/pg_query/include/parser/parse_collate.h +27 -0
  191. data/ext/pg_query/include/parser/parse_expr.h +26 -0
  192. data/ext/pg_query/include/parser/parse_func.h +73 -0
  193. data/ext/pg_query/include/parser/parse_node.h +327 -0
  194. data/ext/pg_query/include/parser/parse_oper.h +67 -0
  195. data/ext/pg_query/include/parser/parse_relation.h +123 -0
  196. data/ext/pg_query/include/parser/parse_target.h +46 -0
  197. data/ext/pg_query/include/parser/parse_type.h +60 -0
  198. data/ext/pg_query/include/parser/parser.h +41 -0
  199. data/ext/pg_query/include/parser/parsetree.h +61 -0
  200. data/ext/pg_query/include/parser/scanner.h +152 -0
  201. data/ext/pg_query/include/parser/scansup.h +30 -0
  202. data/ext/pg_query/include/partitioning/partdefs.h +26 -0
  203. data/ext/pg_query/include/pg_config.h +989 -0
  204. data/ext/pg_query/include/pg_config_ext.h +8 -0
  205. data/ext/pg_query/include/pg_config_manual.h +350 -0
  206. data/ext/pg_query/include/pg_config_os.h +8 -0
  207. data/ext/pg_query/include/pg_getopt.h +56 -0
  208. data/ext/pg_query/include/pg_query.h +121 -0
  209. data/ext/pg_query/include/pg_query_enum_defs.c +2454 -0
  210. data/ext/pg_query/include/pg_query_fingerprint_conds.c +875 -0
  211. data/ext/pg_query/include/pg_query_fingerprint_defs.c +12413 -0
  212. data/ext/pg_query/include/pg_query_json_helper.c +61 -0
  213. data/ext/pg_query/include/pg_query_outfuncs_conds.c +686 -0
  214. data/ext/pg_query/include/pg_query_outfuncs_defs.c +2437 -0
  215. data/ext/pg_query/include/pg_query_readfuncs_conds.c +222 -0
  216. data/ext/pg_query/include/pg_query_readfuncs_defs.c +2878 -0
  217. data/ext/pg_query/include/pg_trace.h +17 -0
  218. data/ext/pg_query/include/pgstat.h +1487 -0
  219. data/ext/pg_query/include/pgtime.h +84 -0
  220. data/ext/pg_query/include/pl_gram.h +385 -0
  221. data/ext/pg_query/include/pl_reserved_kwlist.h +52 -0
  222. data/ext/pg_query/include/pl_reserved_kwlist_d.h +114 -0
  223. data/ext/pg_query/include/pl_unreserved_kwlist.h +112 -0
  224. data/ext/pg_query/include/pl_unreserved_kwlist_d.h +246 -0
  225. data/ext/pg_query/include/plerrcodes.h +990 -0
  226. data/ext/pg_query/include/plpgsql.h +1347 -0
  227. data/ext/pg_query/include/port.h +524 -0
  228. data/ext/pg_query/include/port/atomics.h +524 -0
  229. data/ext/pg_query/include/port/atomics/arch-arm.h +26 -0
  230. data/ext/pg_query/include/port/atomics/arch-ppc.h +254 -0
  231. data/ext/pg_query/include/port/atomics/arch-x86.h +252 -0
  232. data/ext/pg_query/include/port/atomics/fallback.h +170 -0
  233. data/ext/pg_query/include/port/atomics/generic-gcc.h +286 -0
  234. data/ext/pg_query/include/port/atomics/generic.h +401 -0
  235. data/ext/pg_query/include/port/pg_bitutils.h +226 -0
  236. data/ext/pg_query/include/port/pg_bswap.h +161 -0
  237. data/ext/pg_query/include/port/pg_crc32c.h +101 -0
  238. data/ext/pg_query/include/portability/instr_time.h +256 -0
  239. data/ext/pg_query/include/postgres.h +764 -0
  240. data/ext/pg_query/include/postgres_ext.h +74 -0
  241. data/ext/pg_query/include/postmaster/autovacuum.h +83 -0
  242. data/ext/pg_query/include/postmaster/bgworker.h +161 -0
  243. data/ext/pg_query/include/postmaster/bgworker_internals.h +64 -0
  244. data/ext/pg_query/include/postmaster/bgwriter.h +45 -0
  245. data/ext/pg_query/include/postmaster/fork_process.h +17 -0
  246. data/ext/pg_query/include/postmaster/interrupt.h +32 -0
  247. data/ext/pg_query/include/postmaster/pgarch.h +39 -0
  248. data/ext/pg_query/include/postmaster/postmaster.h +77 -0
  249. data/ext/pg_query/include/postmaster/syslogger.h +98 -0
  250. data/ext/pg_query/include/postmaster/walwriter.h +21 -0
  251. data/ext/pg_query/include/protobuf-c.h +1106 -0
  252. data/ext/pg_query/include/protobuf-c/protobuf-c.h +1106 -0
  253. data/ext/pg_query/include/protobuf/pg_query.pb-c.h +10846 -0
  254. data/ext/pg_query/include/protobuf/pg_query.pb.h +124718 -0
  255. data/ext/pg_query/include/regex/regex.h +184 -0
  256. data/ext/pg_query/include/replication/logicallauncher.h +31 -0
  257. data/ext/pg_query/include/replication/logicalproto.h +110 -0
  258. data/ext/pg_query/include/replication/logicalworker.h +19 -0
  259. data/ext/pg_query/include/replication/origin.h +73 -0
  260. data/ext/pg_query/include/replication/reorderbuffer.h +467 -0
  261. data/ext/pg_query/include/replication/slot.h +219 -0
  262. data/ext/pg_query/include/replication/syncrep.h +115 -0
  263. data/ext/pg_query/include/replication/walreceiver.h +340 -0
  264. data/ext/pg_query/include/replication/walsender.h +74 -0
  265. data/ext/pg_query/include/rewrite/prs2lock.h +46 -0
  266. data/ext/pg_query/include/rewrite/rewriteHandler.h +40 -0
  267. data/ext/pg_query/include/rewrite/rewriteManip.h +87 -0
  268. data/ext/pg_query/include/rewrite/rewriteSupport.h +26 -0
  269. data/ext/pg_query/include/storage/backendid.h +37 -0
  270. data/ext/pg_query/include/storage/block.h +121 -0
  271. data/ext/pg_query/include/storage/buf.h +46 -0
  272. data/ext/pg_query/include/storage/bufmgr.h +292 -0
  273. data/ext/pg_query/include/storage/bufpage.h +459 -0
  274. data/ext/pg_query/include/storage/condition_variable.h +62 -0
  275. data/ext/pg_query/include/storage/dsm.h +61 -0
  276. data/ext/pg_query/include/storage/dsm_impl.h +75 -0
  277. data/ext/pg_query/include/storage/fd.h +168 -0
  278. data/ext/pg_query/include/storage/ipc.h +81 -0
  279. data/ext/pg_query/include/storage/item.h +19 -0
  280. data/ext/pg_query/include/storage/itemid.h +184 -0
  281. data/ext/pg_query/include/storage/itemptr.h +206 -0
  282. data/ext/pg_query/include/storage/large_object.h +100 -0
  283. data/ext/pg_query/include/storage/latch.h +190 -0
  284. data/ext/pg_query/include/storage/lmgr.h +114 -0
  285. data/ext/pg_query/include/storage/lock.h +612 -0
  286. data/ext/pg_query/include/storage/lockdefs.h +59 -0
  287. data/ext/pg_query/include/storage/lwlock.h +232 -0
  288. data/ext/pg_query/include/storage/lwlocknames.h +51 -0
  289. data/ext/pg_query/include/storage/off.h +57 -0
  290. data/ext/pg_query/include/storage/pg_sema.h +61 -0
  291. data/ext/pg_query/include/storage/pg_shmem.h +90 -0
  292. data/ext/pg_query/include/storage/pmsignal.h +94 -0
  293. data/ext/pg_query/include/storage/predicate.h +87 -0
  294. data/ext/pg_query/include/storage/proc.h +333 -0
  295. data/ext/pg_query/include/storage/proclist_types.h +51 -0
  296. data/ext/pg_query/include/storage/procsignal.h +75 -0
  297. data/ext/pg_query/include/storage/relfilenode.h +99 -0
  298. data/ext/pg_query/include/storage/s_lock.h +1047 -0
  299. data/ext/pg_query/include/storage/sharedfileset.h +45 -0
  300. data/ext/pg_query/include/storage/shm_mq.h +85 -0
  301. data/ext/pg_query/include/storage/shm_toc.h +58 -0
  302. data/ext/pg_query/include/storage/shmem.h +81 -0
  303. data/ext/pg_query/include/storage/sinval.h +153 -0
  304. data/ext/pg_query/include/storage/sinvaladt.h +43 -0
  305. data/ext/pg_query/include/storage/smgr.h +109 -0
  306. data/ext/pg_query/include/storage/spin.h +77 -0
  307. data/ext/pg_query/include/storage/standby.h +91 -0
  308. data/ext/pg_query/include/storage/standbydefs.h +74 -0
  309. data/ext/pg_query/include/storage/sync.h +62 -0
  310. data/ext/pg_query/include/tcop/cmdtag.h +58 -0
  311. data/ext/pg_query/include/tcop/cmdtaglist.h +217 -0
  312. data/ext/pg_query/include/tcop/deparse_utility.h +108 -0
  313. data/ext/pg_query/include/tcop/dest.h +149 -0
  314. data/ext/pg_query/include/tcop/fastpath.h +21 -0
  315. data/ext/pg_query/include/tcop/pquery.h +45 -0
  316. data/ext/pg_query/include/tcop/tcopprot.h +89 -0
  317. data/ext/pg_query/include/tcop/utility.h +108 -0
  318. data/ext/pg_query/include/tsearch/ts_cache.h +98 -0
  319. data/ext/pg_query/include/utils/acl.h +312 -0
  320. data/ext/pg_query/include/utils/aclchk_internal.h +45 -0
  321. data/ext/pg_query/include/utils/array.h +458 -0
  322. data/ext/pg_query/include/utils/builtins.h +127 -0
  323. data/ext/pg_query/include/utils/bytea.h +27 -0
  324. data/ext/pg_query/include/utils/catcache.h +231 -0
  325. data/ext/pg_query/include/utils/date.h +90 -0
  326. data/ext/pg_query/include/utils/datetime.h +343 -0
  327. data/ext/pg_query/include/utils/datum.h +68 -0
  328. data/ext/pg_query/include/utils/dsa.h +123 -0
  329. data/ext/pg_query/include/utils/dynahash.h +19 -0
  330. data/ext/pg_query/include/utils/elog.h +439 -0
  331. data/ext/pg_query/include/utils/errcodes.h +352 -0
  332. data/ext/pg_query/include/utils/expandeddatum.h +159 -0
  333. data/ext/pg_query/include/utils/expandedrecord.h +231 -0
  334. data/ext/pg_query/include/utils/float.h +356 -0
  335. data/ext/pg_query/include/utils/fmgroids.h +2657 -0
  336. data/ext/pg_query/include/utils/fmgrprotos.h +2646 -0
  337. data/ext/pg_query/include/utils/fmgrtab.h +48 -0
  338. data/ext/pg_query/include/utils/guc.h +443 -0
  339. data/ext/pg_query/include/utils/guc_tables.h +272 -0
  340. data/ext/pg_query/include/utils/hsearch.h +149 -0
  341. data/ext/pg_query/include/utils/inval.h +64 -0
  342. data/ext/pg_query/include/utils/lsyscache.h +197 -0
  343. data/ext/pg_query/include/utils/memdebug.h +82 -0
  344. data/ext/pg_query/include/utils/memutils.h +225 -0
  345. data/ext/pg_query/include/utils/numeric.h +76 -0
  346. data/ext/pg_query/include/utils/palloc.h +136 -0
  347. data/ext/pg_query/include/utils/partcache.h +102 -0
  348. data/ext/pg_query/include/utils/pg_locale.h +119 -0
  349. data/ext/pg_query/include/utils/pg_lsn.h +29 -0
  350. data/ext/pg_query/include/utils/pidfile.h +56 -0
  351. data/ext/pg_query/include/utils/plancache.h +235 -0
  352. data/ext/pg_query/include/utils/portal.h +241 -0
  353. data/ext/pg_query/include/utils/probes.h +114 -0
  354. data/ext/pg_query/include/utils/ps_status.h +25 -0
  355. data/ext/pg_query/include/utils/queryenvironment.h +74 -0
  356. data/ext/pg_query/include/utils/regproc.h +28 -0
  357. data/ext/pg_query/include/utils/rel.h +644 -0
  358. data/ext/pg_query/include/utils/relcache.h +151 -0
  359. data/ext/pg_query/include/utils/reltrigger.h +81 -0
  360. data/ext/pg_query/include/utils/resowner.h +86 -0
  361. data/ext/pg_query/include/utils/rls.h +50 -0
  362. data/ext/pg_query/include/utils/ruleutils.h +44 -0
  363. data/ext/pg_query/include/utils/sharedtuplestore.h +61 -0
  364. data/ext/pg_query/include/utils/snapmgr.h +158 -0
  365. data/ext/pg_query/include/utils/snapshot.h +206 -0
  366. data/ext/pg_query/include/utils/sortsupport.h +276 -0
  367. data/ext/pg_query/include/utils/syscache.h +219 -0
  368. data/ext/pg_query/include/utils/timeout.h +88 -0
  369. data/ext/pg_query/include/utils/timestamp.h +116 -0
  370. data/ext/pg_query/include/utils/tuplesort.h +277 -0
  371. data/ext/pg_query/include/utils/tuplestore.h +91 -0
  372. data/ext/pg_query/include/utils/typcache.h +202 -0
  373. data/ext/pg_query/include/utils/tzparser.h +39 -0
  374. data/ext/pg_query/include/utils/varlena.h +39 -0
  375. data/ext/pg_query/include/utils/xml.h +84 -0
  376. data/ext/pg_query/include/xxhash.h +5445 -0
  377. data/ext/pg_query/include/xxhash/xxhash.h +5445 -0
  378. data/ext/pg_query/pg_query.c +104 -0
  379. data/ext/pg_query/pg_query.pb-c.c +37628 -0
  380. data/ext/pg_query/pg_query_deparse.c +9959 -0
  381. data/ext/pg_query/pg_query_fingerprint.c +295 -0
  382. data/ext/pg_query/pg_query_fingerprint.h +8 -0
  383. data/ext/pg_query/pg_query_internal.h +24 -0
  384. data/ext/pg_query/pg_query_json_plpgsql.c +738 -0
  385. data/ext/pg_query/pg_query_json_plpgsql.h +9 -0
  386. data/ext/pg_query/pg_query_normalize.c +439 -0
  387. data/ext/pg_query/pg_query_outfuncs.h +10 -0
  388. data/ext/pg_query/pg_query_outfuncs_json.c +297 -0
  389. data/ext/pg_query/pg_query_outfuncs_protobuf.c +237 -0
  390. data/ext/pg_query/pg_query_parse.c +148 -0
  391. data/ext/pg_query/pg_query_parse_plpgsql.c +460 -0
  392. data/ext/pg_query/pg_query_readfuncs.h +11 -0
  393. data/ext/pg_query/pg_query_readfuncs_protobuf.c +142 -0
  394. data/ext/pg_query/pg_query_ruby.c +108 -12
  395. data/ext/pg_query/pg_query_scan.c +173 -0
  396. data/ext/pg_query/pg_query_split.c +221 -0
  397. data/ext/pg_query/protobuf-c.c +3660 -0
  398. data/ext/pg_query/src_backend_catalog_namespace.c +1051 -0
  399. data/ext/pg_query/src_backend_catalog_pg_proc.c +142 -0
  400. data/ext/pg_query/src_backend_commands_define.c +117 -0
  401. data/ext/pg_query/src_backend_libpq_pqcomm.c +651 -0
  402. data/ext/pg_query/src_backend_nodes_bitmapset.c +513 -0
  403. data/ext/pg_query/src_backend_nodes_copyfuncs.c +6013 -0
  404. data/ext/pg_query/src_backend_nodes_equalfuncs.c +4003 -0
  405. data/ext/pg_query/src_backend_nodes_extensible.c +99 -0
  406. data/ext/pg_query/src_backend_nodes_list.c +922 -0
  407. data/ext/pg_query/src_backend_nodes_makefuncs.c +417 -0
  408. data/ext/pg_query/src_backend_nodes_nodeFuncs.c +1363 -0
  409. data/ext/pg_query/src_backend_nodes_value.c +84 -0
  410. data/ext/pg_query/src_backend_parser_gram.c +47456 -0
  411. data/ext/pg_query/src_backend_parser_parse_expr.c +313 -0
  412. data/ext/pg_query/src_backend_parser_parser.c +497 -0
  413. data/ext/pg_query/src_backend_parser_scan.c +7091 -0
  414. data/ext/pg_query/src_backend_parser_scansup.c +160 -0
  415. data/ext/pg_query/src_backend_postmaster_postmaster.c +2230 -0
  416. data/ext/pg_query/src_backend_storage_ipc_ipc.c +192 -0
  417. data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +370 -0
  418. data/ext/pg_query/src_backend_tcop_postgres.c +776 -0
  419. data/ext/pg_query/src_backend_utils_adt_datum.c +326 -0
  420. data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +98 -0
  421. data/ext/pg_query/src_backend_utils_adt_format_type.c +136 -0
  422. data/ext/pg_query/src_backend_utils_adt_ruleutils.c +1683 -0
  423. data/ext/pg_query/src_backend_utils_error_assert.c +74 -0
  424. data/ext/pg_query/src_backend_utils_error_elog.c +1748 -0
  425. data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +570 -0
  426. data/ext/pg_query/src_backend_utils_hash_dynahash.c +1086 -0
  427. data/ext/pg_query/src_backend_utils_init_globals.c +168 -0
  428. data/ext/pg_query/src_backend_utils_mb_mbutils.c +839 -0
  429. data/ext/pg_query/src_backend_utils_misc_guc.c +1831 -0
  430. data/ext/pg_query/src_backend_utils_mmgr_aset.c +1560 -0
  431. data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +1006 -0
  432. data/ext/pg_query/src_common_encnames.c +158 -0
  433. data/ext/pg_query/src_common_keywords.c +39 -0
  434. data/ext/pg_query/src_common_kwlist_d.h +1081 -0
  435. data/ext/pg_query/src_common_kwlookup.c +91 -0
  436. data/ext/pg_query/src_common_psprintf.c +158 -0
  437. data/ext/pg_query/src_common_string.c +86 -0
  438. data/ext/pg_query/src_common_stringinfo.c +336 -0
  439. data/ext/pg_query/src_common_wchar.c +1651 -0
  440. data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1133 -0
  441. data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +877 -0
  442. data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +6533 -0
  443. data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +107 -0
  444. data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +123 -0
  445. data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +671 -0
  446. data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +255 -0
  447. data/ext/pg_query/src_port_erand48.c +127 -0
  448. data/ext/pg_query/src_port_pg_bitutils.c +246 -0
  449. data/ext/pg_query/src_port_pgsleep.c +69 -0
  450. data/ext/pg_query/src_port_pgstrcasecmp.c +83 -0
  451. data/ext/pg_query/src_port_qsort.c +240 -0
  452. data/ext/pg_query/src_port_random.c +31 -0
  453. data/ext/pg_query/src_port_snprintf.c +1449 -0
  454. data/ext/pg_query/src_port_strerror.c +324 -0
  455. data/ext/pg_query/src_port_strnlen.c +39 -0
  456. data/ext/pg_query/xxhash.c +43 -0
  457. data/lib/pg_query.rb +7 -4
  458. data/lib/pg_query/constants.rb +21 -0
  459. data/lib/pg_query/deparse.rb +15 -1581
  460. data/lib/pg_query/filter_columns.rb +88 -85
  461. data/lib/pg_query/fingerprint.rb +122 -87
  462. data/lib/pg_query/json_field_names.rb +1402 -0
  463. data/lib/pg_query/node.rb +31 -0
  464. data/lib/pg_query/param_refs.rb +42 -37
  465. data/lib/pg_query/parse.rb +220 -203
  466. data/lib/pg_query/parse_error.rb +1 -1
  467. data/lib/pg_query/pg_query_pb.rb +3211 -0
  468. data/lib/pg_query/scan.rb +23 -0
  469. data/lib/pg_query/treewalker.rb +24 -40
  470. data/lib/pg_query/truncate.rb +71 -42
  471. data/lib/pg_query/version.rb +2 -2
  472. metadata +472 -11
  473. data/ext/pg_query/pg_query_ruby.h +0 -10
  474. data/lib/pg_query/deep_dup.rb +0 -16
  475. data/lib/pg_query/deparse/alter_table.rb +0 -42
  476. data/lib/pg_query/deparse/interval.rb +0 -105
  477. data/lib/pg_query/deparse/keywords.rb +0 -159
  478. data/lib/pg_query/deparse/rename.rb +0 -41
  479. data/lib/pg_query/legacy_parsetree.rb +0 -109
  480. data/lib/pg_query/node_types.rb +0 -296
@@ -0,0 +1,102 @@
1
+ /*
2
+ * pairingheap.h
3
+ *
4
+ * A Pairing Heap implementation
5
+ *
6
+ * Portions Copyright (c) 2012-2020, PostgreSQL Global Development Group
7
+ *
8
+ * src/include/lib/pairingheap.h
9
+ */
10
+
11
+ #ifndef PAIRINGHEAP_H
12
+ #define PAIRINGHEAP_H
13
+
14
+ #include "lib/stringinfo.h"
15
+
16
+ /* Enable if you need the pairingheap_dump() debug function */
17
+ /* #define PAIRINGHEAP_DEBUG */
18
+
19
+ /*
20
+ * This represents an element stored in the heap. Embed this in a larger
21
+ * struct containing the actual data you're storing.
22
+ *
23
+ * A node can have multiple children, which form a double-linked list.
24
+ * first_child points to the node's first child, and the subsequent children
25
+ * can be found by following the next_sibling pointers. The last child has
26
+ * next_sibling == NULL. The prev_or_parent pointer points to the node's
27
+ * previous sibling, or if the node is its parent's first child, to the
28
+ * parent.
29
+ */
30
+ typedef struct pairingheap_node
31
+ {
32
+ struct pairingheap_node *first_child;
33
+ struct pairingheap_node *next_sibling;
34
+ struct pairingheap_node *prev_or_parent;
35
+ } pairingheap_node;
36
+
37
+ /*
38
+ * Return the containing struct of 'type' where 'membername' is the
39
+ * pairingheap_node pointed at by 'ptr'.
40
+ *
41
+ * This is used to convert a pairingheap_node * back to its containing struct.
42
+ */
43
+ #define pairingheap_container(type, membername, ptr) \
44
+ (AssertVariableIsOfTypeMacro(ptr, pairingheap_node *), \
45
+ AssertVariableIsOfTypeMacro(((type *) NULL)->membername, pairingheap_node), \
46
+ ((type *) ((char *) (ptr) - offsetof(type, membername))))
47
+
48
+ /*
49
+ * Like pairingheap_container, but used when the pointer is 'const ptr'
50
+ */
51
+ #define pairingheap_const_container(type, membername, ptr) \
52
+ (AssertVariableIsOfTypeMacro(ptr, const pairingheap_node *), \
53
+ AssertVariableIsOfTypeMacro(((type *) NULL)->membername, pairingheap_node), \
54
+ ((const type *) ((const char *) (ptr) - offsetof(type, membername))))
55
+
56
+ /*
57
+ * For a max-heap, the comparator must return <0 iff a < b, 0 iff a == b,
58
+ * and >0 iff a > b. For a min-heap, the conditions are reversed.
59
+ */
60
+ typedef int (*pairingheap_comparator) (const pairingheap_node *a,
61
+ const pairingheap_node *b,
62
+ void *arg);
63
+
64
+ /*
65
+ * A pairing heap.
66
+ *
67
+ * You can use pairingheap_allocate() to create a new palloc'd heap, or embed
68
+ * this in a larger struct, set ph_compare and ph_arg directly and initialize
69
+ * ph_root to NULL.
70
+ */
71
+ typedef struct pairingheap
72
+ {
73
+ pairingheap_comparator ph_compare; /* comparison function */
74
+ void *ph_arg; /* opaque argument to ph_compare */
75
+ pairingheap_node *ph_root; /* current root of the heap */
76
+ } pairingheap;
77
+
78
+ extern pairingheap *pairingheap_allocate(pairingheap_comparator compare,
79
+ void *arg);
80
+ extern void pairingheap_free(pairingheap *heap);
81
+ extern void pairingheap_add(pairingheap *heap, pairingheap_node *node);
82
+ extern pairingheap_node *pairingheap_first(pairingheap *heap);
83
+ extern pairingheap_node *pairingheap_remove_first(pairingheap *heap);
84
+ extern void pairingheap_remove(pairingheap *heap, pairingheap_node *node);
85
+
86
+ #ifdef PAIRINGHEAP_DEBUG
87
+ extern char *pairingheap_dump(pairingheap *heap,
88
+ void (*dumpfunc) (pairingheap_node *node, StringInfo buf, void *opaque),
89
+ void *opaque);
90
+ #endif
91
+
92
+ /* Resets the heap to be empty. */
93
+ #define pairingheap_reset(h) ((h)->ph_root = NULL)
94
+
95
+ /* Is the heap empty? */
96
+ #define pairingheap_is_empty(h) ((h)->ph_root == NULL)
97
+
98
+ /* Is there exactly one node in the heap? */
99
+ #define pairingheap_is_singular(h) \
100
+ ((h)->ph_root && (h)->ph_root->first_child == NULL)
101
+
102
+ #endif /* PAIRINGHEAP_H */
@@ -0,0 +1,1059 @@
1
+ /*
2
+ * simplehash.h
3
+ *
4
+ * Hash table implementation which will be specialized to user-defined
5
+ * types, by including this file to generate the required code. It's
6
+ * probably not worthwhile to do so for hash tables that aren't performance
7
+ * or space sensitive.
8
+ *
9
+ * Usage notes:
10
+ *
11
+ * To generate a hash-table and associated functions for a use case several
12
+ * macros have to be #define'ed before this file is included. Including
13
+ * the file #undef's all those, so a new hash table can be generated
14
+ * afterwards.
15
+ * The relevant parameters are:
16
+ * - SH_PREFIX - prefix for all symbol names generated. A prefix of 'foo'
17
+ * will result in hash table type 'foo_hash' and functions like
18
+ * 'foo_insert'/'foo_lookup' and so forth.
19
+ * - SH_ELEMENT_TYPE - type of the contained elements
20
+ * - SH_KEY_TYPE - type of the hashtable's key
21
+ * - SH_DECLARE - if defined function prototypes and type declarations are
22
+ * generated
23
+ * - SH_DEFINE - if defined function definitions are generated
24
+ * - SH_SCOPE - in which scope (e.g. extern, static inline) do function
25
+ * declarations reside
26
+ * - SH_RAW_ALLOCATOR - if defined, memory contexts are not used; instead,
27
+ * use this to allocate bytes
28
+ * - SH_USE_NONDEFAULT_ALLOCATOR - if defined no element allocator functions
29
+ * are defined, so you can supply your own
30
+ * The following parameters are only relevant when SH_DEFINE is defined:
31
+ * - SH_KEY - name of the element in SH_ELEMENT_TYPE containing the hash key
32
+ * - SH_EQUAL(table, a, b) - compare two table keys
33
+ * - SH_HASH_KEY(table, key) - generate hash for the key
34
+ * - SH_STORE_HASH - if defined the hash is stored in the elements
35
+ * - SH_GET_HASH(tb, a) - return the field to store the hash in
36
+ *
37
+ * For examples of usage look at tidbitmap.c (file local definition) and
38
+ * execnodes.h/execGrouping.c (exposed declaration, file local
39
+ * implementation).
40
+ *
41
+ * Hash table design:
42
+ *
43
+ * The hash table design chosen is a variant of linear open-addressing. The
44
+ * reason for doing so is that linear addressing is CPU cache & pipeline
45
+ * friendly. The biggest disadvantage of simple linear addressing schemes
46
+ * are highly variable lookup times due to clustering, and deletions
47
+ * leaving a lot of tombstones around. To address these issues a variant
48
+ * of "robin hood" hashing is employed. Robin hood hashing optimizes
49
+ * chaining lengths by moving elements close to their optimal bucket
50
+ * ("rich" elements), out of the way if a to-be-inserted element is further
51
+ * away from its optimal position (i.e. it's "poor"). While that can make
52
+ * insertions slower, the average lookup performance is a lot better, and
53
+ * higher fill factors can be used in a still performant manner. To avoid
54
+ * tombstones - which normally solve the issue that a deleted node's
55
+ * presence is relevant to determine whether a lookup needs to continue
56
+ * looking or is done - buckets following a deleted element are shifted
57
+ * backwards, unless they're empty or already at their optimal position.
58
+ */
59
+
60
+ #include "port/pg_bitutils.h"
61
+
62
+ /* helpers */
63
+ #define SH_MAKE_PREFIX(a) CppConcat(a,_)
64
+ #define SH_MAKE_NAME(name) SH_MAKE_NAME_(SH_MAKE_PREFIX(SH_PREFIX),name)
65
+ #define SH_MAKE_NAME_(a,b) CppConcat(a,b)
66
+
67
+ /* name macros for: */
68
+
69
+ /* type declarations */
70
+ #define SH_TYPE SH_MAKE_NAME(hash)
71
+ #define SH_STATUS SH_MAKE_NAME(status)
72
+ #define SH_STATUS_EMPTY SH_MAKE_NAME(SH_EMPTY)
73
+ #define SH_STATUS_IN_USE SH_MAKE_NAME(SH_IN_USE)
74
+ #define SH_ITERATOR SH_MAKE_NAME(iterator)
75
+
76
+ /* function declarations */
77
+ #define SH_CREATE SH_MAKE_NAME(create)
78
+ #define SH_DESTROY SH_MAKE_NAME(destroy)
79
+ #define SH_RESET SH_MAKE_NAME(reset)
80
+ #define SH_INSERT SH_MAKE_NAME(insert)
81
+ #define SH_INSERT_HASH SH_MAKE_NAME(insert_hash)
82
+ #define SH_DELETE SH_MAKE_NAME(delete)
83
+ #define SH_LOOKUP SH_MAKE_NAME(lookup)
84
+ #define SH_LOOKUP_HASH SH_MAKE_NAME(lookup_hash)
85
+ #define SH_GROW SH_MAKE_NAME(grow)
86
+ #define SH_START_ITERATE SH_MAKE_NAME(start_iterate)
87
+ #define SH_START_ITERATE_AT SH_MAKE_NAME(start_iterate_at)
88
+ #define SH_ITERATE SH_MAKE_NAME(iterate)
89
+ #define SH_ALLOCATE SH_MAKE_NAME(allocate)
90
+ #define SH_FREE SH_MAKE_NAME(free)
91
+ #define SH_STAT SH_MAKE_NAME(stat)
92
+
93
+ /* internal helper functions (no externally visible prototypes) */
94
+ #define SH_COMPUTE_PARAMETERS SH_MAKE_NAME(compute_parameters)
95
+ #define SH_NEXT SH_MAKE_NAME(next)
96
+ #define SH_PREV SH_MAKE_NAME(prev)
97
+ #define SH_DISTANCE_FROM_OPTIMAL SH_MAKE_NAME(distance)
98
+ #define SH_INITIAL_BUCKET SH_MAKE_NAME(initial_bucket)
99
+ #define SH_ENTRY_HASH SH_MAKE_NAME(entry_hash)
100
+ #define SH_INSERT_HASH_INTERNAL SH_MAKE_NAME(insert_hash_internal)
101
+ #define SH_LOOKUP_HASH_INTERNAL SH_MAKE_NAME(lookup_hash_internal)
102
+
103
+ /* generate forward declarations necessary to use the hash table */
104
+ #ifdef SH_DECLARE
105
+
106
+ /* type definitions */
107
+ typedef struct SH_TYPE
108
+ {
109
+ /*
110
+ * Size of data / bucket array, 64 bits to handle UINT32_MAX sized hash
111
+ * tables. Note that the maximum number of elements is lower
112
+ * (SH_MAX_FILLFACTOR)
113
+ */
114
+ uint64 size;
115
+
116
+ /* how many elements have valid contents */
117
+ uint32 members;
118
+
119
+ /* mask for bucket and size calculations, based on size */
120
+ uint32 sizemask;
121
+
122
+ /* boundary after which to grow hashtable */
123
+ uint32 grow_threshold;
124
+
125
+ /* hash buckets */
126
+ SH_ELEMENT_TYPE *data;
127
+
128
+ #ifndef SH_RAW_ALLOCATOR
129
+ /* memory context to use for allocations */
130
+ MemoryContext ctx;
131
+ #endif
132
+
133
+ /* user defined data, useful for callbacks */
134
+ void *private_data;
135
+ } SH_TYPE;
136
+
137
+ typedef enum SH_STATUS
138
+ {
139
+ SH_STATUS_EMPTY = 0x00,
140
+ SH_STATUS_IN_USE = 0x01
141
+ } SH_STATUS;
142
+
143
+ typedef struct SH_ITERATOR
144
+ {
145
+ uint32 cur; /* current element */
146
+ uint32 end;
147
+ bool done; /* iterator exhausted? */
148
+ } SH_ITERATOR;
149
+
150
+ /* externally visible function prototypes */
151
+ #ifdef SH_RAW_ALLOCATOR
152
+ SH_SCOPE SH_TYPE *SH_CREATE(uint32 nelements, void *private_data);
153
+ #else
154
+ SH_SCOPE SH_TYPE *SH_CREATE(MemoryContext ctx, uint32 nelements,
155
+ void *private_data);
156
+ #endif
157
+ SH_SCOPE void SH_DESTROY(SH_TYPE * tb);
158
+ SH_SCOPE void SH_RESET(SH_TYPE * tb);
159
+ SH_SCOPE void SH_GROW(SH_TYPE * tb, uint32 newsize);
160
+ SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT(SH_TYPE * tb, SH_KEY_TYPE key, bool *found);
161
+ SH_SCOPE SH_ELEMENT_TYPE *SH_INSERT_HASH(SH_TYPE * tb, SH_KEY_TYPE key,
162
+ uint32 hash, bool *found);
163
+ SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP(SH_TYPE * tb, SH_KEY_TYPE key);
164
+ SH_SCOPE SH_ELEMENT_TYPE *SH_LOOKUP_HASH(SH_TYPE * tb, SH_KEY_TYPE key,
165
+ uint32 hash);
166
+ SH_SCOPE bool SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key);
167
+ SH_SCOPE void SH_START_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter);
168
+ SH_SCOPE void SH_START_ITERATE_AT(SH_TYPE * tb, SH_ITERATOR * iter, uint32 at);
169
+ SH_SCOPE SH_ELEMENT_TYPE *SH_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter);
170
+ SH_SCOPE void SH_STAT(SH_TYPE * tb);
171
+
172
+ #endif /* SH_DECLARE */
173
+
174
+
175
+ /* generate implementation of the hash table */
176
+ #ifdef SH_DEFINE
177
+
178
+ #ifndef SH_RAW_ALLOCATOR
179
+ #include "utils/memutils.h"
180
+ #endif
181
+
182
+ /* max data array size,we allow up to PG_UINT32_MAX buckets, including 0 */
183
+ #define SH_MAX_SIZE (((uint64) PG_UINT32_MAX) + 1)
184
+
185
+ /* normal fillfactor, unless already close to maximum */
186
+ #ifndef SH_FILLFACTOR
187
+ #define SH_FILLFACTOR (0.9)
188
+ #endif
189
+ /* increase fillfactor if we otherwise would error out */
190
+ #define SH_MAX_FILLFACTOR (0.98)
191
+ /* grow if actual and optimal location bigger than */
192
+ #ifndef SH_GROW_MAX_DIB
193
+ #define SH_GROW_MAX_DIB 25
194
+ #endif
195
+ /* grow if more than elements to move when inserting */
196
+ #ifndef SH_GROW_MAX_MOVE
197
+ #define SH_GROW_MAX_MOVE 150
198
+ #endif
199
+ #ifndef SH_GROW_MIN_FILLFACTOR
200
+ /* but do not grow due to SH_GROW_MAX_* if below */
201
+ #define SH_GROW_MIN_FILLFACTOR 0.1
202
+ #endif
203
+
204
+ #ifdef SH_STORE_HASH
205
+ #define SH_COMPARE_KEYS(tb, ahash, akey, b) (ahash == SH_GET_HASH(tb, b) && SH_EQUAL(tb, b->SH_KEY, akey))
206
+ #else
207
+ #define SH_COMPARE_KEYS(tb, ahash, akey, b) (SH_EQUAL(tb, b->SH_KEY, akey))
208
+ #endif
209
+
210
+ /*
211
+ * Wrap the following definitions in include guards, to avoid multiple
212
+ * definition errors if this header is included more than once. The rest of
213
+ * the file deliberately has no include guards, because it can be included
214
+ * with different parameters to define functions and types with non-colliding
215
+ * names.
216
+ */
217
+ #ifndef SIMPLEHASH_H
218
+ #define SIMPLEHASH_H
219
+
220
+ #ifdef FRONTEND
221
+ #define sh_error(...) pg_log_error(__VA_ARGS__)
222
+ #define sh_log(...) pg_log_info(__VA_ARGS__)
223
+ #else
224
+ #define sh_error(...) elog(ERROR, __VA_ARGS__)
225
+ #define sh_log(...) elog(LOG, __VA_ARGS__)
226
+ #endif
227
+
228
+ #endif
229
+
230
+ /*
231
+ * Compute sizing parameters for hashtable. Called when creating and growing
232
+ * the hashtable.
233
+ */
234
+ static inline void
235
+ SH_COMPUTE_PARAMETERS(SH_TYPE * tb, uint32 newsize)
236
+ {
237
+ uint64 size;
238
+
239
+ /* supporting zero sized hashes would complicate matters */
240
+ size = Max(newsize, 2);
241
+
242
+ /* round up size to the next power of 2, that's how bucketing works */
243
+ size = pg_nextpower2_64(size);
244
+ Assert(size <= SH_MAX_SIZE);
245
+
246
+ /*
247
+ * Verify that allocation of ->data is possible on this platform, without
248
+ * overflowing Size.
249
+ */
250
+ if ((((uint64) sizeof(SH_ELEMENT_TYPE)) * size) >= SIZE_MAX / 2)
251
+ sh_error("hash table too large");
252
+
253
+ /* now set size */
254
+ tb->size = size;
255
+
256
+ if (tb->size == SH_MAX_SIZE)
257
+ tb->sizemask = 0;
258
+ else
259
+ tb->sizemask = tb->size - 1;
260
+
261
+ /*
262
+ * Compute the next threshold at which we need to grow the hash table
263
+ * again.
264
+ */
265
+ if (tb->size == SH_MAX_SIZE)
266
+ tb->grow_threshold = ((double) tb->size) * SH_MAX_FILLFACTOR;
267
+ else
268
+ tb->grow_threshold = ((double) tb->size) * SH_FILLFACTOR;
269
+ }
270
+
271
+ /* return the optimal bucket for the hash */
272
+ static inline uint32
273
+ SH_INITIAL_BUCKET(SH_TYPE * tb, uint32 hash)
274
+ {
275
+ return hash & tb->sizemask;
276
+ }
277
+
278
+ /* return next bucket after the current, handling wraparound */
279
+ static inline uint32
280
+ SH_NEXT(SH_TYPE * tb, uint32 curelem, uint32 startelem)
281
+ {
282
+ curelem = (curelem + 1) & tb->sizemask;
283
+
284
+ Assert(curelem != startelem);
285
+
286
+ return curelem;
287
+ }
288
+
289
+ /* return bucket before the current, handling wraparound */
290
+ static inline uint32
291
+ SH_PREV(SH_TYPE * tb, uint32 curelem, uint32 startelem)
292
+ {
293
+ curelem = (curelem - 1) & tb->sizemask;
294
+
295
+ Assert(curelem != startelem);
296
+
297
+ return curelem;
298
+ }
299
+
300
+ /* return distance between bucket and its optimal position */
301
+ static inline uint32
302
+ SH_DISTANCE_FROM_OPTIMAL(SH_TYPE * tb, uint32 optimal, uint32 bucket)
303
+ {
304
+ if (optimal <= bucket)
305
+ return bucket - optimal;
306
+ else
307
+ return (tb->size + bucket) - optimal;
308
+ }
309
+
310
+ static inline uint32
311
+ SH_ENTRY_HASH(SH_TYPE * tb, SH_ELEMENT_TYPE * entry)
312
+ {
313
+ #ifdef SH_STORE_HASH
314
+ return SH_GET_HASH(tb, entry);
315
+ #else
316
+ return SH_HASH_KEY(tb, entry->SH_KEY);
317
+ #endif
318
+ }
319
+
320
+ /* default memory allocator function */
321
+ static inline void *SH_ALLOCATE(SH_TYPE * type, Size size);
322
+ static inline void SH_FREE(SH_TYPE * type, void *pointer);
323
+
324
+ #ifndef SH_USE_NONDEFAULT_ALLOCATOR
325
+
326
+ /* default memory allocator function */
327
+ static inline void *
328
+ SH_ALLOCATE(SH_TYPE * type, Size size)
329
+ {
330
+ #ifdef SH_RAW_ALLOCATOR
331
+ return SH_RAW_ALLOCATOR(size);
332
+ #else
333
+ return MemoryContextAllocExtended(type->ctx, size,
334
+ MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO);
335
+ #endif
336
+ }
337
+
338
+ /* default memory free function */
339
+ static inline void
340
+ SH_FREE(SH_TYPE * type, void *pointer)
341
+ {
342
+ pfree(pointer);
343
+ }
344
+
345
+ #endif
346
+
347
+ /*
348
+ * Create a hash table with enough space for `nelements` distinct members.
349
+ * Memory for the hash table is allocated from the passed-in context. If
350
+ * desired, the array of elements can be allocated using a passed-in allocator;
351
+ * this could be useful in order to place the array of elements in a shared
352
+ * memory, or in a context that will outlive the rest of the hash table.
353
+ * Memory other than for the array of elements will still be allocated from
354
+ * the passed-in context.
355
+ */
356
+ #ifdef SH_RAW_ALLOCATOR
357
+ SH_SCOPE SH_TYPE *
358
+ SH_CREATE(uint32 nelements, void *private_data)
359
+ #else
360
+ SH_SCOPE SH_TYPE *
361
+ SH_CREATE(MemoryContext ctx, uint32 nelements, void *private_data)
362
+ #endif
363
+ {
364
+ SH_TYPE *tb;
365
+ uint64 size;
366
+
367
+ #ifdef SH_RAW_ALLOCATOR
368
+ tb = SH_RAW_ALLOCATOR(sizeof(SH_TYPE));
369
+ #else
370
+ tb = MemoryContextAllocZero(ctx, sizeof(SH_TYPE));
371
+ tb->ctx = ctx;
372
+ #endif
373
+ tb->private_data = private_data;
374
+
375
+ /* increase nelements by fillfactor, want to store nelements elements */
376
+ size = Min((double) SH_MAX_SIZE, ((double) nelements) / SH_FILLFACTOR);
377
+
378
+ SH_COMPUTE_PARAMETERS(tb, size);
379
+
380
+ tb->data = SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size);
381
+
382
+ return tb;
383
+ }
384
+
385
+ /* destroy a previously created hash table */
386
+ SH_SCOPE void
387
+ SH_DESTROY(SH_TYPE * tb)
388
+ {
389
+ SH_FREE(tb, tb->data);
390
+ pfree(tb);
391
+ }
392
+
393
+ /* reset the contents of a previously created hash table */
394
+ SH_SCOPE void
395
+ SH_RESET(SH_TYPE * tb)
396
+ {
397
+ memset(tb->data, 0, sizeof(SH_ELEMENT_TYPE) * tb->size);
398
+ tb->members = 0;
399
+ }
400
+
401
+ /*
402
+ * Grow a hash table to at least `newsize` buckets.
403
+ *
404
+ * Usually this will automatically be called by insertions/deletions, when
405
+ * necessary. But resizing to the exact input size can be advantageous
406
+ * performance-wise, when known at some point.
407
+ */
408
+ SH_SCOPE void
409
+ SH_GROW(SH_TYPE * tb, uint32 newsize)
410
+ {
411
+ uint64 oldsize = tb->size;
412
+ SH_ELEMENT_TYPE *olddata = tb->data;
413
+ SH_ELEMENT_TYPE *newdata;
414
+ uint32 i;
415
+ uint32 startelem = 0;
416
+ uint32 copyelem;
417
+
418
+ Assert(oldsize == pg_nextpower2_64(oldsize));
419
+ Assert(oldsize != SH_MAX_SIZE);
420
+ Assert(oldsize < newsize);
421
+
422
+ /* compute parameters for new table */
423
+ SH_COMPUTE_PARAMETERS(tb, newsize);
424
+
425
+ tb->data = SH_ALLOCATE(tb, sizeof(SH_ELEMENT_TYPE) * tb->size);
426
+
427
+ newdata = tb->data;
428
+
429
+ /*
430
+ * Copy entries from the old data to newdata. We theoretically could use
431
+ * SH_INSERT here, to avoid code duplication, but that's more general than
432
+ * we need. We neither want tb->members increased, nor do we need to do
433
+ * deal with deleted elements, nor do we need to compare keys. So a
434
+ * special-cased implementation is lot faster. As resizing can be time
435
+ * consuming and frequent, that's worthwhile to optimize.
436
+ *
437
+ * To be able to simply move entries over, we have to start not at the
438
+ * first bucket (i.e olddata[0]), but find the first bucket that's either
439
+ * empty, or is occupied by an entry at its optimal position. Such a
440
+ * bucket has to exist in any table with a load factor under 1, as not all
441
+ * buckets are occupied, i.e. there always has to be an empty bucket. By
442
+ * starting at such a bucket we can move the entries to the larger table,
443
+ * without having to deal with conflicts.
444
+ */
445
+
446
+ /* search for the first element in the hash that's not wrapped around */
447
+ for (i = 0; i < oldsize; i++)
448
+ {
449
+ SH_ELEMENT_TYPE *oldentry = &olddata[i];
450
+ uint32 hash;
451
+ uint32 optimal;
452
+
453
+ if (oldentry->status != SH_STATUS_IN_USE)
454
+ {
455
+ startelem = i;
456
+ break;
457
+ }
458
+
459
+ hash = SH_ENTRY_HASH(tb, oldentry);
460
+ optimal = SH_INITIAL_BUCKET(tb, hash);
461
+
462
+ if (optimal == i)
463
+ {
464
+ startelem = i;
465
+ break;
466
+ }
467
+ }
468
+
469
+ /* and copy all elements in the old table */
470
+ copyelem = startelem;
471
+ for (i = 0; i < oldsize; i++)
472
+ {
473
+ SH_ELEMENT_TYPE *oldentry = &olddata[copyelem];
474
+
475
+ if (oldentry->status == SH_STATUS_IN_USE)
476
+ {
477
+ uint32 hash;
478
+ uint32 startelem;
479
+ uint32 curelem;
480
+ SH_ELEMENT_TYPE *newentry;
481
+
482
+ hash = SH_ENTRY_HASH(tb, oldentry);
483
+ startelem = SH_INITIAL_BUCKET(tb, hash);
484
+ curelem = startelem;
485
+
486
+ /* find empty element to put data into */
487
+ while (true)
488
+ {
489
+ newentry = &newdata[curelem];
490
+
491
+ if (newentry->status == SH_STATUS_EMPTY)
492
+ {
493
+ break;
494
+ }
495
+
496
+ curelem = SH_NEXT(tb, curelem, startelem);
497
+ }
498
+
499
+ /* copy entry to new slot */
500
+ memcpy(newentry, oldentry, sizeof(SH_ELEMENT_TYPE));
501
+ }
502
+
503
+ /* can't use SH_NEXT here, would use new size */
504
+ copyelem++;
505
+ if (copyelem >= oldsize)
506
+ {
507
+ copyelem = 0;
508
+ }
509
+ }
510
+
511
+ SH_FREE(tb, olddata);
512
+ }
513
+
514
+ /*
515
+ * This is a separate static inline function, so it can be reliably be inlined
516
+ * into its wrapper functions even if SH_SCOPE is extern.
517
+ */
518
+ static inline SH_ELEMENT_TYPE *
519
+ SH_INSERT_HASH_INTERNAL(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash, bool *found)
520
+ {
521
+ uint32 startelem;
522
+ uint32 curelem;
523
+ SH_ELEMENT_TYPE *data;
524
+ uint32 insertdist;
525
+
526
+ restart:
527
+ insertdist = 0;
528
+
529
+ /*
530
+ * We do the grow check even if the key is actually present, to avoid
531
+ * doing the check inside the loop. This also lets us avoid having to
532
+ * re-find our position in the hashtable after resizing.
533
+ *
534
+ * Note that this also reached when resizing the table due to
535
+ * SH_GROW_MAX_DIB / SH_GROW_MAX_MOVE.
536
+ */
537
+ if (unlikely(tb->members >= tb->grow_threshold))
538
+ {
539
+ if (tb->size == SH_MAX_SIZE)
540
+ {
541
+ sh_error("hash table size exceeded");
542
+ }
543
+
544
+ /*
545
+ * When optimizing, it can be very useful to print these out.
546
+ */
547
+ /* SH_STAT(tb); */
548
+ SH_GROW(tb, tb->size * 2);
549
+ /* SH_STAT(tb); */
550
+ }
551
+
552
+ /* perform insert, start bucket search at optimal location */
553
+ data = tb->data;
554
+ startelem = SH_INITIAL_BUCKET(tb, hash);
555
+ curelem = startelem;
556
+ while (true)
557
+ {
558
+ uint32 curdist;
559
+ uint32 curhash;
560
+ uint32 curoptimal;
561
+ SH_ELEMENT_TYPE *entry = &data[curelem];
562
+
563
+ /* any empty bucket can directly be used */
564
+ if (entry->status == SH_STATUS_EMPTY)
565
+ {
566
+ tb->members++;
567
+ entry->SH_KEY = key;
568
+ #ifdef SH_STORE_HASH
569
+ SH_GET_HASH(tb, entry) = hash;
570
+ #endif
571
+ entry->status = SH_STATUS_IN_USE;
572
+ *found = false;
573
+ return entry;
574
+ }
575
+
576
+ /*
577
+ * If the bucket is not empty, we either found a match (in which case
578
+ * we're done), or we have to decide whether to skip over or move the
579
+ * colliding entry. When the colliding element's distance to its
580
+ * optimal position is smaller than the to-be-inserted entry's, we
581
+ * shift the colliding entry (and its followers) forward by one.
582
+ */
583
+
584
+ if (SH_COMPARE_KEYS(tb, hash, key, entry))
585
+ {
586
+ Assert(entry->status == SH_STATUS_IN_USE);
587
+ *found = true;
588
+ return entry;
589
+ }
590
+
591
+ curhash = SH_ENTRY_HASH(tb, entry);
592
+ curoptimal = SH_INITIAL_BUCKET(tb, curhash);
593
+ curdist = SH_DISTANCE_FROM_OPTIMAL(tb, curoptimal, curelem);
594
+
595
+ if (insertdist > curdist)
596
+ {
597
+ SH_ELEMENT_TYPE *lastentry = entry;
598
+ uint32 emptyelem = curelem;
599
+ uint32 moveelem;
600
+ int32 emptydist = 0;
601
+
602
+ /* find next empty bucket */
603
+ while (true)
604
+ {
605
+ SH_ELEMENT_TYPE *emptyentry;
606
+
607
+ emptyelem = SH_NEXT(tb, emptyelem, startelem);
608
+ emptyentry = &data[emptyelem];
609
+
610
+ if (emptyentry->status == SH_STATUS_EMPTY)
611
+ {
612
+ lastentry = emptyentry;
613
+ break;
614
+ }
615
+
616
+ /*
617
+ * To avoid negative consequences from overly imbalanced
618
+ * hashtables, grow the hashtable if collisions would require
619
+ * us to move a lot of entries. The most likely cause of such
620
+ * imbalance is filling a (currently) small table, from a
621
+ * currently big one, in hash-table order. Don't grow if the
622
+ * hashtable would be too empty, to prevent quick space
623
+ * explosion for some weird edge cases.
624
+ */
625
+ if (unlikely(++emptydist > SH_GROW_MAX_MOVE) &&
626
+ ((double) tb->members / tb->size) >= SH_GROW_MIN_FILLFACTOR)
627
+ {
628
+ tb->grow_threshold = 0;
629
+ goto restart;
630
+ }
631
+ }
632
+
633
+ /* shift forward, starting at last occupied element */
634
+
635
+ /*
636
+ * TODO: This could be optimized to be one memcpy in many cases,
637
+ * excepting wrapping around at the end of ->data. Hasn't shown up
638
+ * in profiles so far though.
639
+ */
640
+ moveelem = emptyelem;
641
+ while (moveelem != curelem)
642
+ {
643
+ SH_ELEMENT_TYPE *moveentry;
644
+
645
+ moveelem = SH_PREV(tb, moveelem, startelem);
646
+ moveentry = &data[moveelem];
647
+
648
+ memcpy(lastentry, moveentry, sizeof(SH_ELEMENT_TYPE));
649
+ lastentry = moveentry;
650
+ }
651
+
652
+ /* and fill the now empty spot */
653
+ tb->members++;
654
+
655
+ entry->SH_KEY = key;
656
+ #ifdef SH_STORE_HASH
657
+ SH_GET_HASH(tb, entry) = hash;
658
+ #endif
659
+ entry->status = SH_STATUS_IN_USE;
660
+ *found = false;
661
+ return entry;
662
+ }
663
+
664
+ curelem = SH_NEXT(tb, curelem, startelem);
665
+ insertdist++;
666
+
667
+ /*
668
+ * To avoid negative consequences from overly imbalanced hashtables,
669
+ * grow the hashtable if collisions lead to large runs. The most
670
+ * likely cause of such imbalance is filling a (currently) small
671
+ * table, from a currently big one, in hash-table order. Don't grow
672
+ * if the hashtable would be too empty, to prevent quick space
673
+ * explosion for some weird edge cases.
674
+ */
675
+ if (unlikely(insertdist > SH_GROW_MAX_DIB) &&
676
+ ((double) tb->members / tb->size) >= SH_GROW_MIN_FILLFACTOR)
677
+ {
678
+ tb->grow_threshold = 0;
679
+ goto restart;
680
+ }
681
+ }
682
+ }
683
+
684
+ /*
685
+ * Insert the key key into the hash-table, set *found to true if the key
686
+ * already exists, false otherwise. Returns the hash-table entry in either
687
+ * case.
688
+ */
689
+ SH_SCOPE SH_ELEMENT_TYPE *
690
+ SH_INSERT(SH_TYPE * tb, SH_KEY_TYPE key, bool *found)
691
+ {
692
+ uint32 hash = SH_HASH_KEY(tb, key);
693
+
694
+ return SH_INSERT_HASH_INTERNAL(tb, key, hash, found);
695
+ }
696
+
697
+ /*
698
+ * Insert the key key into the hash-table using an already-calculated
699
+ * hash. Set *found to true if the key already exists, false
700
+ * otherwise. Returns the hash-table entry in either case.
701
+ */
702
+ SH_SCOPE SH_ELEMENT_TYPE *
703
+ SH_INSERT_HASH(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash, bool *found)
704
+ {
705
+ return SH_INSERT_HASH_INTERNAL(tb, key, hash, found);
706
+ }
707
+
708
+ /*
709
+ * This is a separate static inline function, so it can be reliably be inlined
710
+ * into its wrapper functions even if SH_SCOPE is extern.
711
+ */
712
+ static inline SH_ELEMENT_TYPE *
713
+ SH_LOOKUP_HASH_INTERNAL(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash)
714
+ {
715
+ const uint32 startelem = SH_INITIAL_BUCKET(tb, hash);
716
+ uint32 curelem = startelem;
717
+
718
+ while (true)
719
+ {
720
+ SH_ELEMENT_TYPE *entry = &tb->data[curelem];
721
+
722
+ if (entry->status == SH_STATUS_EMPTY)
723
+ {
724
+ return NULL;
725
+ }
726
+
727
+ Assert(entry->status == SH_STATUS_IN_USE);
728
+
729
+ if (SH_COMPARE_KEYS(tb, hash, key, entry))
730
+ return entry;
731
+
732
+ /*
733
+ * TODO: we could stop search based on distance. If the current
734
+ * buckets's distance-from-optimal is smaller than what we've skipped
735
+ * already, the entry doesn't exist. Probably only do so if
736
+ * SH_STORE_HASH is defined, to avoid re-computing hashes?
737
+ */
738
+
739
+ curelem = SH_NEXT(tb, curelem, startelem);
740
+ }
741
+ }
742
+
743
+ /*
744
+ * Lookup up entry in hash table. Returns NULL if key not present.
745
+ */
746
+ SH_SCOPE SH_ELEMENT_TYPE *
747
+ SH_LOOKUP(SH_TYPE * tb, SH_KEY_TYPE key)
748
+ {
749
+ uint32 hash = SH_HASH_KEY(tb, key);
750
+
751
+ return SH_LOOKUP_HASH_INTERNAL(tb, key, hash);
752
+ }
753
+
754
+ /*
755
+ * Lookup up entry in hash table using an already-calculated hash.
756
+ *
757
+ * Returns NULL if key not present.
758
+ */
759
+ SH_SCOPE SH_ELEMENT_TYPE *
760
+ SH_LOOKUP_HASH(SH_TYPE * tb, SH_KEY_TYPE key, uint32 hash)
761
+ {
762
+ return SH_LOOKUP_HASH_INTERNAL(tb, key, hash);
763
+ }
764
+
765
+ /*
766
+ * Delete entry from hash table. Returns whether to-be-deleted key was
767
+ * present.
768
+ */
769
+ SH_SCOPE bool
770
+ SH_DELETE(SH_TYPE * tb, SH_KEY_TYPE key)
771
+ {
772
+ uint32 hash = SH_HASH_KEY(tb, key);
773
+ uint32 startelem = SH_INITIAL_BUCKET(tb, hash);
774
+ uint32 curelem = startelem;
775
+
776
+ while (true)
777
+ {
778
+ SH_ELEMENT_TYPE *entry = &tb->data[curelem];
779
+
780
+ if (entry->status == SH_STATUS_EMPTY)
781
+ return false;
782
+
783
+ if (entry->status == SH_STATUS_IN_USE &&
784
+ SH_COMPARE_KEYS(tb, hash, key, entry))
785
+ {
786
+ SH_ELEMENT_TYPE *lastentry = entry;
787
+
788
+ tb->members--;
789
+
790
+ /*
791
+ * Backward shift following elements till either an empty element
792
+ * or an element at its optimal position is encountered.
793
+ *
794
+ * While that sounds expensive, the average chain length is short,
795
+ * and deletions would otherwise require tombstones.
796
+ */
797
+ while (true)
798
+ {
799
+ SH_ELEMENT_TYPE *curentry;
800
+ uint32 curhash;
801
+ uint32 curoptimal;
802
+
803
+ curelem = SH_NEXT(tb, curelem, startelem);
804
+ curentry = &tb->data[curelem];
805
+
806
+ if (curentry->status != SH_STATUS_IN_USE)
807
+ {
808
+ lastentry->status = SH_STATUS_EMPTY;
809
+ break;
810
+ }
811
+
812
+ curhash = SH_ENTRY_HASH(tb, curentry);
813
+ curoptimal = SH_INITIAL_BUCKET(tb, curhash);
814
+
815
+ /* current is at optimal position, done */
816
+ if (curoptimal == curelem)
817
+ {
818
+ lastentry->status = SH_STATUS_EMPTY;
819
+ break;
820
+ }
821
+
822
+ /* shift */
823
+ memcpy(lastentry, curentry, sizeof(SH_ELEMENT_TYPE));
824
+
825
+ lastentry = curentry;
826
+ }
827
+
828
+ return true;
829
+ }
830
+
831
+ /* TODO: return false; if distance too big */
832
+
833
+ curelem = SH_NEXT(tb, curelem, startelem);
834
+ }
835
+ }
836
+
837
+ /*
838
+ * Initialize iterator.
839
+ */
840
+ SH_SCOPE void
841
+ SH_START_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter)
842
+ {
843
+ int i;
844
+ uint64 startelem = PG_UINT64_MAX;
845
+
846
+ /*
847
+ * Search for the first empty element. As deletions during iterations are
848
+ * supported, we want to start/end at an element that cannot be affected
849
+ * by elements being shifted.
850
+ */
851
+ for (i = 0; i < tb->size; i++)
852
+ {
853
+ SH_ELEMENT_TYPE *entry = &tb->data[i];
854
+
855
+ if (entry->status != SH_STATUS_IN_USE)
856
+ {
857
+ startelem = i;
858
+ break;
859
+ }
860
+ }
861
+
862
+ Assert(startelem < SH_MAX_SIZE);
863
+
864
+ /*
865
+ * Iterate backwards, that allows the current element to be deleted, even
866
+ * if there are backward shifts
867
+ */
868
+ iter->cur = startelem;
869
+ iter->end = iter->cur;
870
+ iter->done = false;
871
+ }
872
+
873
+ /*
874
+ * Initialize iterator to a specific bucket. That's really only useful for
875
+ * cases where callers are partially iterating over the hashspace, and that
876
+ * iteration deletes and inserts elements based on visited entries. Doing that
877
+ * repeatedly could lead to an unbalanced keyspace when always starting at the
878
+ * same position.
879
+ */
880
+ SH_SCOPE void
881
+ SH_START_ITERATE_AT(SH_TYPE * tb, SH_ITERATOR * iter, uint32 at)
882
+ {
883
+ /*
884
+ * Iterate backwards, that allows the current element to be deleted, even
885
+ * if there are backward shifts.
886
+ */
887
+ iter->cur = at & tb->sizemask; /* ensure at is within a valid range */
888
+ iter->end = iter->cur;
889
+ iter->done = false;
890
+ }
891
+
892
+ /*
893
+ * Iterate over all entries in the hash-table. Return the next occupied entry,
894
+ * or NULL if done.
895
+ *
896
+ * During iteration the current entry in the hash table may be deleted,
897
+ * without leading to elements being skipped or returned twice. Additionally
898
+ * the rest of the table may be modified (i.e. there can be insertions or
899
+ * deletions), but if so, there's neither a guarantee that all nodes are
900
+ * visited at least once, nor a guarantee that a node is visited at most once.
901
+ */
902
+ SH_SCOPE SH_ELEMENT_TYPE *
903
+ SH_ITERATE(SH_TYPE * tb, SH_ITERATOR * iter)
904
+ {
905
+ while (!iter->done)
906
+ {
907
+ SH_ELEMENT_TYPE *elem;
908
+
909
+ elem = &tb->data[iter->cur];
910
+
911
+ /* next element in backward direction */
912
+ iter->cur = (iter->cur - 1) & tb->sizemask;
913
+
914
+ if ((iter->cur & tb->sizemask) == (iter->end & tb->sizemask))
915
+ iter->done = true;
916
+ if (elem->status == SH_STATUS_IN_USE)
917
+ {
918
+ return elem;
919
+ }
920
+ }
921
+
922
+ return NULL;
923
+ }
924
+
925
+ /*
926
+ * Report some statistics about the state of the hashtable. For
927
+ * debugging/profiling purposes only.
928
+ */
929
+ SH_SCOPE void
930
+ SH_STAT(SH_TYPE * tb)
931
+ {
932
+ uint32 max_chain_length = 0;
933
+ uint32 total_chain_length = 0;
934
+ double avg_chain_length;
935
+ double fillfactor;
936
+ uint32 i;
937
+
938
+ uint32 *collisions = palloc0(tb->size * sizeof(uint32));
939
+ uint32 total_collisions = 0;
940
+ uint32 max_collisions = 0;
941
+ double avg_collisions;
942
+
943
+ for (i = 0; i < tb->size; i++)
944
+ {
945
+ uint32 hash;
946
+ uint32 optimal;
947
+ uint32 dist;
948
+ SH_ELEMENT_TYPE *elem;
949
+
950
+ elem = &tb->data[i];
951
+
952
+ if (elem->status != SH_STATUS_IN_USE)
953
+ continue;
954
+
955
+ hash = SH_ENTRY_HASH(tb, elem);
956
+ optimal = SH_INITIAL_BUCKET(tb, hash);
957
+ dist = SH_DISTANCE_FROM_OPTIMAL(tb, optimal, i);
958
+
959
+ if (dist > max_chain_length)
960
+ max_chain_length = dist;
961
+ total_chain_length += dist;
962
+
963
+ collisions[optimal]++;
964
+ }
965
+
966
+ for (i = 0; i < tb->size; i++)
967
+ {
968
+ uint32 curcoll = collisions[i];
969
+
970
+ if (curcoll == 0)
971
+ continue;
972
+
973
+ /* single contained element is not a collision */
974
+ curcoll--;
975
+ total_collisions += curcoll;
976
+ if (curcoll > max_collisions)
977
+ max_collisions = curcoll;
978
+ }
979
+
980
+ if (tb->members > 0)
981
+ {
982
+ fillfactor = tb->members / ((double) tb->size);
983
+ avg_chain_length = ((double) total_chain_length) / tb->members;
984
+ avg_collisions = ((double) total_collisions) / tb->members;
985
+ }
986
+ else
987
+ {
988
+ fillfactor = 0;
989
+ avg_chain_length = 0;
990
+ avg_collisions = 0;
991
+ }
992
+
993
+ sh_log("size: " UINT64_FORMAT ", members: %u, filled: %f, total chain: %u, max chain: %u, avg chain: %f, total_collisions: %u, max_collisions: %i, avg_collisions: %f",
994
+ tb->size, tb->members, fillfactor, total_chain_length, max_chain_length, avg_chain_length,
995
+ total_collisions, max_collisions, avg_collisions);
996
+ }
997
+
998
+ #endif /* SH_DEFINE */
999
+
1000
+
1001
+ /* undefine external parameters, so next hash table can be defined */
1002
+ #undef SH_PREFIX
1003
+ #undef SH_KEY_TYPE
1004
+ #undef SH_KEY
1005
+ #undef SH_ELEMENT_TYPE
1006
+ #undef SH_HASH_KEY
1007
+ #undef SH_SCOPE
1008
+ #undef SH_DECLARE
1009
+ #undef SH_DEFINE
1010
+ #undef SH_GET_HASH
1011
+ #undef SH_STORE_HASH
1012
+ #undef SH_USE_NONDEFAULT_ALLOCATOR
1013
+ #undef SH_EQUAL
1014
+
1015
+ /* undefine locally declared macros */
1016
+ #undef SH_MAKE_PREFIX
1017
+ #undef SH_MAKE_NAME
1018
+ #undef SH_MAKE_NAME_
1019
+ #undef SH_FILLFACTOR
1020
+ #undef SH_MAX_FILLFACTOR
1021
+ #undef SH_GROW_MAX_DIB
1022
+ #undef SH_GROW_MAX_MOVE
1023
+ #undef SH_GROW_MIN_FILLFACTOR
1024
+ #undef SH_MAX_SIZE
1025
+
1026
+ /* types */
1027
+ #undef SH_TYPE
1028
+ #undef SH_STATUS
1029
+ #undef SH_STATUS_EMPTY
1030
+ #undef SH_STATUS_IN_USE
1031
+ #undef SH_ITERATOR
1032
+
1033
+ /* external function names */
1034
+ #undef SH_CREATE
1035
+ #undef SH_DESTROY
1036
+ #undef SH_RESET
1037
+ #undef SH_INSERT
1038
+ #undef SH_INSERT_HASH
1039
+ #undef SH_DELETE
1040
+ #undef SH_LOOKUP
1041
+ #undef SH_LOOKUP_HASH
1042
+ #undef SH_GROW
1043
+ #undef SH_START_ITERATE
1044
+ #undef SH_START_ITERATE_AT
1045
+ #undef SH_ITERATE
1046
+ #undef SH_ALLOCATE
1047
+ #undef SH_FREE
1048
+ #undef SH_STAT
1049
+
1050
+ /* internal function names */
1051
+ #undef SH_COMPUTE_PARAMETERS
1052
+ #undef SH_COMPARE_KEYS
1053
+ #undef SH_INITIAL_BUCKET
1054
+ #undef SH_NEXT
1055
+ #undef SH_PREV
1056
+ #undef SH_DISTANCE_FROM_OPTIMAL
1057
+ #undef SH_ENTRY_HASH
1058
+ #undef SH_INSERT_HASH_INTERNAL
1059
+ #undef SH_LOOKUP_HASH_INTERNAL