pg_query 4.2.2 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +6 -8
- data/Rakefile +3 -3
- data/ext/pg_query/extconf.rb +1 -3
- data/ext/pg_query/include/access/amapi.h +3 -1
- data/ext/pg_query/include/access/attmap.h +5 -3
- data/ext/pg_query/include/access/attnum.h +1 -1
- data/ext/pg_query/include/access/clog.h +1 -1
- data/ext/pg_query/include/access/commit_ts.h +1 -1
- data/ext/pg_query/include/access/detoast.h +1 -1
- data/ext/pg_query/include/access/genam.h +7 -5
- data/ext/pg_query/include/access/gin.h +16 -3
- data/ext/pg_query/include/access/htup.h +1 -1
- data/ext/pg_query/include/access/htup_details.h +6 -2
- data/ext/pg_query/include/access/itup.h +61 -58
- data/ext/pg_query/include/access/parallel.h +2 -2
- data/ext/pg_query/include/access/printtup.h +1 -1
- data/ext/pg_query/include/access/relation.h +1 -1
- data/ext/pg_query/include/access/relscan.h +1 -1
- data/ext/pg_query/include/access/rmgrlist.h +2 -2
- data/ext/pg_query/include/access/sdir.h +12 -3
- data/ext/pg_query/include/access/skey.h +1 -1
- data/ext/pg_query/include/access/stratnum.h +1 -1
- data/ext/pg_query/include/access/sysattr.h +1 -1
- data/ext/pg_query/include/access/table.h +1 -1
- data/ext/pg_query/include/access/tableam.h +68 -45
- data/ext/pg_query/include/access/toast_compression.h +1 -1
- data/ext/pg_query/include/access/transam.h +1 -1
- data/ext/pg_query/include/access/tsmapi.h +82 -0
- data/ext/pg_query/include/access/tupconvert.h +5 -2
- data/ext/pg_query/include/access/tupdesc.h +2 -2
- data/ext/pg_query/include/access/tupmacs.h +58 -98
- data/ext/pg_query/include/access/twophase.h +2 -2
- data/ext/pg_query/include/access/xact.h +25 -18
- data/ext/pg_query/include/access/xlog.h +15 -16
- data/ext/pg_query/include/access/xlog_internal.h +100 -62
- data/ext/pg_query/include/access/xlogbackup.h +41 -0
- data/ext/pg_query/include/access/xlogdefs.h +6 -25
- data/ext/pg_query/include/access/xlogprefetcher.h +1 -1
- data/ext/pg_query/include/access/xlogreader.h +7 -6
- data/ext/pg_query/include/access/xlogrecord.h +17 -5
- data/ext/pg_query/include/access/xlogrecovery.h +4 -3
- data/ext/pg_query/include/archive/archive_module.h +59 -0
- data/ext/pg_query/include/c.h +144 -156
- data/ext/pg_query/include/catalog/catalog.h +4 -3
- data/ext/pg_query/include/catalog/catversion.h +6 -2
- data/ext/pg_query/include/catalog/dependency.h +5 -4
- data/ext/pg_query/include/catalog/genbki.h +7 -6
- data/ext/pg_query/include/catalog/index.h +4 -4
- data/ext/pg_query/include/catalog/indexing.h +1 -1
- data/ext/pg_query/include/catalog/namespace.h +2 -2
- data/ext/pg_query/include/catalog/objectaccess.h +10 -8
- data/ext/pg_query/include/catalog/objectaddress.h +3 -3
- data/ext/pg_query/include/catalog/pg_aggregate.h +1 -1
- data/ext/pg_query/include/catalog/pg_aggregate_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_am.h +1 -1
- data/ext/pg_query/include/catalog/pg_am_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_attribute.h +19 -17
- data/ext/pg_query/include/catalog/pg_attribute_d.h +19 -19
- data/ext/pg_query/include/catalog/pg_authid.h +1 -1
- data/ext/pg_query/include/catalog/pg_authid_d.h +3 -1
- data/ext/pg_query/include/catalog/pg_class.h +1 -1
- data/ext/pg_query/include/catalog/pg_class_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_collation.h +3 -1
- data/ext/pg_query/include/catalog/pg_collation_d.h +4 -3
- data/ext/pg_query/include/catalog/pg_constraint.h +2 -2
- data/ext/pg_query/include/catalog/pg_constraint_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_control.h +9 -1
- data/ext/pg_query/include/catalog/pg_conversion.h +2 -2
- data/ext/pg_query/include/catalog/pg_conversion_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_database.h +124 -0
- data/ext/pg_query/include/catalog/pg_database_d.h +52 -0
- data/ext/pg_query/include/catalog/pg_depend.h +1 -1
- data/ext/pg_query/include/catalog/pg_depend_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_event_trigger.h +1 -1
- data/ext/pg_query/include/catalog/pg_event_trigger_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_index.h +1 -1
- data/ext/pg_query/include/catalog/pg_index_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_language.h +1 -1
- data/ext/pg_query/include/catalog/pg_language_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_namespace.h +1 -1
- data/ext/pg_query/include/catalog/pg_namespace_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_opclass.h +1 -1
- data/ext/pg_query/include/catalog/pg_opclass_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_operator.h +1 -1
- data/ext/pg_query/include/catalog/pg_operator_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_opfamily.h +3 -2
- data/ext/pg_query/include/catalog/pg_opfamily_d.h +4 -2
- data/ext/pg_query/include/catalog/pg_partitioned_table.h +1 -1
- data/ext/pg_query/include/catalog/pg_partitioned_table_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_proc.h +1 -1
- data/ext/pg_query/include/catalog/pg_proc_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_publication.h +2 -5
- data/ext/pg_query/include/catalog/pg_publication_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_replication_origin.h +1 -1
- data/ext/pg_query/include/catalog/pg_replication_origin_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_statistic.h +1 -1
- data/ext/pg_query/include/catalog/pg_statistic_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_statistic_ext.h +1 -1
- data/ext/pg_query/include/catalog/pg_statistic_ext_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_transform.h +1 -1
- data/ext/pg_query/include/catalog/pg_transform_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_trigger.h +1 -1
- data/ext/pg_query/include/catalog/pg_trigger_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_config.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_config_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_dict.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_dict_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_parser.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_parser_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_template.h +1 -1
- data/ext/pg_query/include/catalog/pg_ts_template_d.h +1 -1
- data/ext/pg_query/include/catalog/pg_type.h +1 -1
- data/ext/pg_query/include/catalog/pg_type_d.h +1 -1
- data/ext/pg_query/include/catalog/storage.h +6 -6
- data/ext/pg_query/include/commands/async.h +1 -1
- data/ext/pg_query/include/commands/dbcommands.h +2 -1
- data/ext/pg_query/include/commands/defrem.h +2 -1
- data/ext/pg_query/include/commands/event_trigger.h +1 -1
- data/ext/pg_query/include/commands/explain.h +3 -1
- data/ext/pg_query/include/commands/prepare.h +1 -1
- data/ext/pg_query/include/commands/tablespace.h +4 -4
- data/ext/pg_query/include/commands/trigger.h +15 -14
- data/ext/pg_query/include/commands/user.h +9 -3
- data/ext/pg_query/include/commands/vacuum.h +60 -14
- data/ext/pg_query/include/common/cryptohash.h +39 -0
- data/ext/pg_query/include/common/file_perm.h +1 -1
- data/ext/pg_query/include/common/hashfn.h +1 -1
- data/ext/pg_query/include/common/int.h +437 -0
- data/ext/pg_query/include/common/ip.h +4 -2
- data/ext/pg_query/include/common/keywords.h +1 -1
- data/ext/pg_query/include/common/kwlookup.h +2 -2
- data/ext/pg_query/include/common/pg_prng.h +3 -2
- data/ext/pg_query/include/common/relpath.h +20 -13
- data/ext/pg_query/include/common/scram-common.h +70 -0
- data/ext/pg_query/include/common/sha2.h +32 -0
- data/ext/pg_query/include/common/string.h +5 -3
- data/ext/pg_query/include/common/unicode_east_asian_fw_table.h +10 -10
- data/ext/pg_query/include/common/{unicode_combining_table.h → unicode_nonspacing_table.h} +31 -13
- data/ext/pg_query/include/copyfuncs.funcs.c +5013 -0
- data/ext/pg_query/include/copyfuncs.switch.c +938 -0
- data/ext/pg_query/include/datatype/timestamp.h +11 -4
- data/ext/pg_query/include/equalfuncs.funcs.c +3097 -0
- data/ext/pg_query/include/equalfuncs.switch.c +785 -0
- data/ext/pg_query/include/executor/execdesc.h +1 -1
- data/ext/pg_query/include/executor/executor.h +34 -17
- data/ext/pg_query/include/executor/functions.h +1 -1
- data/ext/pg_query/include/executor/instrument.h +1 -1
- data/ext/pg_query/include/executor/spi.h +2 -2
- data/ext/pg_query/include/executor/tablefunc.h +1 -1
- data/ext/pg_query/include/executor/tuptable.h +18 -11
- data/ext/pg_query/include/fmgr.h +21 -2
- data/ext/pg_query/include/foreign/fdwapi.h +294 -0
- data/ext/pg_query/include/funcapi.h +12 -12
- data/ext/pg_query/include/gram.h +1127 -0
- data/ext/pg_query/include/{parser/gramparse.h → gramparse.h} +4 -4
- data/ext/pg_query/include/jit/jit.h +2 -2
- data/ext/pg_query/include/kwlist_d.h +534 -510
- data/ext/pg_query/include/lib/dshash.h +4 -1
- data/ext/pg_query/include/lib/ilist.h +435 -22
- data/ext/pg_query/include/lib/pairingheap.h +1 -1
- data/ext/pg_query/include/lib/simplehash.h +9 -9
- data/ext/pg_query/include/lib/sort_template.h +1 -1
- data/ext/pg_query/include/lib/stringinfo.h +3 -3
- data/ext/pg_query/include/libpq/auth.h +8 -2
- data/ext/pg_query/include/libpq/crypt.h +1 -1
- data/ext/pg_query/include/libpq/hba.h +24 -17
- data/ext/pg_query/include/libpq/libpq-be.h +36 -25
- data/ext/pg_query/include/libpq/libpq.h +1 -1
- data/ext/pg_query/include/libpq/pqcomm.h +10 -41
- data/ext/pg_query/include/libpq/pqformat.h +2 -2
- data/ext/pg_query/include/libpq/pqsignal.h +22 -10
- data/ext/pg_query/include/libpq/sasl.h +136 -0
- data/ext/pg_query/include/libpq/scram.h +37 -0
- data/ext/pg_query/include/mb/pg_wchar.h +35 -18
- data/ext/pg_query/include/mb/stringinfo_mb.h +1 -1
- data/ext/pg_query/include/miscadmin.h +26 -14
- data/ext/pg_query/include/nodes/bitmapset.h +11 -7
- data/ext/pg_query/include/nodes/execnodes.h +83 -30
- data/ext/pg_query/include/nodes/extensible.h +5 -3
- data/ext/pg_query/include/nodes/lockoptions.h +1 -1
- data/ext/pg_query/include/nodes/makefuncs.h +14 -2
- data/ext/pg_query/include/nodes/memnodes.h +7 -4
- data/ext/pg_query/include/nodes/miscnodes.h +56 -0
- data/ext/pg_query/include/nodes/nodeFuncs.h +89 -29
- data/ext/pg_query/include/nodes/nodes.h +95 -510
- data/ext/pg_query/include/nodes/nodetags.h +471 -0
- data/ext/pg_query/include/nodes/params.h +3 -3
- data/ext/pg_query/include/nodes/parsenodes.h +377 -139
- data/ext/pg_query/include/nodes/pathnodes.h +1090 -440
- data/ext/pg_query/include/nodes/pg_list.h +30 -7
- data/ext/pg_query/include/nodes/plannodes.h +367 -124
- data/ext/pg_query/include/nodes/primnodes.h +670 -222
- data/ext/pg_query/include/nodes/print.h +1 -1
- data/ext/pg_query/include/{utils → nodes}/queryjumble.h +5 -7
- data/ext/pg_query/include/nodes/replnodes.h +111 -0
- data/ext/pg_query/include/nodes/supportnodes.h +346 -0
- data/ext/pg_query/include/nodes/tidbitmap.h +1 -1
- data/ext/pg_query/include/nodes/value.h +12 -2
- data/ext/pg_query/include/optimizer/cost.h +6 -4
- data/ext/pg_query/include/optimizer/geqo.h +1 -1
- data/ext/pg_query/include/optimizer/geqo_gene.h +1 -1
- data/ext/pg_query/include/optimizer/optimizer.h +8 -8
- data/ext/pg_query/include/optimizer/paths.h +16 -7
- data/ext/pg_query/include/optimizer/planmain.h +3 -6
- data/ext/pg_query/include/parser/analyze.h +4 -3
- data/ext/pg_query/include/parser/kwlist.h +12 -1
- data/ext/pg_query/include/parser/parse_agg.h +4 -2
- data/ext/pg_query/include/parser/parse_coerce.h +3 -1
- data/ext/pg_query/include/parser/parse_expr.h +1 -1
- data/ext/pg_query/include/parser/parse_func.h +1 -1
- data/ext/pg_query/include/parser/parse_node.h +22 -4
- data/ext/pg_query/include/parser/parse_oper.h +3 -3
- data/ext/pg_query/include/parser/parse_relation.h +8 -3
- data/ext/pg_query/include/parser/parse_type.h +4 -3
- data/ext/pg_query/include/parser/parser.h +1 -1
- data/ext/pg_query/include/parser/parsetree.h +1 -1
- data/ext/pg_query/include/parser/scanner.h +2 -2
- data/ext/pg_query/include/parser/scansup.h +1 -1
- data/ext/pg_query/include/partitioning/partdefs.h +1 -1
- data/ext/pg_query/include/pg_config.h +23 -217
- data/ext/pg_query/include/pg_config_manual.h +8 -46
- data/ext/pg_query/include/pg_getopt.h +1 -1
- data/ext/pg_query/include/pg_query.h +27 -3
- data/ext/pg_query/include/pg_query_enum_defs.c +311 -149
- data/ext/pg_query/include/pg_query_fingerprint_conds.c +545 -489
- data/ext/pg_query/include/pg_query_fingerprint_defs.c +5092 -4432
- data/ext/pg_query/include/pg_query_outfuncs_conds.c +385 -343
- data/ext/pg_query/include/pg_query_outfuncs_defs.c +1294 -1161
- data/ext/pg_query/include/pg_query_readfuncs_conds.c +137 -123
- data/ext/pg_query/include/pg_query_readfuncs_defs.c +1657 -1496
- data/ext/pg_query/include/pg_trace.h +1 -1
- data/ext/pg_query/include/pgstat.h +172 -93
- data/ext/pg_query/include/pgtime.h +3 -3
- data/ext/pg_query/include/pl_gram.h +64 -62
- data/ext/pg_query/include/pl_reserved_kwlist.h +1 -1
- data/ext/pg_query/include/pl_reserved_kwlist_d.h +1 -1
- data/ext/pg_query/include/pl_unreserved_kwlist.h +2 -1
- data/ext/pg_query/include/pl_unreserved_kwlist_d.h +48 -46
- data/ext/pg_query/include/plpgsql.h +17 -22
- data/ext/pg_query/include/port/atomics/arch-arm.h +3 -3
- data/ext/pg_query/include/port/atomics/arch-ppc.h +21 -21
- data/ext/pg_query/include/port/atomics/arch-x86.h +2 -2
- data/ext/pg_query/include/port/atomics/fallback.h +3 -3
- data/ext/pg_query/include/port/atomics/generic-gcc.h +1 -1
- data/ext/pg_query/include/port/atomics/generic.h +1 -1
- data/ext/pg_query/include/port/atomics.h +2 -7
- data/ext/pg_query/include/port/pg_bitutils.h +62 -25
- data/ext/pg_query/include/port/pg_bswap.h +1 -1
- data/ext/pg_query/include/port/pg_crc32c.h +1 -1
- data/ext/pg_query/include/port/simd.h +375 -0
- data/ext/pg_query/include/port.h +42 -75
- data/ext/pg_query/include/portability/instr_time.h +81 -140
- data/ext/pg_query/include/postgres.h +205 -434
- data/ext/pg_query/include/postgres_ext.h +0 -1
- data/ext/pg_query/include/postmaster/autovacuum.h +1 -4
- data/ext/pg_query/include/postmaster/auxprocess.h +1 -1
- data/ext/pg_query/include/postmaster/bgworker.h +2 -2
- data/ext/pg_query/include/postmaster/bgworker_internals.h +1 -1
- data/ext/pg_query/include/postmaster/bgwriter.h +2 -2
- data/ext/pg_query/include/postmaster/fork_process.h +1 -1
- data/ext/pg_query/include/postmaster/interrupt.h +1 -1
- data/ext/pg_query/include/postmaster/pgarch.h +1 -38
- data/ext/pg_query/include/postmaster/postmaster.h +5 -2
- data/ext/pg_query/include/postmaster/startup.h +3 -1
- data/ext/pg_query/include/postmaster/syslogger.h +2 -2
- data/ext/pg_query/include/postmaster/walwriter.h +3 -1
- data/ext/pg_query/include/protobuf/pg_query.pb-c.h +6186 -5585
- data/ext/pg_query/include/protobuf/pg_query.pb.h +112443 -91222
- data/ext/pg_query/include/regex/regex.h +9 -6
- data/ext/pg_query/include/replication/logicallauncher.h +6 -1
- data/ext/pg_query/include/replication/logicalproto.h +30 -10
- data/ext/pg_query/include/replication/logicalworker.h +14 -1
- data/ext/pg_query/include/replication/origin.h +4 -4
- data/ext/pg_query/include/replication/reorderbuffer.h +113 -45
- data/ext/pg_query/include/replication/slot.h +25 -6
- data/ext/pg_query/include/replication/syncrep.h +2 -8
- data/ext/pg_query/include/replication/walreceiver.h +15 -9
- data/ext/pg_query/include/replication/walsender.h +13 -13
- data/ext/pg_query/include/rewrite/prs2lock.h +1 -1
- data/ext/pg_query/include/rewrite/rewriteHandler.h +1 -4
- data/ext/pg_query/include/rewrite/rewriteManip.h +11 -2
- data/ext/pg_query/include/rewrite/rewriteSupport.h +1 -1
- data/ext/pg_query/include/src_backend_nodes_copyfuncs.funcs.c +5321 -0
- data/ext/pg_query/include/src_backend_nodes_equalfuncs.funcs.c +3354 -0
- data/ext/pg_query/include/storage/backendid.h +1 -1
- data/ext/pg_query/include/storage/block.h +24 -31
- data/ext/pg_query/include/storage/buf.h +1 -1
- data/ext/pg_query/include/storage/bufmgr.h +183 -87
- data/ext/pg_query/include/storage/bufpage.h +146 -93
- data/ext/pg_query/include/storage/condition_variable.h +2 -2
- data/ext/pg_query/include/storage/dsm.h +3 -6
- data/ext/pg_query/include/storage/dsm_impl.h +4 -1
- data/ext/pg_query/include/storage/fd.h +24 -20
- data/ext/pg_query/include/storage/fileset.h +1 -1
- data/ext/pg_query/include/storage/ipc.h +1 -1
- data/ext/pg_query/include/storage/item.h +1 -1
- data/ext/pg_query/include/storage/itemid.h +1 -1
- data/ext/pg_query/include/storage/itemptr.h +94 -57
- data/ext/pg_query/include/storage/large_object.h +1 -1
- data/ext/pg_query/include/storage/latch.h +9 -1
- data/ext/pg_query/include/storage/lmgr.h +6 -1
- data/ext/pg_query/include/storage/lock.h +21 -13
- data/ext/pg_query/include/storage/lockdefs.h +3 -3
- data/ext/pg_query/include/storage/lwlock.h +16 -2
- data/ext/pg_query/include/storage/off.h +1 -1
- data/ext/pg_query/include/storage/pg_sema.h +1 -1
- data/ext/pg_query/include/storage/pg_shmem.h +1 -1
- data/ext/pg_query/include/storage/pmsignal.h +1 -1
- data/ext/pg_query/include/storage/predicate.h +2 -2
- data/ext/pg_query/include/storage/proc.h +22 -17
- data/ext/pg_query/include/storage/procarray.h +3 -2
- data/ext/pg_query/include/storage/proclist_types.h +1 -1
- data/ext/pg_query/include/storage/procsignal.h +3 -1
- data/ext/pg_query/include/storage/relfilelocator.h +99 -0
- data/ext/pg_query/include/storage/s_lock.h +66 -309
- data/ext/pg_query/include/storage/sharedfileset.h +1 -1
- data/ext/pg_query/include/storage/shm_mq.h +1 -1
- data/ext/pg_query/include/storage/shm_toc.h +1 -1
- data/ext/pg_query/include/storage/shmem.h +1 -23
- data/ext/pg_query/include/storage/sinval.h +3 -3
- data/ext/pg_query/include/storage/sinvaladt.h +4 -2
- data/ext/pg_query/include/storage/smgr.h +12 -10
- data/ext/pg_query/include/storage/spin.h +1 -1
- data/ext/pg_query/include/storage/standby.h +9 -8
- data/ext/pg_query/include/storage/standbydefs.h +1 -1
- data/ext/pg_query/include/storage/sync.h +3 -3
- data/ext/pg_query/include/tcop/cmdtag.h +7 -2
- data/ext/pg_query/include/tcop/cmdtaglist.h +1 -1
- data/ext/pg_query/include/tcop/deparse_utility.h +1 -1
- data/ext/pg_query/include/tcop/dest.h +1 -3
- data/ext/pg_query/include/tcop/fastpath.h +1 -1
- data/ext/pg_query/include/tcop/pquery.h +1 -1
- data/ext/pg_query/include/tcop/tcopprot.h +1 -4
- data/ext/pg_query/include/tcop/utility.h +1 -1
- data/ext/pg_query/include/tsearch/ts_cache.h +2 -4
- data/ext/pg_query/include/utils/acl.h +26 -81
- data/ext/pg_query/include/utils/aclchk_internal.h +1 -1
- data/ext/pg_query/include/utils/array.h +19 -1
- data/ext/pg_query/include/utils/backend_progress.h +2 -1
- data/ext/pg_query/include/utils/backend_status.h +24 -3
- data/ext/pg_query/include/utils/builtins.h +14 -5
- data/ext/pg_query/include/utils/bytea.h +1 -1
- data/ext/pg_query/include/utils/catcache.h +1 -1
- data/ext/pg_query/include/utils/date.h +37 -9
- data/ext/pg_query/include/utils/datetime.h +41 -21
- data/ext/pg_query/include/utils/datum.h +1 -1
- data/ext/pg_query/include/utils/dsa.h +5 -1
- data/ext/pg_query/include/utils/elog.h +101 -26
- data/ext/pg_query/include/utils/expandeddatum.h +14 -3
- data/ext/pg_query/include/utils/expandedrecord.h +14 -4
- data/ext/pg_query/include/utils/float.h +7 -6
- data/ext/pg_query/include/utils/fmgroids.h +54 -1
- data/ext/pg_query/include/utils/fmgrprotos.h +45 -3
- data/ext/pg_query/include/utils/fmgrtab.h +1 -1
- data/ext/pg_query/include/utils/guc.h +55 -82
- data/ext/pg_query/include/utils/guc_hooks.h +163 -0
- data/ext/pg_query/include/utils/guc_tables.h +49 -3
- data/ext/pg_query/include/utils/hsearch.h +1 -1
- data/ext/pg_query/include/utils/inval.h +3 -3
- data/ext/pg_query/include/utils/logtape.h +77 -0
- data/ext/pg_query/include/utils/lsyscache.h +5 -1
- data/ext/pg_query/include/utils/memdebug.h +1 -1
- data/ext/pg_query/include/utils/memutils.h +5 -49
- data/ext/pg_query/include/utils/memutils_internal.h +136 -0
- data/ext/pg_query/include/utils/memutils_memorychunk.h +237 -0
- data/ext/pg_query/include/utils/numeric.h +20 -5
- data/ext/pg_query/include/utils/palloc.h +8 -1
- data/ext/pg_query/include/utils/partcache.h +3 -2
- data/ext/pg_query/include/utils/pg_locale.h +22 -14
- data/ext/pg_query/include/utils/pgstat_internal.h +37 -7
- data/ext/pg_query/include/utils/pidfile.h +1 -1
- data/ext/pg_query/include/utils/plancache.h +1 -1
- data/ext/pg_query/include/utils/portal.h +1 -1
- data/ext/pg_query/include/utils/probes.h +6 -6
- data/ext/pg_query/include/utils/ps_status.h +23 -1
- data/ext/pg_query/include/utils/queryenvironment.h +1 -1
- data/ext/pg_query/include/utils/regproc.h +3 -3
- data/ext/pg_query/include/utils/rel.h +60 -43
- data/ext/pg_query/include/utils/relcache.h +13 -8
- data/ext/pg_query/include/utils/reltrigger.h +1 -1
- data/ext/pg_query/include/utils/resowner.h +1 -1
- data/ext/pg_query/include/utils/ruleutils.h +6 -1
- data/ext/pg_query/include/utils/sharedtuplestore.h +1 -1
- data/ext/pg_query/include/utils/snapmgr.h +4 -2
- data/ext/pg_query/include/utils/snapshot.h +1 -1
- data/ext/pg_query/include/utils/sortsupport.h +2 -2
- data/ext/pg_query/include/utils/syscache.h +4 -1
- data/ext/pg_query/include/utils/timeout.h +1 -1
- data/ext/pg_query/include/utils/timestamp.h +41 -11
- data/ext/pg_query/include/utils/tuplesort.h +189 -35
- data/ext/pg_query/include/utils/tuplestore.h +1 -1
- data/ext/pg_query/include/utils/typcache.h +1 -1
- data/ext/pg_query/include/utils/varlena.h +13 -1
- data/ext/pg_query/include/utils/wait_event.h +9 -4
- data/ext/pg_query/include/utils/xml.h +15 -5
- data/ext/pg_query/include/varatt.h +358 -0
- data/ext/pg_query/pg_query.c +1 -1
- data/ext/pg_query/pg_query.pb-c.c +19755 -17757
- data/ext/pg_query/pg_query_fingerprint.c +8 -3
- data/ext/pg_query/pg_query_fingerprint.h +1 -1
- data/ext/pg_query/pg_query_internal.h +1 -1
- data/ext/pg_query/pg_query_json_plpgsql.c +1 -0
- data/ext/pg_query/pg_query_normalize.c +1 -1
- data/ext/pg_query/pg_query_outfuncs_protobuf.c +2 -2
- data/ext/pg_query/pg_query_parse.c +46 -4
- data/ext/pg_query/pg_query_parse_plpgsql.c +1 -1
- data/ext/pg_query/pg_query_scan.c +1 -1
- data/ext/pg_query/pg_query_split.c +2 -2
- data/ext/pg_query/postgres_deparse.c +511 -109
- data/ext/pg_query/src_backend_catalog_namespace.c +7 -2
- data/ext/pg_query/src_backend_catalog_pg_proc.c +1 -1
- data/ext/pg_query/src_backend_commands_define.c +1 -1
- data/ext/pg_query/src_backend_nodes_bitmapset.c +11 -70
- data/ext/pg_query/src_backend_nodes_copyfuncs.c +96 -6202
- data/ext/pg_query/src_backend_nodes_equalfuncs.c +95 -4068
- data/ext/pg_query/src_backend_nodes_extensible.c +6 -29
- data/ext/pg_query/src_backend_nodes_list.c +14 -2
- data/ext/pg_query/src_backend_nodes_makefuncs.c +95 -1
- data/ext/pg_query/src_backend_nodes_nodeFuncs.c +283 -132
- data/ext/pg_query/src_backend_nodes_value.c +1 -1
- data/ext/pg_query/src_backend_parser_gram.c +33208 -31806
- data/ext/pg_query/src_backend_parser_parser.c +28 -2
- data/ext/pg_query/src_backend_parser_scan.c +4318 -3329
- data/ext/pg_query/src_backend_parser_scansup.c +1 -1
- data/ext/pg_query/src_backend_postmaster_postmaster.c +129 -110
- data/ext/pg_query/src_backend_storage_ipc_ipc.c +1 -1
- data/ext/pg_query/src_backend_tcop_postgres.c +66 -87
- data/ext/pg_query/src_backend_utils_activity_pgstat_database.c +1 -1
- data/ext/pg_query/src_backend_utils_adt_datum.c +5 -7
- data/ext/pg_query/src_backend_utils_adt_expandeddatum.c +1 -1
- data/ext/pg_query/src_backend_utils_adt_format_type.c +1 -1
- data/ext/pg_query/src_backend_utils_adt_numutils.c +489 -0
- data/ext/pg_query/src_backend_utils_adt_ruleutils.c +79 -5
- data/ext/pg_query/src_backend_utils_error_assert.c +4 -7
- data/ext/pg_query/src_backend_utils_error_elog.c +354 -97
- data/ext/pg_query/src_backend_utils_fmgr_fmgr.c +33 -1
- data/ext/pg_query/src_backend_utils_init_globals.c +5 -2
- data/ext/pg_query/src_backend_utils_mb_mbutils.c +13 -4
- data/ext/pg_query/src_backend_utils_misc_guc_tables.c +494 -0
- data/ext/pg_query/src_backend_utils_mmgr_alignedalloc.c +163 -0
- data/ext/pg_query/src_backend_utils_mmgr_aset.c +449 -312
- data/ext/pg_query/src_backend_utils_mmgr_generation.c +1039 -0
- data/ext/pg_query/src_backend_utils_mmgr_mcxt.c +398 -49
- data/ext/pg_query/src_backend_utils_mmgr_slab.c +1021 -0
- data/ext/pg_query/src_common_encnames.c +4 -1
- data/ext/pg_query/src_common_hashfn.c +1 -1
- data/ext/pg_query/src_common_keywords.c +1 -1
- data/ext/pg_query/src_common_kwlist_d.h +534 -510
- data/ext/pg_query/src_common_kwlookup.c +1 -1
- data/ext/pg_query/src_common_psprintf.c +1 -1
- data/ext/pg_query/src_common_stringinfo.c +4 -4
- data/ext/pg_query/src_common_wchar.c +9 -8
- data/ext/pg_query/src_pl_plpgsql_src_pl_comp.c +1 -1
- data/ext/pg_query/src_pl_plpgsql_src_pl_funcs.c +3 -1
- data/ext/pg_query/src_pl_plpgsql_src_pl_gram.c +661 -694
- data/ext/pg_query/src_pl_plpgsql_src_pl_handler.c +1 -1
- data/ext/pg_query/src_pl_plpgsql_src_pl_reserved_kwlist_d.h +1 -1
- data/ext/pg_query/src_pl_plpgsql_src_pl_scanner.c +1 -1
- data/ext/pg_query/src_pl_plpgsql_src_pl_unreserved_kwlist_d.h +48 -46
- data/ext/pg_query/src_port_pg_bitutils.c +1 -1
- data/ext/pg_query/src_port_pgstrcasecmp.c +29 -1
- data/ext/pg_query/src_port_snprintf.c +3 -7
- data/ext/pg_query/src_port_strerror.c +1 -1
- data/ext/pg_query/src_port_strnlen.c +1 -1
- data/lib/pg_query/pg_query_pb.rb +166 -3191
- data/lib/pg_query/treewalker.rb +7 -2
- data/lib/pg_query/version.rb +1 -1
- metadata +43 -24
- data/ext/pg_query/include/catalog/pg_parameter_acl.h +0 -60
- data/ext/pg_query/include/catalog/pg_parameter_acl_d.h +0 -34
- data/ext/pg_query/include/commands/variable.h +0 -38
- data/ext/pg_query/include/getaddrinfo.h +0 -162
- data/ext/pg_query/include/parser/gram.h +0 -1101
- data/ext/pg_query/include/storage/relfilenode.h +0 -99
- data/ext/pg_query/include/utils/dynahash.h +0 -20
- data/ext/pg_query/include/utils/pg_lsn.h +0 -29
- data/ext/pg_query/include/utils/rls.h +0 -50
- data/ext/pg_query/include/utils/tzparser.h +0 -39
- data/ext/pg_query/src_backend_storage_lmgr_s_lock.c +0 -371
- data/ext/pg_query/src_backend_utils_hash_dynahash.c +0 -1116
- data/ext/pg_query/src_backend_utils_misc_guc.c +0 -1993
- data/ext/pg_query/src_common_pg_prng.c +0 -152
- data/ext/pg_query/src_common_string.c +0 -92
- data/ext/pg_query/src_port_pgsleep.c +0 -69
@@ -1,1116 +0,0 @@
|
|
1
|
-
/*--------------------------------------------------------------------
|
2
|
-
* Symbols referenced in this file:
|
3
|
-
* - hash_search
|
4
|
-
* - hash_search_with_hash_value
|
5
|
-
* - has_seq_scans
|
6
|
-
* - num_seq_scans
|
7
|
-
* - seq_scan_tables
|
8
|
-
* - expand_table
|
9
|
-
* - dir_realloc
|
10
|
-
* - CurrentDynaHashCxt
|
11
|
-
* - seg_alloc
|
12
|
-
* - calc_bucket
|
13
|
-
* - hash_corrupted
|
14
|
-
* - DynaHashAlloc
|
15
|
-
* - get_hash_entry
|
16
|
-
* - element_alloc
|
17
|
-
*--------------------------------------------------------------------
|
18
|
-
*/
|
19
|
-
|
20
|
-
/*-------------------------------------------------------------------------
|
21
|
-
*
|
22
|
-
* dynahash.c
|
23
|
-
* dynamic chained hash tables
|
24
|
-
*
|
25
|
-
* dynahash.c supports both local-to-a-backend hash tables and hash tables in
|
26
|
-
* shared memory. For shared hash tables, it is the caller's responsibility
|
27
|
-
* to provide appropriate access interlocking. The simplest convention is
|
28
|
-
* that a single LWLock protects the whole hash table. Searches (HASH_FIND or
|
29
|
-
* hash_seq_search) need only shared lock, but any update requires exclusive
|
30
|
-
* lock. For heavily-used shared tables, the single-lock approach creates a
|
31
|
-
* concurrency bottleneck, so we also support "partitioned" locking wherein
|
32
|
-
* there are multiple LWLocks guarding distinct subsets of the table. To use
|
33
|
-
* a hash table in partitioned mode, the HASH_PARTITION flag must be given
|
34
|
-
* to hash_create. This prevents any attempt to split buckets on-the-fly.
|
35
|
-
* Therefore, each hash bucket chain operates independently, and no fields
|
36
|
-
* of the hash header change after init except nentries and freeList.
|
37
|
-
* (A partitioned table uses multiple copies of those fields, guarded by
|
38
|
-
* spinlocks, for additional concurrency.)
|
39
|
-
* This lets any subset of the hash buckets be treated as a separately
|
40
|
-
* lockable partition. We expect callers to use the low-order bits of a
|
41
|
-
* lookup key's hash value as a partition number --- this will work because
|
42
|
-
* of the way calc_bucket() maps hash values to bucket numbers.
|
43
|
-
*
|
44
|
-
* For hash tables in shared memory, the memory allocator function should
|
45
|
-
* match malloc's semantics of returning NULL on failure. For hash tables
|
46
|
-
* in local memory, we typically use palloc() which will throw error on
|
47
|
-
* failure. The code in this file has to cope with both cases.
|
48
|
-
*
|
49
|
-
* dynahash.c provides support for these types of lookup keys:
|
50
|
-
*
|
51
|
-
* 1. Null-terminated C strings (truncated if necessary to fit in keysize),
|
52
|
-
* compared as though by strcmp(). This is selected by specifying the
|
53
|
-
* HASH_STRINGS flag to hash_create.
|
54
|
-
*
|
55
|
-
* 2. Arbitrary binary data of size keysize, compared as though by memcmp().
|
56
|
-
* (Caller must ensure there are no undefined padding bits in the keys!)
|
57
|
-
* This is selected by specifying the HASH_BLOBS flag to hash_create.
|
58
|
-
*
|
59
|
-
* 3. More complex key behavior can be selected by specifying user-supplied
|
60
|
-
* hashing, comparison, and/or key-copying functions. At least a hashing
|
61
|
-
* function must be supplied; comparison defaults to memcmp() and key copying
|
62
|
-
* to memcpy() when a user-defined hashing function is selected.
|
63
|
-
*
|
64
|
-
* Compared to simplehash, dynahash has the following benefits:
|
65
|
-
*
|
66
|
-
* - It supports partitioning, which is useful for shared memory access using
|
67
|
-
* locks.
|
68
|
-
* - Shared memory hashes are allocated in a fixed size area at startup and
|
69
|
-
* are discoverable by name from other processes.
|
70
|
-
* - Because entries don't need to be moved in the case of hash conflicts,
|
71
|
-
* dynahash has better performance for large entries.
|
72
|
-
* - Guarantees stable pointers to entries.
|
73
|
-
*
|
74
|
-
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
75
|
-
* Portions Copyright (c) 1994, Regents of the University of California
|
76
|
-
*
|
77
|
-
*
|
78
|
-
* IDENTIFICATION
|
79
|
-
* src/backend/utils/hash/dynahash.c
|
80
|
-
*
|
81
|
-
*-------------------------------------------------------------------------
|
82
|
-
*/
|
83
|
-
|
84
|
-
/*
|
85
|
-
* Original comments:
|
86
|
-
*
|
87
|
-
* Dynamic hashing, after CACM April 1988 pp 446-457, by Per-Ake Larson.
|
88
|
-
* Coded into C, with minor code improvements, and with hsearch(3) interface,
|
89
|
-
* by ejp@ausmelb.oz, Jul 26, 1988: 13:16;
|
90
|
-
* also, hcreate/hdestroy routines added to simulate hsearch(3).
|
91
|
-
*
|
92
|
-
* These routines simulate hsearch(3) and family, with the important
|
93
|
-
* difference that the hash table is dynamic - can grow indefinitely
|
94
|
-
* beyond its original size (as supplied to hcreate()).
|
95
|
-
*
|
96
|
-
* Performance appears to be comparable to that of hsearch(3).
|
97
|
-
* The 'source-code' options referred to in hsearch(3)'s 'man' page
|
98
|
-
* are not implemented; otherwise functionality is identical.
|
99
|
-
*
|
100
|
-
* Compilation controls:
|
101
|
-
* HASH_DEBUG controls some informative traces, mainly for debugging.
|
102
|
-
* HASH_STATISTICS causes HashAccesses and HashCollisions to be maintained;
|
103
|
-
* when combined with HASH_DEBUG, these are displayed by hdestroy().
|
104
|
-
*
|
105
|
-
* Problems & fixes to ejp@ausmelb.oz. WARNING: relies on pre-processor
|
106
|
-
* concatenation property, in probably unnecessary code 'optimization'.
|
107
|
-
*
|
108
|
-
* Modified margo@postgres.berkeley.edu February 1990
|
109
|
-
* added multiple table interface
|
110
|
-
* Modified by sullivan@postgres.berkeley.edu April 1990
|
111
|
-
* changed ctl structure for shared memory
|
112
|
-
*/
|
113
|
-
|
114
|
-
#include "postgres.h"
|
115
|
-
|
116
|
-
#include <limits.h>
|
117
|
-
|
118
|
-
#include "access/xact.h"
|
119
|
-
#include "common/hashfn.h"
|
120
|
-
#include "port/pg_bitutils.h"
|
121
|
-
#include "storage/shmem.h"
|
122
|
-
#include "storage/spin.h"
|
123
|
-
#include "utils/dynahash.h"
|
124
|
-
#include "utils/memutils.h"
|
125
|
-
|
126
|
-
|
127
|
-
/*
|
128
|
-
* Constants
|
129
|
-
*
|
130
|
-
* A hash table has a top-level "directory", each of whose entries points
|
131
|
-
* to a "segment" of ssize bucket headers. The maximum number of hash
|
132
|
-
* buckets is thus dsize * ssize (but dsize may be expansible). Of course,
|
133
|
-
* the number of records in the table can be larger, but we don't want a
|
134
|
-
* whole lot of records per bucket or performance goes down.
|
135
|
-
*
|
136
|
-
* In a hash table allocated in shared memory, the directory cannot be
|
137
|
-
* expanded because it must stay at a fixed address. The directory size
|
138
|
-
* should be selected using hash_select_dirsize (and you'd better have
|
139
|
-
* a good idea of the maximum number of entries!). For non-shared hash
|
140
|
-
* tables, the initial directory size can be left at the default.
|
141
|
-
*/
|
142
|
-
#define DEF_SEGSIZE 256
|
143
|
-
#define DEF_SEGSIZE_SHIFT 8 /* must be log2(DEF_SEGSIZE) */
|
144
|
-
#define DEF_DIRSIZE 256
|
145
|
-
|
146
|
-
/* Number of freelists to be used for a partitioned hash table. */
|
147
|
-
#define NUM_FREELISTS 32
|
148
|
-
|
149
|
-
/* A hash bucket is a linked list of HASHELEMENTs */
|
150
|
-
typedef HASHELEMENT *HASHBUCKET;
|
151
|
-
|
152
|
-
/* A hash segment is an array of bucket headers */
|
153
|
-
typedef HASHBUCKET *HASHSEGMENT;
|
154
|
-
|
155
|
-
/*
|
156
|
-
* Per-freelist data.
|
157
|
-
*
|
158
|
-
* In a partitioned hash table, each freelist is associated with a specific
|
159
|
-
* set of hashcodes, as determined by the FREELIST_IDX() macro below.
|
160
|
-
* nentries tracks the number of live hashtable entries having those hashcodes
|
161
|
-
* (NOT the number of entries in the freelist, as you might expect).
|
162
|
-
*
|
163
|
-
* The coverage of a freelist might be more or less than one partition, so it
|
164
|
-
* needs its own lock rather than relying on caller locking. Relying on that
|
165
|
-
* wouldn't work even if the coverage was the same, because of the occasional
|
166
|
-
* need to "borrow" entries from another freelist; see get_hash_entry().
|
167
|
-
*
|
168
|
-
* Using an array of FreeListData instead of separate arrays of mutexes,
|
169
|
-
* nentries and freeLists helps to reduce sharing of cache lines between
|
170
|
-
* different mutexes.
|
171
|
-
*/
|
172
|
-
typedef struct
|
173
|
-
{
|
174
|
-
slock_t mutex; /* spinlock for this freelist */
|
175
|
-
long nentries; /* number of entries in associated buckets */
|
176
|
-
HASHELEMENT *freeList; /* chain of free elements */
|
177
|
-
} FreeListData;
|
178
|
-
|
179
|
-
/*
|
180
|
-
* Header structure for a hash table --- contains all changeable info
|
181
|
-
*
|
182
|
-
* In a shared-memory hash table, the HASHHDR is in shared memory, while
|
183
|
-
* each backend has a local HTAB struct. For a non-shared table, there isn't
|
184
|
-
* any functional difference between HASHHDR and HTAB, but we separate them
|
185
|
-
* anyway to share code between shared and non-shared tables.
|
186
|
-
*/
|
187
|
-
struct HASHHDR
|
188
|
-
{
|
189
|
-
/*
|
190
|
-
* The freelist can become a point of contention in high-concurrency hash
|
191
|
-
* tables, so we use an array of freelists, each with its own mutex and
|
192
|
-
* nentries count, instead of just a single one. Although the freelists
|
193
|
-
* normally operate independently, we will scavenge entries from freelists
|
194
|
-
* other than a hashcode's default freelist when necessary.
|
195
|
-
*
|
196
|
-
* If the hash table is not partitioned, only freeList[0] is used and its
|
197
|
-
* spinlock is not used at all; callers' locking is assumed sufficient.
|
198
|
-
*/
|
199
|
-
FreeListData freeList[NUM_FREELISTS];
|
200
|
-
|
201
|
-
/* These fields can change, but not in a partitioned table */
|
202
|
-
/* Also, dsize can't change in a shared table, even if unpartitioned */
|
203
|
-
long dsize; /* directory size */
|
204
|
-
long nsegs; /* number of allocated segments (<= dsize) */
|
205
|
-
uint32 max_bucket; /* ID of maximum bucket in use */
|
206
|
-
uint32 high_mask; /* mask to modulo into entire table */
|
207
|
-
uint32 low_mask; /* mask to modulo into lower half of table */
|
208
|
-
|
209
|
-
/* These fields are fixed at hashtable creation */
|
210
|
-
Size keysize; /* hash key length in bytes */
|
211
|
-
Size entrysize; /* total user element size in bytes */
|
212
|
-
long num_partitions; /* # partitions (must be power of 2), or 0 */
|
213
|
-
long max_dsize; /* 'dsize' limit if directory is fixed size */
|
214
|
-
long ssize; /* segment size --- must be power of 2 */
|
215
|
-
int sshift; /* segment shift = log2(ssize) */
|
216
|
-
int nelem_alloc; /* number of entries to allocate at once */
|
217
|
-
|
218
|
-
#ifdef HASH_STATISTICS
|
219
|
-
|
220
|
-
/*
|
221
|
-
* Count statistics here. NB: stats code doesn't bother with mutex, so
|
222
|
-
* counts could be corrupted a bit in a partitioned table.
|
223
|
-
*/
|
224
|
-
long accesses;
|
225
|
-
long collisions;
|
226
|
-
#endif
|
227
|
-
};
|
228
|
-
|
229
|
-
#define IS_PARTITIONED(hctl) ((hctl)->num_partitions != 0)
|
230
|
-
|
231
|
-
#define FREELIST_IDX(hctl, hashcode) \
|
232
|
-
(IS_PARTITIONED(hctl) ? (hashcode) % NUM_FREELISTS : 0)
|
233
|
-
|
234
|
-
/*
|
235
|
-
* Top control structure for a hashtable --- in a shared table, each backend
|
236
|
-
* has its own copy (OK since no fields change at runtime)
|
237
|
-
*/
|
238
|
-
struct HTAB
|
239
|
-
{
|
240
|
-
HASHHDR *hctl; /* => shared control information */
|
241
|
-
HASHSEGMENT *dir; /* directory of segment starts */
|
242
|
-
HashValueFunc hash; /* hash function */
|
243
|
-
HashCompareFunc match; /* key comparison function */
|
244
|
-
HashCopyFunc keycopy; /* key copying function */
|
245
|
-
HashAllocFunc alloc; /* memory allocator */
|
246
|
-
MemoryContext hcxt; /* memory context if default allocator used */
|
247
|
-
char *tabname; /* table name (for error messages) */
|
248
|
-
bool isshared; /* true if table is in shared memory */
|
249
|
-
bool isfixed; /* if true, don't enlarge */
|
250
|
-
|
251
|
-
/* freezing a shared table isn't allowed, so we can keep state here */
|
252
|
-
bool frozen; /* true = no more inserts allowed */
|
253
|
-
|
254
|
-
/* We keep local copies of these fixed values to reduce contention */
|
255
|
-
Size keysize; /* hash key length in bytes */
|
256
|
-
long ssize; /* segment size --- must be power of 2 */
|
257
|
-
int sshift; /* segment shift = log2(ssize) */
|
258
|
-
};
|
259
|
-
|
260
|
-
/*
|
261
|
-
* Key (also entry) part of a HASHELEMENT
|
262
|
-
*/
|
263
|
-
#define ELEMENTKEY(helem) (((char *)(helem)) + MAXALIGN(sizeof(HASHELEMENT)))
|
264
|
-
|
265
|
-
/*
|
266
|
-
* Obtain element pointer given pointer to key
|
267
|
-
*/
|
268
|
-
#define ELEMENT_FROM_KEY(key) \
|
269
|
-
((HASHELEMENT *) (((char *) (key)) - MAXALIGN(sizeof(HASHELEMENT))))
|
270
|
-
|
271
|
-
/*
|
272
|
-
* Fast MOD arithmetic, assuming that y is a power of 2 !
|
273
|
-
*/
|
274
|
-
#define MOD(x,y) ((x) & ((y)-1))
|
275
|
-
|
276
|
-
#ifdef HASH_STATISTICS
|
277
|
-
static long hash_accesses,
|
278
|
-
hash_collisions,
|
279
|
-
hash_expansions;
|
280
|
-
#endif
|
281
|
-
|
282
|
-
/*
|
283
|
-
* Private function prototypes
|
284
|
-
*/
|
285
|
-
static void *DynaHashAlloc(Size size);
|
286
|
-
static HASHSEGMENT seg_alloc(HTAB *hashp);
|
287
|
-
static bool element_alloc(HTAB *hashp, int nelem, int freelist_idx);
|
288
|
-
static bool dir_realloc(HTAB *hashp);
|
289
|
-
static bool expand_table(HTAB *hashp);
|
290
|
-
static HASHBUCKET get_hash_entry(HTAB *hashp, int freelist_idx);
|
291
|
-
static void hdefault(HTAB *hashp);
|
292
|
-
static int choose_nelem_alloc(Size entrysize);
|
293
|
-
static bool init_htab(HTAB *hashp, long nelem);
|
294
|
-
static void hash_corrupted(HTAB *hashp);
|
295
|
-
static long next_pow2_long(long num);
|
296
|
-
static int next_pow2_int(long num);
|
297
|
-
static void register_seq_scan(HTAB *hashp);
|
298
|
-
static void deregister_seq_scan(HTAB *hashp);
|
299
|
-
static bool has_seq_scans(HTAB *hashp);
|
300
|
-
|
301
|
-
|
302
|
-
/*
|
303
|
-
* memory allocation support
|
304
|
-
*/
|
305
|
-
static __thread MemoryContext CurrentDynaHashCxt = NULL;
|
306
|
-
|
307
|
-
|
308
|
-
static void *
|
309
|
-
DynaHashAlloc(Size size)
|
310
|
-
{
|
311
|
-
Assert(MemoryContextIsValid(CurrentDynaHashCxt));
|
312
|
-
return MemoryContextAlloc(CurrentDynaHashCxt, size);
|
313
|
-
}
|
314
|
-
|
315
|
-
|
316
|
-
/*
|
317
|
-
* HashCompareFunc for string keys
|
318
|
-
*
|
319
|
-
* Because we copy keys with strlcpy(), they will be truncated at keysize-1
|
320
|
-
* bytes, so we can only compare that many ... hence strncmp is almost but
|
321
|
-
* not quite the right thing.
|
322
|
-
*/
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
/************************** CREATE ROUTINES **********************/
|
327
|
-
|
328
|
-
/*
|
329
|
-
* hash_create -- create a new dynamic hash table
|
330
|
-
*
|
331
|
-
* tabname: a name for the table (for debugging purposes)
|
332
|
-
* nelem: maximum number of elements expected
|
333
|
-
* *info: additional table parameters, as indicated by flags
|
334
|
-
* flags: bitmask indicating which parameters to take from *info
|
335
|
-
*
|
336
|
-
* The flags value *must* include HASH_ELEM. (Formerly, this was nominally
|
337
|
-
* optional, but the default keysize and entrysize values were useless.)
|
338
|
-
* The flags value must also include exactly one of HASH_STRINGS, HASH_BLOBS,
|
339
|
-
* or HASH_FUNCTION, to define the key hashing semantics (C strings,
|
340
|
-
* binary blobs, or custom, respectively). Callers specifying a custom
|
341
|
-
* hash function will likely also want to use HASH_COMPARE, and perhaps
|
342
|
-
* also HASH_KEYCOPY, to control key comparison and copying.
|
343
|
-
* Another often-used flag is HASH_CONTEXT, to allocate the hash table
|
344
|
-
* under info->hcxt rather than under TopMemoryContext; the default
|
345
|
-
* behavior is only suitable for session-lifespan hash tables.
|
346
|
-
* Other flags bits are special-purpose and seldom used, except for those
|
347
|
-
* associated with shared-memory hash tables, for which see ShmemInitHash().
|
348
|
-
*
|
349
|
-
* Fields in *info are read only when the associated flags bit is set.
|
350
|
-
* It is not necessary to initialize other fields of *info.
|
351
|
-
* Neither tabname nor *info need persist after the hash_create() call.
|
352
|
-
*
|
353
|
-
* Note: It is deprecated for callers of hash_create() to explicitly specify
|
354
|
-
* string_hash, tag_hash, uint32_hash, or oid_hash. Just set HASH_STRINGS or
|
355
|
-
* HASH_BLOBS. Use HASH_FUNCTION only when you want something other than
|
356
|
-
* one of these.
|
357
|
-
*
|
358
|
-
* Note: for a shared-memory hashtable, nelem needs to be a pretty good
|
359
|
-
* estimate, since we can't expand the table on the fly. But an unshared
|
360
|
-
* hashtable can be expanded on-the-fly, so it's better for nelem to be
|
361
|
-
* on the small side and let the table grow if it's exceeded. An overly
|
362
|
-
* large nelem will penalize hash_seq_search speed without buying much.
|
363
|
-
*/
|
364
|
-
|
365
|
-
|
366
|
-
/*
|
367
|
-
* Set default HASHHDR parameters.
|
368
|
-
*/
|
369
|
-
#ifdef HASH_STATISTICS
|
370
|
-
#endif
|
371
|
-
|
372
|
-
/*
|
373
|
-
* Given the user-specified entry size, choose nelem_alloc, ie, how many
|
374
|
-
* elements to add to the hash table when we need more.
|
375
|
-
*/
|
376
|
-
|
377
|
-
|
378
|
-
/*
|
379
|
-
* Compute derived fields of hctl and build the initial directory/segment
|
380
|
-
* arrays
|
381
|
-
*/
|
382
|
-
#ifdef HASH_DEBUG
|
383
|
-
#endif
|
384
|
-
|
385
|
-
/*
|
386
|
-
* Estimate the space needed for a hashtable containing the given number
|
387
|
-
* of entries of given size.
|
388
|
-
* NOTE: this is used to estimate the footprint of hashtables in shared
|
389
|
-
* memory; therefore it does not count HTAB which is in local memory.
|
390
|
-
* NB: assumes that all hash structure parameters have default values!
|
391
|
-
*/
|
392
|
-
|
393
|
-
|
394
|
-
/*
|
395
|
-
* Select an appropriate directory size for a hashtable with the given
|
396
|
-
* maximum number of entries.
|
397
|
-
* This is only needed for hashtables in shared memory, whose directories
|
398
|
-
* cannot be expanded dynamically.
|
399
|
-
* NB: assumes that all hash structure parameters have default values!
|
400
|
-
*
|
401
|
-
* XXX this had better agree with the behavior of init_htab()...
|
402
|
-
*/
|
403
|
-
|
404
|
-
|
405
|
-
/*
|
406
|
-
* Compute the required initial memory allocation for a shared-memory
|
407
|
-
* hashtable with the given parameters. We need space for the HASHHDR
|
408
|
-
* and for the (non expansible) directory.
|
409
|
-
*/
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
/********************** DESTROY ROUTINES ************************/
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
#ifdef HASH_STATISTICS
|
418
|
-
#endif
|
419
|
-
|
420
|
-
/*******************************SEARCH ROUTINES *****************************/
|
421
|
-
|
422
|
-
|
423
|
-
/*
|
424
|
-
* get_hash_value -- exported routine to calculate a key's hash value
|
425
|
-
*
|
426
|
-
* We export this because for partitioned tables, callers need to compute
|
427
|
-
* the partition number (from the low-order bits of the hash value) before
|
428
|
-
* searching.
|
429
|
-
*/
|
430
|
-
|
431
|
-
|
432
|
-
/* Convert a hash value to a bucket number */
|
433
|
-
static inline uint32
|
434
|
-
calc_bucket(HASHHDR *hctl, uint32 hash_val)
|
435
|
-
{
|
436
|
-
uint32 bucket;
|
437
|
-
|
438
|
-
bucket = hash_val & hctl->high_mask;
|
439
|
-
if (bucket > hctl->max_bucket)
|
440
|
-
bucket = bucket & hctl->low_mask;
|
441
|
-
|
442
|
-
return bucket;
|
443
|
-
}
|
444
|
-
|
445
|
-
/*
|
446
|
-
* hash_search -- look up key in table and perform action
|
447
|
-
* hash_search_with_hash_value -- same, with key's hash value already computed
|
448
|
-
*
|
449
|
-
* action is one of:
|
450
|
-
* HASH_FIND: look up key in table
|
451
|
-
* HASH_ENTER: look up key in table, creating entry if not present
|
452
|
-
* HASH_ENTER_NULL: same, but return NULL if out of memory
|
453
|
-
* HASH_REMOVE: look up key in table, remove entry if present
|
454
|
-
*
|
455
|
-
* Return value is a pointer to the element found/entered/removed if any,
|
456
|
-
* or NULL if no match was found. (NB: in the case of the REMOVE action,
|
457
|
-
* the result is a dangling pointer that shouldn't be dereferenced!)
|
458
|
-
*
|
459
|
-
* HASH_ENTER will normally ereport a generic "out of memory" error if
|
460
|
-
* it is unable to create a new entry. The HASH_ENTER_NULL operation is
|
461
|
-
* the same except it will return NULL if out of memory. Note that
|
462
|
-
* HASH_ENTER_NULL cannot be used with the default palloc-based allocator,
|
463
|
-
* since palloc internally ereports on out-of-memory.
|
464
|
-
*
|
465
|
-
* If foundPtr isn't NULL, then *foundPtr is set true if we found an
|
466
|
-
* existing entry in the table, false otherwise. This is needed in the
|
467
|
-
* HASH_ENTER case, but is redundant with the return value otherwise.
|
468
|
-
*
|
469
|
-
* For hash_search_with_hash_value, the hashvalue parameter must have been
|
470
|
-
* calculated with get_hash_value().
|
471
|
-
*/
|
472
|
-
void *
|
473
|
-
hash_search(HTAB *hashp,
|
474
|
-
const void *keyPtr,
|
475
|
-
HASHACTION action,
|
476
|
-
bool *foundPtr)
|
477
|
-
{
|
478
|
-
return hash_search_with_hash_value(hashp,
|
479
|
-
keyPtr,
|
480
|
-
hashp->hash(keyPtr, hashp->keysize),
|
481
|
-
action,
|
482
|
-
foundPtr);
|
483
|
-
}
|
484
|
-
|
485
|
-
void *
|
486
|
-
hash_search_with_hash_value(HTAB *hashp,
|
487
|
-
const void *keyPtr,
|
488
|
-
uint32 hashvalue,
|
489
|
-
HASHACTION action,
|
490
|
-
bool *foundPtr)
|
491
|
-
{
|
492
|
-
HASHHDR *hctl = hashp->hctl;
|
493
|
-
int freelist_idx = FREELIST_IDX(hctl, hashvalue);
|
494
|
-
Size keysize;
|
495
|
-
uint32 bucket;
|
496
|
-
long segment_num;
|
497
|
-
long segment_ndx;
|
498
|
-
HASHSEGMENT segp;
|
499
|
-
HASHBUCKET currBucket;
|
500
|
-
HASHBUCKET *prevBucketPtr;
|
501
|
-
HashCompareFunc match;
|
502
|
-
|
503
|
-
#ifdef HASH_STATISTICS
|
504
|
-
hash_accesses++;
|
505
|
-
hctl->accesses++;
|
506
|
-
#endif
|
507
|
-
|
508
|
-
/*
|
509
|
-
* If inserting, check if it is time to split a bucket.
|
510
|
-
*
|
511
|
-
* NOTE: failure to expand table is not a fatal error, it just means we
|
512
|
-
* have to run at higher fill factor than we wanted. However, if we're
|
513
|
-
* using the palloc allocator then it will throw error anyway on
|
514
|
-
* out-of-memory, so we must do this before modifying the table.
|
515
|
-
*/
|
516
|
-
if (action == HASH_ENTER || action == HASH_ENTER_NULL)
|
517
|
-
{
|
518
|
-
/*
|
519
|
-
* Can't split if running in partitioned mode, nor if frozen, nor if
|
520
|
-
* table is the subject of any active hash_seq_search scans.
|
521
|
-
*/
|
522
|
-
if (hctl->freeList[0].nentries > (long) hctl->max_bucket &&
|
523
|
-
!IS_PARTITIONED(hctl) && !hashp->frozen &&
|
524
|
-
!has_seq_scans(hashp))
|
525
|
-
(void) expand_table(hashp);
|
526
|
-
}
|
527
|
-
|
528
|
-
/*
|
529
|
-
* Do the initial lookup
|
530
|
-
*/
|
531
|
-
bucket = calc_bucket(hctl, hashvalue);
|
532
|
-
|
533
|
-
segment_num = bucket >> hashp->sshift;
|
534
|
-
segment_ndx = MOD(bucket, hashp->ssize);
|
535
|
-
|
536
|
-
segp = hashp->dir[segment_num];
|
537
|
-
|
538
|
-
if (segp == NULL)
|
539
|
-
hash_corrupted(hashp);
|
540
|
-
|
541
|
-
prevBucketPtr = &segp[segment_ndx];
|
542
|
-
currBucket = *prevBucketPtr;
|
543
|
-
|
544
|
-
/*
|
545
|
-
* Follow collision chain looking for matching key
|
546
|
-
*/
|
547
|
-
match = hashp->match; /* save one fetch in inner loop */
|
548
|
-
keysize = hashp->keysize; /* ditto */
|
549
|
-
|
550
|
-
while (currBucket != NULL)
|
551
|
-
{
|
552
|
-
if (currBucket->hashvalue == hashvalue &&
|
553
|
-
match(ELEMENTKEY(currBucket), keyPtr, keysize) == 0)
|
554
|
-
break;
|
555
|
-
prevBucketPtr = &(currBucket->link);
|
556
|
-
currBucket = *prevBucketPtr;
|
557
|
-
#ifdef HASH_STATISTICS
|
558
|
-
hash_collisions++;
|
559
|
-
hctl->collisions++;
|
560
|
-
#endif
|
561
|
-
}
|
562
|
-
|
563
|
-
if (foundPtr)
|
564
|
-
*foundPtr = (bool) (currBucket != NULL);
|
565
|
-
|
566
|
-
/*
|
567
|
-
* OK, now what?
|
568
|
-
*/
|
569
|
-
switch (action)
|
570
|
-
{
|
571
|
-
case HASH_FIND:
|
572
|
-
if (currBucket != NULL)
|
573
|
-
return (void *) ELEMENTKEY(currBucket);
|
574
|
-
return NULL;
|
575
|
-
|
576
|
-
case HASH_REMOVE:
|
577
|
-
if (currBucket != NULL)
|
578
|
-
{
|
579
|
-
/* if partitioned, must lock to touch nentries and freeList */
|
580
|
-
if (IS_PARTITIONED(hctl))
|
581
|
-
SpinLockAcquire(&(hctl->freeList[freelist_idx].mutex));
|
582
|
-
|
583
|
-
/* delete the record from the appropriate nentries counter. */
|
584
|
-
Assert(hctl->freeList[freelist_idx].nentries > 0);
|
585
|
-
hctl->freeList[freelist_idx].nentries--;
|
586
|
-
|
587
|
-
/* remove record from hash bucket's chain. */
|
588
|
-
*prevBucketPtr = currBucket->link;
|
589
|
-
|
590
|
-
/* add the record to the appropriate freelist. */
|
591
|
-
currBucket->link = hctl->freeList[freelist_idx].freeList;
|
592
|
-
hctl->freeList[freelist_idx].freeList = currBucket;
|
593
|
-
|
594
|
-
if (IS_PARTITIONED(hctl))
|
595
|
-
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
|
596
|
-
|
597
|
-
/*
|
598
|
-
* better hope the caller is synchronizing access to this
|
599
|
-
* element, because someone else is going to reuse it the next
|
600
|
-
* time something is added to the table
|
601
|
-
*/
|
602
|
-
return (void *) ELEMENTKEY(currBucket);
|
603
|
-
}
|
604
|
-
return NULL;
|
605
|
-
|
606
|
-
case HASH_ENTER_NULL:
|
607
|
-
/* ENTER_NULL does not work with palloc-based allocator */
|
608
|
-
Assert(hashp->alloc != DynaHashAlloc);
|
609
|
-
/* FALL THRU */
|
610
|
-
|
611
|
-
case HASH_ENTER:
|
612
|
-
/* Return existing element if found, else create one */
|
613
|
-
if (currBucket != NULL)
|
614
|
-
return (void *) ELEMENTKEY(currBucket);
|
615
|
-
|
616
|
-
/* disallow inserts if frozen */
|
617
|
-
if (hashp->frozen)
|
618
|
-
elog(ERROR, "cannot insert into frozen hashtable \"%s\"",
|
619
|
-
hashp->tabname);
|
620
|
-
|
621
|
-
currBucket = get_hash_entry(hashp, freelist_idx);
|
622
|
-
if (currBucket == NULL)
|
623
|
-
{
|
624
|
-
/* out of memory */
|
625
|
-
if (action == HASH_ENTER_NULL)
|
626
|
-
return NULL;
|
627
|
-
/* report a generic message */
|
628
|
-
if (hashp->isshared)
|
629
|
-
ereport(ERROR,
|
630
|
-
(errcode(ERRCODE_OUT_OF_MEMORY),
|
631
|
-
errmsg("out of shared memory")));
|
632
|
-
else
|
633
|
-
ereport(ERROR,
|
634
|
-
(errcode(ERRCODE_OUT_OF_MEMORY),
|
635
|
-
errmsg("out of memory")));
|
636
|
-
}
|
637
|
-
|
638
|
-
/* link into hashbucket chain */
|
639
|
-
*prevBucketPtr = currBucket;
|
640
|
-
currBucket->link = NULL;
|
641
|
-
|
642
|
-
/* copy key into record */
|
643
|
-
currBucket->hashvalue = hashvalue;
|
644
|
-
hashp->keycopy(ELEMENTKEY(currBucket), keyPtr, keysize);
|
645
|
-
|
646
|
-
/*
|
647
|
-
* Caller is expected to fill the data field on return. DO NOT
|
648
|
-
* insert any code that could possibly throw error here, as doing
|
649
|
-
* so would leave the table entry incomplete and hence corrupt the
|
650
|
-
* caller's data structure.
|
651
|
-
*/
|
652
|
-
|
653
|
-
return (void *) ELEMENTKEY(currBucket);
|
654
|
-
}
|
655
|
-
|
656
|
-
elog(ERROR, "unrecognized hash action code: %d", (int) action);
|
657
|
-
|
658
|
-
return NULL; /* keep compiler quiet */
|
659
|
-
}
|
660
|
-
|
661
|
-
/*
|
662
|
-
* hash_update_hash_key -- change the hash key of an existing table entry
|
663
|
-
*
|
664
|
-
* This is equivalent to removing the entry, making a new entry, and copying
|
665
|
-
* over its data, except that the entry never goes to the table's freelist.
|
666
|
-
* Therefore this cannot suffer an out-of-memory failure, even if there are
|
667
|
-
* other processes operating in other partitions of the hashtable.
|
668
|
-
*
|
669
|
-
* Returns true if successful, false if the requested new hash key is already
|
670
|
-
* present. Throws error if the specified entry pointer isn't actually a
|
671
|
-
* table member.
|
672
|
-
*
|
673
|
-
* NB: currently, there is no special case for old and new hash keys being
|
674
|
-
* identical, which means we'll report false for that situation. This is
|
675
|
-
* preferable for existing uses.
|
676
|
-
*
|
677
|
-
* NB: for a partitioned hashtable, caller must hold lock on both relevant
|
678
|
-
* partitions, if the new hash key would belong to a different partition.
|
679
|
-
*/
|
680
|
-
#ifdef HASH_STATISTICS
|
681
|
-
#endif
|
682
|
-
#ifdef HASH_STATISTICS
|
683
|
-
#endif
|
684
|
-
|
685
|
-
/*
|
686
|
-
* Allocate a new hashtable entry if possible; return NULL if out of memory.
|
687
|
-
* (Or, if the underlying space allocator throws error for out-of-memory,
|
688
|
-
* we won't return at all.)
|
689
|
-
*/
|
690
|
-
static HASHBUCKET
|
691
|
-
get_hash_entry(HTAB *hashp, int freelist_idx)
|
692
|
-
{
|
693
|
-
HASHHDR *hctl = hashp->hctl;
|
694
|
-
HASHBUCKET newElement;
|
695
|
-
|
696
|
-
for (;;)
|
697
|
-
{
|
698
|
-
/* if partitioned, must lock to touch nentries and freeList */
|
699
|
-
if (IS_PARTITIONED(hctl))
|
700
|
-
SpinLockAcquire(&hctl->freeList[freelist_idx].mutex);
|
701
|
-
|
702
|
-
/* try to get an entry from the freelist */
|
703
|
-
newElement = hctl->freeList[freelist_idx].freeList;
|
704
|
-
|
705
|
-
if (newElement != NULL)
|
706
|
-
break;
|
707
|
-
|
708
|
-
if (IS_PARTITIONED(hctl))
|
709
|
-
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
|
710
|
-
|
711
|
-
/*
|
712
|
-
* No free elements in this freelist. In a partitioned table, there
|
713
|
-
* might be entries in other freelists, but to reduce contention we
|
714
|
-
* prefer to first try to get another chunk of buckets from the main
|
715
|
-
* shmem allocator. If that fails, though, we *MUST* root through all
|
716
|
-
* the other freelists before giving up. There are multiple callers
|
717
|
-
* that assume that they can allocate every element in the initially
|
718
|
-
* requested table size, or that deleting an element guarantees they
|
719
|
-
* can insert a new element, even if shared memory is entirely full.
|
720
|
-
* Failing because the needed element is in a different freelist is
|
721
|
-
* not acceptable.
|
722
|
-
*/
|
723
|
-
if (!element_alloc(hashp, hctl->nelem_alloc, freelist_idx))
|
724
|
-
{
|
725
|
-
int borrow_from_idx;
|
726
|
-
|
727
|
-
if (!IS_PARTITIONED(hctl))
|
728
|
-
return NULL; /* out of memory */
|
729
|
-
|
730
|
-
/* try to borrow element from another freelist */
|
731
|
-
borrow_from_idx = freelist_idx;
|
732
|
-
for (;;)
|
733
|
-
{
|
734
|
-
borrow_from_idx = (borrow_from_idx + 1) % NUM_FREELISTS;
|
735
|
-
if (borrow_from_idx == freelist_idx)
|
736
|
-
break; /* examined all freelists, fail */
|
737
|
-
|
738
|
-
SpinLockAcquire(&(hctl->freeList[borrow_from_idx].mutex));
|
739
|
-
newElement = hctl->freeList[borrow_from_idx].freeList;
|
740
|
-
|
741
|
-
if (newElement != NULL)
|
742
|
-
{
|
743
|
-
hctl->freeList[borrow_from_idx].freeList = newElement->link;
|
744
|
-
SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex));
|
745
|
-
|
746
|
-
/* careful: count the new element in its proper freelist */
|
747
|
-
SpinLockAcquire(&hctl->freeList[freelist_idx].mutex);
|
748
|
-
hctl->freeList[freelist_idx].nentries++;
|
749
|
-
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
|
750
|
-
|
751
|
-
return newElement;
|
752
|
-
}
|
753
|
-
|
754
|
-
SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex));
|
755
|
-
}
|
756
|
-
|
757
|
-
/* no elements available to borrow either, so out of memory */
|
758
|
-
return NULL;
|
759
|
-
}
|
760
|
-
}
|
761
|
-
|
762
|
-
/* remove entry from freelist, bump nentries */
|
763
|
-
hctl->freeList[freelist_idx].freeList = newElement->link;
|
764
|
-
hctl->freeList[freelist_idx].nentries++;
|
765
|
-
|
766
|
-
if (IS_PARTITIONED(hctl))
|
767
|
-
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
|
768
|
-
|
769
|
-
return newElement;
|
770
|
-
}
|
771
|
-
|
772
|
-
/*
|
773
|
-
* hash_get_num_entries -- get the number of entries in a hashtable
|
774
|
-
*/
|
775
|
-
|
776
|
-
|
777
|
-
/*
|
778
|
-
* hash_seq_init/_search/_term
|
779
|
-
* Sequentially search through hash table and return
|
780
|
-
* all the elements one by one, return NULL when no more.
|
781
|
-
*
|
782
|
-
* hash_seq_term should be called if and only if the scan is abandoned before
|
783
|
-
* completion; if hash_seq_search returns NULL then it has already done the
|
784
|
-
* end-of-scan cleanup.
|
785
|
-
*
|
786
|
-
* NOTE: caller may delete the returned element before continuing the scan.
|
787
|
-
* However, deleting any other element while the scan is in progress is
|
788
|
-
* UNDEFINED (it might be the one that curIndex is pointing at!). Also,
|
789
|
-
* if elements are added to the table while the scan is in progress, it is
|
790
|
-
* unspecified whether they will be visited by the scan or not.
|
791
|
-
*
|
792
|
-
* NOTE: it is possible to use hash_seq_init/hash_seq_search without any
|
793
|
-
* worry about hash_seq_term cleanup, if the hashtable is first locked against
|
794
|
-
* further insertions by calling hash_freeze.
|
795
|
-
*
|
796
|
-
* NOTE: to use this with a partitioned hashtable, caller had better hold
|
797
|
-
* at least shared lock on all partitions of the table throughout the scan!
|
798
|
-
* We can cope with insertions or deletions by our own backend, but *not*
|
799
|
-
* with concurrent insertions or deletions by another.
|
800
|
-
*/
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
/*
|
808
|
-
* hash_freeze
|
809
|
-
* Freeze a hashtable against future insertions (deletions are
|
810
|
-
* still allowed)
|
811
|
-
*
|
812
|
-
* The reason for doing this is that by preventing any more bucket splits,
|
813
|
-
* we no longer need to worry about registering hash_seq_search scans,
|
814
|
-
* and thus caller need not be careful about ensuring hash_seq_term gets
|
815
|
-
* called at the right times.
|
816
|
-
*
|
817
|
-
* Multiple calls to hash_freeze() are allowed, but you can't freeze a table
|
818
|
-
* with active scans (since hash_seq_term would then do the wrong thing).
|
819
|
-
*/
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
/********************************* UTILITIES ************************/
|
824
|
-
|
825
|
-
/*
|
826
|
-
* Expand the table by adding one more hash bucket.
|
827
|
-
*/
|
828
|
-
static bool
|
829
|
-
expand_table(HTAB *hashp)
|
830
|
-
{
|
831
|
-
HASHHDR *hctl = hashp->hctl;
|
832
|
-
HASHSEGMENT old_seg,
|
833
|
-
new_seg;
|
834
|
-
long old_bucket,
|
835
|
-
new_bucket;
|
836
|
-
long new_segnum,
|
837
|
-
new_segndx;
|
838
|
-
long old_segnum,
|
839
|
-
old_segndx;
|
840
|
-
HASHBUCKET *oldlink,
|
841
|
-
*newlink;
|
842
|
-
HASHBUCKET currElement,
|
843
|
-
nextElement;
|
844
|
-
|
845
|
-
Assert(!IS_PARTITIONED(hctl));
|
846
|
-
|
847
|
-
#ifdef HASH_STATISTICS
|
848
|
-
hash_expansions++;
|
849
|
-
#endif
|
850
|
-
|
851
|
-
new_bucket = hctl->max_bucket + 1;
|
852
|
-
new_segnum = new_bucket >> hashp->sshift;
|
853
|
-
new_segndx = MOD(new_bucket, hashp->ssize);
|
854
|
-
|
855
|
-
if (new_segnum >= hctl->nsegs)
|
856
|
-
{
|
857
|
-
/* Allocate new segment if necessary -- could fail if dir full */
|
858
|
-
if (new_segnum >= hctl->dsize)
|
859
|
-
if (!dir_realloc(hashp))
|
860
|
-
return false;
|
861
|
-
if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
|
862
|
-
return false;
|
863
|
-
hctl->nsegs++;
|
864
|
-
}
|
865
|
-
|
866
|
-
/* OK, we created a new bucket */
|
867
|
-
hctl->max_bucket++;
|
868
|
-
|
869
|
-
/*
|
870
|
-
* *Before* changing masks, find old bucket corresponding to same hash
|
871
|
-
* values; values in that bucket may need to be relocated to new bucket.
|
872
|
-
* Note that new_bucket is certainly larger than low_mask at this point,
|
873
|
-
* so we can skip the first step of the regular hash mask calc.
|
874
|
-
*/
|
875
|
-
old_bucket = (new_bucket & hctl->low_mask);
|
876
|
-
|
877
|
-
/*
|
878
|
-
* If we crossed a power of 2, readjust masks.
|
879
|
-
*/
|
880
|
-
if ((uint32) new_bucket > hctl->high_mask)
|
881
|
-
{
|
882
|
-
hctl->low_mask = hctl->high_mask;
|
883
|
-
hctl->high_mask = (uint32) new_bucket | hctl->low_mask;
|
884
|
-
}
|
885
|
-
|
886
|
-
/*
|
887
|
-
* Relocate records to the new bucket. NOTE: because of the way the hash
|
888
|
-
* masking is done in calc_bucket, only one old bucket can need to be
|
889
|
-
* split at this point. With a different way of reducing the hash value,
|
890
|
-
* that might not be true!
|
891
|
-
*/
|
892
|
-
old_segnum = old_bucket >> hashp->sshift;
|
893
|
-
old_segndx = MOD(old_bucket, hashp->ssize);
|
894
|
-
|
895
|
-
old_seg = hashp->dir[old_segnum];
|
896
|
-
new_seg = hashp->dir[new_segnum];
|
897
|
-
|
898
|
-
oldlink = &old_seg[old_segndx];
|
899
|
-
newlink = &new_seg[new_segndx];
|
900
|
-
|
901
|
-
for (currElement = *oldlink;
|
902
|
-
currElement != NULL;
|
903
|
-
currElement = nextElement)
|
904
|
-
{
|
905
|
-
nextElement = currElement->link;
|
906
|
-
if ((long) calc_bucket(hctl, currElement->hashvalue) == old_bucket)
|
907
|
-
{
|
908
|
-
*oldlink = currElement;
|
909
|
-
oldlink = &currElement->link;
|
910
|
-
}
|
911
|
-
else
|
912
|
-
{
|
913
|
-
*newlink = currElement;
|
914
|
-
newlink = &currElement->link;
|
915
|
-
}
|
916
|
-
}
|
917
|
-
/* don't forget to terminate the rebuilt hash chains... */
|
918
|
-
*oldlink = NULL;
|
919
|
-
*newlink = NULL;
|
920
|
-
|
921
|
-
return true;
|
922
|
-
}
|
923
|
-
|
924
|
-
|
925
|
-
static bool
|
926
|
-
dir_realloc(HTAB *hashp)
|
927
|
-
{
|
928
|
-
HASHSEGMENT *p;
|
929
|
-
HASHSEGMENT *old_p;
|
930
|
-
long new_dsize;
|
931
|
-
long old_dirsize;
|
932
|
-
long new_dirsize;
|
933
|
-
|
934
|
-
if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
|
935
|
-
return false;
|
936
|
-
|
937
|
-
/* Reallocate directory */
|
938
|
-
new_dsize = hashp->hctl->dsize << 1;
|
939
|
-
old_dirsize = hashp->hctl->dsize * sizeof(HASHSEGMENT);
|
940
|
-
new_dirsize = new_dsize * sizeof(HASHSEGMENT);
|
941
|
-
|
942
|
-
old_p = hashp->dir;
|
943
|
-
CurrentDynaHashCxt = hashp->hcxt;
|
944
|
-
p = (HASHSEGMENT *) hashp->alloc((Size) new_dirsize);
|
945
|
-
|
946
|
-
if (p != NULL)
|
947
|
-
{
|
948
|
-
memcpy(p, old_p, old_dirsize);
|
949
|
-
MemSet(((char *) p) + old_dirsize, 0, new_dirsize - old_dirsize);
|
950
|
-
hashp->dir = p;
|
951
|
-
hashp->hctl->dsize = new_dsize;
|
952
|
-
|
953
|
-
/* XXX assume the allocator is palloc, so we know how to free */
|
954
|
-
Assert(hashp->alloc == DynaHashAlloc);
|
955
|
-
pfree(old_p);
|
956
|
-
|
957
|
-
return true;
|
958
|
-
}
|
959
|
-
|
960
|
-
return false;
|
961
|
-
}
|
962
|
-
|
963
|
-
|
964
|
-
static HASHSEGMENT
|
965
|
-
seg_alloc(HTAB *hashp)
|
966
|
-
{
|
967
|
-
HASHSEGMENT segp;
|
968
|
-
|
969
|
-
CurrentDynaHashCxt = hashp->hcxt;
|
970
|
-
segp = (HASHSEGMENT) hashp->alloc(sizeof(HASHBUCKET) * hashp->ssize);
|
971
|
-
|
972
|
-
if (!segp)
|
973
|
-
return NULL;
|
974
|
-
|
975
|
-
MemSet(segp, 0, sizeof(HASHBUCKET) * hashp->ssize);
|
976
|
-
|
977
|
-
return segp;
|
978
|
-
}
|
979
|
-
|
980
|
-
/*
|
981
|
-
* allocate some new elements and link them into the indicated free list
|
982
|
-
*/
|
983
|
-
static bool
|
984
|
-
element_alloc(HTAB *hashp, int nelem, int freelist_idx)
|
985
|
-
{
|
986
|
-
HASHHDR *hctl = hashp->hctl;
|
987
|
-
Size elementSize;
|
988
|
-
HASHELEMENT *firstElement;
|
989
|
-
HASHELEMENT *tmpElement;
|
990
|
-
HASHELEMENT *prevElement;
|
991
|
-
int i;
|
992
|
-
|
993
|
-
if (hashp->isfixed)
|
994
|
-
return false;
|
995
|
-
|
996
|
-
/* Each element has a HASHELEMENT header plus user data. */
|
997
|
-
elementSize = MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(hctl->entrysize);
|
998
|
-
|
999
|
-
CurrentDynaHashCxt = hashp->hcxt;
|
1000
|
-
firstElement = (HASHELEMENT *) hashp->alloc(nelem * elementSize);
|
1001
|
-
|
1002
|
-
if (!firstElement)
|
1003
|
-
return false;
|
1004
|
-
|
1005
|
-
/* prepare to link all the new entries into the freelist */
|
1006
|
-
prevElement = NULL;
|
1007
|
-
tmpElement = firstElement;
|
1008
|
-
for (i = 0; i < nelem; i++)
|
1009
|
-
{
|
1010
|
-
tmpElement->link = prevElement;
|
1011
|
-
prevElement = tmpElement;
|
1012
|
-
tmpElement = (HASHELEMENT *) (((char *) tmpElement) + elementSize);
|
1013
|
-
}
|
1014
|
-
|
1015
|
-
/* if partitioned, must lock to touch freeList */
|
1016
|
-
if (IS_PARTITIONED(hctl))
|
1017
|
-
SpinLockAcquire(&hctl->freeList[freelist_idx].mutex);
|
1018
|
-
|
1019
|
-
/* freelist could be nonempty if two backends did this concurrently */
|
1020
|
-
firstElement->link = hctl->freeList[freelist_idx].freeList;
|
1021
|
-
hctl->freeList[freelist_idx].freeList = prevElement;
|
1022
|
-
|
1023
|
-
if (IS_PARTITIONED(hctl))
|
1024
|
-
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
|
1025
|
-
|
1026
|
-
return true;
|
1027
|
-
}
|
1028
|
-
|
1029
|
-
/* complain when we have detected a corrupted hashtable */
|
1030
|
-
static void
|
1031
|
-
hash_corrupted(HTAB *hashp)
|
1032
|
-
{
|
1033
|
-
/*
|
1034
|
-
* If the corruption is in a shared hashtable, we'd better force a
|
1035
|
-
* systemwide restart. Otherwise, just shut down this one backend.
|
1036
|
-
*/
|
1037
|
-
if (hashp->isshared)
|
1038
|
-
elog(PANIC, "hash table \"%s\" corrupted", hashp->tabname);
|
1039
|
-
else
|
1040
|
-
elog(FATAL, "hash table \"%s\" corrupted", hashp->tabname);
|
1041
|
-
}
|
1042
|
-
|
1043
|
-
/* calculate ceil(log base 2) of num */
|
1044
|
-
#if SIZEOF_LONG < 8
|
1045
|
-
#else
|
1046
|
-
#endif
|
1047
|
-
|
1048
|
-
/* calculate first power of 2 >= num, bounded to what will fit in a long */
|
1049
|
-
|
1050
|
-
|
1051
|
-
/* calculate first power of 2 >= num, bounded to what will fit in an int */
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
/************************* SEQ SCAN TRACKING ************************/
|
1056
|
-
|
1057
|
-
/*
|
1058
|
-
* We track active hash_seq_search scans here. The need for this mechanism
|
1059
|
-
* comes from the fact that a scan will get confused if a bucket split occurs
|
1060
|
-
* while it's in progress: it might visit entries twice, or even miss some
|
1061
|
-
* entirely (if it's partway through the same bucket that splits). Hence
|
1062
|
-
* we want to inhibit bucket splits if there are any active scans on the
|
1063
|
-
* table being inserted into. This is a fairly rare case in current usage,
|
1064
|
-
* so just postponing the split until the next insertion seems sufficient.
|
1065
|
-
*
|
1066
|
-
* Given present usages of the function, only a few scans are likely to be
|
1067
|
-
* open concurrently; so a finite-size stack of open scans seems sufficient,
|
1068
|
-
* and we don't worry that linear search is too slow. Note that we do
|
1069
|
-
* allow multiple scans of the same hashtable to be open concurrently.
|
1070
|
-
*
|
1071
|
-
* This mechanism can support concurrent scan and insertion in a shared
|
1072
|
-
* hashtable if it's the same backend doing both. It would fail otherwise,
|
1073
|
-
* but locking reasons seem to preclude any such scenario anyway, so we don't
|
1074
|
-
* worry.
|
1075
|
-
*
|
1076
|
-
* This arrangement is reasonably robust if a transient hashtable is deleted
|
1077
|
-
* without notifying us. The absolute worst case is we might inhibit splits
|
1078
|
-
* in another table created later at exactly the same address. We will give
|
1079
|
-
* a warning at transaction end for reference leaks, so any bugs leading to
|
1080
|
-
* lack of notification should be easy to catch.
|
1081
|
-
*/
|
1082
|
-
|
1083
|
-
#define MAX_SEQ_SCANS 100
|
1084
|
-
|
1085
|
-
static __thread HTAB *seq_scan_tables[MAX_SEQ_SCANS];
|
1086
|
-
/* tables being scanned */
|
1087
|
-
/* subtransaction nest level */
|
1088
|
-
static __thread int num_seq_scans = 0;
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
/* Register a table as having an active hash_seq_search scan */
|
1093
|
-
|
1094
|
-
|
1095
|
-
/* Deregister an active scan */
|
1096
|
-
|
1097
|
-
|
1098
|
-
/* Check if a table has any active scan */
|
1099
|
-
static bool
|
1100
|
-
has_seq_scans(HTAB *hashp)
|
1101
|
-
{
|
1102
|
-
int i;
|
1103
|
-
|
1104
|
-
for (i = 0; i < num_seq_scans; i++)
|
1105
|
-
{
|
1106
|
-
if (seq_scan_tables[i] == hashp)
|
1107
|
-
return true;
|
1108
|
-
}
|
1109
|
-
return false;
|
1110
|
-
}
|
1111
|
-
|
1112
|
-
/* Clean up any open scans at end of transaction */
|
1113
|
-
|
1114
|
-
|
1115
|
-
/* Clean up any open scans at end of subtransaction */
|
1116
|
-
|