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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +217 -99
- data/README.md +92 -69
- data/Rakefile +85 -5
- data/ext/pg_query/extconf.rb +3 -40
- data/ext/pg_query/guc-file.c +0 -0
- data/ext/pg_query/include/access/amapi.h +246 -0
- data/ext/pg_query/include/access/attmap.h +52 -0
- data/ext/pg_query/include/access/attnum.h +64 -0
- data/ext/pg_query/include/access/clog.h +61 -0
- data/ext/pg_query/include/access/commit_ts.h +77 -0
- data/ext/pg_query/include/access/detoast.h +92 -0
- data/ext/pg_query/include/access/genam.h +228 -0
- data/ext/pg_query/include/access/gin.h +78 -0
- data/ext/pg_query/include/access/htup.h +89 -0
- data/ext/pg_query/include/access/htup_details.h +819 -0
- data/ext/pg_query/include/access/itup.h +161 -0
- data/ext/pg_query/include/access/parallel.h +82 -0
- data/ext/pg_query/include/access/printtup.h +35 -0
- data/ext/pg_query/include/access/relation.h +28 -0
- data/ext/pg_query/include/access/relscan.h +176 -0
- data/ext/pg_query/include/access/rmgr.h +35 -0
- data/ext/pg_query/include/access/rmgrlist.h +49 -0
- data/ext/pg_query/include/access/sdir.h +58 -0
- data/ext/pg_query/include/access/skey.h +151 -0
- data/ext/pg_query/include/access/stratnum.h +83 -0
- data/ext/pg_query/include/access/sysattr.h +29 -0
- data/ext/pg_query/include/access/table.h +27 -0
- data/ext/pg_query/include/access/tableam.h +1825 -0
- data/ext/pg_query/include/access/transam.h +265 -0
- data/ext/pg_query/include/access/tupconvert.h +51 -0
- data/ext/pg_query/include/access/tupdesc.h +154 -0
- data/ext/pg_query/include/access/tupmacs.h +247 -0
- data/ext/pg_query/include/access/twophase.h +61 -0
- data/ext/pg_query/include/access/xact.h +463 -0
- data/ext/pg_query/include/access/xlog.h +398 -0
- data/ext/pg_query/include/access/xlog_internal.h +330 -0
- data/ext/pg_query/include/access/xlogdefs.h +109 -0
- data/ext/pg_query/include/access/xloginsert.h +64 -0
- data/ext/pg_query/include/access/xlogreader.h +327 -0
- data/ext/pg_query/include/access/xlogrecord.h +227 -0
- data/ext/pg_query/include/bootstrap/bootstrap.h +62 -0
- data/ext/pg_query/include/c.h +1322 -0
- data/ext/pg_query/include/catalog/catalog.h +42 -0
- data/ext/pg_query/include/catalog/catversion.h +58 -0
- data/ext/pg_query/include/catalog/dependency.h +275 -0
- data/ext/pg_query/include/catalog/genbki.h +64 -0
- data/ext/pg_query/include/catalog/index.h +199 -0
- data/ext/pg_query/include/catalog/indexing.h +366 -0
- data/ext/pg_query/include/catalog/namespace.h +188 -0
- data/ext/pg_query/include/catalog/objectaccess.h +197 -0
- data/ext/pg_query/include/catalog/objectaddress.h +84 -0
- data/ext/pg_query/include/catalog/pg_aggregate.h +176 -0
- data/ext/pg_query/include/catalog/pg_aggregate_d.h +77 -0
- data/ext/pg_query/include/catalog/pg_am.h +60 -0
- data/ext/pg_query/include/catalog/pg_am_d.h +45 -0
- data/ext/pg_query/include/catalog/pg_attribute.h +204 -0
- data/ext/pg_query/include/catalog/pg_attribute_d.h +59 -0
- data/ext/pg_query/include/catalog/pg_authid.h +58 -0
- data/ext/pg_query/include/catalog/pg_authid_d.h +49 -0
- data/ext/pg_query/include/catalog/pg_class.h +200 -0
- data/ext/pg_query/include/catalog/pg_class_d.h +103 -0
- data/ext/pg_query/include/catalog/pg_collation.h +73 -0
- data/ext/pg_query/include/catalog/pg_collation_d.h +45 -0
- data/ext/pg_query/include/catalog/pg_constraint.h +247 -0
- data/ext/pg_query/include/catalog/pg_constraint_d.h +67 -0
- data/ext/pg_query/include/catalog/pg_control.h +250 -0
- data/ext/pg_query/include/catalog/pg_conversion.h +72 -0
- data/ext/pg_query/include/catalog/pg_conversion_d.h +35 -0
- data/ext/pg_query/include/catalog/pg_depend.h +73 -0
- data/ext/pg_query/include/catalog/pg_depend_d.h +34 -0
- data/ext/pg_query/include/catalog/pg_event_trigger.h +51 -0
- data/ext/pg_query/include/catalog/pg_event_trigger_d.h +34 -0
- data/ext/pg_query/include/catalog/pg_index.h +80 -0
- data/ext/pg_query/include/catalog/pg_index_d.h +56 -0
- data/ext/pg_query/include/catalog/pg_language.h +67 -0
- data/ext/pg_query/include/catalog/pg_language_d.h +39 -0
- data/ext/pg_query/include/catalog/pg_namespace.h +59 -0
- data/ext/pg_query/include/catalog/pg_namespace_d.h +34 -0
- data/ext/pg_query/include/catalog/pg_opclass.h +85 -0
- data/ext/pg_query/include/catalog/pg_opclass_d.h +49 -0
- data/ext/pg_query/include/catalog/pg_operator.h +102 -0
- data/ext/pg_query/include/catalog/pg_operator_d.h +106 -0
- data/ext/pg_query/include/catalog/pg_opfamily.h +60 -0
- data/ext/pg_query/include/catalog/pg_opfamily_d.h +47 -0
- data/ext/pg_query/include/catalog/pg_partitioned_table.h +63 -0
- data/ext/pg_query/include/catalog/pg_partitioned_table_d.h +35 -0
- data/ext/pg_query/include/catalog/pg_proc.h +211 -0
- data/ext/pg_query/include/catalog/pg_proc_d.h +99 -0
- data/ext/pg_query/include/catalog/pg_publication.h +115 -0
- data/ext/pg_query/include/catalog/pg_publication_d.h +36 -0
- data/ext/pg_query/include/catalog/pg_replication_origin.h +57 -0
- data/ext/pg_query/include/catalog/pg_replication_origin_d.h +29 -0
- data/ext/pg_query/include/catalog/pg_statistic.h +275 -0
- data/ext/pg_query/include/catalog/pg_statistic_d.h +194 -0
- data/ext/pg_query/include/catalog/pg_statistic_ext.h +74 -0
- data/ext/pg_query/include/catalog/pg_statistic_ext_d.h +40 -0
- data/ext/pg_query/include/catalog/pg_transform.h +45 -0
- data/ext/pg_query/include/catalog/pg_transform_d.h +32 -0
- data/ext/pg_query/include/catalog/pg_trigger.h +137 -0
- data/ext/pg_query/include/catalog/pg_trigger_d.h +106 -0
- data/ext/pg_query/include/catalog/pg_ts_config.h +50 -0
- data/ext/pg_query/include/catalog/pg_ts_config_d.h +32 -0
- data/ext/pg_query/include/catalog/pg_ts_dict.h +54 -0
- data/ext/pg_query/include/catalog/pg_ts_dict_d.h +33 -0
- data/ext/pg_query/include/catalog/pg_ts_parser.h +57 -0
- data/ext/pg_query/include/catalog/pg_ts_parser_d.h +35 -0
- data/ext/pg_query/include/catalog/pg_ts_template.h +48 -0
- data/ext/pg_query/include/catalog/pg_ts_template_d.h +32 -0
- data/ext/pg_query/include/catalog/pg_type.h +372 -0
- data/ext/pg_query/include/catalog/pg_type_d.h +285 -0
- data/ext/pg_query/include/catalog/storage.h +48 -0
- data/ext/pg_query/include/commands/async.h +54 -0
- data/ext/pg_query/include/commands/dbcommands.h +35 -0
- data/ext/pg_query/include/commands/defrem.h +173 -0
- data/ext/pg_query/include/commands/event_trigger.h +88 -0
- data/ext/pg_query/include/commands/explain.h +127 -0
- data/ext/pg_query/include/commands/prepare.h +61 -0
- data/ext/pg_query/include/commands/tablespace.h +67 -0
- data/ext/pg_query/include/commands/trigger.h +277 -0
- data/ext/pg_query/include/commands/user.h +37 -0
- data/ext/pg_query/include/commands/vacuum.h +293 -0
- data/ext/pg_query/include/commands/variable.h +38 -0
- data/ext/pg_query/include/common/file_perm.h +56 -0
- data/ext/pg_query/include/common/hashfn.h +104 -0
- data/ext/pg_query/include/common/ip.h +37 -0
- data/ext/pg_query/include/common/keywords.h +33 -0
- data/ext/pg_query/include/common/kwlookup.h +44 -0
- data/ext/pg_query/include/common/relpath.h +90 -0
- data/ext/pg_query/include/common/string.h +19 -0
- data/ext/pg_query/include/common/unicode_combining_table.h +196 -0
- data/ext/pg_query/include/datatype/timestamp.h +197 -0
- data/ext/pg_query/include/executor/execdesc.h +70 -0
- data/ext/pg_query/include/executor/executor.h +614 -0
- data/ext/pg_query/include/executor/functions.h +41 -0
- data/ext/pg_query/include/executor/instrument.h +101 -0
- data/ext/pg_query/include/executor/spi.h +175 -0
- data/ext/pg_query/include/executor/tablefunc.h +67 -0
- data/ext/pg_query/include/executor/tuptable.h +487 -0
- data/ext/pg_query/include/fmgr.h +775 -0
- data/ext/pg_query/include/funcapi.h +348 -0
- data/ext/pg_query/include/getaddrinfo.h +162 -0
- data/ext/pg_query/include/jit/jit.h +105 -0
- data/ext/pg_query/include/kwlist_d.h +1072 -0
- data/ext/pg_query/include/lib/ilist.h +727 -0
- data/ext/pg_query/include/lib/pairingheap.h +102 -0
- data/ext/pg_query/include/lib/simplehash.h +1059 -0
- data/ext/pg_query/include/lib/stringinfo.h +161 -0
- data/ext/pg_query/include/libpq/auth.h +29 -0
- data/ext/pg_query/include/libpq/crypt.h +46 -0
- data/ext/pg_query/include/libpq/hba.h +140 -0
- data/ext/pg_query/include/libpq/libpq-be.h +326 -0
- data/ext/pg_query/include/libpq/libpq.h +133 -0
- data/ext/pg_query/include/libpq/pqcomm.h +208 -0
- data/ext/pg_query/include/libpq/pqformat.h +210 -0
- data/ext/pg_query/include/libpq/pqsignal.h +42 -0
- data/ext/pg_query/include/mb/pg_wchar.h +672 -0
- data/ext/pg_query/include/mb/stringinfo_mb.h +24 -0
- data/ext/pg_query/include/miscadmin.h +476 -0
- data/ext/pg_query/include/nodes/bitmapset.h +122 -0
- data/ext/pg_query/include/nodes/execnodes.h +2520 -0
- data/ext/pg_query/include/nodes/extensible.h +160 -0
- data/ext/pg_query/include/nodes/lockoptions.h +61 -0
- data/ext/pg_query/include/nodes/makefuncs.h +108 -0
- data/ext/pg_query/include/nodes/memnodes.h +108 -0
- data/ext/pg_query/include/nodes/nodeFuncs.h +162 -0
- data/ext/pg_query/include/nodes/nodes.h +842 -0
- data/ext/pg_query/include/nodes/params.h +170 -0
- data/ext/pg_query/include/nodes/parsenodes.h +3579 -0
- data/ext/pg_query/include/nodes/pathnodes.h +2556 -0
- data/ext/pg_query/include/nodes/pg_list.h +605 -0
- data/ext/pg_query/include/nodes/plannodes.h +1251 -0
- data/ext/pg_query/include/nodes/primnodes.h +1541 -0
- data/ext/pg_query/include/nodes/print.h +34 -0
- data/ext/pg_query/include/nodes/tidbitmap.h +75 -0
- data/ext/pg_query/include/nodes/value.h +61 -0
- data/ext/pg_query/include/optimizer/cost.h +206 -0
- data/ext/pg_query/include/optimizer/geqo.h +88 -0
- data/ext/pg_query/include/optimizer/geqo_gene.h +45 -0
- data/ext/pg_query/include/optimizer/optimizer.h +199 -0
- data/ext/pg_query/include/optimizer/paths.h +249 -0
- data/ext/pg_query/include/optimizer/planmain.h +119 -0
- data/ext/pg_query/include/parser/analyze.h +49 -0
- data/ext/pg_query/include/parser/gram.h +1067 -0
- data/ext/pg_query/include/parser/gramparse.h +75 -0
- data/ext/pg_query/include/parser/kwlist.h +477 -0
- data/ext/pg_query/include/parser/parse_agg.h +68 -0
- data/ext/pg_query/include/parser/parse_clause.h +54 -0
- data/ext/pg_query/include/parser/parse_coerce.h +97 -0
- data/ext/pg_query/include/parser/parse_collate.h +27 -0
- data/ext/pg_query/include/parser/parse_expr.h +26 -0
- data/ext/pg_query/include/parser/parse_func.h +73 -0
- data/ext/pg_query/include/parser/parse_node.h +327 -0
- data/ext/pg_query/include/parser/parse_oper.h +67 -0
- data/ext/pg_query/include/parser/parse_relation.h +123 -0
- data/ext/pg_query/include/parser/parse_target.h +46 -0
- data/ext/pg_query/include/parser/parse_type.h +60 -0
- data/ext/pg_query/include/parser/parser.h +41 -0
- data/ext/pg_query/include/parser/parsetree.h +61 -0
- data/ext/pg_query/include/parser/scanner.h +152 -0
- data/ext/pg_query/include/parser/scansup.h +30 -0
- data/ext/pg_query/include/partitioning/partdefs.h +26 -0
- data/ext/pg_query/include/pg_config.h +989 -0
- data/ext/pg_query/include/pg_config_ext.h +8 -0
- data/ext/pg_query/include/pg_config_manual.h +350 -0
- data/ext/pg_query/include/pg_config_os.h +8 -0
- data/ext/pg_query/include/pg_getopt.h +56 -0
- data/ext/pg_query/include/pg_query.h +121 -0
- data/ext/pg_query/include/pg_query_enum_defs.c +2454 -0
- data/ext/pg_query/include/pg_query_fingerprint_conds.c +875 -0
- data/ext/pg_query/include/pg_query_fingerprint_defs.c +12413 -0
- data/ext/pg_query/include/pg_query_json_helper.c +61 -0
- data/ext/pg_query/include/pg_query_outfuncs_conds.c +686 -0
- data/ext/pg_query/include/pg_query_outfuncs_defs.c +2437 -0
- data/ext/pg_query/include/pg_query_readfuncs_conds.c +222 -0
- data/ext/pg_query/include/pg_query_readfuncs_defs.c +2878 -0
- data/ext/pg_query/include/pg_trace.h +17 -0
- data/ext/pg_query/include/pgstat.h +1487 -0
- data/ext/pg_query/include/pgtime.h +84 -0
- data/ext/pg_query/include/pl_gram.h +385 -0
- data/ext/pg_query/include/pl_reserved_kwlist.h +52 -0
- data/ext/pg_query/include/pl_reserved_kwlist_d.h +114 -0
- data/ext/pg_query/include/pl_unreserved_kwlist.h +112 -0
- data/ext/pg_query/include/pl_unreserved_kwlist_d.h +246 -0
- data/ext/pg_query/include/plerrcodes.h +990 -0
- data/ext/pg_query/include/plpgsql.h +1347 -0
- data/ext/pg_query/include/port.h +524 -0
- data/ext/pg_query/include/port/atomics.h +524 -0
- data/ext/pg_query/include/port/atomics/arch-arm.h +26 -0
- data/ext/pg_query/include/port/atomics/arch-ppc.h +254 -0
- data/ext/pg_query/include/port/atomics/arch-x86.h +252 -0
- data/ext/pg_query/include/port/atomics/fallback.h +170 -0
- data/ext/pg_query/include/port/atomics/generic-gcc.h +286 -0
- data/ext/pg_query/include/port/atomics/generic.h +401 -0
- data/ext/pg_query/include/port/pg_bitutils.h +226 -0
- data/ext/pg_query/include/port/pg_bswap.h +161 -0
- data/ext/pg_query/include/port/pg_crc32c.h +101 -0
- data/ext/pg_query/include/portability/instr_time.h +256 -0
- data/ext/pg_query/include/postgres.h +764 -0
- data/ext/pg_query/include/postgres_ext.h +74 -0
- data/ext/pg_query/include/postmaster/autovacuum.h +83 -0
- data/ext/pg_query/include/postmaster/bgworker.h +161 -0
- data/ext/pg_query/include/postmaster/bgworker_internals.h +64 -0
- data/ext/pg_query/include/postmaster/bgwriter.h +45 -0
- data/ext/pg_query/include/postmaster/fork_process.h +17 -0
- data/ext/pg_query/include/postmaster/interrupt.h +32 -0
- data/ext/pg_query/include/postmaster/pgarch.h +39 -0
- data/ext/pg_query/include/postmaster/postmaster.h +77 -0
- data/ext/pg_query/include/postmaster/syslogger.h +98 -0
- data/ext/pg_query/include/postmaster/walwriter.h +21 -0
- data/ext/pg_query/include/protobuf-c.h +1106 -0
- data/ext/pg_query/include/protobuf-c/protobuf-c.h +1106 -0
- data/ext/pg_query/include/protobuf/pg_query.pb-c.h +10846 -0
- data/ext/pg_query/include/protobuf/pg_query.pb.h +124718 -0
- data/ext/pg_query/include/regex/regex.h +184 -0
- data/ext/pg_query/include/replication/logicallauncher.h +31 -0
- data/ext/pg_query/include/replication/logicalproto.h +110 -0
- data/ext/pg_query/include/replication/logicalworker.h +19 -0
- data/ext/pg_query/include/replication/origin.h +73 -0
- data/ext/pg_query/include/replication/reorderbuffer.h +467 -0
- data/ext/pg_query/include/replication/slot.h +219 -0
- data/ext/pg_query/include/replication/syncrep.h +115 -0
- data/ext/pg_query/include/replication/walreceiver.h +340 -0
- data/ext/pg_query/include/replication/walsender.h +74 -0
- data/ext/pg_query/include/rewrite/prs2lock.h +46 -0
- data/ext/pg_query/include/rewrite/rewriteHandler.h +40 -0
- data/ext/pg_query/include/rewrite/rewriteManip.h +87 -0
- data/ext/pg_query/include/rewrite/rewriteSupport.h +26 -0
- data/ext/pg_query/include/storage/backendid.h +37 -0
- data/ext/pg_query/include/storage/block.h +121 -0
- data/ext/pg_query/include/storage/buf.h +46 -0
- data/ext/pg_query/include/storage/bufmgr.h +292 -0
- data/ext/pg_query/include/storage/bufpage.h +459 -0
- data/ext/pg_query/include/storage/condition_variable.h +62 -0
- data/ext/pg_query/include/storage/dsm.h +61 -0
- data/ext/pg_query/include/storage/dsm_impl.h +75 -0
- data/ext/pg_query/include/storage/fd.h +168 -0
- data/ext/pg_query/include/storage/ipc.h +81 -0
- data/ext/pg_query/include/storage/item.h +19 -0
- data/ext/pg_query/include/storage/itemid.h +184 -0
- data/ext/pg_query/include/storage/itemptr.h +206 -0
- data/ext/pg_query/include/storage/large_object.h +100 -0
- data/ext/pg_query/include/storage/latch.h +190 -0
- data/ext/pg_query/include/storage/lmgr.h +114 -0
- data/ext/pg_query/include/storage/lock.h +612 -0
- data/ext/pg_query/include/storage/lockdefs.h +59 -0
- data/ext/pg_query/include/storage/lwlock.h +232 -0
- data/ext/pg_query/include/storage/lwlocknames.h +51 -0
- data/ext/pg_query/include/storage/off.h +57 -0
- data/ext/pg_query/include/storage/pg_sema.h +61 -0
- data/ext/pg_query/include/storage/pg_shmem.h +90 -0
- data/ext/pg_query/include/storage/pmsignal.h +94 -0
- data/ext/pg_query/include/storage/predicate.h +87 -0
- data/ext/pg_query/include/storage/proc.h +333 -0
- data/ext/pg_query/include/storage/proclist_types.h +51 -0
- data/ext/pg_query/include/storage/procsignal.h +75 -0
- data/ext/pg_query/include/storage/relfilenode.h +99 -0
- data/ext/pg_query/include/storage/s_lock.h +1047 -0
- data/ext/pg_query/include/storage/sharedfileset.h +45 -0
- data/ext/pg_query/include/storage/shm_mq.h +85 -0
- data/ext/pg_query/include/storage/shm_toc.h +58 -0
- data/ext/pg_query/include/storage/shmem.h +81 -0
- data/ext/pg_query/include/storage/sinval.h +153 -0
- data/ext/pg_query/include/storage/sinvaladt.h +43 -0
- data/ext/pg_query/include/storage/smgr.h +109 -0
- data/ext/pg_query/include/storage/spin.h +77 -0
- data/ext/pg_query/include/storage/standby.h +91 -0
- data/ext/pg_query/include/storage/standbydefs.h +74 -0
- data/ext/pg_query/include/storage/sync.h +62 -0
- data/ext/pg_query/include/tcop/cmdtag.h +58 -0
- data/ext/pg_query/include/tcop/cmdtaglist.h +217 -0
- data/ext/pg_query/include/tcop/deparse_utility.h +108 -0
- data/ext/pg_query/include/tcop/dest.h +149 -0
- data/ext/pg_query/include/tcop/fastpath.h +21 -0
- data/ext/pg_query/include/tcop/pquery.h +45 -0
- data/ext/pg_query/include/tcop/tcopprot.h +89 -0
- data/ext/pg_query/include/tcop/utility.h +108 -0
- data/ext/pg_query/include/tsearch/ts_cache.h +98 -0
- data/ext/pg_query/include/utils/acl.h +312 -0
- data/ext/pg_query/include/utils/aclchk_internal.h +45 -0
- data/ext/pg_query/include/utils/array.h +458 -0
- data/ext/pg_query/include/utils/builtins.h +127 -0
- data/ext/pg_query/include/utils/bytea.h +27 -0
- data/ext/pg_query/include/utils/catcache.h +231 -0
- data/ext/pg_query/include/utils/date.h +90 -0
- data/ext/pg_query/include/utils/datetime.h +343 -0
- data/ext/pg_query/include/utils/datum.h +68 -0
- data/ext/pg_query/include/utils/dsa.h +123 -0
- data/ext/pg_query/include/utils/dynahash.h +19 -0
- data/ext/pg_query/include/utils/elog.h +439 -0
- data/ext/pg_query/include/utils/errcodes.h +352 -0
- data/ext/pg_query/include/utils/expandeddatum.h +159 -0
- data/ext/pg_query/include/utils/expandedrecord.h +231 -0
- data/ext/pg_query/include/utils/float.h +356 -0
- data/ext/pg_query/include/utils/fmgroids.h +2657 -0
- data/ext/pg_query/include/utils/fmgrprotos.h +2646 -0
- data/ext/pg_query/include/utils/fmgrtab.h +48 -0
- data/ext/pg_query/include/utils/guc.h +443 -0
- data/ext/pg_query/include/utils/guc_tables.h +272 -0
- data/ext/pg_query/include/utils/hsearch.h +149 -0
- data/ext/pg_query/include/utils/inval.h +64 -0
- data/ext/pg_query/include/utils/lsyscache.h +197 -0
- data/ext/pg_query/include/utils/memdebug.h +82 -0
- data/ext/pg_query/include/utils/memutils.h +225 -0
- data/ext/pg_query/include/utils/numeric.h +76 -0
- data/ext/pg_query/include/utils/palloc.h +136 -0
- data/ext/pg_query/include/utils/partcache.h +102 -0
- data/ext/pg_query/include/utils/pg_locale.h +119 -0
- data/ext/pg_query/include/utils/pg_lsn.h +29 -0
- data/ext/pg_query/include/utils/pidfile.h +56 -0
- data/ext/pg_query/include/utils/plancache.h +235 -0
- data/ext/pg_query/include/utils/portal.h +241 -0
- data/ext/pg_query/include/utils/probes.h +114 -0
- data/ext/pg_query/include/utils/ps_status.h +25 -0
- data/ext/pg_query/include/utils/queryenvironment.h +74 -0
- data/ext/pg_query/include/utils/regproc.h +28 -0
- data/ext/pg_query/include/utils/rel.h +644 -0
- data/ext/pg_query/include/utils/relcache.h +151 -0
- data/ext/pg_query/include/utils/reltrigger.h +81 -0
- data/ext/pg_query/include/utils/resowner.h +86 -0
- data/ext/pg_query/include/utils/rls.h +50 -0
- data/ext/pg_query/include/utils/ruleutils.h +44 -0
- data/ext/pg_query/include/utils/sharedtuplestore.h +61 -0
- data/ext/pg_query/include/utils/snapmgr.h +158 -0
- data/ext/pg_query/include/utils/snapshot.h +206 -0
- data/ext/pg_query/include/utils/sortsupport.h +276 -0
- data/ext/pg_query/include/utils/syscache.h +219 -0
- data/ext/pg_query/include/utils/timeout.h +88 -0
- data/ext/pg_query/include/utils/timestamp.h +116 -0
- data/ext/pg_query/include/utils/tuplesort.h +277 -0
- data/ext/pg_query/include/utils/tuplestore.h +91 -0
- data/ext/pg_query/include/utils/typcache.h +202 -0
- data/ext/pg_query/include/utils/tzparser.h +39 -0
- data/ext/pg_query/include/utils/varlena.h +39 -0
- data/ext/pg_query/include/utils/xml.h +84 -0
- data/ext/pg_query/include/xxhash.h +5445 -0
- data/ext/pg_query/include/xxhash/xxhash.h +5445 -0
- data/ext/pg_query/pg_query.c +104 -0
- data/ext/pg_query/pg_query.pb-c.c +37628 -0
- data/ext/pg_query/pg_query_deparse.c +9959 -0
- data/ext/pg_query/pg_query_fingerprint.c +295 -0
- data/ext/pg_query/pg_query_fingerprint.h +8 -0
- data/ext/pg_query/pg_query_internal.h +24 -0
- data/ext/pg_query/pg_query_json_plpgsql.c +738 -0
- data/ext/pg_query/pg_query_json_plpgsql.h +9 -0
- data/ext/pg_query/pg_query_normalize.c +439 -0
- data/ext/pg_query/pg_query_outfuncs.h +10 -0
- data/ext/pg_query/pg_query_outfuncs_json.c +297 -0
- data/ext/pg_query/pg_query_outfuncs_protobuf.c +237 -0
- data/ext/pg_query/pg_query_parse.c +148 -0
- data/ext/pg_query/pg_query_parse_plpgsql.c +460 -0
- data/ext/pg_query/pg_query_readfuncs.h +11 -0
- data/ext/pg_query/pg_query_readfuncs_protobuf.c +142 -0
- data/ext/pg_query/pg_query_ruby.c +108 -12
- data/ext/pg_query/pg_query_scan.c +173 -0
- data/ext/pg_query/pg_query_split.c +221 -0
- data/ext/pg_query/protobuf-c.c +3660 -0
- data/ext/pg_query/src_backend_catalog_namespace.c +1051 -0
- data/ext/pg_query/src_backend_catalog_pg_proc.c +142 -0
- data/ext/pg_query/src_backend_commands_define.c +117 -0
- data/ext/pg_query/src_backend_libpq_pqcomm.c +651 -0
- data/ext/pg_query/src_backend_nodes_bitmapset.c +513 -0
- data/ext/pg_query/src_backend_nodes_copyfuncs.c +6013 -0
- data/ext/pg_query/src_backend_nodes_equalfuncs.c +4003 -0
- data/ext/pg_query/src_backend_nodes_extensible.c +99 -0
- data/ext/pg_query/src_backend_nodes_list.c +922 -0
- data/ext/pg_query/src_backend_nodes_makefuncs.c +417 -0
- data/ext/pg_query/src_backend_nodes_nodeFuncs.c +1363 -0
- data/ext/pg_query/src_backend_nodes_value.c +84 -0
- data/ext/pg_query/src_backend_parser_gram.c +47456 -0
- data/ext/pg_query/src_backend_parser_parse_expr.c +313 -0
- data/ext/pg_query/src_backend_parser_parser.c +497 -0
- data/ext/pg_query/src_backend_parser_scan.c +7091 -0
- data/ext/pg_query/src_backend_parser_scansup.c +160 -0
- data/ext/pg_query/src_backend_postmaster_postmaster.c +2230 -0
- data/ext/pg_query/src_backend_storage_ipc_ipc.c +192 -0
- data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +370 -0
- data/ext/pg_query/src_backend_tcop_postgres.c +776 -0
- data/ext/pg_query/src_backend_utils_adt_datum.c +326 -0
- data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +98 -0
- data/ext/pg_query/src_backend_utils_adt_format_type.c +136 -0
- data/ext/pg_query/src_backend_utils_adt_ruleutils.c +1683 -0
- data/ext/pg_query/src_backend_utils_error_assert.c +74 -0
- data/ext/pg_query/src_backend_utils_error_elog.c +1748 -0
- data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +570 -0
- data/ext/pg_query/src_backend_utils_hash_dynahash.c +1086 -0
- data/ext/pg_query/src_backend_utils_init_globals.c +168 -0
- data/ext/pg_query/src_backend_utils_mb_mbutils.c +839 -0
- data/ext/pg_query/src_backend_utils_misc_guc.c +1831 -0
- data/ext/pg_query/src_backend_utils_mmgr_aset.c +1560 -0
- data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +1006 -0
- data/ext/pg_query/src_common_encnames.c +158 -0
- data/ext/pg_query/src_common_keywords.c +39 -0
- data/ext/pg_query/src_common_kwlist_d.h +1081 -0
- data/ext/pg_query/src_common_kwlookup.c +91 -0
- data/ext/pg_query/src_common_psprintf.c +158 -0
- data/ext/pg_query/src_common_string.c +86 -0
- data/ext/pg_query/src_common_stringinfo.c +336 -0
- data/ext/pg_query/src_common_wchar.c +1651 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1133 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +877 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +6533 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +107 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +123 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +671 -0
- data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +255 -0
- data/ext/pg_query/src_port_erand48.c +127 -0
- data/ext/pg_query/src_port_pg_bitutils.c +246 -0
- data/ext/pg_query/src_port_pgsleep.c +69 -0
- data/ext/pg_query/src_port_pgstrcasecmp.c +83 -0
- data/ext/pg_query/src_port_qsort.c +240 -0
- data/ext/pg_query/src_port_random.c +31 -0
- data/ext/pg_query/src_port_snprintf.c +1449 -0
- data/ext/pg_query/src_port_strerror.c +324 -0
- data/ext/pg_query/src_port_strnlen.c +39 -0
- data/ext/pg_query/xxhash.c +43 -0
- data/lib/pg_query.rb +7 -4
- data/lib/pg_query/constants.rb +21 -0
- data/lib/pg_query/deparse.rb +15 -1581
- data/lib/pg_query/filter_columns.rb +88 -85
- data/lib/pg_query/fingerprint.rb +122 -87
- data/lib/pg_query/json_field_names.rb +1402 -0
- data/lib/pg_query/node.rb +31 -0
- data/lib/pg_query/param_refs.rb +42 -37
- data/lib/pg_query/parse.rb +220 -203
- data/lib/pg_query/parse_error.rb +1 -1
- data/lib/pg_query/pg_query_pb.rb +3211 -0
- data/lib/pg_query/scan.rb +23 -0
- data/lib/pg_query/treewalker.rb +24 -40
- data/lib/pg_query/truncate.rb +71 -42
- data/lib/pg_query/version.rb +2 -2
- metadata +472 -11
- data/ext/pg_query/pg_query_ruby.h +0 -10
- data/lib/pg_query/deep_dup.rb +0 -16
- data/lib/pg_query/deparse/alter_table.rb +0 -42
- data/lib/pg_query/deparse/interval.rb +0 -105
- data/lib/pg_query/deparse/keywords.rb +0 -159
- data/lib/pg_query/deparse/rename.rb +0 -41
- data/lib/pg_query/legacy_parsetree.rb +0 -109
- 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
|