summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorBruce Momjian1997-09-07 05:04:48 +0000
committerBruce Momjian1997-09-07 05:04:48 +0000
commit1ccd423235a48739d6f7a4d7889705b5f9ecc69b (patch)
tree8001c4e839dfad8f29ceda7f8c5f5dbb8759b564 /src/backend
parent8fecd4febf8357f3cc20383ed29ced484877d5ac (diff)
Massive commit to run PGINDENT on all *.c and *.h files.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/common/heaptuple.c1603
-rw-r--r--src/backend/access/common/heapvalid.c206
-rw-r--r--src/backend/access/common/indextuple.c758
-rw-r--r--src/backend/access/common/indexvalid.c104
-rw-r--r--src/backend/access/common/printtup.c431
-rw-r--r--src/backend/access/common/scankey.c54
-rw-r--r--src/backend/access/common/tupdesc.c890
-rw-r--r--src/backend/access/gist/gist.c2267
-rw-r--r--src/backend/access/gist/gistget.c644
-rw-r--r--src/backend/access/gist/gistscan.c620
-rw-r--r--src/backend/access/gist/giststrat.c123
-rw-r--r--src/backend/access/hash/hash.c767
-rw-r--r--src/backend/access/hash/hashfunc.c411
-rw-r--r--src/backend/access/hash/hashinsert.c386
-rw-r--r--src/backend/access/hash/hashovfl.c1065
-rw-r--r--src/backend/access/hash/hashpage.c1107
-rw-r--r--src/backend/access/hash/hashscan.c229
-rw-r--r--src/backend/access/hash/hashsearch.c758
-rw-r--r--src/backend/access/hash/hashstrat.c69
-rw-r--r--src/backend/access/hash/hashutil.c161
-rw-r--r--src/backend/access/heap/heapam.c2531
-rw-r--r--src/backend/access/heap/hio.c229
-rw-r--r--src/backend/access/heap/stats.c531
-rw-r--r--src/backend/access/index/genam.c328
-rw-r--r--src/backend/access/index/indexam.c474
-rw-r--r--src/backend/access/index/istrat.c1095
-rw-r--r--src/backend/access/nbtree/nbtcompare.c201
-rw-r--r--src/backend/access/nbtree/nbtinsert.c2923
-rw-r--r--src/backend/access/nbtree/nbtpage.c902
-rw-r--r--src/backend/access/nbtree/nbtree.c927
-rw-r--r--src/backend/access/nbtree/nbtscan.c267
-rw-r--r--src/backend/access/nbtree/nbtsearch.c2617
-rw-r--r--src/backend/access/nbtree/nbtsort.c1926
-rw-r--r--src/backend/access/nbtree/nbtstrat.c156
-rw-r--r--src/backend/access/nbtree/nbtutils.c623
-rw-r--r--src/backend/access/rtree/rtget.c544
-rw-r--r--src/backend/access/rtree/rtproc.c209
-rw-r--r--src/backend/access/rtree/rtree.c1753
-rw-r--r--src/backend/access/rtree/rtscan.c626
-rw-r--r--src/backend/access/rtree/rtstrat.c346
-rw-r--r--src/backend/access/transam/transam.c964
-rw-r--r--src/backend/access/transam/transsup.c1065
-rw-r--r--src/backend/access/transam/varsup.c1019
-rw-r--r--src/backend/access/transam/xact.c2014
-rw-r--r--src/backend/access/transam/xid.c94
-rw-r--r--src/backend/bootstrap/bootstrap.c1683
-rw-r--r--src/backend/catalog/catalog.c253
-rw-r--r--src/backend/catalog/heap.c2747
-rw-r--r--src/backend/catalog/index.c3019
-rw-r--r--src/backend/catalog/indexing.c808
-rw-r--r--src/backend/catalog/pg_aggregate.c555
-rw-r--r--src/backend/catalog/pg_operator.c1926
-rw-r--r--src/backend/catalog/pg_proc.c445
-rw-r--r--src/backend/catalog/pg_type.c1013
-rw-r--r--src/backend/commands/_deadcode/version.c369
-rw-r--r--src/backend/commands/async.c831
-rw-r--r--src/backend/commands/cluster.c580
-rw-r--r--src/backend/commands/command.c827
-rw-r--r--src/backend/commands/copy.c1884
-rw-r--r--src/backend/commands/creatinh.c1112
-rw-r--r--src/backend/commands/defind.c899
-rw-r--r--src/backend/commands/define.c1113
-rw-r--r--src/backend/commands/explain.c353
-rw-r--r--src/backend/commands/purge.c271
-rw-r--r--src/backend/commands/recipe.c2130
-rw-r--r--src/backend/commands/remove.c796
-rw-r--r--src/backend/commands/rename.c401
-rw-r--r--src/backend/commands/sequence.c924
-rw-r--r--src/backend/commands/trigger.c1050
-rw-r--r--src/backend/commands/vacuum.c3920
-rw-r--r--src/backend/commands/view.c427
-rw-r--r--src/backend/executor/execAmi.c693
-rw-r--r--src/backend/executor/execFlatten.c372
-rw-r--r--src/backend/executor/execJunk.c638
-rw-r--r--src/backend/executor/execMain.c2324
-rw-r--r--src/backend/executor/execProcnode.c820
-rw-r--r--src/backend/executor/execQual.c2665
-rw-r--r--src/backend/executor/execScan.c208
-rw-r--r--src/backend/executor/execTuples.c1526
-rw-r--r--src/backend/executor/execUtils.c1816
-rw-r--r--src/backend/executor/functions.c695
-rw-r--r--src/backend/executor/nodeAgg.c1055
-rw-r--r--src/backend/executor/nodeAppend.c852
-rw-r--r--src/backend/executor/nodeGroup.c632
-rw-r--r--src/backend/executor/nodeHash.c1420
-rw-r--r--src/backend/executor/nodeHashjoin.c1377
-rw-r--r--src/backend/executor/nodeIndexscan.c1623
-rw-r--r--src/backend/executor/nodeMaterial.c631
-rw-r--r--src/backend/executor/nodeMergejoin.c2165
-rw-r--r--src/backend/executor/nodeNestloop.c632
-rw-r--r--src/backend/executor/nodeResult.c454
-rw-r--r--src/backend/executor/nodeSeqscan.c726
-rw-r--r--src/backend/executor/nodeSort.c632
-rw-r--r--src/backend/executor/nodeTee.c899
-rw-r--r--src/backend/executor/nodeUnique.c532
-rw-r--r--src/backend/executor/spi.c1537
-rw-r--r--src/backend/lib/bit.c27
-rw-r--r--src/backend/lib/dllist.c246
-rw-r--r--src/backend/lib/fstack.c146
-rw-r--r--src/backend/lib/hasht.c48
-rw-r--r--src/backend/lib/lispsort.c67
-rw-r--r--src/backend/lib/qsort.c186
-rw-r--r--src/backend/lib/stringinfo.c142
-rw-r--r--src/backend/libpq/auth.c838
-rw-r--r--src/backend/libpq/be-dumpdata.c448
-rw-r--r--src/backend/libpq/be-fsstubs.c470
-rw-r--r--src/backend/libpq/be-pqexec.c613
-rw-r--r--src/backend/libpq/hba.c1336
-rw-r--r--src/backend/libpq/password.c190
-rw-r--r--src/backend/libpq/portal.c946
-rw-r--r--src/backend/libpq/portalbuf.c609
-rw-r--r--src/backend/libpq/pqcomm.c1016
-rw-r--r--src/backend/libpq/pqcomprim.c230
-rw-r--r--src/backend/libpq/pqpacket.c361
-rw-r--r--src/backend/libpq/pqsignal.c78
-rw-r--r--src/backend/libpq/util.c98
-rw-r--r--src/backend/main/main.c71
-rw-r--r--src/backend/nodes/copyfuncs.c2634
-rw-r--r--src/backend/nodes/equalfuncs.c1149
-rw-r--r--src/backend/nodes/list.c685
-rw-r--r--src/backend/nodes/makefuncs.c139
-rw-r--r--src/backend/nodes/nodeFuncs.c119
-rw-r--r--src/backend/nodes/nodes.c36
-rw-r--r--src/backend/nodes/outfuncs.c2640
-rw-r--r--src/backend/nodes/print.c582
-rw-r--r--src/backend/nodes/read.c421
-rw-r--r--src/backend/nodes/readfuncs.c3199
-rw-r--r--src/backend/optimizer/geqo/geqo_copy.c40
-rw-r--r--src/backend/optimizer/geqo/geqo_cx.c132
-rw-r--r--src/backend/optimizer/geqo/geqo_erx.c567
-rw-r--r--src/backend/optimizer/geqo/geqo_eval.c985
-rw-r--r--src/backend/optimizer/geqo/geqo_main.c249
-rw-r--r--src/backend/optimizer/geqo/geqo_misc.c347
-rw-r--r--src/backend/optimizer/geqo/geqo_mutation.c65
-rw-r--r--src/backend/optimizer/geqo/geqo_ox1.c122
-rw-r--r--src/backend/optimizer/geqo/geqo_ox2.c146
-rw-r--r--src/backend/optimizer/geqo/geqo_params.c268
-rw-r--r--src/backend/optimizer/geqo/geqo_paths.c190
-rw-r--r--src/backend/optimizer/geqo/geqo_pmx.c281
-rw-r--r--src/backend/optimizer/geqo/geqo_pool.c301
-rw-r--r--src/backend/optimizer/geqo/geqo_px.c121
-rw-r--r--src/backend/optimizer/geqo/geqo_recombination.c93
-rw-r--r--src/backend/optimizer/geqo/geqo_selection.c88
-rw-r--r--src/backend/optimizer/geqo/minspantree.c317
-rw-r--r--src/backend/optimizer/path/allpaths.c609
-rw-r--r--src/backend/optimizer/path/clausesel.c536
-rw-r--r--src/backend/optimizer/path/costsize.c624
-rw-r--r--src/backend/optimizer/path/hashutils.c174
-rw-r--r--src/backend/optimizer/path/indxpath.c2113
-rw-r--r--src/backend/optimizer/path/joinpath.c1097
-rw-r--r--src/backend/optimizer/path/joinrels.c884
-rw-r--r--src/backend/optimizer/path/joinutils.c679
-rw-r--r--src/backend/optimizer/path/mergeutils.c170
-rw-r--r--src/backend/optimizer/path/orindxpath.c430
-rw-r--r--src/backend/optimizer/path/predmig.c1064
-rw-r--r--src/backend/optimizer/path/prune.c284
-rw-r--r--src/backend/optimizer/path/xfunc.c2192
-rw-r--r--src/backend/optimizer/plan/createplan.c2005
-rw-r--r--src/backend/optimizer/plan/initsplan.c579
-rw-r--r--src/backend/optimizer/plan/planmain.c952
-rw-r--r--src/backend/optimizer/plan/planner.c635
-rw-r--r--src/backend/optimizer/plan/setrefs.c1148
-rw-r--r--src/backend/optimizer/prep/archive.c61
-rw-r--r--src/backend/optimizer/prep/prepqual.c980
-rw-r--r--src/backend/optimizer/prep/preptlist.c544
-rw-r--r--src/backend/optimizer/prep/prepunion.c628
-rw-r--r--src/backend/optimizer/util/clauseinfo.c259
-rw-r--r--src/backend/optimizer/util/clauses.c1026
-rw-r--r--src/backend/optimizer/util/indexnode.c113
-rw-r--r--src/backend/optimizer/util/internal.c48
-rw-r--r--src/backend/optimizer/util/joininfo.c132
-rw-r--r--src/backend/optimizer/util/keys.c261
-rw-r--r--src/backend/optimizer/util/ordering.c154
-rw-r--r--src/backend/optimizer/util/pathnode.c867
-rw-r--r--src/backend/optimizer/util/plancat.c969
-rw-r--r--src/backend/optimizer/util/relnode.c182
-rw-r--r--src/backend/optimizer/util/tlist.c834
-rw-r--r--src/backend/optimizer/util/var.c308
-rw-r--r--src/backend/parser/analyze.c4324
-rw-r--r--src/backend/parser/catalog_utils.c2457
-rw-r--r--src/backend/parser/dbcommands.c409
-rw-r--r--src/backend/parser/keywords.c366
-rw-r--r--src/backend/parser/parse_query.c1340
-rw-r--r--src/backend/parser/parser.c844
-rw-r--r--src/backend/parser/scansup.c173
-rw-r--r--src/backend/parser/sysfunc.c51
-rw-r--r--src/backend/port/BSD44_derived/dl.c56
-rw-r--r--src/backend/port/BSD44_derived/port-protos.h26
-rw-r--r--src/backend/port/aix/dlfcn.c393
-rw-r--r--src/backend/port/aix/dlfcn.h37
-rw-r--r--src/backend/port/aix/port-protos.h8
-rw-r--r--src/backend/port/alpha/port-protos.h14
-rw-r--r--src/backend/port/alpha/port.c23
-rw-r--r--src/backend/port/bsdi/dynloader.c123
-rw-r--r--src/backend/port/bsdi/port-protos.h24
-rw-r--r--src/backend/port/dgux/dynloader.c120
-rw-r--r--src/backend/port/dgux/port-protos.h18
-rw-r--r--src/backend/port/dgux/port.c4
-rw-r--r--src/backend/port/hpux/dynloader.c36
-rw-r--r--src/backend/port/hpux/fixade.h63
-rw-r--r--src/backend/port/hpux/port-protos.h20
-rw-r--r--src/backend/port/hpux/port.c32
-rw-r--r--src/backend/port/hpux/rusagestub.h23
-rw-r--r--src/backend/port/i386_solaris/port-protos.h20
-rw-r--r--src/backend/port/i386_solaris/port.c76
-rw-r--r--src/backend/port/i386_solaris/rusagestub.h25
-rw-r--r--src/backend/port/inet_aton.c96
-rw-r--r--src/backend/port/inet_aton.h2
-rw-r--r--src/backend/port/irix5/port-protos.h16
-rw-r--r--src/backend/port/irix5/port.c6
-rw-r--r--src/backend/port/linux/dynloader.c128
-rw-r--r--src/backend/port/linux/port-protos.h32
-rw-r--r--src/backend/port/linux/port.c4
-rw-r--r--src/backend/port/linuxalpha/machine.h4
-rw-r--r--src/backend/port/linuxalpha/port-protos.h16
-rw-r--r--src/backend/port/linuxalpha/port.c4
-rw-r--r--src/backend/port/nextstep/dynloader.c97
-rw-r--r--src/backend/port/nextstep/port-protos.h24
-rw-r--r--src/backend/port/nextstep/port.c75
-rw-r--r--src/backend/port/sco/port-protos.h16
-rw-r--r--src/backend/port/sco/port.c73
-rw-r--r--src/backend/port/sco/rusagestub.h23
-rw-r--r--src/backend/port/sparc_solaris/port-protos.h28
-rw-r--r--src/backend/port/sparc_solaris/port.c81
-rw-r--r--src/backend/port/sparc_solaris/rusagestub.h25
-rw-r--r--src/backend/port/strerror.c27
-rw-r--r--src/backend/port/sunos4/float.h26
-rw-r--r--src/backend/port/sunos4/port-protos.h18
-rw-r--r--src/backend/port/sunos4/strtol.c96
-rw-r--r--src/backend/port/svr4/port-protos.h18
-rw-r--r--src/backend/port/svr4/port.c98
-rw-r--r--src/backend/port/svr4/rusagestub.h23
-rw-r--r--src/backend/port/ultrix4/dl.h143
-rw-r--r--src/backend/port/ultrix4/dynloader.c85
-rw-r--r--src/backend/port/ultrix4/port-protos.h24
-rw-r--r--src/backend/port/ultrix4/port.c8
-rw-r--r--src/backend/port/ultrix4/strdup.c14
-rw-r--r--src/backend/port/univel/frontend-port-protos.h12
-rw-r--r--src/backend/port/univel/port-protos.h22
-rw-r--r--src/backend/port/univel/port.c111
-rw-r--r--src/backend/port/univel/rusagestub.h23
-rw-r--r--src/backend/postmaster/postmaster.c1949
-rw-r--r--src/backend/regex/engine.c823
-rw-r--r--src/backend/regex/regcomp.c1114
-rw-r--r--src/backend/regex/regerror.c197
-rw-r--r--src/backend/regex/regexec.c156
-rw-r--r--src/backend/regex/regfree.c47
-rw-r--r--src/backend/rewrite/locks.c173
-rw-r--r--src/backend/rewrite/rewriteDefine.c399
-rw-r--r--src/backend/rewrite/rewriteHandler.c1066
-rw-r--r--src/backend/rewrite/rewriteManip.c707
-rw-r--r--src/backend/rewrite/rewriteRemove.c257
-rw-r--r--src/backend/rewrite/rewriteSupport.c428
-rw-r--r--src/backend/storage/buffer/buf_init.c407
-rw-r--r--src/backend/storage/buffer/buf_table.c217
-rw-r--r--src/backend/storage/buffer/bufmgr.c2695
-rw-r--r--src/backend/storage/buffer/freelist.c373
-rw-r--r--src/backend/storage/buffer/localbuf.c370
-rw-r--r--src/backend/storage/file/fd.c1177
-rw-r--r--src/backend/storage/ipc/ipc.c991
-rw-r--r--src/backend/storage/ipc/ipci.c178
-rw-r--r--src/backend/storage/ipc/s_lock.c384
-rw-r--r--src/backend/storage/ipc/shmem.c951
-rw-r--r--src/backend/storage/ipc/shmqueue.c274
-rw-r--r--src/backend/storage/ipc/sinval.c222
-rw-r--r--src/backend/storage/ipc/sinvaladt.c1129
-rw-r--r--src/backend/storage/ipc/spin.c246
-rw-r--r--src/backend/storage/large_object/inv_api.c1877
-rw-r--r--src/backend/storage/lmgr/lmgr.c1129
-rw-r--r--src/backend/storage/lmgr/lock.c2137
-rw-r--r--src/backend/storage/lmgr/multi.c615
-rw-r--r--src/backend/storage/lmgr/proc.c1117
-rw-r--r--src/backend/storage/lmgr/single.c93
-rw-r--r--src/backend/storage/page/bufpage.c670
-rw-r--r--src/backend/storage/page/itemptr.c25
-rw-r--r--src/backend/storage/smgr/md.c1088
-rw-r--r--src/backend/storage/smgr/mm.c761
-rw-r--r--src/backend/storage/smgr/smgr.c432
-rw-r--r--src/backend/storage/smgr/smgrtype.c66
-rw-r--r--src/backend/tcop/aclchk.c952
-rw-r--r--src/backend/tcop/dest.c502
-rw-r--r--src/backend/tcop/fastpath.c520
-rw-r--r--src/backend/tcop/postgres.c2789
-rw-r--r--src/backend/tcop/pquery.c563
-rw-r--r--src/backend/tcop/utility.c1212
-rw-r--r--src/backend/tcop/variable.c598
-rw-r--r--src/backend/tioga/Arr_TgRecipe.h68
-rw-r--r--src/backend/tioga/Varray.c54
-rw-r--r--src/backend/tioga/Varray.h33
-rw-r--r--src/backend/tioga/tgRecipe.c1172
-rw-r--r--src/backend/tioga/tgRecipe.h181
-rw-r--r--src/backend/utils/adt/acl.c979
-rw-r--r--src/backend/utils/adt/arrayfuncs.c2706
-rw-r--r--src/backend/utils/adt/arrayutils.c123
-rw-r--r--src/backend/utils/adt/bool.c58
-rw-r--r--src/backend/utils/adt/cash.c734
-rw-r--r--src/backend/utils/adt/char.c518
-rw-r--r--src/backend/utils/adt/chunk.c989
-rw-r--r--src/backend/utils/adt/date.c1421
-rw-r--r--src/backend/utils/adt/datetime.c667
-rw-r--r--src/backend/utils/adt/datum.c221
-rw-r--r--src/backend/utils/adt/dt.c6008
-rw-r--r--src/backend/utils/adt/filename.c187
-rw-r--r--src/backend/utils/adt/float.c2140
-rw-r--r--src/backend/utils/adt/geo_ops.c5111
-rw-r--r--src/backend/utils/adt/geo_selfuncs.c142
-rw-r--r--src/backend/utils/adt/int.c641
-rw-r--r--src/backend/utils/adt/like.c287
-rw-r--r--src/backend/utils/adt/misc.c73
-rw-r--r--src/backend/utils/adt/nabstime.c682
-rw-r--r--src/backend/utils/adt/name.c242
-rw-r--r--src/backend/utils/adt/not_in.c148
-rw-r--r--src/backend/utils/adt/numutils.c687
-rw-r--r--src/backend/utils/adt/oid.c153
-rw-r--r--src/backend/utils/adt/oidint2.c110
-rw-r--r--src/backend/utils/adt/oidint4.c139
-rw-r--r--src/backend/utils/adt/oidname.c115
-rw-r--r--src/backend/utils/adt/oracle_compat.c714
-rw-r--r--src/backend/utils/adt/regexp.c398
-rw-r--r--src/backend/utils/adt/regproc.c229
-rw-r--r--src/backend/utils/adt/selfuncs.c962
-rw-r--r--src/backend/utils/adt/sets.c260
-rw-r--r--src/backend/utils/adt/tid.c109
-rw-r--r--src/backend/utils/adt/timestamp.c126
-rw-r--r--src/backend/utils/adt/varchar.c738
-rw-r--r--src/backend/utils/adt/varlena.c819
-rw-r--r--src/backend/utils/cache/catcache.c1786
-rw-r--r--src/backend/utils/cache/fcache.c481
-rw-r--r--src/backend/utils/cache/inval.c840
-rw-r--r--src/backend/utils/cache/lsyscache.c618
-rw-r--r--src/backend/utils/cache/rel.c57
-rw-r--r--src/backend/utils/cache/relcache.c3493
-rw-r--r--src/backend/utils/cache/syscache.c1057
-rw-r--r--src/backend/utils/error/assert.c86
-rw-r--r--src/backend/utils/error/elog.c392
-rw-r--r--src/backend/utils/error/exc.c229
-rw-r--r--src/backend/utils/error/excabort.c20
-rw-r--r--src/backend/utils/error/excid.c40
-rw-r--r--src/backend/utils/error/format.c30
-rw-r--r--src/backend/utils/fmgr/dfmgr.c441
-rw-r--r--src/backend/utils/fmgr/fmgr.c390
-rw-r--r--src/backend/utils/hash/dynahash.c1382
-rw-r--r--src/backend/utils/hash/hashfn.c212
-rw-r--r--src/backend/utils/init/enbl.c21
-rw-r--r--src/backend/utils/init/findbe.c377
-rw-r--r--src/backend/utils/init/globals.c127
-rw-r--r--src/backend/utils/init/miscinit.c268
-rw-r--r--src/backend/utils/init/postinit.c1064
-rw-r--r--src/backend/utils/misc/superuser.c28
-rw-r--r--src/backend/utils/mmgr/aset.c411
-rw-r--r--src/backend/utils/mmgr/mcxt.c517
-rw-r--r--src/backend/utils/mmgr/oset.c126
-rw-r--r--src/backend/utils/mmgr/palloc.c82
-rw-r--r--src/backend/utils/mmgr/portalmem.c1222
-rw-r--r--src/backend/utils/sort/lselect.c525
-rw-r--r--src/backend/utils/sort/psort.c1311
-rw-r--r--src/backend/utils/time/tqual.c1263
357 files changed, 124869 insertions, 113750 deletions
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c
index 60ec3e4d3ab..17257690303 100644
--- a/src/backend/access/common/heaptuple.c
+++ b/src/backend/access/common/heaptuple.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* heaptuple.c--
- * This file contains heap tuple accessor and mutator routines, as well
- * as a few various tuple utilities.
+ * This file contains heap tuple accessor and mutator routines, as well
+ * as a few various tuple utilities.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.21 1997/08/26 23:31:20 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.22 1997/09/07 04:37:30 momjian Exp $
*
* NOTES
- * The old interface functions have been converted to macros
- * and moved to heapam.h
+ * The old interface functions have been converted to macros
+ * and moved to heapam.h
*
*-------------------------------------------------------------------------
*/
@@ -27,9 +27,9 @@
#include <utils/memutils.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
@@ -37,902 +37,991 @@
#if !defined(NO_ASSERT_CHECKING) && defined(sparc) && defined(sunos4)
#define register
-#endif /* !NO_ASSERT_CHECKING && sparc && sunos4 */
+#endif /* !NO_ASSERT_CHECKING && sparc && sunos4 */
/* ----------------------------------------------------------------
- * misc support routines
+ * misc support routines
* ----------------------------------------------------------------
*/
/* ----------------
- * ComputeDataSize
+ * ComputeDataSize
* ----------------
*/
Size
ComputeDataSize(TupleDesc tupleDesc,
- Datum value[],
- char nulls[])
+ Datum value[],
+ char nulls[])
{
- uint32 data_length;
- int i;
- int numberOfAttributes = tupleDesc->natts;
- AttributeTupleForm *att = tupleDesc->attrs;
-
- for (data_length = 0, i = 0; i < numberOfAttributes; i++) {
- if (nulls[i] != ' ') continue;
-
- switch (att[i]->attlen) {
- case -1:
- /*
- * This is the size of the disk representation and so
- * must include the additional sizeof long.
- */
- if (att[i]->attalign == 'd') {
- data_length = DOUBLEALIGN(data_length)
- + VARSIZE(DatumGetPointer(value[i]));
- } else {
- data_length = INTALIGN(data_length)
- + VARSIZE(DatumGetPointer(value[i]));
- }
- break;
- case sizeof(char):
- data_length++;
- break;
- case sizeof(short):
- data_length = SHORTALIGN(data_length + sizeof(short));
- break;
- case sizeof(int32):
- data_length = INTALIGN(data_length + sizeof(int32));
- break;
- default:
- if (att[i]->attlen < sizeof(int32))
- elog(WARN, "ComputeDataSize: attribute %d has len %d",
- i, att[i]->attlen);
- if (att[i]->attalign == 'd')
- data_length = DOUBLEALIGN(data_length) + att[i]->attlen;
- else
- data_length = LONGALIGN(data_length) + att[i]->attlen;
- break;
+ uint32 data_length;
+ int i;
+ int numberOfAttributes = tupleDesc->natts;
+ AttributeTupleForm *att = tupleDesc->attrs;
+
+ for (data_length = 0, i = 0; i < numberOfAttributes; i++)
+ {
+ if (nulls[i] != ' ')
+ continue;
+
+ switch (att[i]->attlen)
+ {
+ case -1:
+
+ /*
+ * This is the size of the disk representation and so must
+ * include the additional sizeof long.
+ */
+ if (att[i]->attalign == 'd')
+ {
+ data_length = DOUBLEALIGN(data_length)
+ + VARSIZE(DatumGetPointer(value[i]));
+ }
+ else
+ {
+ data_length = INTALIGN(data_length)
+ + VARSIZE(DatumGetPointer(value[i]));
+ }
+ break;
+ case sizeof(char):
+ data_length++;
+ break;
+ case sizeof(short):
+ data_length = SHORTALIGN(data_length + sizeof(short));
+ break;
+ case sizeof(int32):
+ data_length = INTALIGN(data_length + sizeof(int32));
+ break;
+ default:
+ if (att[i]->attlen < sizeof(int32))
+ elog(WARN, "ComputeDataSize: attribute %d has len %d",
+ i, att[i]->attlen);
+ if (att[i]->attalign == 'd')
+ data_length = DOUBLEALIGN(data_length) + att[i]->attlen;
+ else
+ data_length = LONGALIGN(data_length) + att[i]->attlen;
+ break;
+ }
}
- }
-
- return data_length;
+
+ return data_length;
}
/* ----------------
- * DataFill
+ * DataFill
* ----------------
*/
void
DataFill(char *data,
- TupleDesc tupleDesc,
- Datum value[],
- char nulls[],
- char *infomask,
- bits8 *bit)
+ TupleDesc tupleDesc,
+ Datum value[],
+ char nulls[],
+ char *infomask,
+ bits8 * bit)
{
- bits8 *bitP = 0;
- int bitmask = 0;
- uint32 data_length;
- int i;
- int numberOfAttributes = tupleDesc->natts;
- AttributeTupleForm *att = tupleDesc->attrs;
-
- if (bit != NULL) {
- bitP = &bit[-1];
- bitmask = CSIGNBIT;
- }
-
- *infomask = 0;
-
- for (i = 0; i < numberOfAttributes; i++) {
- if (bit != NULL) {
- if (bitmask != CSIGNBIT) {
- bitmask <<= 1;
- } else {
- bitP += 1;
- *bitP = 0x0;
- bitmask = 1;
- }
-
- if (nulls[i] == 'n') {
- *infomask |= HEAP_HASNULL;
- continue;
- }
-
- *bitP |= bitmask;
+ bits8 *bitP = 0;
+ int bitmask = 0;
+ uint32 data_length;
+ int i;
+ int numberOfAttributes = tupleDesc->natts;
+ AttributeTupleForm *att = tupleDesc->attrs;
+
+ if (bit != NULL)
+ {
+ bitP = &bit[-1];
+ bitmask = CSIGNBIT;
}
-
- switch (att[i]->attlen) {
- case -1:
- *infomask |= HEAP_HASVARLENA;
- if (att[i]->attalign=='d') {
- data = (char *) DOUBLEALIGN(data);
- } else {
- data = (char *) INTALIGN(data);
- }
- data_length = VARSIZE(DatumGetPointer(value[i]));
- memmove(data, DatumGetPointer(value[i]),data_length);
- data += data_length;
- break;
- case sizeof(char):
- *data = att[i]->attbyval ?
- DatumGetChar(value[i]) : *((char *) value[i]);
- data += sizeof(char);
- break;
- case sizeof(int16):
- data = (char *) SHORTALIGN(data);
- * (short *) data = (att[i]->attbyval ?
- DatumGetInt16(value[i]) :
- *((short *) value[i]));
- data += sizeof(short);
- break;
- case sizeof(int32):
- data = (char *) INTALIGN(data);
- * (int32 *) data = (att[i]->attbyval ?
- DatumGetInt32(value[i]) :
- *((int32 *) value[i]));
- data += sizeof(int32);
- break;
- default:
- if (att[i]->attlen < sizeof(int32))
- elog(WARN, "DataFill: attribute %d has len %d",
- i, att[i]->attlen);
- if (att[i]->attalign == 'd') {
- data = (char *) DOUBLEALIGN(data);
- memmove(data, DatumGetPointer(value[i]),
- att[i]->attlen);
- data += att[i]->attlen;
- } else {
- data = (char *) LONGALIGN(data);
- memmove(data, DatumGetPointer(value[i]),
- att[i]->attlen);
- data += att[i]->attlen;
- }
- break;
+
+ *infomask = 0;
+
+ for (i = 0; i < numberOfAttributes; i++)
+ {
+ if (bit != NULL)
+ {
+ if (bitmask != CSIGNBIT)
+ {
+ bitmask <<= 1;
+ }
+ else
+ {
+ bitP += 1;
+ *bitP = 0x0;
+ bitmask = 1;
+ }
+
+ if (nulls[i] == 'n')
+ {
+ *infomask |= HEAP_HASNULL;
+ continue;
+ }
+
+ *bitP |= bitmask;
+ }
+
+ switch (att[i]->attlen)
+ {
+ case -1:
+ *infomask |= HEAP_HASVARLENA;
+ if (att[i]->attalign == 'd')
+ {
+ data = (char *) DOUBLEALIGN(data);
+ }
+ else
+ {
+ data = (char *) INTALIGN(data);
+ }
+ data_length = VARSIZE(DatumGetPointer(value[i]));
+ memmove(data, DatumGetPointer(value[i]), data_length);
+ data += data_length;
+ break;
+ case sizeof(char):
+ *data = att[i]->attbyval ?
+ DatumGetChar(value[i]) : *((char *) value[i]);
+ data += sizeof(char);
+ break;
+ case sizeof(int16):
+ data = (char *) SHORTALIGN(data);
+ *(short *) data = (att[i]->attbyval ?
+ DatumGetInt16(value[i]) :
+ *((short *) value[i]));
+ data += sizeof(short);
+ break;
+ case sizeof(int32):
+ data = (char *) INTALIGN(data);
+ *(int32 *) data = (att[i]->attbyval ?
+ DatumGetInt32(value[i]) :
+ *((int32 *) value[i]));
+ data += sizeof(int32);
+ break;
+ default:
+ if (att[i]->attlen < sizeof(int32))
+ elog(WARN, "DataFill: attribute %d has len %d",
+ i, att[i]->attlen);
+ if (att[i]->attalign == 'd')
+ {
+ data = (char *) DOUBLEALIGN(data);
+ memmove(data, DatumGetPointer(value[i]),
+ att[i]->attlen);
+ data += att[i]->attlen;
+ }
+ else
+ {
+ data = (char *) LONGALIGN(data);
+ memmove(data, DatumGetPointer(value[i]),
+ att[i]->attlen);
+ data += att[i]->attlen;
+ }
+ break;
+ }
}
- }
}
/* ----------------------------------------------------------------
- * heap tuple interface
+ * heap tuple interface
* ----------------------------------------------------------------
*/
/* ----------------
- * heap_attisnull - returns 1 iff tuple attribute is not present
+ * heap_attisnull - returns 1 iff tuple attribute is not present
* ----------------
*/
int
heap_attisnull(HeapTuple tup, int attnum)
{
- if (attnum > (int)tup->t_natts)
- return (1);
-
- if (HeapTupleNoNulls(tup)) return(0);
-
- if (attnum > 0) {
- return(att_isnull(attnum - 1, tup->t_bits));
- } else
- switch (attnum) {
- case SelfItemPointerAttributeNumber:
- case ObjectIdAttributeNumber:
- case MinTransactionIdAttributeNumber:
- case MinCommandIdAttributeNumber:
- case MaxTransactionIdAttributeNumber:
- case MaxCommandIdAttributeNumber:
- case ChainItemPointerAttributeNumber:
- case AnchorItemPointerAttributeNumber:
- case MinAbsoluteTimeAttributeNumber:
- case MaxAbsoluteTimeAttributeNumber:
- case VersionTypeAttributeNumber:
- break;
-
- case 0:
- elog(WARN, "heap_attisnull: zero attnum disallowed");
-
- default:
- elog(WARN, "heap_attisnull: undefined negative attnum");
+ if (attnum > (int) tup->t_natts)
+ return (1);
+
+ if (HeapTupleNoNulls(tup))
+ return (0);
+
+ if (attnum > 0)
+ {
+ return (att_isnull(attnum - 1, tup->t_bits));
}
-
- return (0);
+ else
+ switch (attnum)
+ {
+ case SelfItemPointerAttributeNumber:
+ case ObjectIdAttributeNumber:
+ case MinTransactionIdAttributeNumber:
+ case MinCommandIdAttributeNumber:
+ case MaxTransactionIdAttributeNumber:
+ case MaxCommandIdAttributeNumber:
+ case ChainItemPointerAttributeNumber:
+ case AnchorItemPointerAttributeNumber:
+ case MinAbsoluteTimeAttributeNumber:
+ case MaxAbsoluteTimeAttributeNumber:
+ case VersionTypeAttributeNumber:
+ break;
+
+ case 0:
+ elog(WARN, "heap_attisnull: zero attnum disallowed");
+
+ default:
+ elog(WARN, "heap_attisnull: undefined negative attnum");
+ }
+
+ return (0);
}
/* ----------------------------------------------------------------
- * system attribute heap tuple support
+ * system attribute heap tuple support
* ----------------------------------------------------------------
*/
/* ----------------
- * heap_sysattrlen
+ * heap_sysattrlen
*
- * This routine returns the length of a system attribute.
+ * This routine returns the length of a system attribute.
* ----------------
*/
int
heap_sysattrlen(AttrNumber attno)
{
- HeapTupleData *f = NULL;
-
- switch (attno) {
- case SelfItemPointerAttributeNumber: return sizeof f->t_ctid;
- case ObjectIdAttributeNumber: return sizeof f->t_oid;
- case MinTransactionIdAttributeNumber: return sizeof f->t_xmin;
- case MinCommandIdAttributeNumber: return sizeof f->t_cmin;
- case MaxTransactionIdAttributeNumber: return sizeof f->t_xmax;
- case MaxCommandIdAttributeNumber: return sizeof f->t_cmax;
- case ChainItemPointerAttributeNumber: return sizeof f->t_chain;
- case MinAbsoluteTimeAttributeNumber: return sizeof f->t_tmin;
- case MaxAbsoluteTimeAttributeNumber: return sizeof f->t_tmax;
- case VersionTypeAttributeNumber: return sizeof f->t_vtype;
-
- case AnchorItemPointerAttributeNumber:
- elog(WARN, "heap_sysattrlen: field t_anchor does not exist!");
- return 0;
-
- default:
- elog(WARN, "sysattrlen: System attribute number %d unknown.", attno);
- return 0;
- }
+ HeapTupleData *f = NULL;
+
+ switch (attno)
+ {
+ case SelfItemPointerAttributeNumber:
+ return sizeof f->t_ctid;
+ case ObjectIdAttributeNumber:
+ return sizeof f->t_oid;
+ case MinTransactionIdAttributeNumber:
+ return sizeof f->t_xmin;
+ case MinCommandIdAttributeNumber:
+ return sizeof f->t_cmin;
+ case MaxTransactionIdAttributeNumber:
+ return sizeof f->t_xmax;
+ case MaxCommandIdAttributeNumber:
+ return sizeof f->t_cmax;
+ case ChainItemPointerAttributeNumber:
+ return sizeof f->t_chain;
+ case MinAbsoluteTimeAttributeNumber:
+ return sizeof f->t_tmin;
+ case MaxAbsoluteTimeAttributeNumber:
+ return sizeof f->t_tmax;
+ case VersionTypeAttributeNumber:
+ return sizeof f->t_vtype;
+
+ case AnchorItemPointerAttributeNumber:
+ elog(WARN, "heap_sysattrlen: field t_anchor does not exist!");
+ return 0;
+
+ default:
+ elog(WARN, "sysattrlen: System attribute number %d unknown.", attno);
+ return 0;
+ }
}
/* ----------------
- * heap_sysattrbyval
+ * heap_sysattrbyval
*
- * This routine returns the "by-value" property of a system attribute.
+ * This routine returns the "by-value" property of a system attribute.
* ----------------
*/
bool
heap_sysattrbyval(AttrNumber attno)
{
- bool byval;
-
- switch (attno) {
- case SelfItemPointerAttributeNumber:
- byval = false;
- break;
- case ObjectIdAttributeNumber:
- byval = true;
- break;
- case MinTransactionIdAttributeNumber:
- byval = true;
- break;
- case MinCommandIdAttributeNumber:
- byval = true;
- break;
- case MaxTransactionIdAttributeNumber:
- byval = true;
- break;
- case MaxCommandIdAttributeNumber:
- byval = true;
- break;
- case ChainItemPointerAttributeNumber:
- byval = false;
- break;
- case AnchorItemPointerAttributeNumber:
- byval = false;
- break;
- case MinAbsoluteTimeAttributeNumber:
- byval = true;
- break;
- case MaxAbsoluteTimeAttributeNumber:
- byval = true;
- break;
- case VersionTypeAttributeNumber:
- byval = true;
- break;
- default:
- byval = true;
- elog(WARN, "sysattrbyval: System attribute number %d unknown.",
- attno);
- break;
- }
-
- return byval;
+ bool byval;
+
+ switch (attno)
+ {
+ case SelfItemPointerAttributeNumber:
+ byval = false;
+ break;
+ case ObjectIdAttributeNumber:
+ byval = true;
+ break;
+ case MinTransactionIdAttributeNumber:
+ byval = true;
+ break;
+ case MinCommandIdAttributeNumber:
+ byval = true;
+ break;
+ case MaxTransactionIdAttributeNumber:
+ byval = true;
+ break;
+ case MaxCommandIdAttributeNumber:
+ byval = true;
+ break;
+ case ChainItemPointerAttributeNumber:
+ byval = false;
+ break;
+ case AnchorItemPointerAttributeNumber:
+ byval = false;
+ break;
+ case MinAbsoluteTimeAttributeNumber:
+ byval = true;
+ break;
+ case MaxAbsoluteTimeAttributeNumber:
+ byval = true;
+ break;
+ case VersionTypeAttributeNumber:
+ byval = true;
+ break;
+ default:
+ byval = true;
+ elog(WARN, "sysattrbyval: System attribute number %d unknown.",
+ attno);
+ break;
+ }
+
+ return byval;
}
/* ----------------
- * heap_getsysattr
+ * heap_getsysattr
* ----------------
*/
-char *
+char *
heap_getsysattr(HeapTuple tup, Buffer b, int attnum)
{
- switch (attnum) {
- case SelfItemPointerAttributeNumber:
- return ((char *)&tup->t_ctid);
- case ObjectIdAttributeNumber:
- return ((char *) (long) tup->t_oid);
- case MinTransactionIdAttributeNumber:
- return ((char *) (long) tup->t_xmin);
- case MinCommandIdAttributeNumber:
- return ((char *) (long) tup->t_cmin);
- case MaxTransactionIdAttributeNumber:
- return ((char *) (long) tup->t_xmax);
- case MaxCommandIdAttributeNumber:
- return ((char *) (long) tup->t_cmax);
- case ChainItemPointerAttributeNumber:
- return ((char *) &tup->t_chain);
- case AnchorItemPointerAttributeNumber:
- elog(WARN, "heap_getsysattr: t_anchor does not exist!");
- break;
-
- /*
- * For tmin and tmax, we need to do some extra work. These don't
- * get filled in until the vacuum cleaner runs (or we manage to flush
- * a page after setting the value correctly below). If the vacuum
- * cleaner hasn't run yet, then the times stored in the tuple are
- * wrong, and we need to look up the commit time of the transaction.
- * We cache this value in the tuple to avoid doing the work more than
- * once.
- */
-
- case MinAbsoluteTimeAttributeNumber:
- if (!AbsoluteTimeIsBackwardCompatiblyValid(tup->t_tmin) &&
- TransactionIdDidCommit(tup->t_xmin))
- tup->t_tmin = TransactionIdGetCommitTime(tup->t_xmin);
- return ((char *) (long) tup->t_tmin);
- case MaxAbsoluteTimeAttributeNumber:
- if (!AbsoluteTimeIsBackwardCompatiblyReal(tup->t_tmax)) {
- if (TransactionIdDidCommit(tup->t_xmax))
- tup->t_tmax = TransactionIdGetCommitTime(tup->t_xmax);
- else
- tup->t_tmax = CURRENT_ABSTIME;
+ switch (attnum)
+ {
+ case SelfItemPointerAttributeNumber:
+ return ((char *) &tup->t_ctid);
+ case ObjectIdAttributeNumber:
+ return ((char *) (long) tup->t_oid);
+ case MinTransactionIdAttributeNumber:
+ return ((char *) (long) tup->t_xmin);
+ case MinCommandIdAttributeNumber:
+ return ((char *) (long) tup->t_cmin);
+ case MaxTransactionIdAttributeNumber:
+ return ((char *) (long) tup->t_xmax);
+ case MaxCommandIdAttributeNumber:
+ return ((char *) (long) tup->t_cmax);
+ case ChainItemPointerAttributeNumber:
+ return ((char *) &tup->t_chain);
+ case AnchorItemPointerAttributeNumber:
+ elog(WARN, "heap_getsysattr: t_anchor does not exist!");
+ break;
+
+ /*
+ * For tmin and tmax, we need to do some extra work. These don't
+ * get filled in until the vacuum cleaner runs (or we manage to
+ * flush a page after setting the value correctly below). If the
+ * vacuum cleaner hasn't run yet, then the times stored in the
+ * tuple are wrong, and we need to look up the commit time of the
+ * transaction. We cache this value in the tuple to avoid doing
+ * the work more than once.
+ */
+
+ case MinAbsoluteTimeAttributeNumber:
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(tup->t_tmin) &&
+ TransactionIdDidCommit(tup->t_xmin))
+ tup->t_tmin = TransactionIdGetCommitTime(tup->t_xmin);
+ return ((char *) (long) tup->t_tmin);
+ case MaxAbsoluteTimeAttributeNumber:
+ if (!AbsoluteTimeIsBackwardCompatiblyReal(tup->t_tmax))
+ {
+ if (TransactionIdDidCommit(tup->t_xmax))
+ tup->t_tmax = TransactionIdGetCommitTime(tup->t_xmax);
+ else
+ tup->t_tmax = CURRENT_ABSTIME;
+ }
+ return ((char *) (long) tup->t_tmax);
+ case VersionTypeAttributeNumber:
+ return ((char *) (long) tup->t_vtype);
+ default:
+ elog(WARN, "heap_getsysattr: undefined attnum %d", attnum);
}
- return ((char *) (long) tup->t_tmax);
- case VersionTypeAttributeNumber:
- return ((char *) (long) tup->t_vtype);
- default:
- elog(WARN, "heap_getsysattr: undefined attnum %d", attnum);
- }
- return(NULL);
+ return (NULL);
}
/* ----------------
- * fastgetattr
+ * fastgetattr
*
- * This is a newer version of fastgetattr which attempts to be
- * faster by caching attribute offsets in the attribute descriptor.
+ * This is a newer version of fastgetattr which attempts to be
+ * faster by caching attribute offsets in the attribute descriptor.
*
- * an alternate way to speed things up would be to cache offsets
- * with the tuple, but that seems more difficult unless you take
- * the storage hit of actually putting those offsets into the
- * tuple you send to disk. Yuck.
+ * an alternate way to speed things up would be to cache offsets
+ * with the tuple, but that seems more difficult unless you take
+ * the storage hit of actually putting those offsets into the
+ * tuple you send to disk. Yuck.
*
- * This scheme will be slightly slower than that, but should
- * preform well for queries which hit large #'s of tuples. After
- * you cache the offsets once, examining all the other tuples using
- * the same attribute descriptor will go much quicker. -cim 5/4/91
+ * This scheme will be slightly slower than that, but should
+ * preform well for queries which hit large #'s of tuples. After
+ * you cache the offsets once, examining all the other tuples using
+ * the same attribute descriptor will go much quicker. -cim 5/4/91
* ----------------
*/
-char *
+char *
fastgetattr(HeapTuple tup,
- int attnum,
- TupleDesc tupleDesc,
- bool *isnull)
+ int attnum,
+ TupleDesc tupleDesc,
+ bool * isnull)
{
- char *tp; /* ptr to att in tuple */
- bits8 *bp = NULL; /* ptr to att in tuple */
- int slow; /* do we have to walk nulls? */
- AttributeTupleForm *att = tupleDesc->attrs;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
-
- Assert(attnum > 0);
-
- /* ----------------
- * Three cases:
- *
- * 1: No nulls and no variable length attributes.
- * 2: Has a null or a varlena AFTER att.
- * 3: Has nulls or varlenas BEFORE att.
- * ----------------
- */
-
- if (isnull)
- *isnull = false;
-
- if (HeapTupleNoNulls(tup)) {
- attnum--;
- if (att[attnum]->attcacheoff > 0) {
- return (char *)
- fetchatt( &(att[attnum]),
- (char *)tup + tup->t_hoff + att[attnum]->attcacheoff);
- } else if (attnum == 0) {
- /*
- * first attribute is always at position zero
- */
- return((char *) fetchatt(&(att[0]), (char *) tup + tup->t_hoff));
- }
-
- tp = (char *) tup + tup->t_hoff;
-
- slow = 0;
- } else {
- /*
- * there's a null somewhere in the tuple
- */
+ char *tp; /* ptr to att in tuple */
+ bits8 *bp = NULL; /* ptr to att in tuple */
+ int slow; /* do we have to walk nulls? */
+ AttributeTupleForm *att = tupleDesc->attrs;
- bp = tup->t_bits;
- tp = (char *) tup + tup->t_hoff;
- slow = 0;
- attnum--;
-
/* ----------------
- * check to see if desired att is null
+ * sanity checks
* ----------------
*/
-
- if (att_isnull(attnum, bp)) {
- if (isnull)
- *isnull = true;
- return NULL;
- }
+
+ Assert(attnum > 0);
/* ----------------
- * Now check to see if any preceeding bits are null...
+ * Three cases:
+ *
+ * 1: No nulls and no variable length attributes.
+ * 2: Has a null or a varlena AFTER att.
+ * 3: Has nulls or varlenas BEFORE att.
* ----------------
*/
-
+
+ if (isnull)
+ *isnull = false;
+
+ if (HeapTupleNoNulls(tup))
{
- register int i = 0; /* current offset in bp */
-
- for (i = 0; i < attnum && !slow; i++) {
- if (att_isnull(i, bp)) slow = 1;
- }
+ attnum--;
+ if (att[attnum]->attcacheoff > 0)
+ {
+ return (char *)
+ fetchatt(&(att[attnum]),
+ (char *) tup + tup->t_hoff + att[attnum]->attcacheoff);
+ }
+ else if (attnum == 0)
+ {
+
+ /*
+ * first attribute is always at position zero
+ */
+ return ((char *) fetchatt(&(att[0]), (char *) tup + tup->t_hoff));
+ }
+
+ tp = (char *) tup + tup->t_hoff;
+
+ slow = 0;
}
- }
-
- /*
- * now check for any non-fixed length attrs before our attribute
- */
- if (!slow) {
- if (att[attnum]->attcacheoff > 0) {
- return (char *)
- fetchatt(&(att[attnum]),
- tp + att[attnum]->attcacheoff);
- } else if (attnum == 0) {
- return (char *)
- fetchatt(&(att[0]), (char *) tup + tup->t_hoff);
- } else if (!HeapTupleAllFixed(tup)) {
- register int j = 0;
-
- for (j = 0; j < attnum && !slow; j++)
- if (att[j]->attlen < 1) slow = 1;
+ else
+ {
+
+ /*
+ * there's a null somewhere in the tuple
+ */
+
+ bp = tup->t_bits;
+ tp = (char *) tup + tup->t_hoff;
+ slow = 0;
+ attnum--;
+
+ /* ----------------
+ * check to see if desired att is null
+ * ----------------
+ */
+
+ if (att_isnull(attnum, bp))
+ {
+ if (isnull)
+ *isnull = true;
+ return NULL;
+ }
+
+ /* ----------------
+ * Now check to see if any preceeding bits are null...
+ * ----------------
+ */
+
+ {
+ register int i = 0; /* current offset in bp */
+
+ for (i = 0; i < attnum && !slow; i++)
+ {
+ if (att_isnull(i, bp))
+ slow = 1;
+ }
+ }
}
- }
-
- /*
- * if slow is zero, and we got here, we know that we have a tuple with
- * no nulls. We also have to initialize the remainder of
- * the attribute cached offset values.
- */
- if (!slow) {
- register int j = 1;
- register long off;
-
+
/*
- * need to set cache for some atts
+ * now check for any non-fixed length attrs before our attribute
*/
-
- att[0]->attcacheoff = 0;
-
- while (att[j]->attcacheoff > 0) j++;
-
- off = att[j-1]->attcacheoff + att[j-1]->attlen;
-
- for (; j < attnum + 1; j++) {
- switch(att[j]->attlen) {
- case -1:
- off = (att[j]->attalign=='d') ?
- DOUBLEALIGN(off) : INTALIGN(off);
- break;
- case sizeof(char):
- break;
- case sizeof(short):
- off = SHORTALIGN(off);
- break;
- case sizeof(int32):
- off = INTALIGN(off);
- break;
- default:
- if (att[j]->attlen < sizeof(int32)) {
- elog(WARN,
- "fastgetattr: attribute %d has len %d",
- j, att[j]->attlen);
+ if (!slow)
+ {
+ if (att[attnum]->attcacheoff > 0)
+ {
+ return (char *)
+ fetchatt(&(att[attnum]),
+ tp + att[attnum]->attcacheoff);
+ }
+ else if (attnum == 0)
+ {
+ return (char *)
+ fetchatt(&(att[0]), (char *) tup + tup->t_hoff);
+ }
+ else if (!HeapTupleAllFixed(tup))
+ {
+ register int j = 0;
+
+ for (j = 0; j < attnum && !slow; j++)
+ if (att[j]->attlen < 1)
+ slow = 1;
}
- if (att[j]->attalign == 'd')
- off = DOUBLEALIGN(off);
- else
- off = LONGALIGN(off);
- break;
- }
-
- att[j]->attcacheoff = off;
- off += att[j]->attlen;
}
-
- return
- (char *)fetchatt(&(att[attnum]), tp + att[attnum]->attcacheoff);
- } else {
- register bool usecache = true;
- register int off = 0;
- register int i;
-
+
/*
- * Now we know that we have to walk the tuple CAREFULLY.
- *
- * Note - This loop is a little tricky. On iteration i we
- * first set the offset for attribute i and figure out how much
- * the offset should be incremented. Finally, we need to align the
- * offset based on the size of attribute i+1 (for which the offset
- * has been computed). -mer 12 Dec 1991
+ * if slow is zero, and we got here, we know that we have a tuple with
+ * no nulls. We also have to initialize the remainder of the
+ * attribute cached offset values.
*/
-
- for (i = 0; i < attnum; i++) {
- if (!HeapTupleNoNulls(tup)) {
- if (att_isnull(i, bp)) {
- usecache = false;
- continue;
- }
- }
- switch (att[i]->attlen) {
- case -1:
- off = (att[i]->attalign=='d') ?
- DOUBLEALIGN(off) : INTALIGN(off);
- break;
- case sizeof(char):
- break;
- case sizeof(short):
- off = SHORTALIGN(off);
- break;
- case sizeof(int32):
- off = INTALIGN(off);
- break;
- default:
- if (att[i]->attlen < sizeof(int32))
- elog(WARN,
- "fastgetattr2: attribute %d has len %d",
- i, att[i]->attlen);
- if (att[i]->attalign == 'd')
- off = DOUBLEALIGN(off);
- else
- off = LONGALIGN(off);
- break;
- }
- if (usecache && att[i]->attcacheoff > 0) {
- off = att[i]->attcacheoff;
- if (att[i]->attlen == -1) {
- usecache = false;
+ if (!slow)
+ {
+ register int j = 1;
+ register long off;
+
+ /*
+ * need to set cache for some atts
+ */
+
+ att[0]->attcacheoff = 0;
+
+ while (att[j]->attcacheoff > 0)
+ j++;
+
+ off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
+
+ for (; j < attnum + 1; j++)
+ {
+ switch (att[j]->attlen)
+ {
+ case -1:
+ off = (att[j]->attalign == 'd') ?
+ DOUBLEALIGN(off) : INTALIGN(off);
+ break;
+ case sizeof(char):
+ break;
+ case sizeof(short):
+ off = SHORTALIGN(off);
+ break;
+ case sizeof(int32):
+ off = INTALIGN(off);
+ break;
+ default:
+ if (att[j]->attlen < sizeof(int32))
+ {
+ elog(WARN,
+ "fastgetattr: attribute %d has len %d",
+ j, att[j]->attlen);
+ }
+ if (att[j]->attalign == 'd')
+ off = DOUBLEALIGN(off);
+ else
+ off = LONGALIGN(off);
+ break;
+ }
+
+ att[j]->attcacheoff = off;
+ off += att[j]->attlen;
}
- } else {
- if (usecache) att[i]->attcacheoff = off;
- }
-
- switch(att[i]->attlen) {
- case sizeof(char):
- off++;
- break;
- case sizeof(int16):
- off += sizeof(int16);
- break;
- case sizeof(int32):
- off += sizeof(int32);
- break;
- case -1:
- usecache = false;
- off += VARSIZE(tp + off);
- break;
- default:
- off += att[i]->attlen;
- break;
- }
+
+ return
+ (char *) fetchatt(&(att[attnum]), tp + att[attnum]->attcacheoff);
}
- switch (att[attnum]->attlen) {
- case -1:
- off = (att[attnum]->attalign=='d')?
- DOUBLEALIGN(off) : INTALIGN(off);
- break;
- case sizeof(char):
- break;
- case sizeof(short):
- off = SHORTALIGN(off);
- break;
- case sizeof(int32):
- off = INTALIGN(off);
- break;
- default:
- if (att[attnum]->attlen < sizeof(int32))
- elog(WARN, "fastgetattr3: attribute %d has len %d",
- attnum, att[attnum]->attlen);
- if (att[attnum]->attalign == 'd')
- off = DOUBLEALIGN(off);
- else
- off = LONGALIGN(off);
- break;
+ else
+ {
+ register bool usecache = true;
+ register int off = 0;
+ register int i;
+
+ /*
+ * Now we know that we have to walk the tuple CAREFULLY.
+ *
+ * Note - This loop is a little tricky. On iteration i we first set
+ * the offset for attribute i and figure out how much the offset
+ * should be incremented. Finally, we need to align the offset
+ * based on the size of attribute i+1 (for which the offset has
+ * been computed). -mer 12 Dec 1991
+ */
+
+ for (i = 0; i < attnum; i++)
+ {
+ if (!HeapTupleNoNulls(tup))
+ {
+ if (att_isnull(i, bp))
+ {
+ usecache = false;
+ continue;
+ }
+ }
+ switch (att[i]->attlen)
+ {
+ case -1:
+ off = (att[i]->attalign == 'd') ?
+ DOUBLEALIGN(off) : INTALIGN(off);
+ break;
+ case sizeof(char):
+ break;
+ case sizeof(short):
+ off = SHORTALIGN(off);
+ break;
+ case sizeof(int32):
+ off = INTALIGN(off);
+ break;
+ default:
+ if (att[i]->attlen < sizeof(int32))
+ elog(WARN,
+ "fastgetattr2: attribute %d has len %d",
+ i, att[i]->attlen);
+ if (att[i]->attalign == 'd')
+ off = DOUBLEALIGN(off);
+ else
+ off = LONGALIGN(off);
+ break;
+ }
+ if (usecache && att[i]->attcacheoff > 0)
+ {
+ off = att[i]->attcacheoff;
+ if (att[i]->attlen == -1)
+ {
+ usecache = false;
+ }
+ }
+ else
+ {
+ if (usecache)
+ att[i]->attcacheoff = off;
+ }
+
+ switch (att[i]->attlen)
+ {
+ case sizeof(char):
+ off++;
+ break;
+ case sizeof(int16):
+ off += sizeof(int16);
+ break;
+ case sizeof(int32):
+ off += sizeof(int32);
+ break;
+ case -1:
+ usecache = false;
+ off += VARSIZE(tp + off);
+ break;
+ default:
+ off += att[i]->attlen;
+ break;
+ }
+ }
+ switch (att[attnum]->attlen)
+ {
+ case -1:
+ off = (att[attnum]->attalign == 'd') ?
+ DOUBLEALIGN(off) : INTALIGN(off);
+ break;
+ case sizeof(char):
+ break;
+ case sizeof(short):
+ off = SHORTALIGN(off);
+ break;
+ case sizeof(int32):
+ off = INTALIGN(off);
+ break;
+ default:
+ if (att[attnum]->attlen < sizeof(int32))
+ elog(WARN, "fastgetattr3: attribute %d has len %d",
+ attnum, att[attnum]->attlen);
+ if (att[attnum]->attalign == 'd')
+ off = DOUBLEALIGN(off);
+ else
+ off = LONGALIGN(off);
+ break;
+ }
+ return ((char *) fetchatt(&(att[attnum]), tp + off));
}
- return((char *) fetchatt(&(att[attnum]), tp + off));
- }
}
/* ----------------
- * heap_copytuple
+ * heap_copytuple
*
- * returns a copy of an entire tuple
+ * returns a copy of an entire tuple
* ----------------
*/
HeapTuple
heap_copytuple(HeapTuple tuple)
{
- HeapTuple newTuple;
+ HeapTuple newTuple;
- if (! HeapTupleIsValid(tuple))
- return (NULL);
-
- /* XXX For now, just prevent an undetectable executor related error */
- if (tuple->t_len > MAXTUPLEN) {
- elog(WARN, "palloctup: cannot handle length %d tuples",
- tuple->t_len);
- }
-
- newTuple = (HeapTuple) palloc(tuple->t_len);
- memmove((char *) newTuple, (char *) tuple, (int) tuple->t_len);
- return(newTuple);
+ if (!HeapTupleIsValid(tuple))
+ return (NULL);
+
+ /* XXX For now, just prevent an undetectable executor related error */
+ if (tuple->t_len > MAXTUPLEN)
+ {
+ elog(WARN, "palloctup: cannot handle length %d tuples",
+ tuple->t_len);
+ }
+
+ newTuple = (HeapTuple) palloc(tuple->t_len);
+ memmove((char *) newTuple, (char *) tuple, (int) tuple->t_len);
+ return (newTuple);
}
#ifdef NOT_USED
/* ----------------
- * heap_deformtuple
+ * heap_deformtuple
*
- * the inverse of heap_formtuple (see below)
+ * the inverse of heap_formtuple (see below)
* ----------------
*/
void
heap_deformtuple(HeapTuple tuple,
- TupleDesc tdesc,
- Datum values[],
- char nulls[])
+ TupleDesc tdesc,
+ Datum values[],
+ char nulls[])
{
- int i;
- int natts;
-
- Assert(HeapTupleIsValid(tuple));
-
- natts = tuple->t_natts;
- for (i = 0; i<natts; i++) {
- bool isnull;
-
- values[i] = (Datum)heap_getattr(tuple,
- InvalidBuffer,
- i+1,
- tdesc,
- &isnull);
- if (isnull)
- nulls[i] = 'n';
- else
- nulls[i] = ' ';
- }
+ int i;
+ int natts;
+
+ Assert(HeapTupleIsValid(tuple));
+
+ natts = tuple->t_natts;
+ for (i = 0; i < natts; i++)
+ {
+ bool isnull;
+
+ values[i] = (Datum) heap_getattr(tuple,
+ InvalidBuffer,
+ i + 1,
+ tdesc,
+ &isnull);
+ if (isnull)
+ nulls[i] = 'n';
+ else
+ nulls[i] = ' ';
+ }
}
+
#endif
/* ----------------
- * heap_formtuple
+ * heap_formtuple
*
- * constructs a tuple from the given value[] and null[] arrays
+ * constructs a tuple from the given value[] and null[] arrays
*
* old comments
- * Handles alignment by aligning 2 byte attributes on short boundries
- * and 3 or 4 byte attributes on long word boundries on a vax; and
- * aligning non-byte attributes on short boundries on a sun. Does
- * not properly align fixed length arrays of 1 or 2 byte types (yet).
+ * Handles alignment by aligning 2 byte attributes on short boundries
+ * and 3 or 4 byte attributes on long word boundries on a vax; and
+ * aligning non-byte attributes on short boundries on a sun. Does
+ * not properly align fixed length arrays of 1 or 2 byte types (yet).
*
- * Null attributes are indicated by a 'n' in the appropriate byte
- * of the null[]. Non-null attributes are indicated by a ' ' (space).
+ * Null attributes are indicated by a 'n' in the appropriate byte
+ * of the null[]. Non-null attributes are indicated by a ' ' (space).
*
- * Fix me. (Figure that must keep context if debug--allow give oid.)
- * Assumes in order.
+ * Fix me. (Figure that must keep context if debug--allow give oid.)
+ * Assumes in order.
* ----------------
*/
HeapTuple
heap_formtuple(TupleDesc tupleDescriptor,
- Datum value[],
- char nulls[])
+ Datum value[],
+ char nulls[])
{
- char *tp; /* tuple pointer */
- HeapTuple tuple; /* return tuple */
- int bitmaplen;
- long len;
- int hoff;
- bool hasnull = false;
- int i;
- int numberOfAttributes = tupleDescriptor->natts;
-
- len = sizeof *tuple - sizeof tuple->t_bits;
-
- for (i = 0; i < numberOfAttributes && !hasnull; i++) {
- if (nulls[i] != ' ') hasnull = true;
- }
-
- if (numberOfAttributes > MaxHeapAttributeNumber)
- elog(WARN, "heap_formtuple: numberOfAttributes of %d > %d",
- numberOfAttributes, MaxHeapAttributeNumber);
-
- if (hasnull) {
- bitmaplen = BITMAPLEN(numberOfAttributes);
- len += bitmaplen;
- }
-
- hoff = len = DOUBLEALIGN(len); /* be conservative here */
-
- len += ComputeDataSize(tupleDescriptor, value, nulls);
-
- tp = (char *) palloc(len);
- tuple = (HeapTuple) tp;
-
- memset(tp, 0, (int)len);
-
- tuple->t_len = len;
- tuple->t_natts = numberOfAttributes;
- tuple->t_hoff = hoff;
- tuple->t_tmin = INVALID_ABSTIME;
- tuple->t_tmax = CURRENT_ABSTIME;
-
- DataFill((char *)tuple + tuple->t_hoff,
- tupleDescriptor,
- value,
- nulls,
- &tuple->t_infomask,
- (hasnull ? tuple->t_bits : NULL));
-
- return (tuple);
+ char *tp; /* tuple pointer */
+ HeapTuple tuple; /* return tuple */
+ int bitmaplen;
+ long len;
+ int hoff;
+ bool hasnull = false;
+ int i;
+ int numberOfAttributes = tupleDescriptor->natts;
+
+ len = sizeof *tuple - sizeof tuple->t_bits;
+
+ for (i = 0; i < numberOfAttributes && !hasnull; i++)
+ {
+ if (nulls[i] != ' ')
+ hasnull = true;
+ }
+
+ if (numberOfAttributes > MaxHeapAttributeNumber)
+ elog(WARN, "heap_formtuple: numberOfAttributes of %d > %d",
+ numberOfAttributes, MaxHeapAttributeNumber);
+
+ if (hasnull)
+ {
+ bitmaplen = BITMAPLEN(numberOfAttributes);
+ len += bitmaplen;
+ }
+
+ hoff = len = DOUBLEALIGN(len); /* be conservative here */
+
+ len += ComputeDataSize(tupleDescriptor, value, nulls);
+
+ tp = (char *) palloc(len);
+ tuple = (HeapTuple) tp;
+
+ memset(tp, 0, (int) len);
+
+ tuple->t_len = len;
+ tuple->t_natts = numberOfAttributes;
+ tuple->t_hoff = hoff;
+ tuple->t_tmin = INVALID_ABSTIME;
+ tuple->t_tmax = CURRENT_ABSTIME;
+
+ DataFill((char *) tuple + tuple->t_hoff,
+ tupleDescriptor,
+ value,
+ nulls,
+ &tuple->t_infomask,
+ (hasnull ? tuple->t_bits : NULL));
+
+ return (tuple);
}
/* ----------------
- * heap_modifytuple
+ * heap_modifytuple
*
- * forms a new tuple from an old tuple and a set of replacement values.
+ * forms a new tuple from an old tuple and a set of replacement values.
* ----------------
*/
HeapTuple
heap_modifytuple(HeapTuple tuple,
- Buffer buffer,
- Relation relation,
- Datum replValue[],
- char replNull[],
- char repl[])
+ Buffer buffer,
+ Relation relation,
+ Datum replValue[],
+ char replNull[],
+ char repl[])
{
- int attoff;
- int numberOfAttributes;
- Datum *value;
- char *nulls;
- bool isNull;
- HeapTuple newTuple;
- int madecopy;
- uint8 infomask;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(HeapTupleIsValid(tuple));
- Assert(BufferIsValid(buffer) || RelationIsValid(relation));
- Assert(HeapTupleIsValid(tuple));
- Assert(PointerIsValid(replValue));
- Assert(PointerIsValid(replNull));
- Assert(PointerIsValid(repl));
-
- /* ----------------
- * if we're pointing to a disk page, then first
- * make a copy of our tuple so that all the attributes
- * are available. XXX this is inefficient -cim
- * ----------------
- */
- madecopy = 0;
- if (BufferIsValid(buffer) == true) {
- relation = (Relation) BufferGetRelation(buffer);
- tuple = heap_copytuple(tuple);
- madecopy = 1;
- }
-
- numberOfAttributes = RelationGetRelationTupleForm(relation)->relnatts;
-
- /* ----------------
- * allocate and fill value[] and nulls[] arrays from either
- * the tuple or the repl information, as appropriate.
- * ----------------
- */
- value = (Datum *) palloc(numberOfAttributes * sizeof *value);
- nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
-
- for (attoff = 0;
- attoff < numberOfAttributes;
- attoff += 1) {
-
- if (repl[attoff] == ' ') {
- char *attr;
-
- attr =
- heap_getattr(tuple,
- InvalidBuffer,
- AttrOffsetGetAttrNumber(attoff),
- RelationGetTupleDescriptor(relation),
- &isNull) ;
- value[attoff] = PointerGetDatum(attr);
- nulls[attoff] = (isNull) ? 'n' : ' ';
-
- } else if (repl[attoff] != 'r') {
- elog(WARN, "heap_modifytuple: repl is \\%3d", repl[attoff]);
-
- } else { /* == 'r' */
- value[attoff] = replValue[attoff];
- nulls[attoff] = replNull[attoff];
+ int attoff;
+ int numberOfAttributes;
+ Datum *value;
+ char *nulls;
+ bool isNull;
+ HeapTuple newTuple;
+ int madecopy;
+ uint8 infomask;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(HeapTupleIsValid(tuple));
+ Assert(BufferIsValid(buffer) || RelationIsValid(relation));
+ Assert(HeapTupleIsValid(tuple));
+ Assert(PointerIsValid(replValue));
+ Assert(PointerIsValid(replNull));
+ Assert(PointerIsValid(repl));
+
+ /* ----------------
+ * if we're pointing to a disk page, then first
+ * make a copy of our tuple so that all the attributes
+ * are available. XXX this is inefficient -cim
+ * ----------------
+ */
+ madecopy = 0;
+ if (BufferIsValid(buffer) == true)
+ {
+ relation = (Relation) BufferGetRelation(buffer);
+ tuple = heap_copytuple(tuple);
+ madecopy = 1;
+ }
+
+ numberOfAttributes = RelationGetRelationTupleForm(relation)->relnatts;
+
+ /* ----------------
+ * allocate and fill value[] and nulls[] arrays from either
+ * the tuple or the repl information, as appropriate.
+ * ----------------
+ */
+ value = (Datum *) palloc(numberOfAttributes * sizeof *value);
+ nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
+
+ for (attoff = 0;
+ attoff < numberOfAttributes;
+ attoff += 1)
+ {
+
+ if (repl[attoff] == ' ')
+ {
+ char *attr;
+
+ attr =
+ heap_getattr(tuple,
+ InvalidBuffer,
+ AttrOffsetGetAttrNumber(attoff),
+ RelationGetTupleDescriptor(relation),
+ &isNull);
+ value[attoff] = PointerGetDatum(attr);
+ nulls[attoff] = (isNull) ? 'n' : ' ';
+
+ }
+ else if (repl[attoff] != 'r')
+ {
+ elog(WARN, "heap_modifytuple: repl is \\%3d", repl[attoff]);
+
+ }
+ else
+ { /* == 'r' */
+ value[attoff] = replValue[attoff];
+ nulls[attoff] = replNull[attoff];
+ }
}
- }
-
- /* ----------------
- * create a new tuple from the values[] and nulls[] arrays
- * ----------------
- */
- newTuple = heap_formtuple(RelationGetTupleDescriptor(relation),
- value,
- nulls);
-
- /* ----------------
- * copy the header except for t_len, t_natts, t_hoff, t_bits, t_infomask
- * ----------------
- */
- infomask = newTuple->t_infomask;
- memmove((char *) &newTuple->t_ctid, /*XXX*/
- (char *) &tuple->t_ctid,
- ((char *) &tuple->t_hoff - (char *) &tuple->t_ctid)); /*XXX*/
- newTuple->t_infomask = infomask;
- newTuple->t_natts = numberOfAttributes; /* fix t_natts just in case */
-
- /* ----------------
- * if we made a copy of the tuple, then free it.
- * ----------------
- */
- if (madecopy)
- pfree(tuple);
-
- return
- newTuple;
+
+ /* ----------------
+ * create a new tuple from the values[] and nulls[] arrays
+ * ----------------
+ */
+ newTuple = heap_formtuple(RelationGetTupleDescriptor(relation),
+ value,
+ nulls);
+
+ /* ----------------
+ * copy the header except for t_len, t_natts, t_hoff, t_bits, t_infomask
+ * ----------------
+ */
+ infomask = newTuple->t_infomask;
+ memmove((char *) &newTuple->t_ctid, /* XXX */
+ (char *) &tuple->t_ctid,
+ ((char *) &tuple->t_hoff - (char *) &tuple->t_ctid)); /* XXX */
+ newTuple->t_infomask = infomask;
+ newTuple->t_natts = numberOfAttributes; /* fix t_natts just in
+ * case */
+
+ /* ----------------
+ * if we made a copy of the tuple, then free it.
+ * ----------------
+ */
+ if (madecopy)
+ pfree(tuple);
+
+ return
+ newTuple;
}
/* ----------------------------------------------------------------
- * other misc functions
+ * other misc functions
* ----------------------------------------------------------------
*/
HeapTuple
heap_addheader(uint32 natts, /* max domain index */
- int structlen, /* its length */
- char *structure) /* pointer to the struct */
+ int structlen, /* its length */
+ char *structure) /* pointer to the struct */
{
- register char *tp; /* tuple data pointer */
- HeapTuple tup;
- long len;
- int hoff;
-
- AssertArg(natts > 0);
-
- len = sizeof (HeapTupleData) - sizeof (tup->t_bits);
-
- hoff = len = DOUBLEALIGN(len); /* be conservative */
- len += structlen;
- tp = (char *) palloc(len);
- tup = (HeapTuple) tp;
- memset((char*)tup, 0, len);
-
- tup->t_len = (short) len; /* XXX */
- tp += tup->t_hoff = hoff;
- tup->t_natts = natts;
- tup->t_infomask = 0;
-
- memmove(tp, structure, structlen);
-
- return (tup);
+ register char *tp; /* tuple data pointer */
+ HeapTuple tup;
+ long len;
+ int hoff;
+
+ AssertArg(natts > 0);
+
+ len = sizeof(HeapTupleData) - sizeof(tup->t_bits);
+
+ hoff = len = DOUBLEALIGN(len); /* be conservative */
+ len += structlen;
+ tp = (char *) palloc(len);
+ tup = (HeapTuple) tp;
+ memset((char *) tup, 0, len);
+
+ tup->t_len = (short) len; /* XXX */
+ tp += tup->t_hoff = hoff;
+ tup->t_natts = natts;
+ tup->t_infomask = 0;
+
+ memmove(tp, structure, structlen);
+
+ return (tup);
}
diff --git a/src/backend/access/common/heapvalid.c b/src/backend/access/common/heapvalid.c
index 186ee654b32..0caeb54e17c 100644
--- a/src/backend/access/common/heapvalid.c
+++ b/src/backend/access/common/heapvalid.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* heapvalid.c--
- * heap tuple qualification validity checking code
+ * heap tuple qualification validity checking code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/Attic/heapvalid.c,v 1.16 1997/08/29 09:12:20 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/Attic/heapvalid.c,v 1.17 1997/09/07 04:37:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,128 +25,138 @@
#include <utils/builtins.h>
/* ----------------
- * heap_keytest
+ * heap_keytest
*
- * Test a heap tuple with respect to a scan key.
+ * Test a heap tuple with respect to a scan key.
* ----------------
*/
bool
heap_keytest(HeapTuple t,
- TupleDesc tupdesc,
- int nkeys,
- ScanKey keys)
+ TupleDesc tupdesc,
+ int nkeys,
+ ScanKey keys)
{
- bool isnull;
- Datum atp;
- int test;
-
- for (; nkeys--; keys++) {
- atp = (Datum)heap_getattr(t, InvalidBuffer,
- keys->sk_attno,
- tupdesc,
- &isnull);
-
- if (isnull)
- /* XXX eventually should check if SK_ISNULL */
- return false;
-
- if (keys->sk_flags & SK_ISNULL) {
- return (false);
+ bool isnull;
+ Datum atp;
+ int test;
+
+ for (; nkeys--; keys++)
+ {
+ atp = (Datum) heap_getattr(t, InvalidBuffer,
+ keys->sk_attno,
+ tupdesc,
+ &isnull);
+
+ if (isnull)
+ /* XXX eventually should check if SK_ISNULL */
+ return false;
+
+ if (keys->sk_flags & SK_ISNULL)
+ {
+ return (false);
+ }
+
+ if (keys->sk_func == (func_ptr) oideq) /* optimization */
+ test = (keys->sk_argument == atp);
+ else if (keys->sk_flags & SK_COMMUTE)
+ test = (long) FMGR_PTR2(keys->sk_func, keys->sk_procedure,
+ keys->sk_argument, atp);
+ else
+ test = (long) FMGR_PTR2(keys->sk_func, keys->sk_procedure,
+ atp, keys->sk_argument);
+
+ if (!test == !(keys->sk_flags & SK_NEGATE))
+ return false;
}
- if (keys->sk_func == (func_ptr)oideq) /* optimization */
- test = (keys->sk_argument == atp);
- else if (keys->sk_flags & SK_COMMUTE)
- test = (long) FMGR_PTR2(keys->sk_func, keys->sk_procedure,
- keys->sk_argument, atp);
- else
- test = (long) FMGR_PTR2(keys->sk_func, keys->sk_procedure,
- atp, keys->sk_argument);
-
- if (!test == !(keys->sk_flags & SK_NEGATE))
- return false;
- }
-
- return true;
+ return true;
}
/* ----------------
- * heap_tuple_satisfies
+ * heap_tuple_satisfies
*
- * Returns a valid HeapTuple if it satisfies the timequal and keytest.
- * Returns NULL otherwise. Used to be heap_satisifies (sic) which
- * returned a boolean. It now returns a tuple so that we can avoid doing two
- * PageGetItem's per tuple.
+ * Returns a valid HeapTuple if it satisfies the timequal and keytest.
+ * Returns NULL otherwise. Used to be heap_satisifies (sic) which
+ * returned a boolean. It now returns a tuple so that we can avoid doing two
+ * PageGetItem's per tuple.
*
- * Complete check of validity including LP_CTUP and keytest.
- * This should perhaps be combined with valid somehow in the
- * future. (Also, additional rule tests/time range tests.)
+ * Complete check of validity including LP_CTUP and keytest.
+ * This should perhaps be combined with valid somehow in the
+ * future. (Also, additional rule tests/time range tests.)
*
- * on 8/21/92 mao says: i rearranged the tests here to do keytest before
- * SatisfiesTimeQual. profiling indicated that even for vacuumed relations,
- * time qual checking was more expensive than key testing. time qual is
- * least likely to fail, too. we should really add the time qual test to
- * the restriction and optimize it in the normal way. this has interactions
- * with joey's expensive function work.
+ * on 8/21/92 mao says: i rearranged the tests here to do keytest before
+ * SatisfiesTimeQual. profiling indicated that even for vacuumed relations,
+ * time qual checking was more expensive than key testing. time qual is
+ * least likely to fail, too. we should really add the time qual test to
+ * the restriction and optimize it in the normal way. this has interactions
+ * with joey's expensive function work.
* ----------------
*/
HeapTuple
heap_tuple_satisfies(ItemId itemId,
- Relation relation,
- Buffer buffer,
- PageHeader disk_page,
- TimeQual qual,
- int nKeys,
- ScanKey key)
+ Relation relation,
+ Buffer buffer,
+ PageHeader disk_page,
+ TimeQual qual,
+ int nKeys,
+ ScanKey key)
{
- HeapTuple tuple, result;
- bool res;
- TransactionId old_tmin, old_tmax;
-
- if (! ItemIdIsUsed(itemId))
- return NULL;
-
- tuple = (HeapTuple) PageGetItem((Page) disk_page, itemId);
-
- if (key != NULL)
- res = heap_keytest(tuple, RelationGetTupleDescriptor(relation),
- nKeys, key);
- else
- res = TRUE;
-
- result = (HeapTuple)NULL;
- if (res) {
- if(relation->rd_rel->relkind == RELKIND_UNCATALOGED) {
- result = tuple;
- } else {
- old_tmin = tuple->t_tmin;
- old_tmax = tuple->t_tmax;
- res = HeapTupleSatisfiesTimeQual(tuple,qual);
- if(tuple->t_tmin != old_tmin ||
- tuple->t_tmax != old_tmax) {
- SetBufferCommitInfoNeedsSave(buffer);
- }
- if(res) {
- result = tuple;
- }
+ HeapTuple tuple,
+ result;
+ bool res;
+ TransactionId old_tmin,
+ old_tmax;
+
+ if (!ItemIdIsUsed(itemId))
+ return NULL;
+
+ tuple = (HeapTuple) PageGetItem((Page) disk_page, itemId);
+
+ if (key != NULL)
+ res = heap_keytest(tuple, RelationGetTupleDescriptor(relation),
+ nKeys, key);
+ else
+ res = TRUE;
+
+ result = (HeapTuple) NULL;
+ if (res)
+ {
+ if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
+ {
+ result = tuple;
+ }
+ else
+ {
+ old_tmin = tuple->t_tmin;
+ old_tmax = tuple->t_tmax;
+ res = HeapTupleSatisfiesTimeQual(tuple, qual);
+ if (tuple->t_tmin != old_tmin ||
+ tuple->t_tmax != old_tmax)
+ {
+ SetBufferCommitInfoNeedsSave(buffer);
+ }
+ if (res)
+ {
+ result = tuple;
+ }
+ }
}
- }
- return result;
+ return result;
}
/*
- * TupleUpdatedByCurXactAndCmd() -- Returns true if this tuple has
- * already been updated once by the current transaction/command
- * pair.
+ * TupleUpdatedByCurXactAndCmd() -- Returns true if this tuple has
+ * already been updated once by the current transaction/command
+ * pair.
*/
bool
TupleUpdatedByCurXactAndCmd(HeapTuple t)
{
- if (TransactionIdEquals(t->t_xmax,
- GetCurrentTransactionId()) &&
- CommandIdGEScanCommandId (t->t_cmax))
- return true;
-
- return false;
+ if (TransactionIdEquals(t->t_xmax,
+ GetCurrentTransactionId()) &&
+ CommandIdGEScanCommandId(t->t_cmax))
+ return true;
+
+ return false;
}
diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c
index a71fc46dc98..c133693801b 100644
--- a/src/backend/access/common/indextuple.c
+++ b/src/backend/access/common/indextuple.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* indextuple.c--
- * This file contains index tuple accessor and mutator routines,
- * as well as a few various tuple utilities.
+ * This file contains index tuple accessor and mutator routines,
+ * as well as a few various tuple utilities.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.15 1997/08/19 21:28:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.16 1997/09/07 04:37:37 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,402 +21,438 @@
#include <access/tupmacs.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static Size IndexInfoFindDataOffset(unsigned short t_info);
-static char *fastgetiattr(IndexTuple tup, int attnum,
- TupleDesc att, bool *isnull);
+static Size IndexInfoFindDataOffset(unsigned short t_info);
+static char *
+fastgetiattr(IndexTuple tup, int attnum,
+ TupleDesc att, bool * isnull);
/* ----------------------------------------------------------------
- * index_ tuple interface routines
+ * index_ tuple interface routines
* ----------------------------------------------------------------
*/
/* ----------------
- * index_formtuple
+ * index_formtuple
* ----------------
*/
IndexTuple
index_formtuple(TupleDesc tupleDescriptor,
- Datum value[],
- char null[])
+ Datum value[],
+ char null[])
{
- register char *tp; /* tuple pointer */
- IndexTuple tuple; /* return tuple */
- Size size, hoff;
- int i;
- unsigned short infomask = 0;
- bool hasnull = false;
- char tupmask = 0;
- int numberOfAttributes = tupleDescriptor->natts;
-
- if (numberOfAttributes > MaxIndexAttributeNumber)
- elog(WARN, "index_formtuple: numberOfAttributes of %d > %d",
- numberOfAttributes, MaxIndexAttributeNumber);
-
-
- for (i = 0; i < numberOfAttributes && !hasnull; i++) {
- if (null[i] != ' ') hasnull = true;
- }
-
- if (hasnull) infomask |= INDEX_NULL_MASK;
-
- hoff = IndexInfoFindDataOffset(infomask);
- size = hoff
- + ComputeDataSize(tupleDescriptor,
- value, null);
- size = DOUBLEALIGN(size); /* be conservative */
-
- tp = (char *) palloc(size);
- tuple = (IndexTuple) tp;
- memset(tp,0,(int)size);
-
- DataFill((char *)tp + hoff,
- tupleDescriptor,
- value,
- null,
- &tupmask,
- (hasnull ? (bits8*)tp + sizeof(*tuple) : NULL));
-
- /*
- * We do this because DataFill wants to initialize a "tupmask" which
- * is used for HeapTuples, but we want an indextuple infomask. The only
- * "relevent" info is the "has variable attributes" field, which is in
- * mask position 0x02. We have already set the null mask above.
- */
-
- if (tupmask & 0x02) infomask |= INDEX_VAR_MASK;
-
- /*
- * Here we make sure that we can actually hold the size. We also want
- * to make sure that size is not aligned oddly. This actually is a
- * rather odd way to make sure the size is not too large overall.
- */
-
- if (size & 0xE000)
- elog(WARN, "index_formtuple: data takes %d bytes: too big", size);
-
-
- infomask |= size;
-
- /* ----------------
- * initialize metadata
- * ----------------
- */
- tuple->t_info = infomask;
- return (tuple);
+ register char *tp; /* tuple pointer */
+ IndexTuple tuple; /* return tuple */
+ Size size,
+ hoff;
+ int i;
+ unsigned short infomask = 0;
+ bool hasnull = false;
+ char tupmask = 0;
+ int numberOfAttributes = tupleDescriptor->natts;
+
+ if (numberOfAttributes > MaxIndexAttributeNumber)
+ elog(WARN, "index_formtuple: numberOfAttributes of %d > %d",
+ numberOfAttributes, MaxIndexAttributeNumber);
+
+
+ for (i = 0; i < numberOfAttributes && !hasnull; i++)
+ {
+ if (null[i] != ' ')
+ hasnull = true;
+ }
+
+ if (hasnull)
+ infomask |= INDEX_NULL_MASK;
+
+ hoff = IndexInfoFindDataOffset(infomask);
+ size = hoff
+ + ComputeDataSize(tupleDescriptor,
+ value, null);
+ size = DOUBLEALIGN(size); /* be conservative */
+
+ tp = (char *) palloc(size);
+ tuple = (IndexTuple) tp;
+ memset(tp, 0, (int) size);
+
+ DataFill((char *) tp + hoff,
+ tupleDescriptor,
+ value,
+ null,
+ &tupmask,
+ (hasnull ? (bits8 *) tp + sizeof(*tuple) : NULL));
+
+ /*
+ * We do this because DataFill wants to initialize a "tupmask" which
+ * is used for HeapTuples, but we want an indextuple infomask. The
+ * only "relevent" info is the "has variable attributes" field, which
+ * is in mask position 0x02. We have already set the null mask above.
+ */
+
+ if (tupmask & 0x02)
+ infomask |= INDEX_VAR_MASK;
+
+ /*
+ * Here we make sure that we can actually hold the size. We also want
+ * to make sure that size is not aligned oddly. This actually is a
+ * rather odd way to make sure the size is not too large overall.
+ */
+
+ if (size & 0xE000)
+ elog(WARN, "index_formtuple: data takes %d bytes: too big", size);
+
+
+ infomask |= size;
+
+ /* ----------------
+ * initialize metadata
+ * ----------------
+ */
+ tuple->t_info = infomask;
+ return (tuple);
}
/* ----------------
- * fastgetiattr
+ * fastgetiattr
*
- * This is a newer version of fastgetiattr which attempts to be
- * faster by caching attribute offsets in the attribute descriptor.
+ * This is a newer version of fastgetiattr which attempts to be
+ * faster by caching attribute offsets in the attribute descriptor.
*
- * an alternate way to speed things up would be to cache offsets
- * with the tuple, but that seems more difficult unless you take
- * the storage hit of actually putting those offsets into the
- * tuple you send to disk. Yuck.
+ * an alternate way to speed things up would be to cache offsets
+ * with the tuple, but that seems more difficult unless you take
+ * the storage hit of actually putting those offsets into the
+ * tuple you send to disk. Yuck.
*
- * This scheme will be slightly slower than that, but should
- * preform well for queries which hit large #'s of tuples. After
- * you cache the offsets once, examining all the other tuples using
- * the same attribute descriptor will go much quicker. -cim 5/4/91
+ * This scheme will be slightly slower than that, but should
+ * preform well for queries which hit large #'s of tuples. After
+ * you cache the offsets once, examining all the other tuples using
+ * the same attribute descriptor will go much quicker. -cim 5/4/91
* ----------------
*/
-static char *
+static char *
fastgetiattr(IndexTuple tup,
- int attnum,
- TupleDesc tupleDesc,
- bool *isnull)
+ int attnum,
+ TupleDesc tupleDesc,
+ bool * isnull)
{
- register char *tp; /* ptr to att in tuple */
- register char *bp = NULL; /* ptr to att in tuple */
- int slow; /* do we have to walk nulls? */
- register int data_off; /* tuple data offset */
- AttributeTupleForm *att = tupleDesc->attrs;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
-
- Assert(PointerIsValid(isnull));
- Assert(attnum > 0);
-
- /* ----------------
- * Three cases:
- *
- * 1: No nulls and no variable length attributes.
- * 2: Has a null or a varlena AFTER att.
- * 3: Has nulls or varlenas BEFORE att.
- * ----------------
- */
-
- *isnull = false;
- data_off = IndexTupleHasMinHeader(tup) ? sizeof *tup :
- IndexInfoFindDataOffset(tup->t_info);
-
- if (IndexTupleNoNulls(tup)) {
-
- /* first attribute is always at position zero */
-
- if (attnum == 1) {
- return(fetchatt(&(att[0]), (char *) tup + data_off));
- }
- attnum--;
-
- if (att[attnum]->attcacheoff > 0) {
- return(fetchatt(&(att[attnum]),
- (char *) tup + data_off +
- att[attnum]->attcacheoff));
- }
-
- tp = (char *) tup + data_off;
-
- slow = 0;
- }else { /* there's a null somewhere in the tuple */
-
- bp = (char *) tup + sizeof(*tup); /* "knows" t_bits are here! */
- slow = 0;
+ register char *tp; /* ptr to att in tuple */
+ register char *bp = NULL; /* ptr to att in tuple */
+ int slow; /* do we have to walk nulls? */
+ register int data_off; /* tuple data offset */
+ AttributeTupleForm *att = tupleDesc->attrs;
+
/* ----------------
- * check to see if desired att is null
+ * sanity checks
* ----------------
*/
-
- attnum--;
- {
- if (att_isnull(attnum, bp)) {
- *isnull = true;
- return NULL;
- }
- }
+
+ Assert(PointerIsValid(isnull));
+ Assert(attnum > 0);
+
/* ----------------
- * Now check to see if any preceeding bits are null...
+ * Three cases:
+ *
+ * 1: No nulls and no variable length attributes.
+ * 2: Has a null or a varlena AFTER att.
+ * 3: Has nulls or varlenas BEFORE att.
* ----------------
*/
+
+ *isnull = false;
+ data_off = IndexTupleHasMinHeader(tup) ? sizeof *tup :
+ IndexInfoFindDataOffset(tup->t_info);
+
+ if (IndexTupleNoNulls(tup))
{
- register int i = 0; /* current offset in bp */
- register int mask; /* bit in byte we're looking at */
- register char n; /* current byte in bp */
- register int byte, finalbit;
-
- byte = attnum >> 3;
- finalbit = attnum & 0x07;
-
- for (; i <= byte; i++) {
- n = bp[i];
- if (i < byte) {
- /* check for nulls in any "earlier" bytes */
- if ((~n) != 0) {
- slow++;
- break;
- }
- } else {
- /* check for nulls "before" final bit of last byte*/
- mask = (finalbit << 1) - 1;
- if ((~n) & mask)
- slow++;
+
+ /* first attribute is always at position zero */
+
+ if (attnum == 1)
+ {
+ return (fetchatt(&(att[0]), (char *) tup + data_off));
+ }
+ attnum--;
+
+ if (att[attnum]->attcacheoff > 0)
+ {
+ return (fetchatt(&(att[attnum]),
+ (char *) tup + data_off +
+ att[attnum]->attcacheoff));
}
- }
+
+ tp = (char *) tup + data_off;
+
+ slow = 0;
}
- tp = (char *) tup + data_off;
- }
-
- /* now check for any non-fixed length attrs before our attribute */
-
- if (!slow) {
- if (att[attnum]->attcacheoff > 0) {
- return(fetchatt(&(att[attnum]),
- tp + att[attnum]->attcacheoff));
- }else if (!IndexTupleAllFixed(tup)) {
- register int j = 0;
-
- for (j = 0; j < attnum && !slow; j++)
- if (att[j]->attlen < 1) slow = 1;
+ else
+ { /* there's a null somewhere in the tuple */
+
+ bp = (char *) tup + sizeof(*tup); /* "knows" t_bits are
+ * here! */
+ slow = 0;
+ /* ----------------
+ * check to see if desired att is null
+ * ----------------
+ */
+
+ attnum--;
+ {
+ if (att_isnull(attnum, bp))
+ {
+ *isnull = true;
+ return NULL;
+ }
+ }
+ /* ----------------
+ * Now check to see if any preceeding bits are null...
+ * ----------------
+ */
+ {
+ register int i = 0; /* current offset in bp */
+ register int mask; /* bit in byte we're looking at */
+ register char n; /* current byte in bp */
+ register int byte,
+ finalbit;
+
+ byte = attnum >> 3;
+ finalbit = attnum & 0x07;
+
+ for (; i <= byte; i++)
+ {
+ n = bp[i];
+ if (i < byte)
+ {
+ /* check for nulls in any "earlier" bytes */
+ if ((~n) != 0)
+ {
+ slow++;
+ break;
+ }
+ }
+ else
+ {
+ /* check for nulls "before" final bit of last byte */
+ mask = (finalbit << 1) - 1;
+ if ((~n) & mask)
+ slow++;
+ }
+ }
+ }
+ tp = (char *) tup + data_off;
}
- }
-
- /*
- * if slow is zero, and we got here, we know that we have a tuple with
- * no nulls. We also know that we have to initialize the remainder of
- * the attribute cached offset values.
- */
-
- if (!slow) {
- register int j = 1;
- register long off;
-
- /*
- * need to set cache for some atts
- */
-
- att[0]->attcacheoff = 0;
-
- while (att[j]->attcacheoff > 0) j++;
-
- off = att[j-1]->attcacheoff +
- att[j-1]->attlen;
-
- for (; j < attnum + 1; j++) {
- /*
- * Fix me when going to a machine with more than a four-byte
- * word!
- */
-
- switch(att[j]->attlen)
+
+ /* now check for any non-fixed length attrs before our attribute */
+
+ if (!slow)
+ {
+ if (att[attnum]->attcacheoff > 0)
{
- case -1:
- off = (att[j]->attalign=='d')?
- DOUBLEALIGN(off):INTALIGN(off);
- break;
- case sizeof(char):
- break;
- case sizeof(short):
- off = SHORTALIGN(off);
- break;
- case sizeof(int32):
- off = INTALIGN(off);
- break;
- default:
- if (att[j]->attlen > sizeof(int32))
- off = (att[j]->attalign=='d')?
- DOUBLEALIGN(off) : LONGALIGN(off);
- else
- elog(WARN, "fastgetiattr: attribute %d has len %d",
- j, att[j]->attlen);
- break;
-
+ return (fetchatt(&(att[attnum]),
+ tp + att[attnum]->attcacheoff));
+ }
+ else if (!IndexTupleAllFixed(tup))
+ {
+ register int j = 0;
+
+ for (j = 0; j < attnum && !slow; j++)
+ if (att[j]->attlen < 1)
+ slow = 1;
}
-
- att[j]->attcacheoff = off;
- off += att[j]->attlen;
}
-
- return(fetchatt( &(att[attnum]),
- tp + att[attnum]->attcacheoff));
- }else {
- register bool usecache = true;
- register int off = 0;
- register int i;
-
+
/*
- * Now we know that we have to walk the tuple CAREFULLY.
+ * if slow is zero, and we got here, we know that we have a tuple with
+ * no nulls. We also know that we have to initialize the remainder of
+ * the attribute cached offset values.
*/
-
- for (i = 0; i < attnum; i++) {
- if (!IndexTupleNoNulls(tup)) {
- if (att_isnull(i, bp)) {
- usecache = false;
- continue;
+
+ if (!slow)
+ {
+ register int j = 1;
+ register long off;
+
+ /*
+ * need to set cache for some atts
+ */
+
+ att[0]->attcacheoff = 0;
+
+ while (att[j]->attcacheoff > 0)
+ j++;
+
+ off = att[j - 1]->attcacheoff +
+ att[j - 1]->attlen;
+
+ for (; j < attnum + 1; j++)
+ {
+
+ /*
+ * Fix me when going to a machine with more than a four-byte
+ * word!
+ */
+
+ switch (att[j]->attlen)
+ {
+ case -1:
+ off = (att[j]->attalign == 'd') ?
+ DOUBLEALIGN(off) : INTALIGN(off);
+ break;
+ case sizeof(char):
+ break;
+ case sizeof(short):
+ off = SHORTALIGN(off);
+ break;
+ case sizeof(int32):
+ off = INTALIGN(off);
+ break;
+ default:
+ if (att[j]->attlen > sizeof(int32))
+ off = (att[j]->attalign == 'd') ?
+ DOUBLEALIGN(off) : LONGALIGN(off);
+ else
+ elog(WARN, "fastgetiattr: attribute %d has len %d",
+ j, att[j]->attlen);
+ break;
+
+ }
+
+ att[j]->attcacheoff = off;
+ off += att[j]->attlen;
}
- }
-
- if (usecache && att[i]->attcacheoff > 0) {
- off = att[i]->attcacheoff;
- if (att[i]->attlen == -1)
- usecache = false;
- else
- continue;
- }
-
- if (usecache) att[i]->attcacheoff = off;
- switch(att[i]->attlen)
+
+ return (fetchatt(&(att[attnum]),
+ tp + att[attnum]->attcacheoff));
+ }
+ else
+ {
+ register bool usecache = true;
+ register int off = 0;
+ register int i;
+
+ /*
+ * Now we know that we have to walk the tuple CAREFULLY.
+ */
+
+ for (i = 0; i < attnum; i++)
{
+ if (!IndexTupleNoNulls(tup))
+ {
+ if (att_isnull(i, bp))
+ {
+ usecache = false;
+ continue;
+ }
+ }
+
+ if (usecache && att[i]->attcacheoff > 0)
+ {
+ off = att[i]->attcacheoff;
+ if (att[i]->attlen == -1)
+ usecache = false;
+ else
+ continue;
+ }
+
+ if (usecache)
+ att[i]->attcacheoff = off;
+ switch (att[i]->attlen)
+ {
+ case sizeof(char):
+ off++;
+ break;
+ case sizeof(short):
+ off = SHORTALIGN(off) +sizeof(short);
+ break;
+ case sizeof(int32):
+ off = INTALIGN(off) + sizeof(int32);
+ break;
+ case -1:
+ usecache = false;
+ off = (att[i]->attalign == 'd') ?
+ DOUBLEALIGN(off) : INTALIGN(off);
+ off += VARSIZE(tp + off);
+ break;
+ default:
+ if (att[i]->attlen > sizeof(int32))
+ off = (att[i]->attalign == 'd') ?
+ DOUBLEALIGN(off) + att[i]->attlen :
+ LONGALIGN(off) + att[i]->attlen;
+ else
+ elog(WARN, "fastgetiattr2: attribute %d has len %d",
+ i, att[i]->attlen);
+
+ break;
+ }
+ }
+
+ /*
+ * I don't know why this code was missed here! I've got it from
+ * heaptuple.c:fastgetattr(). - vadim 06/12/97
+ */
+ switch (att[attnum]->attlen)
+ {
+ case -1:
+ off = (att[attnum]->attalign == 'd') ?
+ DOUBLEALIGN(off) : INTALIGN(off);
+ break;
case sizeof(char):
- off++;
- break;
+ break;
case sizeof(short):
- off = SHORTALIGN(off) + sizeof(short);
- break;
+ off = SHORTALIGN(off);
+ break;
case sizeof(int32):
- off = INTALIGN(off) + sizeof(int32);
- break;
- case -1:
- usecache = false;
- off = (att[i]->attalign=='d')?
- DOUBLEALIGN(off):INTALIGN(off);
- off += VARSIZE(tp + off);
- break;
+ off = INTALIGN(off);
+ break;
default:
- if (att[i]->attlen > sizeof(int32))
- off = (att[i]->attalign=='d') ?
- DOUBLEALIGN(off) + att[i]->attlen :
- LONGALIGN(off) + att[i]->attlen;
- else
- elog(WARN, "fastgetiattr2: attribute %d has len %d",
- i, att[i]->attlen);
-
- break;
+ if (att[attnum]->attlen < sizeof(int32))
+ elog(WARN, "fastgetattr3: attribute %d has len %d",
+ attnum, att[attnum]->attlen);
+ if (att[attnum]->attalign == 'd')
+ off = DOUBLEALIGN(off);
+ else
+ off = LONGALIGN(off);
+ break;
}
+
+ return (fetchatt(&att[attnum], tp + off));
}
- /*
- * I don't know why this code was missed here!
- * I've got it from heaptuple.c:fastgetattr().
- * - vadim 06/12/97
- */
- switch (att[attnum]->attlen) {
- case -1:
- off = (att[attnum]->attalign=='d')?
- DOUBLEALIGN(off) : INTALIGN(off);
- break;
- case sizeof(char):
- break;
- case sizeof(short):
- off = SHORTALIGN(off);
- break;
- case sizeof(int32):
- off = INTALIGN(off);
- break;
- default:
- if (att[attnum]->attlen < sizeof(int32))
- elog(WARN, "fastgetattr3: attribute %d has len %d",
- attnum, att[attnum]->attlen);
- if (att[attnum]->attalign == 'd')
- off = DOUBLEALIGN(off);
- else
- off = LONGALIGN(off);
- break;
- }
-
- return(fetchatt(&att[attnum], tp + off));
- }
}
/* ----------------
- * index_getattr
+ * index_getattr
* ----------------
*/
Datum
index_getattr(IndexTuple tuple,
- AttrNumber attNum,
- TupleDesc tupDesc,
- bool *isNullOutP)
+ AttrNumber attNum,
+ TupleDesc tupDesc,
+ bool * isNullOutP)
{
- Assert (attNum > 0);
+ Assert(attNum > 0);
- return (Datum)
- fastgetiattr(tuple, attNum, tupDesc, isNullOutP);
+ return (Datum)
+ fastgetiattr(tuple, attNum, tupDesc, isNullOutP);
}
RetrieveIndexResult
FormRetrieveIndexResult(ItemPointer indexItemPointer,
- ItemPointer heapItemPointer)
+ ItemPointer heapItemPointer)
{
- RetrieveIndexResult result;
-
- Assert(ItemPointerIsValid(indexItemPointer));
- Assert(ItemPointerIsValid(heapItemPointer));
-
- result = (RetrieveIndexResult) palloc(sizeof *result);
-
- result->index_iptr = *indexItemPointer;
- result->heap_iptr = *heapItemPointer;
-
- return (result);
+ RetrieveIndexResult result;
+
+ Assert(ItemPointerIsValid(indexItemPointer));
+ Assert(ItemPointerIsValid(heapItemPointer));
+
+ result = (RetrieveIndexResult) palloc(sizeof *result);
+
+ result->index_iptr = *indexItemPointer;
+ result->heap_iptr = *heapItemPointer;
+
+ return (result);
}
/*
@@ -425,19 +461,21 @@ FormRetrieveIndexResult(ItemPointer indexItemPointer,
*
* Change me if adding an attribute to IndexTuples!!!!!!!!!!!
*/
-static Size
+static Size
IndexInfoFindDataOffset(unsigned short t_info)
{
- if (!(t_info & INDEX_NULL_MASK))
- return((Size) sizeof(IndexTupleData));
- else {
- Size size = sizeof(IndexTupleData);
-
- if (t_info & INDEX_NULL_MASK) {
- size += sizeof(IndexAttributeBitMapData);
+ if (!(t_info & INDEX_NULL_MASK))
+ return ((Size) sizeof(IndexTupleData));
+ else
+ {
+ Size size = sizeof(IndexTupleData);
+
+ if (t_info & INDEX_NULL_MASK)
+ {
+ size += sizeof(IndexAttributeBitMapData);
+ }
+ return DOUBLEALIGN(size); /* be conservative */
}
- return DOUBLEALIGN(size); /* be conservative */
- }
}
/*
@@ -445,17 +483,17 @@ IndexInfoFindDataOffset(unsigned short t_info)
* we assume we have space that is already palloc'ed.
*/
void
-CopyIndexTuple(IndexTuple source, IndexTuple *target)
+CopyIndexTuple(IndexTuple source, IndexTuple * target)
{
- Size size;
- IndexTuple ret;
-
- size = IndexTupleSize(source);
- if (*target == NULL) {
- *target = (IndexTuple) palloc(size);
- }
-
- ret = *target;
- memmove((char*)ret, (char*)source, size);
-}
+ Size size;
+ IndexTuple ret;
+
+ size = IndexTupleSize(source);
+ if (*target == NULL)
+ {
+ *target = (IndexTuple) palloc(size);
+ }
+ ret = *target;
+ memmove((char *) ret, (char *) source, size);
+}
diff --git a/src/backend/access/common/indexvalid.c b/src/backend/access/common/indexvalid.c
index aff9af42f8d..9f8501beb2e 100644
--- a/src/backend/access/common/indexvalid.c
+++ b/src/backend/access/common/indexvalid.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* indexvalid.c--
- * index tuple qualification validity checking code
+ * index tuple qualification validity checking code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/Attic/indexvalid.c,v 1.14 1997/03/18 18:38:19 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/Attic/indexvalid.c,v 1.15 1997/09/07 04:37:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,64 +21,70 @@
#include <executor/execdebug.h>
/* ----------------------------------------------------------------
- * index scan key qualification code
+ * index scan key qualification code
* ----------------------------------------------------------------
*/
-int NIndexTupleProcessed;
+int NIndexTupleProcessed;
/* ----------------
- * index_keytest
+ * index_keytest
*
* old comments
- * May eventually combine with other tests (like timeranges)?
- * Should have Buffer buffer; as an argument and pass it to amgetattr.
+ * May eventually combine with other tests (like timeranges)?
+ * Should have Buffer buffer; as an argument and pass it to amgetattr.
* ----------------
*/
bool
index_keytest(IndexTuple tuple,
- TupleDesc tupdesc,
- int scanKeySize,
- ScanKey key)
+ TupleDesc tupdesc,
+ int scanKeySize,
+ ScanKey key)
{
- bool isNull;
- Datum datum;
- int test;
-
- IncrIndexProcessed();
-
- while (scanKeySize > 0) {
- datum = index_getattr(tuple,
- key[0].sk_attno,
- tupdesc,
- &isNull);
-
- if (isNull) {
- /* XXX eventually should check if SK_ISNULL */
- return (false);
- }
-
- if (key[0].sk_flags & SK_ISNULL) {
- return (false);
- }
+ bool isNull;
+ Datum datum;
+ int test;
- if (key[0].sk_flags & SK_COMMUTE) {
- test = (*(key[0].sk_func))
- (DatumGetPointer(key[0].sk_argument),
- datum) ? 1 : 0;
- } else {
- test = (*(key[0].sk_func))
- (datum,
- DatumGetPointer(key[0].sk_argument)) ? 1 : 0;
- }
-
- if (!test == !(key[0].sk_flags & SK_NEGATE)) {
- return (false);
+ IncrIndexProcessed();
+
+ while (scanKeySize > 0)
+ {
+ datum = index_getattr(tuple,
+ key[0].sk_attno,
+ tupdesc,
+ &isNull);
+
+ if (isNull)
+ {
+ /* XXX eventually should check if SK_ISNULL */
+ return (false);
+ }
+
+ if (key[0].sk_flags & SK_ISNULL)
+ {
+ return (false);
+ }
+
+ if (key[0].sk_flags & SK_COMMUTE)
+ {
+ test = (*(key[0].sk_func))
+ (DatumGetPointer(key[0].sk_argument),
+ datum) ? 1 : 0;
+ }
+ else
+ {
+ test = (*(key[0].sk_func))
+ (datum,
+ DatumGetPointer(key[0].sk_argument)) ? 1 : 0;
+ }
+
+ if (!test == !(key[0].sk_flags & SK_NEGATE))
+ {
+ return (false);
+ }
+
+ scanKeySize -= 1;
+ key++;
}
-
- scanKeySize -= 1;
- key++;
- }
-
- return (true);
-}
+ return (true);
+}
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index 98fbddc639d..599ac59a455 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* printtup.c--
- * Routines to print out tuples to the destination (binary or non-binary
- * portals, frontend/interactive backend, etc.).
+ * Routines to print out tuples to the destination (binary or non-binary
+ * portals, frontend/interactive backend, etc.).
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.15 1997/08/26 23:31:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.16 1997/09/07 04:37:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,279 +16,304 @@
#include <string.h>
#include <postgres.h>
-#include <fmgr.h>
-#include <access/heapam.h>
-#include <access/printtup.h>
+#include <fmgr.h>
+#include <access/heapam.h>
+#include <access/printtup.h>
#include <catalog/pg_type.h>
#include <libpq/libpq.h>
#include <utils/syscache.h>
/* ----------------------------------------------------------------
- * printtup / debugtup support
+ * printtup / debugtup support
* ----------------------------------------------------------------
*/
/* ----------------
- * typtoout - used by printtup and debugtup
+ * typtoout - used by printtup and debugtup
* ----------------
*/
Oid
typtoout(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0, 0, 0);
-
- if (HeapTupleIsValid(typeTuple))
- return((Oid)
- ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput);
-
- elog(WARN, "typtoout: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((Oid)
+ ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput);
+
+ elog(WARN, "typtoout: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
Oid
gettypelem(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
- if (HeapTupleIsValid(typeTuple))
- return((Oid)
- ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem);
-
- elog(WARN, "typtoout: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((Oid)
+ ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem);
+
+ elog(WARN, "typtoout: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
/* ----------------
- * printtup
+ * printtup
* ----------------
*/
void
printtup(HeapTuple tuple, TupleDesc typeinfo)
{
- int i, j, k;
- char *outputstr, *attr;
- bool isnull;
- Oid typoutput;
-
- /* ----------------
- * tell the frontend to expect new tuple data
- * ----------------
- */
- pq_putnchar("D", 1);
-
- /* ----------------
- * send a bitmap of which attributes are null
- * ----------------
- */
- j = 0;
- k = 1 << 7;
- for (i = 0; i < tuple->t_natts; ) {
- i++; /* heap_getattr is a macro, so no increment */
- attr = heap_getattr(tuple, InvalidBuffer, i, typeinfo, &isnull);
- if (!isnull)
- j |= k;
- k >>= 1;
- if (!(i & 7)) {
- pq_putint(j, 1);
- j = 0;
- k = 1 << 7;
+ int i,
+ j,
+ k;
+ char *outputstr,
+ *attr;
+ bool isnull;
+ Oid typoutput;
+
+ /* ----------------
+ * tell the frontend to expect new tuple data
+ * ----------------
+ */
+ pq_putnchar("D", 1);
+
+ /* ----------------
+ * send a bitmap of which attributes are null
+ * ----------------
+ */
+ j = 0;
+ k = 1 << 7;
+ for (i = 0; i < tuple->t_natts;)
+ {
+ i++; /* heap_getattr is a macro, so no
+ * increment */
+ attr = heap_getattr(tuple, InvalidBuffer, i, typeinfo, &isnull);
+ if (!isnull)
+ j |= k;
+ k >>= 1;
+ if (!(i & 7))
+ {
+ pq_putint(j, 1);
+ j = 0;
+ k = 1 << 7;
+ }
}
- }
- if (i & 7)
- pq_putint(j, 1);
-
- /* ----------------
- * send the attributes of this tuple
- * ----------------
- */
- for (i = 0; i < tuple->t_natts; ++i) {
- attr = heap_getattr(tuple, InvalidBuffer, i+1, typeinfo, &isnull);
- typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
-
- if (!isnull && OidIsValid(typoutput)) {
- outputstr = fmgr(typoutput, attr,
- gettypelem(typeinfo->attrs[i]->atttypid));
- pq_putint(strlen(outputstr)+4, 4);
- pq_putnchar(outputstr, strlen(outputstr));
- pfree(outputstr);
+ if (i & 7)
+ pq_putint(j, 1);
+
+ /* ----------------
+ * send the attributes of this tuple
+ * ----------------
+ */
+ for (i = 0; i < tuple->t_natts; ++i)
+ {
+ attr = heap_getattr(tuple, InvalidBuffer, i + 1, typeinfo, &isnull);
+ typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
+
+ if (!isnull && OidIsValid(typoutput))
+ {
+ outputstr = fmgr(typoutput, attr,
+ gettypelem(typeinfo->attrs[i]->atttypid));
+ pq_putint(strlen(outputstr) + 4, 4);
+ pq_putnchar(outputstr, strlen(outputstr));
+ pfree(outputstr);
+ }
}
- }
}
/* ----------------
- * printatt
+ * printatt
* ----------------
*/
static void
printatt(unsigned attributeId,
- AttributeTupleForm attributeP,
- char *value)
+ AttributeTupleForm attributeP,
+ char *value)
{
- printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, byval = %c)\n",
- attributeId,
- attributeP->attname.data,
- value != NULL ? " = \"" : "",
- value != NULL ? value : "",
- value != NULL ? "\"" : "",
- (unsigned int) (attributeP->atttypid),
- attributeP->attlen,
- attributeP->attbyval ? 't' : 'f');
+ printf("\t%2d: %s%s%s%s\t(typeid = %u, len = %d, byval = %c)\n",
+ attributeId,
+ attributeP->attname.data,
+ value != NULL ? " = \"" : "",
+ value != NULL ? value : "",
+ value != NULL ? "\"" : "",
+ (unsigned int) (attributeP->atttypid),
+ attributeP->attlen,
+ attributeP->attbyval ? 't' : 'f');
}
/* ----------------
- * showatts
+ * showatts
* ----------------
*/
void
showatts(char *name, TupleDesc tupleDesc)
{
- int i;
- int natts = tupleDesc->natts;
- AttributeTupleForm *attinfo = tupleDesc->attrs;
+ int i;
+ int natts = tupleDesc->natts;
+ AttributeTupleForm *attinfo = tupleDesc->attrs;
- puts(name);
- for (i = 0; i < natts; ++i)
- printatt((unsigned) i+1, attinfo[i], (char *) NULL);
- printf("\t----\n");
+ puts(name);
+ for (i = 0; i < natts; ++i)
+ printatt((unsigned) i + 1, attinfo[i], (char *) NULL);
+ printf("\t----\n");
}
/* ----------------
- * debugtup
+ * debugtup
* ----------------
*/
void
debugtup(HeapTuple tuple, TupleDesc typeinfo)
{
- register int i;
- char *attr, *value;
- bool isnull;
- Oid typoutput;
-
- for (i = 0; i < tuple->t_natts; ++i) {
- attr = heap_getattr(tuple, InvalidBuffer, i+1, typeinfo, &isnull);
- typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
-
- if (!isnull && OidIsValid(typoutput)) {
- value = fmgr(typoutput, attr,
- gettypelem(typeinfo->attrs[i]->atttypid));
- printatt((unsigned) i+1, typeinfo->attrs[i], value);
- pfree(value);
+ register int i;
+ char *attr,
+ *value;
+ bool isnull;
+ Oid typoutput;
+
+ for (i = 0; i < tuple->t_natts; ++i)
+ {
+ attr = heap_getattr(tuple, InvalidBuffer, i + 1, typeinfo, &isnull);
+ typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
+
+ if (!isnull && OidIsValid(typoutput))
+ {
+ value = fmgr(typoutput, attr,
+ gettypelem(typeinfo->attrs[i]->atttypid));
+ printatt((unsigned) i + 1, typeinfo->attrs[i], value);
+ pfree(value);
+ }
}
- }
- printf("\t----\n");
+ printf("\t----\n");
}
/* ----------------
- * printtup_internal
- * Protocol expects either T, D, C, E, or N.
- * We use a different data prefix, e.g. 'B' instead of 'D' to
- * indicate a tuple in internal (binary) form.
+ * printtup_internal
+ * Protocol expects either T, D, C, E, or N.
+ * We use a different data prefix, e.g. 'B' instead of 'D' to
+ * indicate a tuple in internal (binary) form.
*
- * This is same as printtup, except we don't use the typout func.
+ * This is same as printtup, except we don't use the typout func.
* ----------------
*/
void
printtup_internal(HeapTuple tuple, TupleDesc typeinfo)
{
- int i, j, k;
- char *attr;
- bool isnull;
-
- /* ----------------
- * tell the frontend to expect new tuple data
- * ----------------
- */
- pq_putnchar("B", 1);
-
- /* ----------------
- * send a bitmap of which attributes are null
- * ----------------
- */
- j = 0;
- k = 1 << 7;
- for (i = 0; i < tuple->t_natts; ) {
- i++; /* heap_getattr is a macro, so no increment */
- attr = heap_getattr(tuple, InvalidBuffer, i, typeinfo, &isnull);
- if (!isnull)
- j |= k;
- k >>= 1;
- if (!(i & 7)) {
- pq_putint(j, 1);
- j = 0;
- k = 1 << 7;
+ int i,
+ j,
+ k;
+ char *attr;
+ bool isnull;
+
+ /* ----------------
+ * tell the frontend to expect new tuple data
+ * ----------------
+ */
+ pq_putnchar("B", 1);
+
+ /* ----------------
+ * send a bitmap of which attributes are null
+ * ----------------
+ */
+ j = 0;
+ k = 1 << 7;
+ for (i = 0; i < tuple->t_natts;)
+ {
+ i++; /* heap_getattr is a macro, so no
+ * increment */
+ attr = heap_getattr(tuple, InvalidBuffer, i, typeinfo, &isnull);
+ if (!isnull)
+ j |= k;
+ k >>= 1;
+ if (!(i & 7))
+ {
+ pq_putint(j, 1);
+ j = 0;
+ k = 1 << 7;
+ }
}
- }
- if (i & 7)
- pq_putint(j, 1);
-
- /* ----------------
- * send the attributes of this tuple
- * ----------------
- */
+ if (i & 7)
+ pq_putint(j, 1);
+
+ /* ----------------
+ * send the attributes of this tuple
+ * ----------------
+ */
#ifdef IPORTAL_DEBUG
- fprintf(stderr, "sending tuple with %d atts\n", tuple->t_natts);
+ fprintf(stderr, "sending tuple with %d atts\n", tuple->t_natts);
#endif
- for (i = 0; i < tuple->t_natts; ++i) {
- int32 len = typeinfo->attrs[i]->attlen;
-
- attr = heap_getattr(tuple, InvalidBuffer, i+1, typeinfo, &isnull);
- if (!isnull) {
- /* # of bytes, and opaque data */
- if (len == -1) {
- /* variable length, assume a varlena structure */
- len = VARSIZE(attr) - VARHDRSZ;
-
- pq_putint(len, sizeof(int32));
- pq_putnchar(VARDATA(attr), len);
-#ifdef IPORTAL_DEBUG
+ for (i = 0; i < tuple->t_natts; ++i)
+ {
+ int32 len = typeinfo->attrs[i]->attlen;
+
+ attr = heap_getattr(tuple, InvalidBuffer, i + 1, typeinfo, &isnull);
+ if (!isnull)
{
- char *d = VARDATA(attr);
-
- fprintf(stderr, "length %d data %x%x%x%x\n",
- len, *d, *(d+1), *(d+2), *(d+3));
- }
+ /* # of bytes, and opaque data */
+ if (len == -1)
+ {
+ /* variable length, assume a varlena structure */
+ len = VARSIZE(attr) - VARHDRSZ;
+
+ pq_putint(len, sizeof(int32));
+ pq_putnchar(VARDATA(attr), len);
+#ifdef IPORTAL_DEBUG
+ {
+ char *d = VARDATA(attr);
+
+ fprintf(stderr, "length %d data %x%x%x%x\n",
+ len, *d, *(d + 1), *(d + 2), *(d + 3));
+ }
#endif
- } else {
- /* fixed size */
- if (typeinfo->attrs[i]->attbyval) {
- int8 i8;
- int16 i16;
- int32 i32;
-
- pq_putint(len, sizeof(int32));
- switch (len) {
- case sizeof(int8):
- i8 = DatumGetChar(attr);
- pq_putnchar((char *) &i8, len);
- break;
- case sizeof(int16):
- i16 = DatumGetInt16(attr);
- pq_putnchar((char *) &i16, len);
- break;
- case sizeof(int32):
- i32 = DatumGetInt32(attr);
- pq_putnchar((char *) &i32, len);
- break;
- }
+ }
+ else
+ {
+ /* fixed size */
+ if (typeinfo->attrs[i]->attbyval)
+ {
+ int8 i8;
+ int16 i16;
+ int32 i32;
+
+ pq_putint(len, sizeof(int32));
+ switch (len)
+ {
+ case sizeof(int8):
+ i8 = DatumGetChar(attr);
+ pq_putnchar((char *) &i8, len);
+ break;
+ case sizeof(int16):
+ i16 = DatumGetInt16(attr);
+ pq_putnchar((char *) &i16, len);
+ break;
+ case sizeof(int32):
+ i32 = DatumGetInt32(attr);
+ pq_putnchar((char *) &i32, len);
+ break;
+ }
#ifdef IPORTAL_DEBUG
- fprintf(stderr, "byval length %d data %d\n", len, attr);
+ fprintf(stderr, "byval length %d data %d\n", len, attr);
#endif
- } else {
- pq_putint(len, sizeof(int32));
- pq_putnchar(attr, len);
+ }
+ else
+ {
+ pq_putint(len, sizeof(int32));
+ pq_putnchar(attr, len);
#ifdef IPORTAL_DEBUG
- fprintf(stderr, "byref length %d data %x\n", len, attr);
+ fprintf(stderr, "byref length %d data %x\n", len, attr);
#endif
+ }
+ }
}
- }
}
- }
}
diff --git a/src/backend/access/common/scankey.c b/src/backend/access/common/scankey.c
index fb242497ebc..9fbe264ae5c 100644
--- a/src/backend/access/common/scankey.c
+++ b/src/backend/access/common/scankey.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* scan.c--
- * scan direction and key code
+ * scan direction and key code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.9 1996/11/05 07:42:45 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/scankey.c,v 1.10 1997/09/07 04:37:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,49 +19,49 @@
/*
* ScanKeyEntryIsLegal --
- * True iff the scan key entry is legal.
+ * True iff the scan key entry is legal.
*/
#define ScanKeyEntryIsLegal(entry) \
- ((bool) (AssertMacro(PointerIsValid(entry)) && \
- AttributeNumberIsValid(entry->sk_attno)))
+ ((bool) (AssertMacro(PointerIsValid(entry)) && \
+ AttributeNumberIsValid(entry->sk_attno)))
/*
* ScanKeyEntrySetIllegal --
- * Marks a scan key entry as illegal.
+ * Marks a scan key entry as illegal.
*/
void
ScanKeyEntrySetIllegal(ScanKey entry)
{
- Assert(PointerIsValid(entry));
-
- entry->sk_flags = 0; /* just in case... */
- entry->sk_attno = InvalidAttrNumber;
- entry->sk_procedure = 0; /* should be InvalidRegProcedure */
+ Assert(PointerIsValid(entry));
+
+ entry->sk_flags = 0; /* just in case... */
+ entry->sk_attno = InvalidAttrNumber;
+ entry->sk_procedure = 0; /* should be InvalidRegProcedure */
}
/*
* ScanKeyEntryInitialize --
- * Initializes an scan key entry.
+ * Initializes an scan key entry.
*
* Note:
- * Assumes the scan key entry is valid.
- * Assumes the intialized scan key entry will be legal.
+ * Assumes the scan key entry is valid.
+ * Assumes the intialized scan key entry will be legal.
*/
void
ScanKeyEntryInitialize(ScanKey entry,
- bits16 flags,
- AttrNumber attributeNumber,
- RegProcedure procedure,
- Datum argument)
+ bits16 flags,
+ AttrNumber attributeNumber,
+ RegProcedure procedure,
+ Datum argument)
{
- Assert(PointerIsValid(entry));
-
- entry->sk_flags = flags;
- entry->sk_attno = attributeNumber;
- entry->sk_procedure = procedure;
- entry->sk_argument = argument;
- fmgr_info(procedure, &entry->sk_func, &entry->sk_nargs);
-
- Assert(ScanKeyEntryIsLegal(entry));
+ Assert(PointerIsValid(entry));
+
+ entry->sk_flags = flags;
+ entry->sk_attno = attributeNumber;
+ entry->sk_procedure = procedure;
+ entry->sk_argument = argument;
+ fmgr_info(procedure, &entry->sk_func, &entry->sk_nargs);
+
+ Assert(ScanKeyEntryIsLegal(entry));
}
diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c
index a38a5229f28..e616702a8ea 100644
--- a/src/backend/access/common/tupdesc.c
+++ b/src/backend/access/common/tupdesc.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* tupdesc.c--
- * POSTGRES tuple descriptor support code
+ * POSTGRES tuple descriptor support code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.19 1997/08/22 02:55:39 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.20 1997/09/07 04:37:41 momjian Exp $
*
* NOTES
- * some of the executor utility code such as "ExecTypeFromTL" should be
- * moved here.
+ * some of the executor utility code such as "ExecTypeFromTL" should be
+ * moved here.
*
*-------------------------------------------------------------------------
*/
@@ -28,518 +28,534 @@
#include <utils/syscache.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/* ----------------------------------------------------------------
- * CreateTemplateTupleDesc
+ * CreateTemplateTupleDesc
*
- * This function allocates and zeros a tuple descriptor structure.
+ * This function allocates and zeros a tuple descriptor structure.
* ----------------------------------------------------------------
*/
TupleDesc
CreateTemplateTupleDesc(int natts)
{
- uint32 size;
- TupleDesc desc;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertArg(natts >= 1);
-
- /* ----------------
- * allocate enough memory for the tuple descriptor and
- * zero it as TupleDescInitEntry assumes that the descriptor
- * is filled with NULL pointers.
- * ----------------
- */
- size = natts * sizeof (AttributeTupleForm);
- desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
- desc->attrs = (AttributeTupleForm*) palloc(size);
- desc->constr = NULL;
- memset(desc->attrs, 0, size);
-
- desc->natts = natts;
-
- return (desc);
+ uint32 size;
+ TupleDesc desc;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ AssertArg(natts >= 1);
+
+ /* ----------------
+ * allocate enough memory for the tuple descriptor and
+ * zero it as TupleDescInitEntry assumes that the descriptor
+ * is filled with NULL pointers.
+ * ----------------
+ */
+ size = natts * sizeof(AttributeTupleForm);
+ desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
+ desc->attrs = (AttributeTupleForm *) palloc(size);
+ desc->constr = NULL;
+ memset(desc->attrs, 0, size);
+
+ desc->natts = natts;
+
+ return (desc);
}
/* ----------------------------------------------------------------
- * CreateTupleDesc
+ * CreateTupleDesc
*
- * This function allocates a new TupleDesc from AttributeTupleForm array
+ * This function allocates a new TupleDesc from AttributeTupleForm array
* ----------------------------------------------------------------
*/
TupleDesc
-CreateTupleDesc(int natts, AttributeTupleForm* attrs)
+CreateTupleDesc(int natts, AttributeTupleForm * attrs)
{
- TupleDesc desc;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertArg(natts >= 1);
-
- desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
- desc->attrs = attrs;
- desc->natts = natts;
- desc->constr = NULL;
-
- return (desc);
+ TupleDesc desc;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ AssertArg(natts >= 1);
+
+ desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
+ desc->attrs = attrs;
+ desc->natts = natts;
+ desc->constr = NULL;
+
+ return (desc);
}
/* ----------------------------------------------------------------
- * CreateTupleDescCopy
+ * CreateTupleDescCopy
*
- * This function creates a new TupleDesc by copying from an existing
- * TupleDesc
- *
- * !!! Constraints are not copied !!!
+ * This function creates a new TupleDesc by copying from an existing
+ * TupleDesc
+ *
+ * !!! Constraints are not copied !!!
* ----------------------------------------------------------------
*/
TupleDesc
CreateTupleDescCopy(TupleDesc tupdesc)
{
- TupleDesc desc;
- int i, size;
-
- desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
- desc->natts = tupdesc->natts;
- size = desc->natts * sizeof (AttributeTupleForm);
- desc->attrs = (AttributeTupleForm*) palloc(size);
- for (i=0;i<desc->natts;i++) {
- desc->attrs[i] =
- (AttributeTupleForm)palloc(ATTRIBUTE_TUPLE_SIZE);
- memmove(desc->attrs[i],
- tupdesc->attrs[i],
- ATTRIBUTE_TUPLE_SIZE);
- desc->attrs[i]->attnotnull = false;
- desc->attrs[i]->atthasdef = false;
- }
- desc->constr = NULL;
-
- return desc;
+ TupleDesc desc;
+ int i,
+ size;
+
+ desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
+ desc->natts = tupdesc->natts;
+ size = desc->natts * sizeof(AttributeTupleForm);
+ desc->attrs = (AttributeTupleForm *) palloc(size);
+ for (i = 0; i < desc->natts; i++)
+ {
+ desc->attrs[i] =
+ (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+ memmove(desc->attrs[i],
+ tupdesc->attrs[i],
+ ATTRIBUTE_TUPLE_SIZE);
+ desc->attrs[i]->attnotnull = false;
+ desc->attrs[i]->atthasdef = false;
+ }
+ desc->constr = NULL;
+
+ return desc;
}
/* ----------------------------------------------------------------
- * CreateTupleDescCopyConstr
+ * CreateTupleDescCopyConstr
+ *
+ * This function creates a new TupleDesc by copying from an existing
+ * TupleDesc (with Constraints)
*
- * This function creates a new TupleDesc by copying from an existing
- * TupleDesc (with Constraints)
- *
* ----------------------------------------------------------------
*/
TupleDesc
CreateTupleDescCopyConstr(TupleDesc tupdesc)
{
- TupleDesc desc;
- TupleConstr *constr = tupdesc->constr;
- int i, size;
-
- desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
- desc->natts = tupdesc->natts;
- size = desc->natts * sizeof (AttributeTupleForm);
- desc->attrs = (AttributeTupleForm*) palloc(size);
- for (i=0;i<desc->natts;i++) {
- desc->attrs[i] =
- (AttributeTupleForm)palloc(ATTRIBUTE_TUPLE_SIZE);
- memmove(desc->attrs[i],
- tupdesc->attrs[i],
- ATTRIBUTE_TUPLE_SIZE);
- }
- if (constr)
- {
- TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr));
-
- cpy->has_not_null = constr->has_not_null;
-
- if ( ( cpy->num_defval = constr->num_defval ) > 0 )
- {
- cpy->defval = (AttrDefault *) palloc (cpy->num_defval * sizeof (AttrDefault));
- memcpy (cpy->defval, constr->defval, cpy->num_defval * sizeof (AttrDefault));
- for (i = cpy->num_defval - 1; i >= 0; i--)
- {
- if ( constr->defval[i].adbin )
- cpy->defval[i].adbin = pstrdup (constr->defval[i].adbin);
- if ( constr->defval[i].adsrc )
- cpy->defval[i].adsrc = pstrdup (constr->defval[i].adsrc);
- }
- }
-
- if ( ( cpy->num_check = constr->num_check ) > 0 )
- {
- cpy->check = (ConstrCheck *) palloc (cpy->num_check * sizeof (ConstrCheck));
- memcpy (cpy->check, constr->check, cpy->num_check * sizeof (ConstrCheck));
- for (i = cpy->num_check - 1; i >= 0; i--)
- {
- if ( constr->check[i].ccname )
- cpy->check[i].ccname = pstrdup (constr->check[i].ccname);
- if ( constr->check[i].ccbin )
- cpy->check[i].ccbin = pstrdup (constr->check[i].ccbin);
- if ( constr->check[i].ccsrc )
- cpy->check[i].ccsrc = pstrdup (constr->check[i].ccsrc);
- }
- }
-
- desc->constr = cpy;
- }
- else
- desc->constr = NULL;
-
- return desc;
+ TupleDesc desc;
+ TupleConstr *constr = tupdesc->constr;
+ int i,
+ size;
+
+ desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
+ desc->natts = tupdesc->natts;
+ size = desc->natts * sizeof(AttributeTupleForm);
+ desc->attrs = (AttributeTupleForm *) palloc(size);
+ for (i = 0; i < desc->natts; i++)
+ {
+ desc->attrs[i] =
+ (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+ memmove(desc->attrs[i],
+ tupdesc->attrs[i],
+ ATTRIBUTE_TUPLE_SIZE);
+ }
+ if (constr)
+ {
+ TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr));
+
+ cpy->has_not_null = constr->has_not_null;
+
+ if ((cpy->num_defval = constr->num_defval) > 0)
+ {
+ cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
+ memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
+ for (i = cpy->num_defval - 1; i >= 0; i--)
+ {
+ if (constr->defval[i].adbin)
+ cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
+ if (constr->defval[i].adsrc)
+ cpy->defval[i].adsrc = pstrdup(constr->defval[i].adsrc);
+ }
+ }
+
+ if ((cpy->num_check = constr->num_check) > 0)
+ {
+ cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
+ memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
+ for (i = cpy->num_check - 1; i >= 0; i--)
+ {
+ if (constr->check[i].ccname)
+ cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
+ if (constr->check[i].ccbin)
+ cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
+ if (constr->check[i].ccsrc)
+ cpy->check[i].ccsrc = pstrdup(constr->check[i].ccsrc);
+ }
+ }
+
+ desc->constr = cpy;
+ }
+ else
+ desc->constr = NULL;
+
+ return desc;
}
void
-FreeTupleDesc (TupleDesc tupdesc)
+FreeTupleDesc(TupleDesc tupdesc)
{
- int i;
-
- for (i = 0; i < tupdesc->natts; i++)
- pfree (tupdesc->attrs[i]);
- pfree (tupdesc->attrs);
- if ( tupdesc->constr )
- {
- if ( tupdesc->constr->num_defval > 0 )
- {
- AttrDefault *attrdef = tupdesc->constr->defval;
-
- for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
- {
- if ( attrdef[i].adbin )
- pfree (attrdef[i].adbin);
- if ( attrdef[i].adsrc )
- pfree (attrdef[i].adsrc);
- }
- pfree (attrdef);
- }
- if ( tupdesc->constr->num_check > 0 )
- {
- ConstrCheck *check = tupdesc->constr->check;
-
- for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
- {
- if ( check[i].ccname )
- pfree (check[i].ccname);
- if ( check[i].ccbin )
- pfree (check[i].ccbin);
- if ( check[i].ccsrc )
- pfree (check[i].ccsrc);
- }
- pfree (check);
- }
- pfree (tupdesc->constr);
- }
-
- pfree (tupdesc);
+ int i;
+
+ for (i = 0; i < tupdesc->natts; i++)
+ pfree(tupdesc->attrs[i]);
+ pfree(tupdesc->attrs);
+ if (tupdesc->constr)
+ {
+ if (tupdesc->constr->num_defval > 0)
+ {
+ AttrDefault *attrdef = tupdesc->constr->defval;
+
+ for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
+ {
+ if (attrdef[i].adbin)
+ pfree(attrdef[i].adbin);
+ if (attrdef[i].adsrc)
+ pfree(attrdef[i].adsrc);
+ }
+ pfree(attrdef);
+ }
+ if (tupdesc->constr->num_check > 0)
+ {
+ ConstrCheck *check = tupdesc->constr->check;
+
+ for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
+ {
+ if (check[i].ccname)
+ pfree(check[i].ccname);
+ if (check[i].ccbin)
+ pfree(check[i].ccbin);
+ if (check[i].ccsrc)
+ pfree(check[i].ccsrc);
+ }
+ pfree(check);
+ }
+ pfree(tupdesc->constr);
+ }
+
+ pfree(tupdesc);
}
/* ----------------------------------------------------------------
- * TupleDescInitEntry
+ * TupleDescInitEntry
*
- * This function initializes a single attribute structure in
- * a preallocated tuple descriptor.
+ * This function initializes a single attribute structure in
+ * a preallocated tuple descriptor.
* ----------------------------------------------------------------
*/
bool
TupleDescInitEntry(TupleDesc desc,
- AttrNumber attributeNumber,
- char *attributeName,
- char *typeName,
- int attdim,
- bool attisset)
+ AttrNumber attributeNumber,
+ char *attributeName,
+ char *typeName,
+ int attdim,
+ bool attisset)
{
- HeapTuple tuple;
- TypeTupleForm typeForm;
- AttributeTupleForm att;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertArg(PointerIsValid(desc));
- AssertArg(attributeNumber >= 1);
- /* attributeName's are sometimes NULL,
- from resdom's. I don't know why that is, though -- Jolly */
-/* AssertArg(NameIsValid(attributeName));*/
-/* AssertArg(NameIsValid(typeName));*/
-
- AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
-
-
- /* ----------------
- * allocate storage for this attribute
- * ----------------
- */
-
- att = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
- desc->attrs[attributeNumber - 1] = att;
-
- /* ----------------
- * initialize some of the attribute fields
- * ----------------
- */
- att->attrelid = 0; /* dummy value */
-
- if (attributeName != NULL)
- namestrcpy(&(att->attname), attributeName);
- else
- memset(att->attname.data,0,NAMEDATALEN);
-
-
- att->attdisbursion = 0; /* dummy value */
- att->attcacheoff = -1;
-
- att->attnum = attributeNumber;
- att->attnelems = attdim;
- att->attisset = attisset;
-
- att->attnotnull = false;
- att->atthasdef = false;
-
- /* ----------------
- * search the system cache for the type tuple of the attribute
- * we are creating so that we can get the typeid and some other
- * stuff.
- *
- * Note: in the special case of
- *
- * create EMP (name = char16, manager = EMP)
- *
- * RelationNameCreateHeapRelation() calls BuildDesc() which
- * calls this routine and since EMP does not exist yet, the
- * system cache lookup below fails. That's fine, but rather
- * then doing a elog(WARN) we just leave that information
- * uninitialized, return false, then fix things up later.
- * -cim 6/14/90
- * ----------------
- */
- tuple = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typeName),
- 0,0,0);
- if (! HeapTupleIsValid(tuple)) {
+ HeapTuple tuple;
+ TypeTupleForm typeForm;
+ AttributeTupleForm att;
+
/* ----------------
- * here type info does not exist yet so we just fill
- * the attribute with dummy information and return false.
+ * sanity checks
* ----------------
*/
- att->atttypid = InvalidOid;
- att->attlen = (int16) 0;
- att->attbyval = (bool) 0;
- att->attalign = 'i';
- return false;
- }
-
- /* ----------------
- * type info exists so we initialize our attribute
- * information from the type tuple we found..
- * ----------------
- */
- typeForm = (TypeTupleForm) GETSTRUCT(tuple);
-
- att->atttypid = tuple->t_oid;
- att->attalign = typeForm->typalign;
-
- /* ------------------------
- If this attribute is a set, what is really stored in the
- attribute is the OID of a tuple in the pg_proc catalog.
- The pg_proc tuple contains the query string which defines
- this set - i.e., the query to run to get the set.
- So the atttypid (just assigned above) refers to the type returned
- by this query, but the actual length of this attribute is the
- length (size) of an OID.
-
- Why not just make the atttypid point to the OID type, instead
- of the type the query returns? Because the executor uses the atttypid
- to tell the front end what type will be returned (in BeginCommand),
- and in the end the type returned will be the result of the query, not
- an OID.
-
- Why not wait until the return type of the set is known (i.e., the
- recursive call to the executor to execute the set has returned)
- before telling the front end what the return type will be? Because
- the executor is a delicate thing, and making sure that the correct
- order of front-end commands is maintained is messy, especially
- considering that target lists may change as inherited attributes
- are considered, etc. Ugh.
- -----------------------------------------
- */
- if (attisset) {
- Type t = type("oid");
- att->attlen = tlen(t);
- att->attbyval = tbyval(t);
- } else {
- att->attlen = typeForm->typlen;
- att->attbyval = typeForm->typbyval;
- }
-
-
- return true;
+ AssertArg(PointerIsValid(desc));
+ AssertArg(attributeNumber >= 1);
+
+ /*
+ * attributeName's are sometimes NULL, from resdom's. I don't know
+ * why that is, though -- Jolly
+ */
+/* AssertArg(NameIsValid(attributeName));*/
+/* AssertArg(NameIsValid(typeName));*/
+
+ AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
+
+
+ /* ----------------
+ * allocate storage for this attribute
+ * ----------------
+ */
+
+ att = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+ desc->attrs[attributeNumber - 1] = att;
+
+ /* ----------------
+ * initialize some of the attribute fields
+ * ----------------
+ */
+ att->attrelid = 0; /* dummy value */
+
+ if (attributeName != NULL)
+ namestrcpy(&(att->attname), attributeName);
+ else
+ memset(att->attname.data, 0, NAMEDATALEN);
+
+
+ att->attdisbursion = 0; /* dummy value */
+ att->attcacheoff = -1;
+
+ att->attnum = attributeNumber;
+ att->attnelems = attdim;
+ att->attisset = attisset;
+
+ att->attnotnull = false;
+ att->atthasdef = false;
+
+ /* ----------------
+ * search the system cache for the type tuple of the attribute
+ * we are creating so that we can get the typeid and some other
+ * stuff.
+ *
+ * Note: in the special case of
+ *
+ * create EMP (name = char16, manager = EMP)
+ *
+ * RelationNameCreateHeapRelation() calls BuildDesc() which
+ * calls this routine and since EMP does not exist yet, the
+ * system cache lookup below fails. That's fine, but rather
+ * then doing a elog(WARN) we just leave that information
+ * uninitialized, return false, then fix things up later.
+ * -cim 6/14/90
+ * ----------------
+ */
+ tuple = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typeName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ /* ----------------
+ * here type info does not exist yet so we just fill
+ * the attribute with dummy information and return false.
+ * ----------------
+ */
+ att->atttypid = InvalidOid;
+ att->attlen = (int16) 0;
+ att->attbyval = (bool) 0;
+ att->attalign = 'i';
+ return false;
+ }
+
+ /* ----------------
+ * type info exists so we initialize our attribute
+ * information from the type tuple we found..
+ * ----------------
+ */
+ typeForm = (TypeTupleForm) GETSTRUCT(tuple);
+
+ att->atttypid = tuple->t_oid;
+ att->attalign = typeForm->typalign;
+
+ /* ------------------------
+ If this attribute is a set, what is really stored in the
+ attribute is the OID of a tuple in the pg_proc catalog.
+ The pg_proc tuple contains the query string which defines
+ this set - i.e., the query to run to get the set.
+ So the atttypid (just assigned above) refers to the type returned
+ by this query, but the actual length of this attribute is the
+ length (size) of an OID.
+
+ Why not just make the atttypid point to the OID type, instead
+ of the type the query returns? Because the executor uses the atttypid
+ to tell the front end what type will be returned (in BeginCommand),
+ and in the end the type returned will be the result of the query, not
+ an OID.
+
+ Why not wait until the return type of the set is known (i.e., the
+ recursive call to the executor to execute the set has returned)
+ before telling the front end what the return type will be? Because
+ the executor is a delicate thing, and making sure that the correct
+ order of front-end commands is maintained is messy, especially
+ considering that target lists may change as inherited attributes
+ are considered, etc. Ugh.
+ -----------------------------------------
+ */
+ if (attisset)
+ {
+ Type t = type("oid");
+
+ att->attlen = tlen(t);
+ att->attbyval = tbyval(t);
+ }
+ else
+ {
+ att->attlen = typeForm->typlen;
+ att->attbyval = typeForm->typbyval;
+ }
+
+
+ return true;
}
/* ----------------------------------------------------------------
- * TupleDescMakeSelfReference
+ * TupleDescMakeSelfReference
*
- * This function initializes a "self-referential" attribute like
- * manager in "create EMP (name=text, manager = EMP)".
- * It calls TypeShellMake() which inserts a "shell" type
- * tuple into pg_type. A self-reference is one kind of set, so
- * its size and byval are the same as for a set. See the comments
- * above in TupleDescInitEntry.
+ * This function initializes a "self-referential" attribute like
+ * manager in "create EMP (name=text, manager = EMP)".
+ * It calls TypeShellMake() which inserts a "shell" type
+ * tuple into pg_type. A self-reference is one kind of set, so
+ * its size and byval are the same as for a set. See the comments
+ * above in TupleDescInitEntry.
* ----------------------------------------------------------------
*/
static void
TupleDescMakeSelfReference(TupleDesc desc,
- AttrNumber attnum,
- char *relname)
+ AttrNumber attnum,
+ char *relname)
{
- AttributeTupleForm att;
- Type t = type("oid");
-
- att = desc->attrs[attnum-1];
- att->atttypid = TypeShellMake(relname);
- att->attlen = tlen(t);
- att->attbyval = tbyval(t);
- att->attnelems = 0;
+ AttributeTupleForm att;
+ Type t = type("oid");
+
+ att = desc->attrs[attnum - 1];
+ att->atttypid = TypeShellMake(relname);
+ att->attlen = tlen(t);
+ att->attbyval = tbyval(t);
+ att->attnelems = 0;
}
/* ----------------------------------------------------------------
- * BuildDescForRelation
+ * BuildDescForRelation
*
- * This is a general purpose function identical to BuildDesc
- * but is used by the DefineRelation() code to catch the
- * special case where you
+ * This is a general purpose function identical to BuildDesc
+ * but is used by the DefineRelation() code to catch the
+ * special case where you
*
- * create FOO ( ..., x = FOO )
+ * create FOO ( ..., x = FOO )
*
- * here, the initial type lookup for "x = FOO" will fail
- * because FOO isn't in the catalogs yet. But since we
- * are creating FOO, instead of doing an elog() we add
- * a shell type tuple to pg_type and fix things later
- * in amcreate().
+ * here, the initial type lookup for "x = FOO" will fail
+ * because FOO isn't in the catalogs yet. But since we
+ * are creating FOO, instead of doing an elog() we add
+ * a shell type tuple to pg_type and fix things later
+ * in amcreate().
* ----------------------------------------------------------------
*/
TupleDesc
-BuildDescForRelation(List *schema, char *relname)
+BuildDescForRelation(List * schema, char *relname)
{
- int natts;
- AttrNumber attnum;
- List *p;
- TupleDesc desc;
- AttrDefault *attrdef = NULL;
- TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
- char *attname;
- char *typename;
- int attdim;
- int ndef = 0;
- bool attisset;
-
- /* ----------------
- * allocate a new tuple descriptor
- * ----------------
- */
- natts = length(schema);
- desc = CreateTemplateTupleDesc(natts);
- constr->has_not_null = false;
-
- attnum = 0;
-
- typename = palloc(NAMEDATALEN);
-
- foreach(p, schema) {
- ColumnDef *entry;
- List *arry;
+ int natts;
+ AttrNumber attnum;
+ List *p;
+ TupleDesc desc;
+ AttrDefault *attrdef = NULL;
+ TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
+ char *attname;
+ char *typename;
+ int attdim;
+ int ndef = 0;
+ bool attisset;
/* ----------------
- * for each entry in the list, get the name and type
- * information from the list and have TupleDescInitEntry
- * fill in the attribute information we need.
+ * allocate a new tuple descriptor
* ----------------
- */
- attnum++;
-
- entry = lfirst(p);
- attname = entry->colname;
- arry = entry->typename->arrayBounds;
- attisset = entry->typename->setof;
-
- strNcpy(typename, entry->typename->name,NAMEDATALEN-1);
- if (arry != NIL)
- attdim = length(arry);
- else
- attdim = 0;
-
- if (! TupleDescInitEntry(desc, attnum, attname,
- typename, attdim, attisset)) {
- /* ----------------
- * if TupleDescInitEntry() fails, it means there is
- * no type in the system catalogs. So now we check if
- * the type name equals the relation name. If so we
- * have a self reference, otherwise it's an error.
- * ----------------
- */
- if (!strcmp(typename, relname)) {
- TupleDescMakeSelfReference(desc, attnum, relname);
- } else
- elog(WARN, "DefineRelation: no such type %s",
- typename);
- }
-
- /*
- * this is for char() and varchar(). When an entry is of type
- * char() or varchar(), typlen is set to the appropriate length,
- * which we'll use here instead. (The catalog lookup only returns
- * the length of bpchar and varchar which is not what we want!)
- * - ay 6/95
*/
- if (entry->typename->typlen > 0) {
- desc->attrs[attnum - 1]->attlen = entry->typename->typlen;
- }
+ natts = length(schema);
+ desc = CreateTemplateTupleDesc(natts);
+ constr->has_not_null = false;
- /* This is for constraints */
- if (entry->is_not_null)
- constr->has_not_null = true;
- desc->attrs[attnum-1]->attnotnull = entry->is_not_null;
-
- if ( entry->defval != NULL )
+ attnum = 0;
+
+ typename = palloc(NAMEDATALEN);
+
+ foreach(p, schema)
{
- if ( attrdef == NULL )
- attrdef = (AttrDefault*) palloc (natts * sizeof (AttrDefault));
- attrdef[ndef].adnum = attnum;
- attrdef[ndef].adbin = NULL;
- attrdef[ndef].adsrc = entry->defval;
- ndef++;
- desc->attrs[attnum-1]->atthasdef = true;
+ ColumnDef *entry;
+ List *arry;
+
+ /* ----------------
+ * for each entry in the list, get the name and type
+ * information from the list and have TupleDescInitEntry
+ * fill in the attribute information we need.
+ * ----------------
+ */
+ attnum++;
+
+ entry = lfirst(p);
+ attname = entry->colname;
+ arry = entry->typename->arrayBounds;
+ attisset = entry->typename->setof;
+
+ strNcpy(typename, entry->typename->name, NAMEDATALEN - 1);
+ if (arry != NIL)
+ attdim = length(arry);
+ else
+ attdim = 0;
+
+ if (!TupleDescInitEntry(desc, attnum, attname,
+ typename, attdim, attisset))
+ {
+ /* ----------------
+ * if TupleDescInitEntry() fails, it means there is
+ * no type in the system catalogs. So now we check if
+ * the type name equals the relation name. If so we
+ * have a self reference, otherwise it's an error.
+ * ----------------
+ */
+ if (!strcmp(typename, relname))
+ {
+ TupleDescMakeSelfReference(desc, attnum, relname);
+ }
+ else
+ elog(WARN, "DefineRelation: no such type %s",
+ typename);
+ }
+
+ /*
+ * this is for char() and varchar(). When an entry is of type
+ * char() or varchar(), typlen is set to the appropriate length,
+ * which we'll use here instead. (The catalog lookup only returns
+ * the length of bpchar and varchar which is not what we want!) -
+ * ay 6/95
+ */
+ if (entry->typename->typlen > 0)
+ {
+ desc->attrs[attnum - 1]->attlen = entry->typename->typlen;
+ }
+
+ /* This is for constraints */
+ if (entry->is_not_null)
+ constr->has_not_null = true;
+ desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
+
+ if (entry->defval != NULL)
+ {
+ if (attrdef == NULL)
+ attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));
+ attrdef[ndef].adnum = attnum;
+ attrdef[ndef].adbin = NULL;
+ attrdef[ndef].adsrc = entry->defval;
+ ndef++;
+ desc->attrs[attnum - 1]->atthasdef = true;
+ }
+
}
+ if (constr->has_not_null || ndef > 0)
+ {
+ desc->constr = constr;
- }
- if ( constr->has_not_null || ndef > 0 )
- {
- desc->constr = constr;
-
- if ( ndef > 0 ) /* DEFAULTs */
- {
- if ( ndef < natts )
- constr->defval = (AttrDefault*)
- repalloc (attrdef, ndef * sizeof (AttrDefault));
- else
- constr->defval = attrdef;
- constr->num_defval = ndef;
- }
- else
- constr->num_defval = 0;
- constr->num_check = 0;
- }
- else
- {
- pfree (constr);
- desc->constr = NULL;
- }
- return desc;
+ if (ndef > 0) /* DEFAULTs */
+ {
+ if (ndef < natts)
+ constr->defval = (AttrDefault *)
+ repalloc(attrdef, ndef * sizeof(AttrDefault));
+ else
+ constr->defval = attrdef;
+ constr->num_defval = ndef;
+ }
+ else
+ constr->num_defval = 0;
+ constr->num_check = 0;
+ }
+ else
+ {
+ pfree(constr);
+ desc->constr = NULL;
+ }
+ return desc;
}
-
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 1d36f340ed6..598f9ed8f02 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* gist.c--
- * interface routines for the postgres GiST index access method.
+ * interface routines for the postgres GiST index access method.
*
*
*
@@ -26,308 +26,345 @@
#include <utils/syscache.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/* non-export function prototypes */
-static InsertIndexResult gistdoinsert(Relation r, IndexTuple itup,
- GISTSTATE *GISTstate);
-static InsertIndexResult gistentryinsert(Relation r, GISTSTACK *stk,
- IndexTuple tup,
- GISTSTATE *giststate);
-static void gistentryinserttwo(Relation r, GISTSTACK *stk, IndexTuple ltup,
- IndexTuple rtup, GISTSTATE *giststate);
-static void gistAdjustKeys(Relation r, GISTSTACK *stk, BlockNumber blk,
- char *datum, int att_size, GISTSTATE *giststate);
-static void gistintinsert(Relation r, GISTSTACK *stk, IndexTuple ltup,
- IndexTuple rtup, GISTSTATE *giststate);
-static InsertIndexResult gistSplit(Relation r, Buffer buffer,
- GISTSTACK *stack, IndexTuple itup,
- GISTSTATE *giststate);
-static void gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt,
+static InsertIndexResult
+gistdoinsert(Relation r, IndexTuple itup,
+ GISTSTATE * GISTstate);
+static InsertIndexResult
+gistentryinsert(Relation r, GISTSTACK * stk,
+ IndexTuple tup,
+ GISTSTATE * giststate);
+static void
+gistentryinserttwo(Relation r, GISTSTACK * stk, IndexTuple ltup,
+ IndexTuple rtup, GISTSTATE * giststate);
+static void
+gistAdjustKeys(Relation r, GISTSTACK * stk, BlockNumber blk,
+ char *datum, int att_size, GISTSTATE * giststate);
+static void
+gistintinsert(Relation r, GISTSTACK * stk, IndexTuple ltup,
+ IndexTuple rtup, GISTSTATE * giststate);
+static InsertIndexResult
+gistSplit(Relation r, Buffer buffer,
+ GISTSTACK * stack, IndexTuple itup,
+ GISTSTATE * giststate);
+static void
+gistnewroot(GISTSTATE * giststate, Relation r, IndexTuple lt,
IndexTuple rt);
-static void GISTInitBuffer(Buffer b, uint32 f);
-static BlockNumber gistChooseSubtree(Relation r, IndexTuple itup, int level,
- GISTSTATE *giststate,
- GISTSTACK **retstack, Buffer *leafbuf);
-static OffsetNumber gistchoose(Relation r, Page p, IndexTuple it,
- GISTSTATE *giststate);
-static int gistnospace(Page p, IndexTuple it);
-void gistdelete(Relation r, ItemPointer tid);
+static void GISTInitBuffer(Buffer b, uint32 f);
+static BlockNumber
+gistChooseSubtree(Relation r, IndexTuple itup, int level,
+ GISTSTATE * giststate,
+ GISTSTACK ** retstack, Buffer * leafbuf);
+static OffsetNumber
+gistchoose(Relation r, Page p, IndexTuple it,
+ GISTSTATE * giststate);
+static int gistnospace(Page p, IndexTuple it);
+void gistdelete(Relation r, ItemPointer tid);
static IndexTuple gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t);
-static void gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr,
- Relation r, Page pg, OffsetNumber o, int b, bool l) ;
-static char *int_range_out(INTRANGE *r);
+static void
+gistcentryinit(GISTSTATE * giststate, GISTENTRY * e, char *pr,
+ Relation r, Page pg, OffsetNumber o, int b, bool l);
+static char *int_range_out(INTRANGE * r);
/*
** routine to build an index. Basically calls insert over and over
*/
void
gistbuild(Relation heap,
- Relation index,
- int natts,
- AttrNumber *attnum,
- IndexStrategy istrat,
- uint16 pint,
- Datum *params,
- FuncIndexInfo *finfo,
- PredInfo *predInfo)
+ Relation index,
+ int natts,
+ AttrNumber * attnum,
+ IndexStrategy istrat,
+ uint16 pint,
+ Datum * params,
+ FuncIndexInfo * finfo,
+ PredInfo * predInfo)
{
- HeapScanDesc scan;
- Buffer buffer;
- AttrNumber i;
- HeapTuple htup;
- IndexTuple itup;
- TupleDesc hd, id;
- InsertIndexResult res;
- Datum *d;
- bool *nulls;
- int nb, nh, ni;
+ HeapScanDesc scan;
+ Buffer buffer;
+ AttrNumber i;
+ HeapTuple htup;
+ IndexTuple itup;
+ TupleDesc hd,
+ id;
+ InsertIndexResult res;
+ Datum *d;
+ bool *nulls;
+ int nb,
+ nh,
+ ni;
+
#ifndef OMIT_PARTIAL_INDEX
- ExprContext *econtext;
- TupleTable tupleTable;
- TupleTableSlot *slot;
+ ExprContext *econtext;
+ TupleTable tupleTable;
+ TupleTableSlot *slot;
+
#endif
- Oid hrelid, irelid;
- Node *pred, *oldPred;
- GISTSTATE giststate;
- GISTENTRY tmpcentry;
- bool *compvec;
-
- /* GiSTs only know how to do stupid locking now */
- RelationSetLockForWrite(index);
-
- setheapoverride(TRUE); /* so we can see the new pg_index tuple */
- initGISTstate(&giststate, index);
- setheapoverride(FALSE);
-
- pred = predInfo->pred;
- oldPred = predInfo->oldPred;
-
- /*
- * We expect to be called exactly once for any index relation.
- * If that's not the case, big trouble's what we have.
- */
-
- if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
- elog(WARN, "%.16s already contains data", &(index->rd_rel->relname.data[0]));
-
- /* initialize the root page (if this is a new index) */
- if (oldPred == NULL) {
- buffer = ReadBuffer(index, P_NEW);
- GISTInitBuffer(buffer, F_LEAF);
- WriteBuffer(buffer);
- }
-
- /* init the tuple descriptors and get set for a heap scan */
- hd = RelationGetTupleDescriptor(heap);
- id = RelationGetTupleDescriptor(index);
- d = (Datum *)palloc(natts * sizeof (*d));
- nulls = (bool *)palloc(natts * sizeof (*nulls));
-
- /*
- * If this is a predicate (partial) index, we will need to evaluate the
- * predicate using ExecQual, which requires the current tuple to be in a
- * slot of a TupleTable. In addition, ExecQual must have an ExprContext
- * referring to that slot. Here, we initialize dummy TupleTable and
- * ExprContext objects for this purpose. --Nels, Feb '92
- */
+ Oid hrelid,
+ irelid;
+ Node *pred,
+ *oldPred;
+ GISTSTATE giststate;
+ GISTENTRY tmpcentry;
+ bool *compvec;
+
+ /* GiSTs only know how to do stupid locking now */
+ RelationSetLockForWrite(index);
+
+ setheapoverride(TRUE); /* so we can see the new pg_index tuple */
+ initGISTstate(&giststate, index);
+ setheapoverride(FALSE);
+
+ pred = predInfo->pred;
+ oldPred = predInfo->oldPred;
+
+ /*
+ * We expect to be called exactly once for any index relation. If
+ * that's not the case, big trouble's what we have.
+ */
+
+ if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
+ elog(WARN, "%.16s already contains data", &(index->rd_rel->relname.data[0]));
+
+ /* initialize the root page (if this is a new index) */
+ if (oldPred == NULL)
+ {
+ buffer = ReadBuffer(index, P_NEW);
+ GISTInitBuffer(buffer, F_LEAF);
+ WriteBuffer(buffer);
+ }
+
+ /* init the tuple descriptors and get set for a heap scan */
+ hd = RelationGetTupleDescriptor(heap);
+ id = RelationGetTupleDescriptor(index);
+ d = (Datum *) palloc(natts * sizeof(*d));
+ nulls = (bool *) palloc(natts * sizeof(*nulls));
+
+ /*
+ * If this is a predicate (partial) index, we will need to evaluate
+ * the predicate using ExecQual, which requires the current tuple to
+ * be in a slot of a TupleTable. In addition, ExecQual must have an
+ * ExprContext referring to that slot. Here, we initialize dummy
+ * TupleTable and ExprContext objects for this purpose. --Nels, Feb
+ * '92
+ */
#ifndef OMIT_PARTIAL_INDEX
- if (pred != NULL || oldPred != NULL) {
- tupleTable = ExecCreateTupleTable(1);
- slot = ExecAllocTableSlot(tupleTable);
- econtext = makeNode(ExprContext);
- FillDummyExprContext(econtext, slot, hd, buffer);
- }
- else /* shut the compiler up */
+ if (pred != NULL || oldPred != NULL)
+ {
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ econtext = makeNode(ExprContext);
+ FillDummyExprContext(econtext, slot, hd, buffer);
+ }
+ else
+/* shut the compiler up */
{
tupleTable = NULL;
slot = NULL;
econtext = NULL;
}
-#endif /* OMIT_PARTIAL_INDEX */
- scan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
- htup = heap_getnext(scan, 0, &buffer);
-
- /* int the tuples as we insert them */
- nh = ni = 0;
-
- for (; HeapTupleIsValid(htup); htup = heap_getnext(scan, 0, &buffer)) {
-
- nh++;
-
- /*
- * If oldPred != NULL, this is an EXTEND INDEX command, so skip
- * this tuple if it was already in the existing partial index
- */
- if (oldPred != NULL) {
+#endif /* OMIT_PARTIAL_INDEX */
+ scan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
+ htup = heap_getnext(scan, 0, &buffer);
+
+ /* int the tuples as we insert them */
+ nh = ni = 0;
+
+ for (; HeapTupleIsValid(htup); htup = heap_getnext(scan, 0, &buffer))
+ {
+
+ nh++;
+
+ /*
+ * If oldPred != NULL, this is an EXTEND INDEX command, so skip
+ * this tuple if it was already in the existing partial index
+ */
+ if (oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, htup); */
- slot->val = htup;
- if (ExecQual((List*)oldPred, econtext) == true) {
+ /* SetSlotContents(slot, htup); */
+ slot->val = htup;
+ if (ExecQual((List *) oldPred, econtext) == true)
+ {
+ ni++;
+ continue;
+ }
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
+ /*
+ * Skip this tuple if it doesn't satisfy the partial-index
+ * predicate
+ */
+ if (pred != NULL)
+ {
+#ifndef OMIT_PARTIAL_INDEX
+ /* SetSlotContents(slot, htup); */
+ slot->val = htup;
+ if (ExecQual((List *) pred, econtext) == false)
+ continue;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
ni++;
- continue;
- }
-#endif /* OMIT_PARTIAL_INDEX */
+
+ /*
+ * For the current heap tuple, extract all the attributes we use
+ * in this index, and note which are null.
+ */
+
+ for (i = 1; i <= natts; i++)
+ {
+ int attoff;
+ bool attnull;
+
+ /*
+ * Offsets are from the start of the tuple, and are
+ * zero-based; indices are one-based. The next call returns i
+ * - 1. That's data hiding for you.
+ */
+
+ attoff = AttrNumberGetAttrOffset(i);
+
+ /*
+ * d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
+ */
+ d[attoff] = GetIndexValue(htup,
+ hd,
+ attoff,
+ attnum,
+ finfo,
+ &attnull,
+ buffer);
+ nulls[attoff] = (attnull ? 'n' : ' ');
+ }
+
+ /* immediately compress keys to normalize */
+ compvec = (bool *) palloc(sizeof(bool) * natts);
+ for (i = 0; i < natts; i++)
+ {
+ gistcentryinit(&giststate, &tmpcentry, (char *) d[i],
+ (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
+ -1 /* size is currently bogus */ , TRUE);
+ if (d[i] != (Datum) tmpcentry.pred && !(giststate.keytypbyval))
+ compvec[i] = TRUE;
+ else
+ compvec[i] = FALSE;
+ d[i] = (Datum) tmpcentry.pred;
+ }
+
+ /* form an index tuple and point it at the heap tuple */
+ itup = index_formtuple(id, &d[0], nulls);
+ itup->t_tid = htup->t_ctid;
+
+ /*
+ * Since we already have the index relation locked, we call
+ * gistdoinsert directly. Normal access method calls dispatch
+ * through gistinsert, which locks the relation for write. This
+ * is the right thing to do if you're inserting single tups, but
+ * not when you're initializing the whole index at once.
+ */
+
+ res = gistdoinsert(index, itup, &giststate);
+ for (i = 0; i < natts; i++)
+ if (compvec[i] == TRUE)
+ pfree((char *) d[i]);
+ pfree(itup);
+ pfree(res);
+ pfree(compvec);
}
-
- /* Skip this tuple if it doesn't satisfy the partial-index predicate */
- if (pred != NULL) {
+
+ /* okay, all heap tuples are indexed */
+ heap_endscan(scan);
+ RelationUnsetLockForWrite(index);
+
+ if (pred != NULL || oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, htup); */
- slot->val = htup;
- if (ExecQual((List*)pred, econtext) == false)
- continue;
-#endif /* OMIT_PARTIAL_INDEX */
+ ExecDestroyTupleTable(tupleTable, true);
+ pfree(econtext);
+#endif /* OMIT_PARTIAL_INDEX */
}
-
- ni++;
-
+
/*
- * For the current heap tuple, extract all the attributes
- * we use in this index, and note which are null.
+ * Since we just inted the tuples in the heap, we update its stats in
+ * pg_relation to guarantee that the planner takes advantage of the
+ * index we just created. UpdateStats() does a
+ * CommandinterIncrement(), which flushes changed entries from the
+ * system relcache. The act of constructing an index changes these
+ * heap and index tuples in the system catalogs, so they need to be
+ * flushed. We close them to guarantee that they will be.
*/
-
- for (i = 1; i <= natts; i++) {
- int attoff;
- bool attnull;
-
- /*
- * Offsets are from the start of the tuple, and are
- * zero-based; indices are one-based. The next call
- * returns i - 1. That's data hiding for you.
- */
-
- attoff = AttrNumberGetAttrOffset(i);
- /*
- d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
- */
- d[attoff] = GetIndexValue(htup,
- hd,
- attoff,
- attnum,
- finfo,
- &attnull,
- buffer);
- nulls[attoff] = (attnull ? 'n' : ' ');
- }
-
- /* immediately compress keys to normalize */
- compvec = (bool *)palloc(sizeof(bool) * natts);
- for (i = 0; i < natts; i++) {
- gistcentryinit(&giststate, &tmpcentry, (char *)d[i],
- (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
- -1 /* size is currently bogus */, TRUE);
- if (d[i] != (Datum)tmpcentry.pred && !(giststate.keytypbyval))
- compvec[i] = TRUE;
- else compvec[i] = FALSE;
- d[i] = (Datum)tmpcentry.pred;
+
+ hrelid = heap->rd_id;
+ irelid = index->rd_id;
+ heap_close(heap);
+ index_close(index);
+
+ UpdateStats(hrelid, nh, true);
+ UpdateStats(irelid, ni, false);
+
+ if (oldPred != NULL)
+ {
+ if (ni == nh)
+ pred = NULL;
+ UpdateIndexPredicate(irelid, oldPred, pred);
}
- /* form an index tuple and point it at the heap tuple */
- itup = index_formtuple(id, &d[0], nulls);
- itup->t_tid = htup->t_ctid;
-
- /*
- * Since we already have the index relation locked, we
- * call gistdoinsert directly. Normal access method calls
- * dispatch through gistinsert, which locks the relation
- * for write. This is the right thing to do if you're
- * inserting single tups, but not when you're initializing
- * the whole index at once.
- */
-
- res = gistdoinsert(index, itup, &giststate);
- for (i = 0; i < natts; i++)
- if (compvec[i] == TRUE) pfree((char *)d[i]);
- pfree(itup);
- pfree(res);
- pfree(compvec);
- }
-
- /* okay, all heap tuples are indexed */
- heap_endscan(scan);
- RelationUnsetLockForWrite(index);
-
- if (pred != NULL || oldPred != NULL) {
-#ifndef OMIT_PARTIAL_INDEX
- ExecDestroyTupleTable(tupleTable, true);
- pfree(econtext);
-#endif /* OMIT_PARTIAL_INDEX */
- }
-
- /*
- * Since we just inted the tuples in the heap, we update its
- * stats in pg_relation to guarantee that the planner takes
- * advantage of the index we just created. UpdateStats() does a
- * CommandinterIncrement(), which flushes changed entries from
- * the system relcache. The act of constructing an index changes
- * these heap and index tuples in the system catalogs, so they
- * need to be flushed. We close them to guarantee that they
- * will be.
- */
-
- hrelid = heap->rd_id;
- irelid = index->rd_id;
- heap_close(heap);
- index_close(index);
-
- UpdateStats(hrelid, nh, true);
- UpdateStats(irelid, ni, false);
-
- if (oldPred != NULL) {
- if (ni == nh) pred = NULL;
- UpdateIndexPredicate(irelid, oldPred, pred);
- }
-
- /* be tidy */
- pfree(nulls);
- pfree(d);
+ /* be tidy */
+ pfree(nulls);
+ pfree(d);
}
/*
- * gistinsert -- wrapper for GiST tuple insertion.
+ * gistinsert -- wrapper for GiST tuple insertion.
*
- * This is the public interface routine for tuple insertion in GiSTs.
- * It doesn't do any work; just locks the relation and passes the buck.
+ * This is the public interface routine for tuple insertion in GiSTs.
+ * It doesn't do any work; just locks the relation and passes the buck.
*/
InsertIndexResult
-gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
+gistinsert(Relation r, Datum * datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
{
- InsertIndexResult res;
- IndexTuple itup;
- GISTSTATE giststate;
- GISTENTRY tmpentry;
- int i;
- bool *compvec;
-
- initGISTstate(&giststate, r);
-
- /* immediately compress keys to normalize */
- compvec = (bool *)palloc(sizeof(bool) * r->rd_att->natts);
- for (i = 0; i < r->rd_att->natts; i++) {
- gistcentryinit(&giststate, &tmpentry, (char *)datum[i],
- (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
- -1 /* size is currently bogus */, TRUE);
- if (datum[i] != (Datum)tmpentry.pred && !(giststate.keytypbyval))
- compvec[i] = TRUE;
- else compvec[i] = FALSE;
- datum[i] = (Datum)tmpentry.pred;
- }
- itup = index_formtuple(RelationGetTupleDescriptor(r), datum, nulls);
- itup->t_tid = *ht_ctid;
-
- RelationSetLockForWrite(r);
- res = gistdoinsert(r, itup, &giststate);
- for (i = 0; i < r->rd_att->natts; i++)
- if (compvec[i] == TRUE) pfree((char *)datum[i]);
- pfree(itup);
- pfree(compvec);
-
- /* XXX two-phase locking -- don't unlock the relation until EOT */
- return (res);
+ InsertIndexResult res;
+ IndexTuple itup;
+ GISTSTATE giststate;
+ GISTENTRY tmpentry;
+ int i;
+ bool *compvec;
+
+ initGISTstate(&giststate, r);
+
+ /* immediately compress keys to normalize */
+ compvec = (bool *) palloc(sizeof(bool) * r->rd_att->natts);
+ for (i = 0; i < r->rd_att->natts; i++)
+ {
+ gistcentryinit(&giststate, &tmpentry, (char *) datum[i],
+ (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
+ -1 /* size is currently bogus */ , TRUE);
+ if (datum[i] != (Datum) tmpentry.pred && !(giststate.keytypbyval))
+ compvec[i] = TRUE;
+ else
+ compvec[i] = FALSE;
+ datum[i] = (Datum) tmpentry.pred;
+ }
+ itup = index_formtuple(RelationGetTupleDescriptor(r), datum, nulls);
+ itup->t_tid = *ht_ctid;
+
+ RelationSetLockForWrite(r);
+ res = gistdoinsert(r, itup, &giststate);
+ for (i = 0; i < r->rd_att->natts; i++)
+ if (compvec[i] == TRUE)
+ pfree((char *) datum[i]);
+ pfree(itup);
+ pfree(compvec);
+
+ /* XXX two-phase locking -- don't unlock the relation until EOT */
+ return (res);
}
/*
@@ -336,475 +373,509 @@ gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation
** that knowledge (some compression routines may want to fish around
** on the page, for example, or do something special for leaf nodes.)
*/
-static OffsetNumber
-gistPageAddItem(GISTSTATE *giststate,
- Relation r,
- Page page,
- Item item,
- Size size,
- OffsetNumber offsetNumber,
- ItemIdFlags flags,
- GISTENTRY *dentry,
- IndexTuple *newtup)
+static OffsetNumber
+gistPageAddItem(GISTSTATE * giststate,
+ Relation r,
+ Page page,
+ Item item,
+ Size size,
+ OffsetNumber offsetNumber,
+ ItemIdFlags flags,
+ GISTENTRY * dentry,
+ IndexTuple * newtup)
{
- GISTENTRY tmpcentry;
- IndexTuple itup = (IndexTuple)item;
-
- /* recompress the item given that we now know the exact page and
- offset for insertion */
- gistdentryinit(giststate, dentry,
- (((char *) itup) + sizeof(IndexTupleData)),
- (Relation)0, (Page)0, (OffsetNumber)InvalidOffsetNumber,
- IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE);
- gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page,
- offsetNumber, dentry->bytes, FALSE);
- *newtup = gist_tuple_replacekey(r, *dentry, itup);
- /* be tidy */
- if (tmpcentry.pred != dentry->pred
- && tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
- pfree(tmpcentry.pred);
-
- return(PageAddItem(page, (Item) *newtup, IndexTupleSize(*newtup),
- offsetNumber, flags));
+ GISTENTRY tmpcentry;
+ IndexTuple itup = (IndexTuple) item;
+
+ /*
+ * recompress the item given that we now know the exact page and
+ * offset for insertion
+ */
+ gistdentryinit(giststate, dentry,
+ (((char *) itup) + sizeof(IndexTupleData)),
+ (Relation) 0, (Page) 0, (OffsetNumber) InvalidOffsetNumber,
+ IndexTupleSize(itup) - sizeof(IndexTupleData), FALSE);
+ gistcentryinit(giststate, &tmpcentry, dentry->pred, r, page,
+ offsetNumber, dentry->bytes, FALSE);
+ *newtup = gist_tuple_replacekey(r, *dentry, itup);
+ /* be tidy */
+ if (tmpcentry.pred != dentry->pred
+ && tmpcentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
+ pfree(tmpcentry.pred);
+
+ return (PageAddItem(page, (Item) * newtup, IndexTupleSize(*newtup),
+ offsetNumber, flags));
}
-static InsertIndexResult
-gistdoinsert(Relation r,
- IndexTuple itup, /* itup contains compressed entry */
- GISTSTATE *giststate)
+static InsertIndexResult
+gistdoinsert(Relation r,
+ IndexTuple itup, /* itup contains compressed entry */
+ GISTSTATE * giststate)
{
- GISTENTRY tmpdentry;
- InsertIndexResult res;
- OffsetNumber l;
- GISTSTACK *stack;
- Buffer buffer;
- BlockNumber blk;
- Page page;
- OffsetNumber off;
- IndexTuple newtup;
-
- /* 3rd arg is ignored for now */
- blk = gistChooseSubtree(r, itup, 0, giststate, &stack, &buffer);
- page = (Page) BufferGetPage(buffer);
-
- if (gistnospace(page, itup)) {
- /* need to do a split */
- res = gistSplit(r, buffer, stack, itup, giststate);
+ GISTENTRY tmpdentry;
+ InsertIndexResult res;
+ OffsetNumber l;
+ GISTSTACK *stack;
+ Buffer buffer;
+ BlockNumber blk;
+ Page page;
+ OffsetNumber off;
+ IndexTuple newtup;
+
+ /* 3rd arg is ignored for now */
+ blk = gistChooseSubtree(r, itup, 0, giststate, &stack, &buffer);
+ page = (Page) BufferGetPage(buffer);
+
+ if (gistnospace(page, itup))
+ {
+ /* need to do a split */
+ res = gistSplit(r, buffer, stack, itup, giststate);
+ gistfreestack(stack);
+ WriteBuffer(buffer); /* don't forget to release buffer! */
+ return (res);
+ }
+
+ if (PageIsEmpty(page))
+ off = FirstOffsetNumber;
+ else
+ off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
+
+ /* add the item and write the buffer */
+ l = gistPageAddItem(giststate, r, page, (Item) itup, IndexTupleSize(itup),
+ off, LP_USED, &tmpdentry, &newtup);
+ WriteBuffer(buffer);
+
+ /* now expand the page boundary in the parent to include the new child */
+ gistAdjustKeys(r, stack, blk, tmpdentry.pred, tmpdentry.bytes, giststate);
gistfreestack(stack);
- WriteBuffer(buffer); /* don't forget to release buffer! */
+
+ /* be tidy */
+ if (itup != newtup)
+ pfree(newtup);
+ if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
+ pfree(tmpdentry.pred);
+
+ /* build and return an InsertIndexResult for this insertion */
+ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
+ ItemPointerSet(&(res->pointerData), blk, l);
+
return (res);
- }
-
- if (PageIsEmpty(page))
- off = FirstOffsetNumber;
- else
- off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
-
- /* add the item and write the buffer */
- l = gistPageAddItem(giststate, r, page, (Item) itup, IndexTupleSize(itup),
- off, LP_USED, &tmpdentry, &newtup);
- WriteBuffer(buffer);
-
- /* now expand the page boundary in the parent to include the new child */
- gistAdjustKeys(r, stack, blk, tmpdentry.pred, tmpdentry.bytes, giststate);
- gistfreestack(stack);
-
- /* be tidy */
- if (itup != newtup)
- pfree(newtup);
- if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
- pfree(tmpdentry.pred);
-
- /* build and return an InsertIndexResult for this insertion */
- res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
- ItemPointerSet(&(res->pointerData), blk, l);
-
- return (res);
}
-static BlockNumber
-gistChooseSubtree(Relation r, IndexTuple itup, /* itup has compressed entry */
- int level,
- GISTSTATE *giststate,
- GISTSTACK **retstack /*out*/,
- Buffer *leafbuf /*out*/)
+static BlockNumber
+gistChooseSubtree(Relation r, IndexTuple itup, /* itup has compressed
+ * entry */
+ int level,
+ GISTSTATE * giststate,
+ GISTSTACK ** retstack /* out */ ,
+ Buffer * leafbuf /* out */ )
{
- Buffer buffer;
- BlockNumber blk;
- GISTSTACK *stack;
- Page page;
- GISTPageOpaque opaque;
- IndexTuple which;
-
- blk = GISTP_ROOT;
- buffer = InvalidBuffer;
- stack = (GISTSTACK *) NULL;
-
- do {
- /* let go of current buffer before getting next */
- if (buffer != InvalidBuffer)
- ReleaseBuffer(buffer);
-
- /* get next buffer */
- buffer = ReadBuffer(r, blk);
- page = (Page) BufferGetPage(buffer);
-
- opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
- if (!(opaque->flags & F_LEAF)) {
- GISTSTACK *n;
- ItemId iid;
-
- n = (GISTSTACK *) palloc(sizeof(GISTSTACK));
- n->gs_parent = stack;
- n->gs_blk = blk;
- n->gs_child = gistchoose(r, page, itup, giststate);
- stack = n;
-
- iid = PageGetItemId(page, n->gs_child);
- which = (IndexTuple) PageGetItem(page, iid);
- blk = ItemPointerGetBlockNumber(&(which->t_tid));
- }
- } while (!(opaque->flags & F_LEAF));
-
- *retstack = stack;
- *leafbuf = buffer;
-
- return(blk);
+ Buffer buffer;
+ BlockNumber blk;
+ GISTSTACK *stack;
+ Page page;
+ GISTPageOpaque opaque;
+ IndexTuple which;
+
+ blk = GISTP_ROOT;
+ buffer = InvalidBuffer;
+ stack = (GISTSTACK *) NULL;
+
+ do
+ {
+ /* let go of current buffer before getting next */
+ if (buffer != InvalidBuffer)
+ ReleaseBuffer(buffer);
+
+ /* get next buffer */
+ buffer = ReadBuffer(r, blk);
+ page = (Page) BufferGetPage(buffer);
+
+ opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
+ if (!(opaque->flags & F_LEAF))
+ {
+ GISTSTACK *n;
+ ItemId iid;
+
+ n = (GISTSTACK *) palloc(sizeof(GISTSTACK));
+ n->gs_parent = stack;
+ n->gs_blk = blk;
+ n->gs_child = gistchoose(r, page, itup, giststate);
+ stack = n;
+
+ iid = PageGetItemId(page, n->gs_child);
+ which = (IndexTuple) PageGetItem(page, iid);
+ blk = ItemPointerGetBlockNumber(&(which->t_tid));
+ }
+ } while (!(opaque->flags & F_LEAF));
+
+ *retstack = stack;
+ *leafbuf = buffer;
+
+ return (blk);
}
static void
gistAdjustKeys(Relation r,
- GISTSTACK *stk,
- BlockNumber blk,
- char *datum, /* datum is uncompressed */
- int att_size,
- GISTSTATE *giststate)
+ GISTSTACK * stk,
+ BlockNumber blk,
+ char *datum, /* datum is uncompressed */
+ int att_size,
+ GISTSTATE * giststate)
{
- char *oldud;
- Page p;
- Buffer b;
- bool result;
- bytea *evec;
- GISTENTRY centry, *ev0p, *ev1p;
- int size, datumsize;
- IndexTuple tid;
-
- if (stk == (GISTSTACK *) NULL)
- return;
-
- b = ReadBuffer(r, stk->gs_blk);
- p = BufferGetPage(b);
-
- oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->gs_child));
- tid = (IndexTuple) oldud;
- size = IndexTupleSize((IndexTuple)oldud) - sizeof(IndexTupleData);
- oldud += sizeof(IndexTupleData);
-
- evec = (bytea *) palloc(2*sizeof(GISTENTRY) + VARHDRSZ);
- VARSIZE(evec) = 2*sizeof(GISTENTRY) + VARHDRSZ;
-
- /* insert decompressed oldud into entry vector */
- gistdentryinit(giststate, &((GISTENTRY *)VARDATA(evec))[0],
- oldud, r, p, stk->gs_child,
- size, FALSE);
- ev0p = &((GISTENTRY *)VARDATA(evec))[0];
-
- /* insert datum entry into entry vector */
- gistentryinit(((GISTENTRY *)VARDATA(evec))[1], datum,
- (Relation)NULL,(Page)NULL,(OffsetNumber)0, att_size, FALSE);
- ev1p = &((GISTENTRY *)VARDATA(evec))[1];
-
- /* form union of decompressed entries */
- datum = (char *) (giststate->unionFn)(evec, &datumsize);
-
- /* did union leave decompressed version of oldud unchanged? */
- (giststate->equalFn)(ev0p->pred, datum, &result);
- if (!result) {
- TupleDesc td = RelationGetTupleDescriptor(r);
-
- /* compress datum for storage on page */
- gistcentryinit(giststate, &centry, datum, ev0p->rel, ev0p->page,
- ev0p->offset, datumsize, FALSE);
- if (td->attrs[0]->attlen >= 0) {
- memmove(oldud, centry.pred, att_size);
- gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size,
- giststate);
+ char *oldud;
+ Page p;
+ Buffer b;
+ bool result;
+ bytea *evec;
+ GISTENTRY centry,
+ *ev0p,
+ *ev1p;
+ int size,
+ datumsize;
+ IndexTuple tid;
+
+ if (stk == (GISTSTACK *) NULL)
+ return;
+
+ b = ReadBuffer(r, stk->gs_blk);
+ p = BufferGetPage(b);
+
+ oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->gs_child));
+ tid = (IndexTuple) oldud;
+ size = IndexTupleSize((IndexTuple) oldud) - sizeof(IndexTupleData);
+ oldud += sizeof(IndexTupleData);
+
+ evec = (bytea *) palloc(2 * sizeof(GISTENTRY) + VARHDRSZ);
+ VARSIZE(evec) = 2 * sizeof(GISTENTRY) + VARHDRSZ;
+
+ /* insert decompressed oldud into entry vector */
+ gistdentryinit(giststate, &((GISTENTRY *) VARDATA(evec))[0],
+ oldud, r, p, stk->gs_child,
+ size, FALSE);
+ ev0p = &((GISTENTRY *) VARDATA(evec))[0];
+
+ /* insert datum entry into entry vector */
+ gistentryinit(((GISTENTRY *) VARDATA(evec))[1], datum,
+ (Relation) NULL, (Page) NULL, (OffsetNumber) 0, att_size, FALSE);
+ ev1p = &((GISTENTRY *) VARDATA(evec))[1];
+
+ /* form union of decompressed entries */
+ datum = (char *) (giststate->unionFn) (evec, &datumsize);
+
+ /* did union leave decompressed version of oldud unchanged? */
+ (giststate->equalFn) (ev0p->pred, datum, &result);
+ if (!result)
+ {
+ TupleDesc td = RelationGetTupleDescriptor(r);
+
+ /* compress datum for storage on page */
+ gistcentryinit(giststate, &centry, datum, ev0p->rel, ev0p->page,
+ ev0p->offset, datumsize, FALSE);
+ if (td->attrs[0]->attlen >= 0)
+ {
+ memmove(oldud, centry.pred, att_size);
+ gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size,
+ giststate);
+ }
+ else if (VARSIZE(centry.pred) == VARSIZE(oldud))
+ {
+ memmove(oldud, centry.pred, VARSIZE(centry.pred));
+ gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size,
+ giststate);
+ }
+ else
+ {
+
+ /*
+ * * new datum is not the same size as the old. * We have to
+ * delete the old entry and insert the new * one. Note that
+ * this may cause a split here!
+ */
+ IndexTuple newtup;
+ ItemPointerData oldtid;
+ char *isnull;
+ TupleDesc tupDesc;
+ InsertIndexResult res;
+
+ /* delete old tuple */
+ ItemPointerSet(&oldtid, stk->gs_blk, stk->gs_child);
+ gistdelete(r, (ItemPointer) & oldtid);
+
+ /* generate and insert new tuple */
+ tupDesc = r->rd_att;
+ isnull = (char *) palloc(r->rd_rel->relnatts);
+ memset(isnull, ' ', r->rd_rel->relnatts);
+ newtup = (IndexTuple) index_formtuple(tupDesc,
+ (Datum *) & centry.pred, isnull);
+ pfree(isnull);
+ /* set pointer in new tuple to point to current child */
+ ItemPointerSet(&oldtid, blk, 1);
+ newtup->t_tid = oldtid;
+
+ /* inserting the new entry also adjust keys above */
+ res = gistentryinsert(r, stk, newtup, giststate);
+
+ /* in stack, set info to point to new tuple */
+ stk->gs_blk = ItemPointerGetBlockNumber(&(res->pointerData));
+ stk->gs_child = ItemPointerGetOffsetNumber(&(res->pointerData));
+
+ pfree(res);
+ }
+ WriteBuffer(b);
+
+ if (centry.pred != datum)
+ pfree(datum);
}
- else if (VARSIZE(centry.pred) == VARSIZE(oldud)) {
- memmove(oldud, centry.pred, VARSIZE(centry.pred));
- gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, datum, att_size,
- giststate);
+ else
+ {
+ ReleaseBuffer(b);
}
- else {
- /*
- ** new datum is not the same size as the old.
- ** We have to delete the old entry and insert the new
- ** one. Note that this may cause a split here!
- */
- IndexTuple newtup;
- ItemPointerData oldtid;
- char *isnull;
- TupleDesc tupDesc;
- InsertIndexResult res;
-
- /* delete old tuple */
- ItemPointerSet(&oldtid, stk->gs_blk, stk->gs_child);
- gistdelete(r, (ItemPointer)&oldtid);
-
- /* generate and insert new tuple */
- tupDesc = r->rd_att;
- isnull = (char *) palloc(r->rd_rel->relnatts);
- memset(isnull, ' ', r->rd_rel->relnatts);
- newtup = (IndexTuple) index_formtuple(tupDesc,
- (Datum *) &centry.pred, isnull);
- pfree(isnull);
- /* set pointer in new tuple to point to current child */
- ItemPointerSet(&oldtid, blk, 1);
- newtup->t_tid = oldtid;
-
- /* inserting the new entry also adjust keys above */
- res = gistentryinsert(r, stk, newtup, giststate);
-
- /* in stack, set info to point to new tuple */
- stk->gs_blk = ItemPointerGetBlockNumber(&(res->pointerData));
- stk->gs_child = ItemPointerGetOffsetNumber(&(res->pointerData));
-
- pfree(res);
- }
- WriteBuffer(b);
-
- if (centry.pred != datum)
- pfree(datum);
- }
- else {
- ReleaseBuffer(b);
- }
- pfree(evec);
+ pfree(evec);
}
/*
- * gistSplit -- split a page in the tree.
+ * gistSplit -- split a page in the tree.
*
*/
-static InsertIndexResult
+static InsertIndexResult
gistSplit(Relation r,
- Buffer buffer,
- GISTSTACK *stack,
- IndexTuple itup, /* contains compressed entry */
- GISTSTATE *giststate)
+ Buffer buffer,
+ GISTSTACK * stack,
+ IndexTuple itup, /* contains compressed entry */
+ GISTSTATE * giststate)
{
- Page p;
- Buffer leftbuf, rightbuf;
- Page left, right;
- ItemId itemid;
- IndexTuple item;
- IndexTuple ltup, rtup, newtup;
- OffsetNumber maxoff;
- OffsetNumber i;
- OffsetNumber leftoff, rightoff;
- BlockNumber lbknum, rbknum;
- BlockNumber bufblock;
- GISTPageOpaque opaque;
- int blank;
- InsertIndexResult res;
- char *isnull;
- GIST_SPLITVEC v;
- TupleDesc tupDesc;
- bytea *entryvec;
- bool *decompvec;
- IndexTuple item_1;
- GISTENTRY tmpdentry, tmpentry;
-
- isnull = (char *) palloc(r->rd_rel->relnatts);
- for (blank = 0; blank < r->rd_rel->relnatts; blank++)
- isnull[blank] = ' ';
- p = (Page) BufferGetPage(buffer);
- opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
-
-
- /*
- * The root of the tree is the first block in the relation. If
- * we're about to split the root, we need to do some hocus-pocus
- * to enforce this guarantee.
- */
-
- if (BufferGetBlockNumber(buffer) == GISTP_ROOT) {
- leftbuf = ReadBuffer(r, P_NEW);
- GISTInitBuffer(leftbuf, opaque->flags);
- lbknum = BufferGetBlockNumber(leftbuf);
- left = (Page) BufferGetPage(leftbuf);
- } else {
- leftbuf = buffer;
- IncrBufferRefCount(buffer);
- lbknum = BufferGetBlockNumber(buffer);
- left = (Page) PageGetTempPage(p, sizeof(GISTPageOpaqueData));
- }
-
- rightbuf = ReadBuffer(r, P_NEW);
- GISTInitBuffer(rightbuf, opaque->flags);
- rbknum = BufferGetBlockNumber(rightbuf);
- right = (Page) BufferGetPage(rightbuf);
-
- /* generate the item array */
- maxoff = PageGetMaxOffsetNumber(p);
- entryvec = (bytea *)palloc(VARHDRSZ + (maxoff + 2) * sizeof(GISTENTRY));
- decompvec = (bool *)palloc(VARHDRSZ + (maxoff + 2) * sizeof(bool));
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
- item_1 = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
- gistdentryinit(giststate, &((GISTENTRY *)VARDATA(entryvec))[i],
- (((char *) item_1) + sizeof(IndexTupleData)),
- r, p, i,
- IndexTupleSize(item_1) - sizeof(IndexTupleData), FALSE);
- if ((char *)(((GISTENTRY *)VARDATA(entryvec))[i].pred)
- == (((char *) item_1) + sizeof(IndexTupleData)))
- decompvec[i] = FALSE;
- else decompvec[i] = TRUE;
- }
-
- /* add the new datum as the last entry */
- gistdentryinit(giststate, &(((GISTENTRY *)VARDATA(entryvec))[maxoff+1]),
- (((char *) itup) + sizeof(IndexTupleData)),
- (Relation)NULL, (Page)NULL,
- (OffsetNumber)0, tmpentry.bytes, FALSE);
- if ((char *)(((GISTENTRY *)VARDATA(entryvec))[maxoff+1]).pred !=
- (((char *) itup) + sizeof(IndexTupleData)))
- decompvec[maxoff+1] = TRUE;
- else decompvec[maxoff+1] = FALSE;
-
- VARSIZE(entryvec) = (maxoff + 2) * sizeof(GISTENTRY) + VARHDRSZ;
-
- /* now let the user-defined picksplit function set up the split vector */
- (giststate->picksplitFn)(entryvec, &v);
-
- /* compress ldatum and rdatum */
- gistcentryinit(giststate, &tmpentry, v.spl_ldatum, (Relation)NULL,
- (Page)NULL, (OffsetNumber)0,
- ((GISTENTRY *)VARDATA(entryvec))[i].bytes, FALSE);
- if (v.spl_ldatum != tmpentry.pred)
- pfree(v.spl_ldatum);
- v.spl_ldatum = tmpentry.pred;
-
- gistcentryinit(giststate, &tmpentry, v.spl_rdatum, (Relation)NULL,
- (Page)NULL, (OffsetNumber)0,
- ((GISTENTRY *)VARDATA(entryvec))[i].bytes, FALSE);
- if (v.spl_rdatum != tmpentry.pred)
- pfree(v.spl_rdatum);
- v.spl_rdatum = tmpentry.pred;
-
- /* clean up the entry vector: its preds need to be deleted, too */
- for (i = FirstOffsetNumber; i <= maxoff+1; i = OffsetNumberNext(i))
- if (decompvec[i])
- pfree(((GISTENTRY *)VARDATA(entryvec))[i].pred);
- pfree(entryvec);
- pfree(decompvec);
-
- leftoff = rightoff = FirstOffsetNumber;
- maxoff = PageGetMaxOffsetNumber(p);
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
- itemid = PageGetItemId(p, i);
- item = (IndexTuple) PageGetItem(p, itemid);
-
- if (i == *(v.spl_left)) {
- gistPageAddItem(giststate, r, left, (Item) item,
- IndexTupleSize(item),
- leftoff, LP_USED, &tmpdentry, &newtup);
- leftoff = OffsetNumberNext(leftoff);
- v.spl_left++; /* advance in left split vector */
- /* be tidy */
- if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData)))
- pfree(tmpdentry.pred);
- if ((IndexTuple)item != newtup)
- pfree(newtup);
- }
- else {
- gistPageAddItem(giststate, r, right, (Item) item,
- IndexTupleSize(item),
- rightoff, LP_USED, &tmpdentry, &newtup);
- rightoff = OffsetNumberNext(rightoff);
- v.spl_right++; /* advance in right split vector */
- /* be tidy */
- if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData)))
- pfree(tmpdentry.pred);
- if (item != newtup)
- pfree(newtup);
+ Page p;
+ Buffer leftbuf,
+ rightbuf;
+ Page left,
+ right;
+ ItemId itemid;
+ IndexTuple item;
+ IndexTuple ltup,
+ rtup,
+ newtup;
+ OffsetNumber maxoff;
+ OffsetNumber i;
+ OffsetNumber leftoff,
+ rightoff;
+ BlockNumber lbknum,
+ rbknum;
+ BlockNumber bufblock;
+ GISTPageOpaque opaque;
+ int blank;
+ InsertIndexResult res;
+ char *isnull;
+ GIST_SPLITVEC v;
+ TupleDesc tupDesc;
+ bytea *entryvec;
+ bool *decompvec;
+ IndexTuple item_1;
+ GISTENTRY tmpdentry,
+ tmpentry;
+
+ isnull = (char *) palloc(r->rd_rel->relnatts);
+ for (blank = 0; blank < r->rd_rel->relnatts; blank++)
+ isnull[blank] = ' ';
+ p = (Page) BufferGetPage(buffer);
+ opaque = (GISTPageOpaque) PageGetSpecialPointer(p);
+
+
+ /*
+ * The root of the tree is the first block in the relation. If we're
+ * about to split the root, we need to do some hocus-pocus to enforce
+ * this guarantee.
+ */
+
+ if (BufferGetBlockNumber(buffer) == GISTP_ROOT)
+ {
+ leftbuf = ReadBuffer(r, P_NEW);
+ GISTInitBuffer(leftbuf, opaque->flags);
+ lbknum = BufferGetBlockNumber(leftbuf);
+ left = (Page) BufferGetPage(leftbuf);
}
- }
-
- /* build an InsertIndexResult for this insertion */
- res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
-
- /* now insert the new index tuple */
- if (*(v.spl_left) != FirstOffsetNumber) {
- gistPageAddItem(giststate, r, left, (Item) itup,
- IndexTupleSize(itup),
- leftoff, LP_USED, &tmpdentry, &newtup);
- leftoff = OffsetNumberNext(leftoff);
- ItemPointerSet(&(res->pointerData), lbknum, leftoff);
- /* be tidy */
- if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
- pfree(tmpdentry.pred);
- if (itup != newtup)
- pfree(newtup);
- } else {
- gistPageAddItem(giststate, r, right, (Item) itup,
- IndexTupleSize(itup),
- rightoff, LP_USED, &tmpdentry, &newtup);
- rightoff = OffsetNumberNext(rightoff);
- ItemPointerSet(&(res->pointerData), rbknum, rightoff);
- /* be tidy */
- if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
- pfree(tmpdentry.pred);
- if (itup != newtup)
- pfree(newtup);
- }
-
- if ((bufblock = BufferGetBlockNumber(buffer)) != GISTP_ROOT) {
- PageRestoreTempPage(left, p);
- }
- WriteBuffer(leftbuf);
- WriteBuffer(rightbuf);
-
- /*
- * Okay, the page is split. We have three things left to do:
- *
- * 1) Adjust any active scans on this index to cope with changes
- * we introduced in its structure by splitting this page.
- *
- * 2) "Tighten" the bounding box of the pointer to the left
- * page in the parent node in the tree, if any. Since we
- * moved a bunch of stuff off the left page, we expect it
- * to get smaller. This happens in the internal insertion
- * routine.
- *
- * 3) Insert a pointer to the right page in the parent. This
- * may cause the parent to split. If it does, we need to
- * repeat steps one and two for each split node in the tree.
- */
-
- /* adjust active scans */
- gistadjscans(r, GISTOP_SPLIT, bufblock, FirstOffsetNumber);
-
- tupDesc = r->rd_att;
-
- ltup = (IndexTuple) index_formtuple(tupDesc,
- (Datum *) &(v.spl_ldatum), isnull);
- rtup = (IndexTuple) index_formtuple(tupDesc,
- (Datum *) &(v.spl_rdatum), isnull);
- pfree(isnull);
-
- /* set pointers to new child pages in the internal index tuples */
- ItemPointerSet(&(ltup->t_tid), lbknum, 1);
- ItemPointerSet(&(rtup->t_tid), rbknum, 1);
-
- gistintinsert(r, stack, ltup, rtup, giststate);
-
- pfree(ltup);
- pfree(rtup);
-
- return (res);
+ else
+ {
+ leftbuf = buffer;
+ IncrBufferRefCount(buffer);
+ lbknum = BufferGetBlockNumber(buffer);
+ left = (Page) PageGetTempPage(p, sizeof(GISTPageOpaqueData));
+ }
+
+ rightbuf = ReadBuffer(r, P_NEW);
+ GISTInitBuffer(rightbuf, opaque->flags);
+ rbknum = BufferGetBlockNumber(rightbuf);
+ right = (Page) BufferGetPage(rightbuf);
+
+ /* generate the item array */
+ maxoff = PageGetMaxOffsetNumber(p);
+ entryvec = (bytea *) palloc(VARHDRSZ + (maxoff + 2) * sizeof(GISTENTRY));
+ decompvec = (bool *) palloc(VARHDRSZ + (maxoff + 2) * sizeof(bool));
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ item_1 = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
+ gistdentryinit(giststate, &((GISTENTRY *) VARDATA(entryvec))[i],
+ (((char *) item_1) + sizeof(IndexTupleData)),
+ r, p, i,
+ IndexTupleSize(item_1) - sizeof(IndexTupleData), FALSE);
+ if ((char *) (((GISTENTRY *) VARDATA(entryvec))[i].pred)
+ == (((char *) item_1) + sizeof(IndexTupleData)))
+ decompvec[i] = FALSE;
+ else
+ decompvec[i] = TRUE;
+ }
+
+ /* add the new datum as the last entry */
+ gistdentryinit(giststate, &(((GISTENTRY *) VARDATA(entryvec))[maxoff + 1]),
+ (((char *) itup) + sizeof(IndexTupleData)),
+ (Relation) NULL, (Page) NULL,
+ (OffsetNumber) 0, tmpentry.bytes, FALSE);
+ if ((char *) (((GISTENTRY *) VARDATA(entryvec))[maxoff + 1]).pred !=
+ (((char *) itup) + sizeof(IndexTupleData)))
+ decompvec[maxoff + 1] = TRUE;
+ else
+ decompvec[maxoff + 1] = FALSE;
+
+ VARSIZE(entryvec) = (maxoff + 2) * sizeof(GISTENTRY) + VARHDRSZ;
+
+ /* now let the user-defined picksplit function set up the split vector */
+ (giststate->picksplitFn) (entryvec, &v);
+
+ /* compress ldatum and rdatum */
+ gistcentryinit(giststate, &tmpentry, v.spl_ldatum, (Relation) NULL,
+ (Page) NULL, (OffsetNumber) 0,
+ ((GISTENTRY *) VARDATA(entryvec))[i].bytes, FALSE);
+ if (v.spl_ldatum != tmpentry.pred)
+ pfree(v.spl_ldatum);
+ v.spl_ldatum = tmpentry.pred;
+
+ gistcentryinit(giststate, &tmpentry, v.spl_rdatum, (Relation) NULL,
+ (Page) NULL, (OffsetNumber) 0,
+ ((GISTENTRY *) VARDATA(entryvec))[i].bytes, FALSE);
+ if (v.spl_rdatum != tmpentry.pred)
+ pfree(v.spl_rdatum);
+ v.spl_rdatum = tmpentry.pred;
+
+ /* clean up the entry vector: its preds need to be deleted, too */
+ for (i = FirstOffsetNumber; i <= maxoff + 1; i = OffsetNumberNext(i))
+ if (decompvec[i])
+ pfree(((GISTENTRY *) VARDATA(entryvec))[i].pred);
+ pfree(entryvec);
+ pfree(decompvec);
+
+ leftoff = rightoff = FirstOffsetNumber;
+ maxoff = PageGetMaxOffsetNumber(p);
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ itemid = PageGetItemId(p, i);
+ item = (IndexTuple) PageGetItem(p, itemid);
+
+ if (i == *(v.spl_left))
+ {
+ gistPageAddItem(giststate, r, left, (Item) item,
+ IndexTupleSize(item),
+ leftoff, LP_USED, &tmpdentry, &newtup);
+ leftoff = OffsetNumberNext(leftoff);
+ v.spl_left++; /* advance in left split vector */
+ /* be tidy */
+ if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData)))
+ pfree(tmpdentry.pred);
+ if ((IndexTuple) item != newtup)
+ pfree(newtup);
+ }
+ else
+ {
+ gistPageAddItem(giststate, r, right, (Item) item,
+ IndexTupleSize(item),
+ rightoff, LP_USED, &tmpdentry, &newtup);
+ rightoff = OffsetNumberNext(rightoff);
+ v.spl_right++; /* advance in right split vector */
+ /* be tidy */
+ if (tmpdentry.pred != (((char *) item) + sizeof(IndexTupleData)))
+ pfree(tmpdentry.pred);
+ if (item != newtup)
+ pfree(newtup);
+ }
+ }
+
+ /* build an InsertIndexResult for this insertion */
+ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
+
+ /* now insert the new index tuple */
+ if (*(v.spl_left) != FirstOffsetNumber)
+ {
+ gistPageAddItem(giststate, r, left, (Item) itup,
+ IndexTupleSize(itup),
+ leftoff, LP_USED, &tmpdentry, &newtup);
+ leftoff = OffsetNumberNext(leftoff);
+ ItemPointerSet(&(res->pointerData), lbknum, leftoff);
+ /* be tidy */
+ if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
+ pfree(tmpdentry.pred);
+ if (itup != newtup)
+ pfree(newtup);
+ }
+ else
+ {
+ gistPageAddItem(giststate, r, right, (Item) itup,
+ IndexTupleSize(itup),
+ rightoff, LP_USED, &tmpdentry, &newtup);
+ rightoff = OffsetNumberNext(rightoff);
+ ItemPointerSet(&(res->pointerData), rbknum, rightoff);
+ /* be tidy */
+ if (tmpdentry.pred != (((char *) itup) + sizeof(IndexTupleData)))
+ pfree(tmpdentry.pred);
+ if (itup != newtup)
+ pfree(newtup);
+ }
+
+ if ((bufblock = BufferGetBlockNumber(buffer)) != GISTP_ROOT)
+ {
+ PageRestoreTempPage(left, p);
+ }
+ WriteBuffer(leftbuf);
+ WriteBuffer(rightbuf);
+
+ /*
+ * Okay, the page is split. We have three things left to do:
+ *
+ * 1) Adjust any active scans on this index to cope with changes we
+ * introduced in its structure by splitting this page.
+ *
+ * 2) "Tighten" the bounding box of the pointer to the left page in the
+ * parent node in the tree, if any. Since we moved a bunch of stuff
+ * off the left page, we expect it to get smaller. This happens in
+ * the internal insertion routine.
+ *
+ * 3) Insert a pointer to the right page in the parent. This may cause
+ * the parent to split. If it does, we need to repeat steps one and
+ * two for each split node in the tree.
+ */
+
+ /* adjust active scans */
+ gistadjscans(r, GISTOP_SPLIT, bufblock, FirstOffsetNumber);
+
+ tupDesc = r->rd_att;
+
+ ltup = (IndexTuple) index_formtuple(tupDesc,
+ (Datum *) & (v.spl_ldatum), isnull);
+ rtup = (IndexTuple) index_formtuple(tupDesc,
+ (Datum *) & (v.spl_rdatum), isnull);
+ pfree(isnull);
+
+ /* set pointers to new child pages in the internal index tuples */
+ ItemPointerSet(&(ltup->t_tid), lbknum, 1);
+ ItemPointerSet(&(rtup->t_tid), rbknum, 1);
+
+ gistintinsert(r, stack, ltup, rtup, giststate);
+
+ pfree(ltup);
+ pfree(rtup);
+
+ return (res);
}
/*
@@ -813,22 +884,23 @@ gistSplit(Relation r,
*/
static void
gistintinsert(Relation r,
- GISTSTACK *stk,
- IndexTuple ltup, /* new version of entry for old page */
- IndexTuple rtup, /* entry for new page */
- GISTSTATE *giststate)
+ GISTSTACK * stk,
+ IndexTuple ltup, /* new version of entry for old page */
+ IndexTuple rtup, /* entry for new page */
+ GISTSTATE * giststate)
{
- ItemPointerData ltid;
+ ItemPointerData ltid;
- if (stk == (GISTSTACK *) NULL) {
- gistnewroot(giststate, r, ltup, rtup);
- return;
- }
-
- /* remove old left pointer, insert the 2 new entries */
- ItemPointerSet(&ltid, stk->gs_blk, stk->gs_child);
- gistdelete(r, (ItemPointer)&ltid);
- gistentryinserttwo(r, stk, ltup, rtup, giststate);
+ if (stk == (GISTSTACK *) NULL)
+ {
+ gistnewroot(giststate, r, ltup, rtup);
+ return;
+ }
+
+ /* remove old left pointer, insert the 2 new entries */
+ ItemPointerSet(&ltid, stk->gs_blk, stk->gs_child);
+ gistdelete(r, (ItemPointer) & ltid);
+ gistentryinserttwo(r, stk, ltup, rtup, giststate);
}
@@ -836,280 +908,299 @@ gistintinsert(Relation r,
** Insert two entries onto one page, handling a split for either one!
*/
static void
-gistentryinserttwo(Relation r, GISTSTACK *stk, IndexTuple ltup,
- IndexTuple rtup, GISTSTATE *giststate)
+gistentryinserttwo(Relation r, GISTSTACK * stk, IndexTuple ltup,
+ IndexTuple rtup, GISTSTATE * giststate)
{
- Buffer b;
- Page p;
- InsertIndexResult res;
- GISTENTRY tmpentry;
- IndexTuple newtup;
-
- b = ReadBuffer(r, stk->gs_blk);
- p = BufferGetPage(b);
-
- if (gistnospace(p, ltup)) {
- res = gistSplit(r, b, stk->gs_parent, ltup, giststate);
- WriteBuffer(b); /* don't forget to release buffer! - 01/31/94 */
- pfree(res);
- gistdoinsert(r, rtup, giststate);
- } else {
- gistPageAddItem(giststate, r, p, (Item)ltup,
- IndexTupleSize(ltup), InvalidOffsetNumber,
- LP_USED, &tmpentry, &newtup);
- WriteBuffer(b);
- gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred,
- tmpentry.bytes, giststate);
- /* be tidy */
- if (tmpentry.pred != (((char *) ltup) + sizeof(IndexTupleData)))
- pfree(tmpentry.pred);
- if (ltup != newtup)
- pfree(newtup);
- gistentryinsert(r, stk, rtup, giststate);
- }
-}
+ Buffer b;
+ Page p;
+ InsertIndexResult res;
+ GISTENTRY tmpentry;
+ IndexTuple newtup;
+
+ b = ReadBuffer(r, stk->gs_blk);
+ p = BufferGetPage(b);
+
+ if (gistnospace(p, ltup))
+ {
+ res = gistSplit(r, b, stk->gs_parent, ltup, giststate);
+ WriteBuffer(b); /* don't forget to release buffer! -
+ * 01/31/94 */
+ pfree(res);
+ gistdoinsert(r, rtup, giststate);
+ }
+ else
+ {
+ gistPageAddItem(giststate, r, p, (Item) ltup,
+ IndexTupleSize(ltup), InvalidOffsetNumber,
+ LP_USED, &tmpentry, &newtup);
+ WriteBuffer(b);
+ gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred,
+ tmpentry.bytes, giststate);
+ /* be tidy */
+ if (tmpentry.pred != (((char *) ltup) + sizeof(IndexTupleData)))
+ pfree(tmpentry.pred);
+ if (ltup != newtup)
+ pfree(newtup);
+ gistentryinsert(r, stk, rtup, giststate);
+ }
+}
/*
** Insert an entry onto a page
*/
-static InsertIndexResult
-gistentryinsert(Relation r, GISTSTACK *stk, IndexTuple tup,
- GISTSTATE *giststate)
+static InsertIndexResult
+gistentryinsert(Relation r, GISTSTACK * stk, IndexTuple tup,
+ GISTSTATE * giststate)
{
- Buffer b;
- Page p;
- InsertIndexResult res;
- OffsetNumber off;
- GISTENTRY tmpentry;
- IndexTuple newtup;
-
- b = ReadBuffer(r, stk->gs_blk);
- p = BufferGetPage(b);
-
- if (gistnospace(p, tup)) {
- res = gistSplit(r, b, stk->gs_parent, tup, giststate);
- WriteBuffer(b); /* don't forget to release buffer! - 01/31/94 */
- return(res);
- }
- else {
- res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
- off = gistPageAddItem(giststate, r, p, (Item) tup, IndexTupleSize(tup),
- InvalidOffsetNumber, LP_USED, &tmpentry, &newtup);
- WriteBuffer(b);
- ItemPointerSet(&(res->pointerData), stk->gs_blk, off);
- gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred,
- tmpentry.bytes, giststate);
- /* be tidy */
- if (tmpentry.pred != (((char *) tup) + sizeof(IndexTupleData)))
- pfree(tmpentry.pred);
- if (tup != newtup)
- pfree(newtup);
- return(res);
- }
-}
+ Buffer b;
+ Page p;
+ InsertIndexResult res;
+ OffsetNumber off;
+ GISTENTRY tmpentry;
+ IndexTuple newtup;
+
+ b = ReadBuffer(r, stk->gs_blk);
+ p = BufferGetPage(b);
+
+ if (gistnospace(p, tup))
+ {
+ res = gistSplit(r, b, stk->gs_parent, tup, giststate);
+ WriteBuffer(b); /* don't forget to release buffer! -
+ * 01/31/94 */
+ return (res);
+ }
+ else
+ {
+ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
+ off = gistPageAddItem(giststate, r, p, (Item) tup, IndexTupleSize(tup),
+ InvalidOffsetNumber, LP_USED, &tmpentry, &newtup);
+ WriteBuffer(b);
+ ItemPointerSet(&(res->pointerData), stk->gs_blk, off);
+ gistAdjustKeys(r, stk->gs_parent, stk->gs_blk, tmpentry.pred,
+ tmpentry.bytes, giststate);
+ /* be tidy */
+ if (tmpentry.pred != (((char *) tup) + sizeof(IndexTupleData)))
+ pfree(tmpentry.pred);
+ if (tup != newtup)
+ pfree(newtup);
+ return (res);
+ }
+}
static void
-gistnewroot(GISTSTATE *giststate, Relation r, IndexTuple lt, IndexTuple rt)
+gistnewroot(GISTSTATE * giststate, Relation r, IndexTuple lt, IndexTuple rt)
{
- Buffer b;
- Page p;
- GISTENTRY tmpentry;
- IndexTuple newtup;
-
- b = ReadBuffer(r, GISTP_ROOT);
- GISTInitBuffer(b, 0);
- p = BufferGetPage(b);
- gistPageAddItem(giststate, r, p, (Item) lt, IndexTupleSize(lt),
- FirstOffsetNumber,
- LP_USED, &tmpentry, &newtup);
- /* be tidy */
- if (tmpentry.pred != (((char *) lt) + sizeof(IndexTupleData)))
- pfree(tmpentry.pred);
- if (lt != newtup)
- pfree(newtup);
- gistPageAddItem(giststate, r, p, (Item) rt, IndexTupleSize(rt),
- OffsetNumberNext(FirstOffsetNumber), LP_USED,
- &tmpentry, &newtup);
- /* be tidy */
- if (tmpentry.pred != (((char *) rt) + sizeof(IndexTupleData)))
- pfree(tmpentry.pred);
- if (rt != newtup)
- pfree(newtup);
- WriteBuffer(b);
+ Buffer b;
+ Page p;
+ GISTENTRY tmpentry;
+ IndexTuple newtup;
+
+ b = ReadBuffer(r, GISTP_ROOT);
+ GISTInitBuffer(b, 0);
+ p = BufferGetPage(b);
+ gistPageAddItem(giststate, r, p, (Item) lt, IndexTupleSize(lt),
+ FirstOffsetNumber,
+ LP_USED, &tmpentry, &newtup);
+ /* be tidy */
+ if (tmpentry.pred != (((char *) lt) + sizeof(IndexTupleData)))
+ pfree(tmpentry.pred);
+ if (lt != newtup)
+ pfree(newtup);
+ gistPageAddItem(giststate, r, p, (Item) rt, IndexTupleSize(rt),
+ OffsetNumberNext(FirstOffsetNumber), LP_USED,
+ &tmpentry, &newtup);
+ /* be tidy */
+ if (tmpentry.pred != (((char *) rt) + sizeof(IndexTupleData)))
+ pfree(tmpentry.pred);
+ if (rt != newtup)
+ pfree(newtup);
+ WriteBuffer(b);
}
static void
GISTInitBuffer(Buffer b, uint32 f)
{
- GISTPageOpaque opaque;
- Page page;
- Size pageSize;
-
- pageSize = BufferGetPageSize(b);
-
- page = BufferGetPage(b);
- memset(page, 0, (int) pageSize);
- PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
-
- opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
- opaque->flags = f;
+ GISTPageOpaque opaque;
+ Page page;
+ Size pageSize;
+
+ pageSize = BufferGetPageSize(b);
+
+ page = BufferGetPage(b);
+ memset(page, 0, (int) pageSize);
+ PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
+
+ opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
+ opaque->flags = f;
}
/*
** find entry with lowest penalty
*/
-static OffsetNumber
-gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
- GISTSTATE *giststate)
+static OffsetNumber
+gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
+ GISTSTATE * giststate)
{
- OffsetNumber maxoff;
- OffsetNumber i;
- char *id;
- char *datum;
- float usize;
- OffsetNumber which;
- float which_grow;
- GISTENTRY entry, identry;
- int size, idsize;
-
- idsize = IndexTupleSize(it) - sizeof(IndexTupleData);
- id = ((char *) it) + sizeof(IndexTupleData);
- maxoff = PageGetMaxOffsetNumber(p);
- which_grow = -1.0;
- which = -1;
-
- gistdentryinit(giststate,&identry,id,(Relation)NULL,(Page)NULL,
- (OffsetNumber)0, idsize, FALSE);
-
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
- datum = (char *) PageGetItem(p, PageGetItemId(p, i));
- size = IndexTupleSize(datum) - sizeof(IndexTupleData);
- datum += sizeof(IndexTupleData);
- gistdentryinit(giststate,&entry,datum,r,p,i,size,FALSE);
- (giststate->penaltyFn)(&entry, &identry, &usize);
- if (which_grow < 0 || usize < which_grow) {
- which = i;
- which_grow = usize;
- if (which_grow == 0)
- break;
+ OffsetNumber maxoff;
+ OffsetNumber i;
+ char *id;
+ char *datum;
+ float usize;
+ OffsetNumber which;
+ float which_grow;
+ GISTENTRY entry,
+ identry;
+ int size,
+ idsize;
+
+ idsize = IndexTupleSize(it) - sizeof(IndexTupleData);
+ id = ((char *) it) + sizeof(IndexTupleData);
+ maxoff = PageGetMaxOffsetNumber(p);
+ which_grow = -1.0;
+ which = -1;
+
+ gistdentryinit(giststate, &identry, id, (Relation) NULL, (Page) NULL,
+ (OffsetNumber) 0, idsize, FALSE);
+
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ datum = (char *) PageGetItem(p, PageGetItemId(p, i));
+ size = IndexTupleSize(datum) - sizeof(IndexTupleData);
+ datum += sizeof(IndexTupleData);
+ gistdentryinit(giststate, &entry, datum, r, p, i, size, FALSE);
+ (giststate->penaltyFn) (&entry, &identry, &usize);
+ if (which_grow < 0 || usize < which_grow)
+ {
+ which = i;
+ which_grow = usize;
+ if (which_grow == 0)
+ break;
+ }
+ if (entry.pred != datum)
+ pfree(entry.pred);
}
- if (entry.pred != datum)
- pfree(entry.pred);
- }
- if (identry.pred != id)
- pfree(identry.pred);
-
- return (which);
+ if (identry.pred != id)
+ pfree(identry.pred);
+
+ return (which);
}
static int
gistnospace(Page p, IndexTuple it)
{
- return (PageGetFreeSpace(p) < IndexTupleSize(it));
+ return (PageGetFreeSpace(p) < IndexTupleSize(it));
}
void
-gistfreestack(GISTSTACK *s)
+gistfreestack(GISTSTACK * s)
{
- GISTSTACK *p;
-
- while (s != (GISTSTACK *) NULL) {
- p = s->gs_parent;
- pfree(s);
- s = p;
- }
+ GISTSTACK *p;
+
+ while (s != (GISTSTACK *) NULL)
+ {
+ p = s->gs_parent;
+ pfree(s);
+ s = p;
+ }
}
-/*
-** remove an entry from a page
+/*
+** remove an entry from a page
*/
void
gistdelete(Relation r, ItemPointer tid)
{
- BlockNumber blkno;
- OffsetNumber offnum;
- Buffer buf;
- Page page;
-
- /* must write-lock on delete */
- RelationSetLockForWrite(r);
-
- blkno = ItemPointerGetBlockNumber(tid);
- offnum = ItemPointerGetOffsetNumber(tid);
-
- /* adjust any scans that will be affected by this deletion */
- gistadjscans(r, GISTOP_DEL, blkno, offnum);
-
- /* delete the index tuple */
- buf = ReadBuffer(r, blkno);
- page = BufferGetPage(buf);
-
- PageIndexTupleDelete(page, offnum);
-
- WriteBuffer(buf);
-
- /* XXX -- two-phase locking, don't release the write lock */
+ BlockNumber blkno;
+ OffsetNumber offnum;
+ Buffer buf;
+ Page page;
+
+ /* must write-lock on delete */
+ RelationSetLockForWrite(r);
+
+ blkno = ItemPointerGetBlockNumber(tid);
+ offnum = ItemPointerGetOffsetNumber(tid);
+
+ /* adjust any scans that will be affected by this deletion */
+ gistadjscans(r, GISTOP_DEL, blkno, offnum);
+
+ /* delete the index tuple */
+ buf = ReadBuffer(r, blkno);
+ page = BufferGetPage(buf);
+
+ PageIndexTupleDelete(page, offnum);
+
+ WriteBuffer(buf);
+
+ /* XXX -- two-phase locking, don't release the write lock */
}
-void
-initGISTstate(GISTSTATE *giststate, Relation index)
+void
+initGISTstate(GISTSTATE * giststate, Relation index)
{
- RegProcedure consistent_proc, union_proc, compress_proc, decompress_proc;
- RegProcedure penalty_proc, picksplit_proc, equal_proc;
- func_ptr user_fn;
- int pronargs;
- HeapTuple htup;
- IndexTupleForm itupform;
-
- consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC);
- union_proc = index_getprocid(index, 1, GIST_UNION_PROC);
- compress_proc = index_getprocid(index, 1, GIST_COMPRESS_PROC);
- decompress_proc = index_getprocid(index, 1, GIST_DECOMPRESS_PROC);
- penalty_proc = index_getprocid(index, 1, GIST_PENALTY_PROC);
- picksplit_proc = index_getprocid(index, 1, GIST_PICKSPLIT_PROC);
- equal_proc = index_getprocid(index, 1, GIST_EQUAL_PROC);
- fmgr_info(consistent_proc, &user_fn, &pronargs);
- giststate->consistentFn = user_fn;
- fmgr_info(union_proc, &user_fn, &pronargs);
- giststate->unionFn = user_fn;
- fmgr_info(compress_proc, &user_fn, &pronargs);
- giststate->compressFn = user_fn;
- fmgr_info(decompress_proc, &user_fn, &pronargs);
- giststate->decompressFn = user_fn;
- fmgr_info(penalty_proc, &user_fn, &pronargs);
- giststate->penaltyFn = user_fn;
- fmgr_info(picksplit_proc, &user_fn, &pronargs);
- giststate->picksplitFn = user_fn;
- fmgr_info(equal_proc, &user_fn, &pronargs);
- giststate->equalFn = user_fn;
-
- /* see if key type is different from type of attribute being indexed */
- htup = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(index->rd_id),
- 0,0,0);
- itupform = (IndexTupleForm)GETSTRUCT(htup);
- if (!HeapTupleIsValid(htup))
- elog(WARN, "initGISTstate: index %d not found", index->rd_id);
- giststate->haskeytype = itupform->indhaskeytype;
- if (giststate->haskeytype) {
- /* key type is different -- is it byval? */
- htup = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(itupform->indexrelid),
- UInt16GetDatum(FirstOffsetNumber),
- 0,0);
- if (!HeapTupleIsValid(htup)) {
- elog(WARN, "initGISTstate: no attribute tuple %d %d",
- itupform->indexrelid, FirstOffsetNumber);
- return;
+ RegProcedure consistent_proc,
+ union_proc,
+ compress_proc,
+ decompress_proc;
+ RegProcedure penalty_proc,
+ picksplit_proc,
+ equal_proc;
+ func_ptr user_fn;
+ int pronargs;
+ HeapTuple htup;
+ IndexTupleForm itupform;
+
+ consistent_proc = index_getprocid(index, 1, GIST_CONSISTENT_PROC);
+ union_proc = index_getprocid(index, 1, GIST_UNION_PROC);
+ compress_proc = index_getprocid(index, 1, GIST_COMPRESS_PROC);
+ decompress_proc = index_getprocid(index, 1, GIST_DECOMPRESS_PROC);
+ penalty_proc = index_getprocid(index, 1, GIST_PENALTY_PROC);
+ picksplit_proc = index_getprocid(index, 1, GIST_PICKSPLIT_PROC);
+ equal_proc = index_getprocid(index, 1, GIST_EQUAL_PROC);
+ fmgr_info(consistent_proc, &user_fn, &pronargs);
+ giststate->consistentFn = user_fn;
+ fmgr_info(union_proc, &user_fn, &pronargs);
+ giststate->unionFn = user_fn;
+ fmgr_info(compress_proc, &user_fn, &pronargs);
+ giststate->compressFn = user_fn;
+ fmgr_info(decompress_proc, &user_fn, &pronargs);
+ giststate->decompressFn = user_fn;
+ fmgr_info(penalty_proc, &user_fn, &pronargs);
+ giststate->penaltyFn = user_fn;
+ fmgr_info(picksplit_proc, &user_fn, &pronargs);
+ giststate->picksplitFn = user_fn;
+ fmgr_info(equal_proc, &user_fn, &pronargs);
+ giststate->equalFn = user_fn;
+
+ /* see if key type is different from type of attribute being indexed */
+ htup = SearchSysCacheTuple(INDEXRELID, ObjectIdGetDatum(index->rd_id),
+ 0, 0, 0);
+ itupform = (IndexTupleForm) GETSTRUCT(htup);
+ if (!HeapTupleIsValid(htup))
+ elog(WARN, "initGISTstate: index %d not found", index->rd_id);
+ giststate->haskeytype = itupform->indhaskeytype;
+ if (giststate->haskeytype)
+ {
+ /* key type is different -- is it byval? */
+ htup = SearchSysCacheTuple(ATTNUM,
+ ObjectIdGetDatum(itupform->indexrelid),
+ UInt16GetDatum(FirstOffsetNumber),
+ 0, 0);
+ if (!HeapTupleIsValid(htup))
+ {
+ elog(WARN, "initGISTstate: no attribute tuple %d %d",
+ itupform->indexrelid, FirstOffsetNumber);
+ return;
+ }
+ giststate->keytypbyval = (((AttributeTupleForm) htup)->attbyval);
}
- giststate->keytypbyval = (((AttributeTupleForm)htup)->attbyval);
- }
- else
- giststate->keytypbyval = FALSE;
- return;
+ else
+ giststate->keytypbyval = FALSE;
+ return;
}
@@ -1118,56 +1209,61 @@ initGISTstate(GISTSTATE *giststate, Relation index)
** the key with another key, which may involve generating a new IndexTuple
** if the sizes don't match
*/
-static IndexTuple
+static IndexTuple
gist_tuple_replacekey(Relation r, GISTENTRY entry, IndexTuple t)
{
- char * datum = (((char *) t) + sizeof(IndexTupleData));
-
- /* if new entry fits in index tuple, copy it in */
- if (entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData)) {
- memcpy(datum, entry.pred, entry.bytes);
- /* clear out old size */
- t->t_info &= 0xe000;
- /* or in new size */
- t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData));
-
- return(t);
- }
- else {
- /* generate a new index tuple for the compressed entry */
- TupleDesc tupDesc = r->rd_att;
- IndexTuple newtup;
- char *isnull;
- int blank;
-
- isnull = (char *) palloc(r->rd_rel->relnatts);
- for (blank = 0; blank < r->rd_rel->relnatts; blank++)
- isnull[blank] = ' ';
- newtup = (IndexTuple) index_formtuple(tupDesc,
- (Datum *)&(entry.pred),
- isnull);
- newtup->t_tid = t->t_tid;
- pfree(isnull);
- return(newtup);
- }
+ char *datum = (((char *) t) + sizeof(IndexTupleData));
+
+ /* if new entry fits in index tuple, copy it in */
+ if (entry.bytes < IndexTupleSize(t) - sizeof(IndexTupleData))
+ {
+ memcpy(datum, entry.pred, entry.bytes);
+ /* clear out old size */
+ t->t_info &= 0xe000;
+ /* or in new size */
+ t->t_info |= MAXALIGN(entry.bytes + sizeof(IndexTupleData));
+
+ return (t);
+ }
+ else
+ {
+ /* generate a new index tuple for the compressed entry */
+ TupleDesc tupDesc = r->rd_att;
+ IndexTuple newtup;
+ char *isnull;
+ int blank;
+
+ isnull = (char *) palloc(r->rd_rel->relnatts);
+ for (blank = 0; blank < r->rd_rel->relnatts; blank++)
+ isnull[blank] = ' ';
+ newtup = (IndexTuple) index_formtuple(tupDesc,
+ (Datum *) & (entry.pred),
+ isnull);
+ newtup->t_tid = t->t_tid;
+ pfree(isnull);
+ return (newtup);
+ }
}
-
+
/*
** initialize a GiST entry with a decompressed version of pred
*/
void
-gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r,
- Page pg, OffsetNumber o, int b, bool l)
-{
- GISTENTRY *dep;
- gistentryinit(*e, pr, r, pg, o, b, l);
- if (giststate->haskeytype) {
- dep = (GISTENTRY *)((giststate->decompressFn)(e));
- gistentryinit(*e, dep->pred, dep->rel, dep->page, dep->offset, dep->bytes,
- dep->leafkey);
- if (dep != e) pfree(dep);
- }
+gistdentryinit(GISTSTATE * giststate, GISTENTRY * e, char *pr, Relation r,
+ Page pg, OffsetNumber o, int b, bool l)
+{
+ GISTENTRY *dep;
+
+ gistentryinit(*e, pr, r, pg, o, b, l);
+ if (giststate->haskeytype)
+ {
+ dep = (GISTENTRY *) ((giststate->decompressFn) (e));
+ gistentryinit(*e, dep->pred, dep->rel, dep->page, dep->offset, dep->bytes,
+ dep->leafkey);
+ if (dep != e)
+ pfree(dep);
+ }
}
@@ -1175,19 +1271,22 @@ gistdentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r,
** initialize a GiST entry with a compressed version of pred
*/
static void
-gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r,
- Page pg, OffsetNumber o, int b, bool l)
-{
- GISTENTRY *cep;
- gistentryinit(*e, pr, r, pg, o, b, l);
- if (giststate->haskeytype) {
- cep = (GISTENTRY *)((giststate->compressFn)(e));
- gistentryinit(*e, cep->pred, cep->rel, cep->page, cep->offset, cep->bytes,
- cep->leafkey);
- if (cep != e) pfree(cep);
- }
+gistcentryinit(GISTSTATE * giststate, GISTENTRY * e, char *pr, Relation r,
+ Page pg, OffsetNumber o, int b, bool l)
+{
+ GISTENTRY *cep;
+
+ gistentryinit(*e, pr, r, pg, o, b, l);
+ if (giststate->haskeytype)
+ {
+ cep = (GISTENTRY *) ((giststate->compressFn) (e));
+ gistentryinit(*e, cep->pred, cep->rel, cep->page, cep->offset, cep->bytes,
+ cep->leafkey);
+ if (cep != e)
+ pfree(cep);
+ }
}
-
+
#ifdef GISTDEBUG
@@ -1200,89 +1299,95 @@ gistcentryinit(GISTSTATE *giststate, GISTENTRY *e, char *pr, Relation r,
void
_gistdump(Relation r)
{
- Buffer buf;
- Page page;
- OffsetNumber offnum, maxoff;
- BlockNumber blkno;
- BlockNumber nblocks;
- GISTPageOpaque po;
- IndexTuple itup;
- BlockNumber itblkno;
- OffsetNumber itoffno;
- char *datum;
- char *itkey;
-
- nblocks = RelationGetNumberOfBlocks(r);
- for (blkno = 0; blkno < nblocks; blkno++) {
- buf = ReadBuffer(r, blkno);
- page = BufferGetPage(buf);
- po = (GISTPageOpaque) PageGetSpecialPointer(page);
- maxoff = PageGetMaxOffsetNumber(page);
- printf("Page %d maxoff %d <%s>\n", blkno, maxoff,
- (po->flags & F_LEAF ? "LEAF" : "INTERNAL"));
-
- if (PageIsEmpty(page)) {
- ReleaseBuffer(buf);
- continue;
- }
-
- for (offnum = FirstOffsetNumber;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum)) {
- itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
- itblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
- itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid));
- datum = ((char *) itup);
- datum += sizeof(IndexTupleData);
- /* get out function for type of key, and out it! */
- itkey = (char *) int_range_out((INTRANGE *)datum);
- /* itkey = " unable to print"; */
- printf("\t[%d] size %d heap <%d,%d> key:%s\n",
- offnum, IndexTupleSize(itup), itblkno, itoffno, itkey);
- pfree(itkey);
+ Buffer buf;
+ Page page;
+ OffsetNumber offnum,
+ maxoff;
+ BlockNumber blkno;
+ BlockNumber nblocks;
+ GISTPageOpaque po;
+ IndexTuple itup;
+ BlockNumber itblkno;
+ OffsetNumber itoffno;
+ char *datum;
+ char *itkey;
+
+ nblocks = RelationGetNumberOfBlocks(r);
+ for (blkno = 0; blkno < nblocks; blkno++)
+ {
+ buf = ReadBuffer(r, blkno);
+ page = BufferGetPage(buf);
+ po = (GISTPageOpaque) PageGetSpecialPointer(page);
+ maxoff = PageGetMaxOffsetNumber(page);
+ printf("Page %d maxoff %d <%s>\n", blkno, maxoff,
+ (po->flags & F_LEAF ? "LEAF" : "INTERNAL"));
+
+ if (PageIsEmpty(page))
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
+
+ for (offnum = FirstOffsetNumber;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
+ itblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
+ itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid));
+ datum = ((char *) itup);
+ datum += sizeof(IndexTupleData);
+ /* get out function for type of key, and out it! */
+ itkey = (char *) int_range_out((INTRANGE *) datum);
+ /* itkey = " unable to print"; */
+ printf("\t[%d] size %d heap <%d,%d> key:%s\n",
+ offnum, IndexTupleSize(itup), itblkno, itoffno, itkey);
+ pfree(itkey);
+ }
+
+ ReleaseBuffer(buf);
}
-
- ReleaseBuffer(buf);
- }
}
#ifdef NOT_USED
-static char *text_range_out(TXTRANGE *r)
+static char *
+text_range_out(TXTRANGE * r)
{
- char *result;
- char *lower, *upper;
-
- if (r == NULL)
- return(NULL);
- result = (char *)palloc(16 + VARSIZE(TRLOWER(r)) + VARSIZE(TRUPPER(r))
- - 2*VARHDRSZ);
-
- lower = (char *)palloc(VARSIZE(TRLOWER(r)) + 1 - VARHDRSZ);
- memcpy(lower, VARDATA(TRLOWER(r)), VARSIZE(TRLOWER(r)) - VARHDRSZ);
- lower[VARSIZE(TRLOWER(r)) - VARHDRSZ] = '\0';
- upper = (char *)palloc(VARSIZE(TRUPPER(r)) + 1 - VARHDRSZ);
- memcpy(upper, VARDATA(TRUPPER(r)), VARSIZE(TRUPPER(r)) - VARHDRSZ);
- upper[VARSIZE(TRUPPER(r)) - VARHDRSZ] = '\0';
-
- sprintf(result, "[%s,%s): %d", lower, upper, r->flag);
- pfree(lower);
- pfree(upper);
- return(result);
+ char *result;
+ char *lower,
+ *upper;
+
+ if (r == NULL)
+ return (NULL);
+ result = (char *) palloc(16 + VARSIZE(TRLOWER(r)) + VARSIZE(TRUPPER(r))
+ - 2 * VARHDRSZ);
+
+ lower = (char *) palloc(VARSIZE(TRLOWER(r)) + 1 - VARHDRSZ);
+ memcpy(lower, VARDATA(TRLOWER(r)), VARSIZE(TRLOWER(r)) - VARHDRSZ);
+ lower[VARSIZE(TRLOWER(r)) - VARHDRSZ] = '\0';
+ upper = (char *) palloc(VARSIZE(TRUPPER(r)) + 1 - VARHDRSZ);
+ memcpy(upper, VARDATA(TRUPPER(r)), VARSIZE(TRUPPER(r)) - VARHDRSZ);
+ upper[VARSIZE(TRUPPER(r)) - VARHDRSZ] = '\0';
+
+ sprintf(result, "[%s,%s): %d", lower, upper, r->flag);
+ pfree(lower);
+ pfree(upper);
+ return (result);
}
+
#endif
-static char *
-int_range_out(INTRANGE *r)
+static char *
+int_range_out(INTRANGE * r)
{
- char *result;
-
- if (r == NULL)
- return(NULL);
- result = (char *)palloc(80);
- sprintf(result, "[%d,%d): %d",r->lower, r->upper, r->flag);
-
- return(result);
-}
+ char *result;
+
+ if (r == NULL)
+ return (NULL);
+ result = (char *) palloc(80);
+ sprintf(result, "[%d,%d): %d", r->lower, r->upper, r->flag);
-#endif /* defined GISTDEBUG */
+ return (result);
+}
+#endif /* defined GISTDEBUG */
diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c
index ac1697e5ed2..cad4cef267e 100644
--- a/src/backend/access/gist/gistget.c
+++ b/src/backend/access/gist/gistget.c
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* gistget.c--
- * fetch tuples from a GiST scan.
+ * fetch tuples from a GiST scan.
*
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/access/gisr/gistget.c,v 1.9.1 1996/11/21 01:00:00 vadim Exp
+ * /usr/local/devel/pglite/cvs/src/backend/access/gisr/gistget.c,v 1.9.1 1996/11/21 01:00:00 vadim Exp
*
*-------------------------------------------------------------------------
*/
@@ -22,350 +22,392 @@
#include <storage/bufmgr.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static OffsetNumber gistfindnext(IndexScanDesc s, Page p, OffsetNumber n,
- ScanDirection dir);
+static OffsetNumber
+gistfindnext(IndexScanDesc s, Page p, OffsetNumber n,
+ ScanDirection dir);
static RetrieveIndexResult gistscancache(IndexScanDesc s, ScanDirection dir);
static RetrieveIndexResult gistfirst(IndexScanDesc s, ScanDirection dir);
static RetrieveIndexResult gistnext(IndexScanDesc s, ScanDirection dir);
static ItemPointer gistheapptr(Relation r, ItemPointer itemp);
-static bool gistindex_keytest(IndexTuple tuple, TupleDesc tupdesc,
- int scanKeySize, ScanKey key, GISTSTATE *giststate,
- Relation r, Page p, OffsetNumber offset);
+static bool
+gistindex_keytest(IndexTuple tuple, TupleDesc tupdesc,
+ int scanKeySize, ScanKey key, GISTSTATE * giststate,
+ Relation r, Page p, OffsetNumber offset);
RetrieveIndexResult
gistgettuple(IndexScanDesc s, ScanDirection dir)
{
- RetrieveIndexResult res;
-
- /* if we have it cached in the scan desc, just return the value */
- if ((res = gistscancache(s, dir)) != (RetrieveIndexResult) NULL)
+ RetrieveIndexResult res;
+
+ /* if we have it cached in the scan desc, just return the value */
+ if ((res = gistscancache(s, dir)) != (RetrieveIndexResult) NULL)
+ return (res);
+
+ /* not cached, so we'll have to do some work */
+ if (ItemPointerIsValid(&(s->currentItemData)))
+ {
+ res = gistnext(s, dir);
+ }
+ else
+ {
+ res = gistfirst(s, dir);
+ }
return (res);
-
- /* not cached, so we'll have to do some work */
- if (ItemPointerIsValid(&(s->currentItemData))) {
- res = gistnext(s, dir);
- } else {
- res = gistfirst(s, dir);
- }
- return (res);
}
-static RetrieveIndexResult
+static RetrieveIndexResult
gistfirst(IndexScanDesc s, ScanDirection dir)
{
- Buffer b;
- Page p;
- OffsetNumber n;
- OffsetNumber maxoff;
- RetrieveIndexResult res;
- GISTPageOpaque po;
- GISTScanOpaque so;
- GISTSTACK *stk;
- BlockNumber blk;
- IndexTuple it;
-
- b = ReadBuffer(s->relation, GISTP_ROOT);
- p = BufferGetPage(b);
- po = (GISTPageOpaque) PageGetSpecialPointer(p);
- so = (GISTScanOpaque) s->opaque;
-
- for (;;) {
- maxoff = PageGetMaxOffsetNumber(p);
- if (ScanDirectionIsBackward(dir))
- n = gistfindnext(s, p, maxoff, dir);
- else
- n = gistfindnext(s, p, FirstOffsetNumber, dir);
-
- while (n < FirstOffsetNumber || n > maxoff) {
-
- ReleaseBuffer(b);
- if (so->s_stack == (GISTSTACK *) NULL)
- return ((RetrieveIndexResult) NULL);
-
- stk = so->s_stack;
- b = ReadBuffer(s->relation, stk->gs_blk);
- p = BufferGetPage(b);
- po = (GISTPageOpaque) PageGetSpecialPointer(p);
- maxoff = PageGetMaxOffsetNumber(p);
-
- if (ScanDirectionIsBackward(dir)) {
- n = OffsetNumberPrev(stk->gs_child);
- } else {
- n = OffsetNumberNext(stk->gs_child);
- }
- so->s_stack = stk->gs_parent;
- pfree(stk);
-
- n = gistfindnext(s, p, n, dir);
- }
- if (po->flags & F_LEAF) {
- ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
-
- res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
-
- ReleaseBuffer(b);
- return (res);
- } else {
- stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
- stk->gs_child = n;
- stk->gs_blk = BufferGetBlockNumber(b);
- stk->gs_parent = so->s_stack;
- so->s_stack = stk;
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- blk = ItemPointerGetBlockNumber(&(it->t_tid));
-
- ReleaseBuffer(b);
- b = ReadBuffer(s->relation, blk);
- p = BufferGetPage(b);
- po = (GISTPageOpaque) PageGetSpecialPointer(p);
+ Buffer b;
+ Page p;
+ OffsetNumber n;
+ OffsetNumber maxoff;
+ RetrieveIndexResult res;
+ GISTPageOpaque po;
+ GISTScanOpaque so;
+ GISTSTACK *stk;
+ BlockNumber blk;
+ IndexTuple it;
+
+ b = ReadBuffer(s->relation, GISTP_ROOT);
+ p = BufferGetPage(b);
+ po = (GISTPageOpaque) PageGetSpecialPointer(p);
+ so = (GISTScanOpaque) s->opaque;
+
+ for (;;)
+ {
+ maxoff = PageGetMaxOffsetNumber(p);
+ if (ScanDirectionIsBackward(dir))
+ n = gistfindnext(s, p, maxoff, dir);
+ else
+ n = gistfindnext(s, p, FirstOffsetNumber, dir);
+
+ while (n < FirstOffsetNumber || n > maxoff)
+ {
+
+ ReleaseBuffer(b);
+ if (so->s_stack == (GISTSTACK *) NULL)
+ return ((RetrieveIndexResult) NULL);
+
+ stk = so->s_stack;
+ b = ReadBuffer(s->relation, stk->gs_blk);
+ p = BufferGetPage(b);
+ po = (GISTPageOpaque) PageGetSpecialPointer(p);
+ maxoff = PageGetMaxOffsetNumber(p);
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = OffsetNumberPrev(stk->gs_child);
+ }
+ else
+ {
+ n = OffsetNumberNext(stk->gs_child);
+ }
+ so->s_stack = stk->gs_parent;
+ pfree(stk);
+
+ n = gistfindnext(s, p, n, dir);
+ }
+ if (po->flags & F_LEAF)
+ {
+ ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+
+ res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
+
+ ReleaseBuffer(b);
+ return (res);
+ }
+ else
+ {
+ stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
+ stk->gs_child = n;
+ stk->gs_blk = BufferGetBlockNumber(b);
+ stk->gs_parent = so->s_stack;
+ so->s_stack = stk;
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+ blk = ItemPointerGetBlockNumber(&(it->t_tid));
+
+ ReleaseBuffer(b);
+ b = ReadBuffer(s->relation, blk);
+ p = BufferGetPage(b);
+ po = (GISTPageOpaque) PageGetSpecialPointer(p);
+ }
}
- }
}
-static RetrieveIndexResult
+static RetrieveIndexResult
gistnext(IndexScanDesc s, ScanDirection dir)
{
- Buffer b;
- Page p;
- OffsetNumber n;
- OffsetNumber maxoff;
- RetrieveIndexResult res;
- GISTPageOpaque po;
- GISTScanOpaque so;
- GISTSTACK *stk;
- BlockNumber blk;
- IndexTuple it;
-
- blk = ItemPointerGetBlockNumber(&(s->currentItemData));
- n = ItemPointerGetOffsetNumber(&(s->currentItemData));
-
- if (ScanDirectionIsForward(dir)) {
- n = OffsetNumberNext(n);
- } else {
- n = OffsetNumberPrev(n);
- }
-
- b = ReadBuffer(s->relation, blk);
- p = BufferGetPage(b);
- po = (GISTPageOpaque) PageGetSpecialPointer(p);
- so = (GISTScanOpaque) s->opaque;
-
- for (;;) {
- maxoff = PageGetMaxOffsetNumber(p);
- n = gistfindnext(s, p, n, dir);
-
- while (n < FirstOffsetNumber || n > maxoff) {
-
- ReleaseBuffer(b);
- if (so->s_stack == (GISTSTACK *) NULL)
- return ((RetrieveIndexResult) NULL);
-
- stk = so->s_stack;
- b = ReadBuffer(s->relation, stk->gs_blk);
- p = BufferGetPage(b);
- maxoff = PageGetMaxOffsetNumber(p);
- po = (GISTPageOpaque) PageGetSpecialPointer(p);
-
- if (ScanDirectionIsBackward(dir)) {
- n = OffsetNumberPrev(stk->gs_child);
- } else {
- n = OffsetNumberNext(stk->gs_child);
- }
- so->s_stack = stk->gs_parent;
- pfree(stk);
-
- n = gistfindnext(s, p, n, dir);
+ Buffer b;
+ Page p;
+ OffsetNumber n;
+ OffsetNumber maxoff;
+ RetrieveIndexResult res;
+ GISTPageOpaque po;
+ GISTScanOpaque so;
+ GISTSTACK *stk;
+ BlockNumber blk;
+ IndexTuple it;
+
+ blk = ItemPointerGetBlockNumber(&(s->currentItemData));
+ n = ItemPointerGetOffsetNumber(&(s->currentItemData));
+
+ if (ScanDirectionIsForward(dir))
+ {
+ n = OffsetNumberNext(n);
+ }
+ else
+ {
+ n = OffsetNumberPrev(n);
}
- if (po->flags & F_LEAF) {
- ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
-
- res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
-
- ReleaseBuffer(b);
- return (res);
- } else {
- stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
- stk->gs_child = n;
- stk->gs_blk = BufferGetBlockNumber(b);
- stk->gs_parent = so->s_stack;
- so->s_stack = stk;
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- blk = ItemPointerGetBlockNumber(&(it->t_tid));
-
- ReleaseBuffer(b);
- b = ReadBuffer(s->relation, blk);
- p = BufferGetPage(b);
- po = (GISTPageOpaque) PageGetSpecialPointer(p);
-
- if (ScanDirectionIsBackward(dir)) {
- n = PageGetMaxOffsetNumber(p);
- } else {
- n = FirstOffsetNumber;
- }
+
+ b = ReadBuffer(s->relation, blk);
+ p = BufferGetPage(b);
+ po = (GISTPageOpaque) PageGetSpecialPointer(p);
+ so = (GISTScanOpaque) s->opaque;
+
+ for (;;)
+ {
+ maxoff = PageGetMaxOffsetNumber(p);
+ n = gistfindnext(s, p, n, dir);
+
+ while (n < FirstOffsetNumber || n > maxoff)
+ {
+
+ ReleaseBuffer(b);
+ if (so->s_stack == (GISTSTACK *) NULL)
+ return ((RetrieveIndexResult) NULL);
+
+ stk = so->s_stack;
+ b = ReadBuffer(s->relation, stk->gs_blk);
+ p = BufferGetPage(b);
+ maxoff = PageGetMaxOffsetNumber(p);
+ po = (GISTPageOpaque) PageGetSpecialPointer(p);
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = OffsetNumberPrev(stk->gs_child);
+ }
+ else
+ {
+ n = OffsetNumberNext(stk->gs_child);
+ }
+ so->s_stack = stk->gs_parent;
+ pfree(stk);
+
+ n = gistfindnext(s, p, n, dir);
+ }
+ if (po->flags & F_LEAF)
+ {
+ ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+
+ res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
+
+ ReleaseBuffer(b);
+ return (res);
+ }
+ else
+ {
+ stk = (GISTSTACK *) palloc(sizeof(GISTSTACK));
+ stk->gs_child = n;
+ stk->gs_blk = BufferGetBlockNumber(b);
+ stk->gs_parent = so->s_stack;
+ so->s_stack = stk;
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+ blk = ItemPointerGetBlockNumber(&(it->t_tid));
+
+ ReleaseBuffer(b);
+ b = ReadBuffer(s->relation, blk);
+ p = BufferGetPage(b);
+ po = (GISTPageOpaque) PageGetSpecialPointer(p);
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = PageGetMaxOffsetNumber(p);
+ }
+ else
+ {
+ n = FirstOffsetNumber;
+ }
+ }
}
- }
}
/* Similar to index_keytest, but decompresses the key in the IndexTuple */
-static bool
+static bool
gistindex_keytest(IndexTuple tuple,
- TupleDesc tupdesc,
- int scanKeySize,
- ScanKey key,
- GISTSTATE *giststate,
- Relation r,
- Page p,
- OffsetNumber offset)
+ TupleDesc tupdesc,
+ int scanKeySize,
+ ScanKey key,
+ GISTSTATE * giststate,
+ Relation r,
+ Page p,
+ OffsetNumber offset)
{
- bool isNull;
- Datum datum;
- int test;
- GISTENTRY de;
-
- IncrIndexProcessed();
-
-
- while (scanKeySize > 0) {
- datum = index_getattr(tuple,
- 1,
- tupdesc,
- &isNull);
- gistdentryinit(giststate, &de, (char *)datum, r, p, offset,
- IndexTupleSize(tuple) - sizeof(IndexTupleData),
- FALSE);
-
- if (isNull) {
- /* XXX eventually should check if SK_ISNULL */
- return (false);
- }
-
- if (key[0].sk_flags & SK_COMMUTE) {
- test = (*(key[0].sk_func))
- (DatumGetPointer(key[0].sk_argument),
- &de, key[0].sk_procedure) ? 1 : 0;
- } else {
- test = (*(key[0].sk_func))
- (&de,
- DatumGetPointer(key[0].sk_argument),
- key[0].sk_procedure) ? 1 : 0;
- }
-
- if (!test == !(key[0].sk_flags & SK_NEGATE)) {
- return (false);
+ bool isNull;
+ Datum datum;
+ int test;
+ GISTENTRY de;
+
+ IncrIndexProcessed();
+
+
+ while (scanKeySize > 0)
+ {
+ datum = index_getattr(tuple,
+ 1,
+ tupdesc,
+ &isNull);
+ gistdentryinit(giststate, &de, (char *) datum, r, p, offset,
+ IndexTupleSize(tuple) - sizeof(IndexTupleData),
+ FALSE);
+
+ if (isNull)
+ {
+ /* XXX eventually should check if SK_ISNULL */
+ return (false);
+ }
+
+ if (key[0].sk_flags & SK_COMMUTE)
+ {
+ test = (*(key[0].sk_func))
+ (DatumGetPointer(key[0].sk_argument),
+ &de, key[0].sk_procedure) ? 1 : 0;
+ }
+ else
+ {
+ test = (*(key[0].sk_func))
+ (&de,
+ DatumGetPointer(key[0].sk_argument),
+ key[0].sk_procedure) ? 1 : 0;
+ }
+
+ if (!test == !(key[0].sk_flags & SK_NEGATE))
+ {
+ return (false);
+ }
+
+ scanKeySize -= 1;
+ key++;
}
-
- scanKeySize -= 1;
- key++;
- }
-
- return (true);
+
+ return (true);
}
-static OffsetNumber
+static OffsetNumber
gistfindnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
{
- OffsetNumber maxoff;
- char *it;
- GISTPageOpaque po;
- GISTScanOpaque so;
- GISTSTATE *giststate;
-
- maxoff = PageGetMaxOffsetNumber(p);
- po = (GISTPageOpaque) PageGetSpecialPointer(p);
- so = (GISTScanOpaque) s->opaque;
- giststate = so->giststate;
-
- /*
- * If we modified the index during the scan, we may have a pointer to
- * a ghost tuple, before the scan. If this is the case, back up one.
- */
-
- if (so->s_flags & GS_CURBEFORE) {
- so->s_flags &= ~GS_CURBEFORE;
- n = OffsetNumberPrev(n);
- }
-
- while (n >= FirstOffsetNumber && n <= maxoff) {
- it = (char *) PageGetItem(p, PageGetItemId(p, n));
- if (gistindex_keytest((IndexTuple) it,
- RelationGetTupleDescriptor(s->relation),
- s->numberOfKeys, s->keyData, giststate,
- s->relation, p, n))
- break;
-
- if (ScanDirectionIsBackward(dir)) {
- n = OffsetNumberPrev(n);
- } else {
- n = OffsetNumberNext(n);
+ OffsetNumber maxoff;
+ char *it;
+ GISTPageOpaque po;
+ GISTScanOpaque so;
+ GISTSTATE *giststate;
+
+ maxoff = PageGetMaxOffsetNumber(p);
+ po = (GISTPageOpaque) PageGetSpecialPointer(p);
+ so = (GISTScanOpaque) s->opaque;
+ giststate = so->giststate;
+
+ /*
+ * If we modified the index during the scan, we may have a pointer to
+ * a ghost tuple, before the scan. If this is the case, back up one.
+ */
+
+ if (so->s_flags & GS_CURBEFORE)
+ {
+ so->s_flags &= ~GS_CURBEFORE;
+ n = OffsetNumberPrev(n);
}
- }
-
- return (n);
+
+ while (n >= FirstOffsetNumber && n <= maxoff)
+ {
+ it = (char *) PageGetItem(p, PageGetItemId(p, n));
+ if (gistindex_keytest((IndexTuple) it,
+ RelationGetTupleDescriptor(s->relation),
+ s->numberOfKeys, s->keyData, giststate,
+ s->relation, p, n))
+ break;
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = OffsetNumberPrev(n);
+ }
+ else
+ {
+ n = OffsetNumberNext(n);
+ }
+ }
+
+ return (n);
}
-static RetrieveIndexResult
+static RetrieveIndexResult
gistscancache(IndexScanDesc s, ScanDirection dir)
{
- RetrieveIndexResult res;
- ItemPointer ip;
-
- if (!(ScanDirectionIsNoMovement(dir)
- && ItemPointerIsValid(&(s->currentItemData)))) {
-
- return ((RetrieveIndexResult) NULL);
- }
-
- ip = gistheapptr(s->relation, &(s->currentItemData));
-
- if (ItemPointerIsValid(ip))
- res = FormRetrieveIndexResult(&(s->currentItemData), ip);
- else
- res = (RetrieveIndexResult) NULL;
-
- pfree (ip);
-
- return (res);
+ RetrieveIndexResult res;
+ ItemPointer ip;
+
+ if (!(ScanDirectionIsNoMovement(dir)
+ && ItemPointerIsValid(&(s->currentItemData))))
+ {
+
+ return ((RetrieveIndexResult) NULL);
+ }
+
+ ip = gistheapptr(s->relation, &(s->currentItemData));
+
+ if (ItemPointerIsValid(ip))
+ res = FormRetrieveIndexResult(&(s->currentItemData), ip);
+ else
+ res = (RetrieveIndexResult) NULL;
+
+ pfree(ip);
+
+ return (res);
}
/*
- * gistheapptr returns the item pointer to the tuple in the heap relation
- * for which itemp is the index relation item pointer.
+ * gistheapptr returns the item pointer to the tuple in the heap relation
+ * for which itemp is the index relation item pointer.
*/
-static ItemPointer
+static ItemPointer
gistheapptr(Relation r, ItemPointer itemp)
{
- Buffer b;
- Page p;
- IndexTuple it;
- ItemPointer ip;
- OffsetNumber n;
-
- ip = (ItemPointer) palloc(sizeof(ItemPointerData));
- if (ItemPointerIsValid(itemp)) {
- b = ReadBuffer(r, ItemPointerGetBlockNumber(itemp));
- p = BufferGetPage(b);
- n = ItemPointerGetOffsetNumber(itemp);
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- memmove((char *) ip, (char *) &(it->t_tid),
- sizeof(ItemPointerData));
- ReleaseBuffer(b);
- } else {
- ItemPointerSetInvalid(ip);
- }
-
- return (ip);
+ Buffer b;
+ Page p;
+ IndexTuple it;
+ ItemPointer ip;
+ OffsetNumber n;
+
+ ip = (ItemPointer) palloc(sizeof(ItemPointerData));
+ if (ItemPointerIsValid(itemp))
+ {
+ b = ReadBuffer(r, ItemPointerGetBlockNumber(itemp));
+ p = BufferGetPage(b);
+ n = ItemPointerGetOffsetNumber(itemp);
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+ memmove((char *) ip, (char *) &(it->t_tid),
+ sizeof(ItemPointerData));
+ ReleaseBuffer(b);
+ }
+ else
+ {
+ ItemPointerSetInvalid(ip);
+ }
+
+ return (ip);
}
diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c
index c877538472c..ec680558d88 100644
--- a/src/backend/access/gist/gistscan.c
+++ b/src/backend/access/gist/gistscan.c
@@ -1,11 +1,11 @@
/*-------------------------------------------------------------------------
*
* gistscan.c--
- * routines to manage scans on index relations
+ * routines to manage scans on index relations
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/access/gist/gistscan.c,v 1.7 1995/06/14 00:10:05 jolly Exp
+ * /usr/local/devel/pglite/cvs/src/backend/access/gist/gistscan.c,v 1.7 1995/06/14 00:10:05 jolly Exp
*
*-------------------------------------------------------------------------
*/
@@ -18,375 +18,411 @@
#include <access/rtree.h>
#include <storage/bufmgr.h>
#include <access/giststrat.h>
-#include <storage/lmgr.h>
+#include <storage/lmgr.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/* routines defined and used here */
-static void gistregscan(IndexScanDesc s);
-static void gistdropscan(IndexScanDesc s);
-static void gistadjone(IndexScanDesc s, int op, BlockNumber blkno,
- OffsetNumber offnum);
-static void adjuststack(GISTSTACK *stk, BlockNumber blkno,
+static void gistregscan(IndexScanDesc s);
+static void gistdropscan(IndexScanDesc s);
+static void
+gistadjone(IndexScanDesc s, int op, BlockNumber blkno,
+ OffsetNumber offnum);
+static void
+adjuststack(GISTSTACK * stk, BlockNumber blkno,
OffsetNumber offnum);
-static void adjustiptr(IndexScanDesc s, ItemPointer iptr,
- int op, BlockNumber blkno, OffsetNumber offnum);
+static void
+adjustiptr(IndexScanDesc s, ItemPointer iptr,
+ int op, BlockNumber blkno, OffsetNumber offnum);
/*
- * Whenever we start a GiST scan in a backend, we register it in private
- * space. Then if the GiST index gets updated, we check all registered
- * scans and adjust them if the tuple they point at got moved by the
- * update. We only need to do this in private space, because when we update
- * an GiST we have a write lock on the tree, so no other process can have
- * any locks at all on it. A single transaction can have write and read
- * locks on the same object, so that's why we need to handle this case.
+ * Whenever we start a GiST scan in a backend, we register it in private
+ * space. Then if the GiST index gets updated, we check all registered
+ * scans and adjust them if the tuple they point at got moved by the
+ * update. We only need to do this in private space, because when we update
+ * an GiST we have a write lock on the tree, so no other process can have
+ * any locks at all on it. A single transaction can have write and read
+ * locks on the same object, so that's why we need to handle this case.
*/
-typedef struct GISTScanListData {
- IndexScanDesc gsl_scan;
- struct GISTScanListData *gsl_next;
-} GISTScanListData;
+typedef struct GISTScanListData
+{
+ IndexScanDesc gsl_scan;
+ struct GISTScanListData *gsl_next;
+} GISTScanListData;
-typedef GISTScanListData *GISTScanList;
+typedef GISTScanListData *GISTScanList;
/* pointer to list of local scans on GiSTs */
static GISTScanList GISTScans = (GISTScanList) NULL;
-
+
IndexScanDesc
gistbeginscan(Relation r,
- bool fromEnd,
- uint16 nkeys,
- ScanKey key)
+ bool fromEnd,
+ uint16 nkeys,
+ ScanKey key)
{
- IndexScanDesc s;
-
- RelationSetLockForRead(r);
- s = RelationGetIndexScan(r, fromEnd, nkeys, key);
- gistregscan(s);
-
- return (s);
+ IndexScanDesc s;
+
+ RelationSetLockForRead(r);
+ s = RelationGetIndexScan(r, fromEnd, nkeys, key);
+ gistregscan(s);
+
+ return (s);
}
void
gistrescan(IndexScanDesc s, bool fromEnd, ScanKey key)
{
- GISTScanOpaque p;
- int i;
-
- if (!IndexScanIsValid(s)) {
- elog(WARN, "gistrescan: invalid scan.");
- return;
- }
-
- /*
- * Clear all the pointers.
- */
-
- ItemPointerSetInvalid(&s->previousItemData);
- ItemPointerSetInvalid(&s->currentItemData);
- ItemPointerSetInvalid(&s->nextItemData);
- ItemPointerSetInvalid(&s->previousMarkData);
- ItemPointerSetInvalid(&s->currentMarkData);
- ItemPointerSetInvalid(&s->nextMarkData);
-
- /*
- * Set flags.
- */
- if (RelationGetNumberOfBlocks(s->relation) == 0) {
- s->flags = ScanUnmarked;
- } else if (fromEnd) {
- s->flags = ScanUnmarked | ScanUncheckedPrevious;
- } else {
- s->flags = ScanUnmarked | ScanUncheckedNext;
- }
-
- s->scanFromEnd = fromEnd;
-
- if (s->numberOfKeys > 0) {
- memmove(s->keyData,
- key,
- s->numberOfKeys * sizeof(ScanKeyData));
- }
-
- p = (GISTScanOpaque) s->opaque;
- if (p != (GISTScanOpaque) NULL) {
- gistfreestack(p->s_stack);
- gistfreestack(p->s_markstk);
- p->s_stack = p->s_markstk = (GISTSTACK *) NULL;
- p->s_flags = 0x0;
- for (i = 0; i < s->numberOfKeys; i++)
+ GISTScanOpaque p;
+ int i;
+
+ if (!IndexScanIsValid(s))
{
- s->keyData[i].sk_procedure
- = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
- s->keyData[i].sk_procedure);
- s->keyData[i].sk_func = p->giststate->consistentFn;
+ elog(WARN, "gistrescan: invalid scan.");
+ return;
+ }
+
+ /*
+ * Clear all the pointers.
+ */
+
+ ItemPointerSetInvalid(&s->previousItemData);
+ ItemPointerSetInvalid(&s->currentItemData);
+ ItemPointerSetInvalid(&s->nextItemData);
+ ItemPointerSetInvalid(&s->previousMarkData);
+ ItemPointerSetInvalid(&s->currentMarkData);
+ ItemPointerSetInvalid(&s->nextMarkData);
+
+ /*
+ * Set flags.
+ */
+ if (RelationGetNumberOfBlocks(s->relation) == 0)
+ {
+ s->flags = ScanUnmarked;
+ }
+ else if (fromEnd)
+ {
+ s->flags = ScanUnmarked | ScanUncheckedPrevious;
+ }
+ else
+ {
+ s->flags = ScanUnmarked | ScanUncheckedNext;
+ }
+
+ s->scanFromEnd = fromEnd;
+
+ if (s->numberOfKeys > 0)
+ {
+ memmove(s->keyData,
+ key,
+ s->numberOfKeys * sizeof(ScanKeyData));
+ }
+
+ p = (GISTScanOpaque) s->opaque;
+ if (p != (GISTScanOpaque) NULL)
+ {
+ gistfreestack(p->s_stack);
+ gistfreestack(p->s_markstk);
+ p->s_stack = p->s_markstk = (GISTSTACK *) NULL;
+ p->s_flags = 0x0;
+ for (i = 0; i < s->numberOfKeys; i++)
+ {
+ s->keyData[i].sk_procedure
+ = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
+ s->keyData[i].sk_procedure);
+ s->keyData[i].sk_func = p->giststate->consistentFn;
+ }
+ }
+ else
+ {
+ /* initialize opaque data */
+ p = (GISTScanOpaque) palloc(sizeof(GISTScanOpaqueData));
+ p->s_stack = p->s_markstk = (GISTSTACK *) NULL;
+ p->s_flags = 0x0;
+ s->opaque = p;
+ p->giststate = (GISTSTATE *) palloc(sizeof(GISTSTATE));
+ initGISTstate(p->giststate, s->relation);
+ if (s->numberOfKeys > 0)
+
+ /*
+ * * Play games here with the scan key to use the Consistent *
+ * function for all comparisons: * 1) the sk_procedure field
+ * will now be used to hold the * strategy number * 2) the
+ * sk_func field will point to the Consistent function
+ */
+ for (i = 0; i < s->numberOfKeys; i++)
+ {
+
+ /*
+ * s->keyData[i].sk_procedure =
+ * index_getprocid(s->relation, 1, GIST_CONSISTENT_PROC);
+ */
+ s->keyData[i].sk_procedure
+ = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
+ s->keyData[i].sk_procedure);
+ s->keyData[i].sk_func = p->giststate->consistentFn;
+ }
}
- } else {
- /* initialize opaque data */
- p = (GISTScanOpaque) palloc(sizeof(GISTScanOpaqueData));
- p->s_stack = p->s_markstk = (GISTSTACK *) NULL;
- p->s_flags = 0x0;
- s->opaque = p;
- p->giststate = (GISTSTATE *)palloc(sizeof(GISTSTATE));
- initGISTstate(p->giststate, s->relation);
- if (s->numberOfKeys > 0)
- /*
- ** Play games here with the scan key to use the Consistent
- ** function for all comparisons:
- ** 1) the sk_procedure field will now be used to hold the
- ** strategy number
- ** 2) the sk_func field will point to the Consistent function
- */
- for (i = 0; i < s->numberOfKeys; i++) {
- /* s->keyData[i].sk_procedure
- = index_getprocid(s->relation, 1, GIST_CONSISTENT_PROC); */
- s->keyData[i].sk_procedure
- = RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
- s->keyData[i].sk_procedure);
- s->keyData[i].sk_func = p->giststate->consistentFn;
- }
- }
}
void
gistmarkpos(IndexScanDesc s)
{
- GISTScanOpaque p;
- GISTSTACK *o, *n, *tmp;
-
- s->currentMarkData = s->currentItemData;
- p = (GISTScanOpaque) s->opaque;
- if (p->s_flags & GS_CURBEFORE)
- p->s_flags |= GS_MRKBEFORE;
- else
- p->s_flags &= ~GS_MRKBEFORE;
-
- o = (GISTSTACK *) NULL;
- n = p->s_stack;
-
- /* copy the parent stack from the current item data */
- while (n != (GISTSTACK *) NULL) {
- tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
- tmp->gs_child = n->gs_child;
- tmp->gs_blk = n->gs_blk;
- tmp->gs_parent = o;
- o = tmp;
- n = n->gs_parent;
- }
-
- gistfreestack(p->s_markstk);
- p->s_markstk = o;
+ GISTScanOpaque p;
+ GISTSTACK *o,
+ *n,
+ *tmp;
+
+ s->currentMarkData = s->currentItemData;
+ p = (GISTScanOpaque) s->opaque;
+ if (p->s_flags & GS_CURBEFORE)
+ p->s_flags |= GS_MRKBEFORE;
+ else
+ p->s_flags &= ~GS_MRKBEFORE;
+
+ o = (GISTSTACK *) NULL;
+ n = p->s_stack;
+
+ /* copy the parent stack from the current item data */
+ while (n != (GISTSTACK *) NULL)
+ {
+ tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
+ tmp->gs_child = n->gs_child;
+ tmp->gs_blk = n->gs_blk;
+ tmp->gs_parent = o;
+ o = tmp;
+ n = n->gs_parent;
+ }
+
+ gistfreestack(p->s_markstk);
+ p->s_markstk = o;
}
void
gistrestrpos(IndexScanDesc s)
{
- GISTScanOpaque p;
- GISTSTACK *o, *n, *tmp;
-
- s->currentItemData = s->currentMarkData;
- p = (GISTScanOpaque) s->opaque;
- if (p->s_flags & GS_MRKBEFORE)
- p->s_flags |= GS_CURBEFORE;
- else
- p->s_flags &= ~GS_CURBEFORE;
-
- o = (GISTSTACK *) NULL;
- n = p->s_markstk;
-
- /* copy the parent stack from the current item data */
- while (n != (GISTSTACK *) NULL) {
- tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
- tmp->gs_child = n->gs_child;
- tmp->gs_blk = n->gs_blk;
- tmp->gs_parent = o;
- o = tmp;
- n = n->gs_parent;
- }
-
- gistfreestack(p->s_stack);
- p->s_stack = o;
+ GISTScanOpaque p;
+ GISTSTACK *o,
+ *n,
+ *tmp;
+
+ s->currentItemData = s->currentMarkData;
+ p = (GISTScanOpaque) s->opaque;
+ if (p->s_flags & GS_MRKBEFORE)
+ p->s_flags |= GS_CURBEFORE;
+ else
+ p->s_flags &= ~GS_CURBEFORE;
+
+ o = (GISTSTACK *) NULL;
+ n = p->s_markstk;
+
+ /* copy the parent stack from the current item data */
+ while (n != (GISTSTACK *) NULL)
+ {
+ tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
+ tmp->gs_child = n->gs_child;
+ tmp->gs_blk = n->gs_blk;
+ tmp->gs_parent = o;
+ o = tmp;
+ n = n->gs_parent;
+ }
+
+ gistfreestack(p->s_stack);
+ p->s_stack = o;
}
void
gistendscan(IndexScanDesc s)
{
- GISTScanOpaque p;
-
- p = (GISTScanOpaque) s->opaque;
-
- if (p != (GISTScanOpaque) NULL) {
- gistfreestack(p->s_stack);
- gistfreestack(p->s_markstk);
- pfree (s->opaque);
- }
-
- gistdropscan(s);
- /* XXX don't unset read lock -- two-phase locking */
+ GISTScanOpaque p;
+
+ p = (GISTScanOpaque) s->opaque;
+
+ if (p != (GISTScanOpaque) NULL)
+ {
+ gistfreestack(p->s_stack);
+ gistfreestack(p->s_markstk);
+ pfree(s->opaque);
+ }
+
+ gistdropscan(s);
+ /* XXX don't unset read lock -- two-phase locking */
}
static void
gistregscan(IndexScanDesc s)
{
- GISTScanList l;
-
- l = (GISTScanList) palloc(sizeof(GISTScanListData));
- l->gsl_scan = s;
- l->gsl_next = GISTScans;
- GISTScans = l;
+ GISTScanList l;
+
+ l = (GISTScanList) palloc(sizeof(GISTScanListData));
+ l->gsl_scan = s;
+ l->gsl_next = GISTScans;
+ GISTScans = l;
}
static void
gistdropscan(IndexScanDesc s)
{
- GISTScanList l;
- GISTScanList prev;
-
- prev = (GISTScanList) NULL;
-
- for (l = GISTScans;
- l != (GISTScanList) NULL && l->gsl_scan != s;
- l = l->gsl_next) {
- prev = l;
- }
-
- if (l == (GISTScanList) NULL)
- elog(WARN, "GiST scan list corrupted -- cannot find 0x%lx", s);
-
- if (prev == (GISTScanList) NULL)
- GISTScans = l->gsl_next;
- else
- prev->gsl_next = l->gsl_next;
-
- pfree(l);
+ GISTScanList l;
+ GISTScanList prev;
+
+ prev = (GISTScanList) NULL;
+
+ for (l = GISTScans;
+ l != (GISTScanList) NULL && l->gsl_scan != s;
+ l = l->gsl_next)
+ {
+ prev = l;
+ }
+
+ if (l == (GISTScanList) NULL)
+ elog(WARN, "GiST scan list corrupted -- cannot find 0x%lx", s);
+
+ if (prev == (GISTScanList) NULL)
+ GISTScans = l->gsl_next;
+ else
+ prev->gsl_next = l->gsl_next;
+
+ pfree(l);
}
void
gistadjscans(Relation r, int op, BlockNumber blkno, OffsetNumber offnum)
{
- GISTScanList l;
- Oid relid;
-
- relid = r->rd_id;
- for (l = GISTScans; l != (GISTScanList) NULL; l = l->gsl_next) {
- if (l->gsl_scan->relation->rd_id == relid)
- gistadjone(l->gsl_scan, op, blkno, offnum);
- }
+ GISTScanList l;
+ Oid relid;
+
+ relid = r->rd_id;
+ for (l = GISTScans; l != (GISTScanList) NULL; l = l->gsl_next)
+ {
+ if (l->gsl_scan->relation->rd_id == relid)
+ gistadjone(l->gsl_scan, op, blkno, offnum);
+ }
}
/*
- * gistadjone() -- adjust one scan for update.
+ * gistadjone() -- adjust one scan for update.
*
- * By here, the scan passed in is on a modified relation. Op tells
- * us what the modification is, and blkno and offind tell us what
- * block and offset index were affected. This routine checks the
- * current and marked positions, and the current and marked stacks,
- * to see if any stored location needs to be changed because of the
- * update. If so, we make the change here.
+ * By here, the scan passed in is on a modified relation. Op tells
+ * us what the modification is, and blkno and offind tell us what
+ * block and offset index were affected. This routine checks the
+ * current and marked positions, and the current and marked stacks,
+ * to see if any stored location needs to be changed because of the
+ * update. If so, we make the change here.
*/
static void
gistadjone(IndexScanDesc s,
- int op,
- BlockNumber blkno,
- OffsetNumber offnum)
+ int op,
+ BlockNumber blkno,
+ OffsetNumber offnum)
{
- GISTScanOpaque so;
-
- adjustiptr(s, &(s->currentItemData), op, blkno, offnum);
- adjustiptr(s, &(s->currentMarkData), op, blkno, offnum);
-
- so = (GISTScanOpaque) s->opaque;
-
- if (op == GISTOP_SPLIT) {
- adjuststack(so->s_stack, blkno, offnum);
- adjuststack(so->s_markstk, blkno, offnum);
- }
+ GISTScanOpaque so;
+
+ adjustiptr(s, &(s->currentItemData), op, blkno, offnum);
+ adjustiptr(s, &(s->currentMarkData), op, blkno, offnum);
+
+ so = (GISTScanOpaque) s->opaque;
+
+ if (op == GISTOP_SPLIT)
+ {
+ adjuststack(so->s_stack, blkno, offnum);
+ adjuststack(so->s_markstk, blkno, offnum);
+ }
}
/*
- * adjustiptr() -- adjust current and marked item pointers in the scan
+ * adjustiptr() -- adjust current and marked item pointers in the scan
*
- * Depending on the type of update and the place it happened, we
- * need to do nothing, to back up one record, or to start over on
- * the same page.
+ * Depending on the type of update and the place it happened, we
+ * need to do nothing, to back up one record, or to start over on
+ * the same page.
*/
static void
adjustiptr(IndexScanDesc s,
- ItemPointer iptr,
- int op,
- BlockNumber blkno,
- OffsetNumber offnum)
+ ItemPointer iptr,
+ int op,
+ BlockNumber blkno,
+ OffsetNumber offnum)
{
- OffsetNumber curoff;
- GISTScanOpaque so;
-
- if (ItemPointerIsValid(iptr)) {
- if (ItemPointerGetBlockNumber(iptr) == blkno) {
- curoff = ItemPointerGetOffsetNumber(iptr);
- so = (GISTScanOpaque) s->opaque;
-
- switch (op) {
- case GISTOP_DEL:
- /* back up one if we need to */
- if (curoff >= offnum) {
-
- if (curoff > FirstOffsetNumber) {
- /* just adjust the item pointer */
- ItemPointerSet(iptr, blkno, OffsetNumberPrev(curoff));
- } else {
- /* remember that we're before the current tuple */
- ItemPointerSet(iptr, blkno, FirstOffsetNumber);
- if (iptr == &(s->currentItemData))
- so->s_flags |= GS_CURBEFORE;
- else
- so->s_flags |= GS_MRKBEFORE;
- }
+ OffsetNumber curoff;
+ GISTScanOpaque so;
+
+ if (ItemPointerIsValid(iptr))
+ {
+ if (ItemPointerGetBlockNumber(iptr) == blkno)
+ {
+ curoff = ItemPointerGetOffsetNumber(iptr);
+ so = (GISTScanOpaque) s->opaque;
+
+ switch (op)
+ {
+ case GISTOP_DEL:
+ /* back up one if we need to */
+ if (curoff >= offnum)
+ {
+
+ if (curoff > FirstOffsetNumber)
+ {
+ /* just adjust the item pointer */
+ ItemPointerSet(iptr, blkno, OffsetNumberPrev(curoff));
+ }
+ else
+ {
+ /* remember that we're before the current tuple */
+ ItemPointerSet(iptr, blkno, FirstOffsetNumber);
+ if (iptr == &(s->currentItemData))
+ so->s_flags |= GS_CURBEFORE;
+ else
+ so->s_flags |= GS_MRKBEFORE;
+ }
+ }
+ break;
+
+ case GISTOP_SPLIT:
+ /* back to start of page on split */
+ ItemPointerSet(iptr, blkno, FirstOffsetNumber);
+ if (iptr == &(s->currentItemData))
+ so->s_flags &= ~GS_CURBEFORE;
+ else
+ so->s_flags &= ~GS_MRKBEFORE;
+ break;
+
+ default:
+ elog(WARN, "Bad operation in GiST scan adjust: %d", op);
+ }
}
- break;
-
- case GISTOP_SPLIT:
- /* back to start of page on split */
- ItemPointerSet(iptr, blkno, FirstOffsetNumber);
- if (iptr == &(s->currentItemData))
- so->s_flags &= ~GS_CURBEFORE;
- else
- so->s_flags &= ~GS_MRKBEFORE;
- break;
-
- default:
- elog(WARN, "Bad operation in GiST scan adjust: %d", op);
- }
}
- }
}
/*
- * adjuststack() -- adjust the supplied stack for a split on a page in
- * the index we're scanning.
+ * adjuststack() -- adjust the supplied stack for a split on a page in
+ * the index we're scanning.
*
- * If a page on our parent stack has split, we need to back up to the
- * beginning of the page and rescan it. The reason for this is that
- * the split algorithm for GiSTs doesn't order tuples in any useful
- * way on a single page. This means on that a split, we may wind up
- * looking at some heap tuples more than once. This is handled in the
- * access method update code for heaps; if we've modified the tuple we
- * are looking at already in this transaction, we ignore the update
- * request.
+ * If a page on our parent stack has split, we need to back up to the
+ * beginning of the page and rescan it. The reason for this is that
+ * the split algorithm for GiSTs doesn't order tuples in any useful
+ * way on a single page. This means on that a split, we may wind up
+ * looking at some heap tuples more than once. This is handled in the
+ * access method update code for heaps; if we've modified the tuple we
+ * are looking at already in this transaction, we ignore the update
+ * request.
*/
/*ARGSUSED*/
static void
-adjuststack(GISTSTACK *stk,
- BlockNumber blkno,
- OffsetNumber offnum)
+adjuststack(GISTSTACK * stk,
+ BlockNumber blkno,
+ OffsetNumber offnum)
{
- while (stk != (GISTSTACK *) NULL) {
- if (stk->gs_blk == blkno)
- stk->gs_child = FirstOffsetNumber;
-
- stk = stk->gs_parent;
- }
+ while (stk != (GISTSTACK *) NULL)
+ {
+ if (stk->gs_blk == blkno)
+ stk->gs_child = FirstOffsetNumber;
+
+ stk = stk->gs_parent;
+ }
}
diff --git a/src/backend/access/gist/giststrat.c b/src/backend/access/gist/giststrat.c
index 8c78ccec3ae..c7a6f9ff784 100644
--- a/src/backend/access/gist/giststrat.c
+++ b/src/backend/access/gist/giststrat.c
@@ -1,116 +1,117 @@
/*-------------------------------------------------------------------------
*
* giststrat.c--
- * strategy map data for GiSTs.
+ * strategy map data for GiSTs.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/access/gist/giststrat.c,v 1.4 1995/06/14 00:10:05 jolly Exp
+ * /usr/local/devel/pglite/cvs/src/backend/access/gist/giststrat.c,v 1.4 1995/06/14 00:10:05 jolly Exp
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/gist.h>
#include <access/istrat.h>
/*
- * Note: negate, commute, and negatecommute all assume that operators are
- * ordered as follows in the strategy map:
+ * Note: negate, commute, and negatecommute all assume that operators are
+ * ordered as follows in the strategy map:
*
- * contains, contained-by
+ * contains, contained-by
*
- * The negate, commute, and negatecommute arrays are used by the planner
- * to plan indexed scans over data that appears in the qualificiation in
- * a boolean negation, or whose operands appear in the wrong order. For
- * example, if the operator "<%" means "contains", and the user says
+ * The negate, commute, and negatecommute arrays are used by the planner
+ * to plan indexed scans over data that appears in the qualificiation in
+ * a boolean negation, or whose operands appear in the wrong order. For
+ * example, if the operator "<%" means "contains", and the user says
*
- * where not rel.box <% "(10,10,20,20)"::box
+ * where not rel.box <% "(10,10,20,20)"::box
*
- * the planner can plan an index scan by noting that GiST indices have
- * an operator in their operator class for negating <%.
+ * the planner can plan an index scan by noting that GiST indices have
+ * an operator in their operator class for negating <%.
*
- * Similarly, if the user says something like
+ * Similarly, if the user says something like
*
- * where "(10,10,20,20)"::box <% rel.box
+ * where "(10,10,20,20)"::box <% rel.box
*
- * the planner can see that the GiST index on rel.box has an operator in
- * its opclass for commuting <%, and plan the scan using that operator.
- * This added complexity in the access methods makes the planner a lot easier
- * to write.
+ * the planner can see that the GiST index on rel.box has an operator in
+ * its opclass for commuting <%, and plan the scan using that operator.
+ * This added complexity in the access methods makes the planner a lot easier
+ * to write.
*/
/* if a op b, what operator tells us if (not a op b)? */
-static StrategyNumber GISTNegate[GISTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
+static StrategyNumber GISTNegate[GISTNStrategies] = {
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy
+};
/* if a op_1 b, what is the operator op_2 such that b op_2 a? */
-static StrategyNumber GISTCommute[GISTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
+static StrategyNumber GISTCommute[GISTNStrategies] = {
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy
+};
/* if a op_1 b, what is the operator op_2 such that (b !op_2 a)? */
-static StrategyNumber GISTNegateCommute[GISTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
+static StrategyNumber GISTNegateCommute[GISTNStrategies] = {
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy
+};
/*
- * GiSTs do not currently support TermData (see rtree/rtstrat.c for
+ * GiSTs do not currently support TermData (see rtree/rtstrat.c for
* discussion of
* TermData) -- such logic must be encoded in the user's Consistent function.
*/
/*
- * If you were sufficiently attentive to detail, you would go through
- * the ExpressionData pain above for every one of the strategies
- * we defined. I am not. Now we declare the StrategyEvaluationData
- * structure that gets shipped around to help the planner and the access
- * method decide what sort of scan it should do, based on (a) what the
- * user asked for, (b) what operators are defined for a particular opclass,
- * and (c) the reams of information we supplied above.
+ * If you were sufficiently attentive to detail, you would go through
+ * the ExpressionData pain above for every one of the strategies
+ * we defined. I am not. Now we declare the StrategyEvaluationData
+ * structure that gets shipped around to help the planner and the access
+ * method decide what sort of scan it should do, based on (a) what the
+ * user asked for, (b) what operators are defined for a particular opclass,
+ * and (c) the reams of information we supplied above.
*
- * The idea of all of this initialized data is to make life easier on the
- * user when he defines a new operator class to use this access method.
- * By filling in all the data, we let him get away with leaving holes in his
- * operator class, and still let him use the index. The added complexity
- * in the access methods just isn't worth the trouble, though.
+ * The idea of all of this initialized data is to make life easier on the
+ * user when he defines a new operator class to use this access method.
+ * By filling in all the data, we let him get away with leaving holes in his
+ * operator class, and still let him use the index. The added complexity
+ * in the access methods just isn't worth the trouble, though.
*/
static StrategyEvaluationData GISTEvaluationData = {
- GISTNStrategies, /* # of strategies */
- (StrategyTransformMap) GISTNegate, /* how to do (not qual) */
- (StrategyTransformMap) GISTCommute, /* how to swap operands */
- (StrategyTransformMap) GISTNegateCommute, /* how to do both */
- { NULL }
+ GISTNStrategies, /* # of strategies */
+ (StrategyTransformMap) GISTNegate, /* how to do (not qual) */
+ (StrategyTransformMap) GISTCommute, /* how to swap operands */
+ (StrategyTransformMap) GISTNegateCommute, /* how to do both */
+ {NULL}
};
StrategyNumber
RelationGetGISTStrategy(Relation r,
- AttrNumber attnum,
- RegProcedure proc)
+ AttrNumber attnum,
+ RegProcedure proc)
{
- return (RelationGetStrategy(r, attnum, &GISTEvaluationData, proc));
+ return (RelationGetStrategy(r, attnum, &GISTEvaluationData, proc));
}
#ifdef NOT_USED
bool
RelationInvokeGISTStrategy(Relation r,
- AttrNumber attnum,
- StrategyNumber s,
- Datum left,
- Datum right)
+ AttrNumber attnum,
+ StrategyNumber s,
+ Datum left,
+ Datum right)
{
- return (RelationInvokeStrategy(r, &GISTEvaluationData, attnum, s,
- left, right));
+ return (RelationInvokeStrategy(r, &GISTEvaluationData, attnum, s,
+ left, right));
}
+
#endif
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 89f81fc56a5..e13539c4ad9 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* hash.c--
- * Implementation of Margo Seltzer's Hashing package for postgres.
+ * Implementation of Margo Seltzer's Hashing package for postgres.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.12 1997/01/10 09:46:13 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.13 1997/09/07 04:37:49 momjian Exp $
*
* NOTES
- * This file contains only the public interface routines.
+ * This file contains only the public interface routines.
*
*-------------------------------------------------------------------------
*/
@@ -26,452 +26,483 @@
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-bool BuildingHash = false;
+bool BuildingHash = false;
/*
- * hashbuild() -- build a new hash index.
+ * hashbuild() -- build a new hash index.
*
- * We use a global variable to record the fact that we're creating
- * a new index. This is used to avoid high-concurrency locking,
- * since the index won't be visible until this transaction commits
- * and since building is guaranteed to be single-threaded.
+ * We use a global variable to record the fact that we're creating
+ * a new index. This is used to avoid high-concurrency locking,
+ * since the index won't be visible until this transaction commits
+ * and since building is guaranteed to be single-threaded.
*/
void
hashbuild(Relation heap,
- Relation index,
- int natts,
- AttrNumber *attnum,
- IndexStrategy istrat,
- uint16 pcount,
- Datum *params,
- FuncIndexInfo *finfo,
- PredInfo *predInfo)
+ Relation index,
+ int natts,
+ AttrNumber * attnum,
+ IndexStrategy istrat,
+ uint16 pcount,
+ Datum * params,
+ FuncIndexInfo * finfo,
+ PredInfo * predInfo)
{
- HeapScanDesc hscan;
- Buffer buffer;
- HeapTuple htup;
- IndexTuple itup;
- TupleDesc htupdesc, itupdesc;
- Datum *attdata;
- bool *nulls;
- InsertIndexResult res;
- int nhtups, nitups;
- int i;
- HashItem hitem;
+ HeapScanDesc hscan;
+ Buffer buffer;
+ HeapTuple htup;
+ IndexTuple itup;
+ TupleDesc htupdesc,
+ itupdesc;
+ Datum *attdata;
+ bool *nulls;
+ InsertIndexResult res;
+ int nhtups,
+ nitups;
+ int i;
+ HashItem hitem;
+
#ifndef OMIT_PARTIAL_INDEX
- ExprContext *econtext;
- TupleTable tupleTable;
- TupleTableSlot *slot;
+ ExprContext *econtext;
+ TupleTable tupleTable;
+ TupleTableSlot *slot;
+
#endif
- Oid hrelid, irelid;
- Node *pred, *oldPred;
-
- /* note that this is a new btree */
- BuildingHash = true;
-
- pred = predInfo->pred;
- oldPred = predInfo->oldPred;
-
- /* initialize the hash index metadata page (if this is a new index) */
- if (oldPred == NULL)
- _hash_metapinit(index);
-
- /* get tuple descriptors for heap and index relations */
- htupdesc = RelationGetTupleDescriptor(heap);
- itupdesc = RelationGetTupleDescriptor(index);
-
- /* get space for data items that'll appear in the index tuple */
- attdata = (Datum *) palloc(natts * sizeof(Datum));
- nulls = (bool *) palloc(natts * sizeof(bool));
-
- /*
- * If this is a predicate (partial) index, we will need to evaluate the
- * predicate using ExecQual, which requires the current tuple to be in a
- * slot of a TupleTable. In addition, ExecQual must have an ExprContext
- * referring to that slot. Here, we initialize dummy TupleTable and
- * ExprContext objects for this purpose. --Nels, Feb '92
- */
+ Oid hrelid,
+ irelid;
+ Node *pred,
+ *oldPred;
+
+ /* note that this is a new btree */
+ BuildingHash = true;
+
+ pred = predInfo->pred;
+ oldPred = predInfo->oldPred;
+
+ /* initialize the hash index metadata page (if this is a new index) */
+ if (oldPred == NULL)
+ _hash_metapinit(index);
+
+ /* get tuple descriptors for heap and index relations */
+ htupdesc = RelationGetTupleDescriptor(heap);
+ itupdesc = RelationGetTupleDescriptor(index);
+
+ /* get space for data items that'll appear in the index tuple */
+ attdata = (Datum *) palloc(natts * sizeof(Datum));
+ nulls = (bool *) palloc(natts * sizeof(bool));
+
+ /*
+ * If this is a predicate (partial) index, we will need to evaluate
+ * the predicate using ExecQual, which requires the current tuple to
+ * be in a slot of a TupleTable. In addition, ExecQual must have an
+ * ExprContext referring to that slot. Here, we initialize dummy
+ * TupleTable and ExprContext objects for this purpose. --Nels, Feb
+ * '92
+ */
#ifndef OMIT_PARTIAL_INDEX
- if (pred != NULL || oldPred != NULL) {
- tupleTable = ExecCreateTupleTable(1);
- slot = ExecAllocTableSlot(tupleTable);
- econtext = makeNode(ExprContext);
- FillDummyExprContext(econtext, slot, htupdesc, buffer);
- }
- else /* quiet the compiler */
+ if (pred != NULL || oldPred != NULL)
+ {
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ econtext = makeNode(ExprContext);
+ FillDummyExprContext(econtext, slot, htupdesc, buffer);
+ }
+ else
+/* quiet the compiler */
{
econtext = NULL;
tupleTable = 0;
slot = 0;
}
-#endif /* OMIT_PARTIAL_INDEX */
-
- /* start a heap scan */
- hscan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
- htup = heap_getnext(hscan, 0, &buffer);
-
- /* build the index */
- nhtups = nitups = 0;
-
- for (; HeapTupleIsValid(htup); htup = heap_getnext(hscan, 0, &buffer)) {
-
- nhtups++;
-
- /*
- * If oldPred != NULL, this is an EXTEND INDEX command, so skip
- * this tuple if it was already in the existing partial index
- */
- if (oldPred != NULL) {
- /*SetSlotContents(slot, htup); */
+#endif /* OMIT_PARTIAL_INDEX */
+
+ /* start a heap scan */
+ hscan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
+ htup = heap_getnext(hscan, 0, &buffer);
+
+ /* build the index */
+ nhtups = nitups = 0;
+
+ for (; HeapTupleIsValid(htup); htup = heap_getnext(hscan, 0, &buffer))
+ {
+
+ nhtups++;
+
+ /*
+ * If oldPred != NULL, this is an EXTEND INDEX command, so skip
+ * this tuple if it was already in the existing partial index
+ */
+ if (oldPred != NULL)
+ {
+ /* SetSlotContents(slot, htup); */
#ifndef OMIT_PARTIAL_INDEX
- slot->val = htup;
- if (ExecQual((List*)oldPred, econtext) == true) {
+ slot->val = htup;
+ if (ExecQual((List *) oldPred, econtext) == true)
+ {
+ nitups++;
+ continue;
+ }
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
+ /*
+ * Skip this tuple if it doesn't satisfy the partial-index
+ * predicate
+ */
+ if (pred != NULL)
+ {
+#ifndef OMIT_PARTIAL_INDEX
+ /* SetSlotContents(slot, htup); */
+ slot->val = htup;
+ if (ExecQual((List *) pred, econtext) == false)
+ continue;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
nitups++;
- continue;
- }
-#endif /* OMIT_PARTIAL_INDEX */
+
+ /*
+ * For the current heap tuple, extract all the attributes we use
+ * in this index, and note which are null.
+ */
+ for (i = 1; i <= natts; i++)
+ {
+ int attoff;
+ bool attnull;
+
+ /*
+ * Offsets are from the start of the tuple, and are
+ * zero-based; indices are one-based. The next call returns i
+ * - 1. That's data hiding for you.
+ */
+
+ /* attoff = i - 1 */
+ attoff = AttrNumberGetAttrOffset(i);
+
+ /*
+ * below, attdata[attoff] set to equal some datum & attnull is
+ * changed to indicate whether or not the attribute is null
+ * for this tuple
+ */
+ attdata[attoff] = GetIndexValue(htup,
+ htupdesc,
+ attoff,
+ attnum,
+ finfo,
+ &attnull,
+ buffer);
+ nulls[attoff] = (attnull ? 'n' : ' ');
+ }
+
+ /* form an index tuple and point it at the heap tuple */
+ itup = index_formtuple(itupdesc, attdata, nulls);
+
+ /*
+ * If the single index key is null, we don't insert it into the
+ * index. Hash tables support scans on '='. Relational algebra
+ * says that A = B returns null if either A or B is null. This
+ * means that no qualification used in an index scan could ever
+ * return true on a null attribute. It also means that indices
+ * can't be used by ISNULL or NOTNULL scans, but that's an
+ * artifact of the strategy map architecture chosen in 1986, not
+ * of the way nulls are handled here.
+ */
+
+ if (itup->t_info & INDEX_NULL_MASK)
+ {
+ pfree(itup);
+ continue;
+ }
+
+ itup->t_tid = htup->t_ctid;
+ hitem = _hash_formitem(itup);
+ res = _hash_doinsert(index, hitem);
+ pfree(hitem);
+ pfree(itup);
+ pfree(res);
}
-
- /* Skip this tuple if it doesn't satisfy the partial-index predicate */
- if (pred != NULL) {
+
+ /* okay, all heap tuples are indexed */
+ heap_endscan(hscan);
+
+ if (pred != NULL || oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, htup); */
- slot->val = htup;
- if (ExecQual((List*)pred, econtext) == false)
- continue;
-#endif /* OMIT_PARTIAL_INDEX */
-}
-
- nitups++;
-
- /*
- * For the current heap tuple, extract all the attributes
- * we use in this index, and note which are null.
- */
- for (i = 1; i <= natts; i++) {
- int attoff;
- bool attnull;
-
- /*
- * Offsets are from the start of the tuple, and are
- * zero-based; indices are one-based. The next call
- * returns i - 1. That's data hiding for you.
- */
-
- /* attoff = i - 1 */
- attoff = AttrNumberGetAttrOffset(i);
-
- /* below, attdata[attoff] set to equal some datum &
- * attnull is changed to indicate whether or not the attribute
- * is null for this tuple
- */
- attdata[attoff] = GetIndexValue(htup,
- htupdesc,
- attoff,
- attnum,
- finfo,
- &attnull,
- buffer);
- nulls[attoff] = (attnull ? 'n' : ' ');
+ ExecDestroyTupleTable(tupleTable, true);
+ pfree(econtext);
+#endif /* OMIT_PARTIAL_INDEX */
}
-
- /* form an index tuple and point it at the heap tuple */
- itup = index_formtuple(itupdesc, attdata, nulls);
-
+
/*
- * If the single index key is null, we don't insert it into
- * the index. Hash tables support scans on '='.
- * Relational algebra says that A = B
- * returns null if either A or B is null. This
- * means that no qualification used in an index scan could ever
- * return true on a null attribute. It also means that indices
- * can't be used by ISNULL or NOTNULL scans, but that's an
- * artifact of the strategy map architecture chosen in 1986, not
- * of the way nulls are handled here.
+ * Since we just counted the tuples in the heap, we update its stats
+ * in pg_class to guarantee that the planner takes advantage of the
+ * index we just created. Finally, only update statistics during
+ * normal index definitions, not for indices on system catalogs
+ * created during bootstrap processing. We must close the relations
+ * before updatings statistics to guarantee that the relcache entries
+ * are flushed when we increment the command counter in UpdateStats().
*/
-
- if (itup->t_info & INDEX_NULL_MASK) {
- pfree(itup);
- continue;
- }
-
- itup->t_tid = htup->t_ctid;
- hitem = _hash_formitem(itup);
- res = _hash_doinsert(index, hitem);
- pfree(hitem);
- pfree(itup);
- pfree(res);
- }
-
- /* okay, all heap tuples are indexed */
- heap_endscan(hscan);
-
- if (pred != NULL || oldPred != NULL) {
-#ifndef OMIT_PARTIAL_INDEX
- ExecDestroyTupleTable(tupleTable, true);
- pfree(econtext);
-#endif /* OMIT_PARTIAL_INDEX */
- }
-
- /*
- * Since we just counted the tuples in the heap, we update its
- * stats in pg_class to guarantee that the planner takes advantage
- * of the index we just created. Finally, only update statistics
- * during normal index definitions, not for indices on system catalogs
- * created during bootstrap processing. We must close the relations
- * before updatings statistics to guarantee that the relcache entries
- * are flushed when we increment the command counter in UpdateStats().
- */
- if (IsNormalProcessingMode())
+ if (IsNormalProcessingMode())
{
- hrelid = heap->rd_id;
- irelid = index->rd_id;
- heap_close(heap);
- index_close(index);
- UpdateStats(hrelid, nhtups, true);
- UpdateStats(irelid, nitups, false);
- if (oldPred != NULL) {
- if (nitups == nhtups) pred = NULL;
- UpdateIndexPredicate(irelid, oldPred, pred);
- }
+ hrelid = heap->rd_id;
+ irelid = index->rd_id;
+ heap_close(heap);
+ index_close(index);
+ UpdateStats(hrelid, nhtups, true);
+ UpdateStats(irelid, nitups, false);
+ if (oldPred != NULL)
+ {
+ if (nitups == nhtups)
+ pred = NULL;
+ UpdateIndexPredicate(irelid, oldPred, pred);
+ }
}
-
- /* be tidy */
- pfree(nulls);
- pfree(attdata);
-
- /* all done */
- BuildingHash = false;
+
+ /* be tidy */
+ pfree(nulls);
+ pfree(attdata);
+
+ /* all done */
+ BuildingHash = false;
}
/*
- * hashinsert() -- insert an index tuple into a hash table.
+ * hashinsert() -- insert an index tuple into a hash table.
*
- * Hash on the index tuple's key, find the appropriate location
- * for the new tuple, put it there, and return an InsertIndexResult
- * to the caller.
+ * Hash on the index tuple's key, find the appropriate location
+ * for the new tuple, put it there, and return an InsertIndexResult
+ * to the caller.
*/
InsertIndexResult
-hashinsert(Relation rel, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
+hashinsert(Relation rel, Datum * datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
{
- HashItem hitem;
- IndexTuple itup;
- InsertIndexResult res;
-
-
- /* generate an index tuple */
- itup = index_formtuple(RelationGetTupleDescriptor(rel), datum, nulls);
- itup->t_tid = *ht_ctid;
-
- if (itup->t_info & INDEX_NULL_MASK)
- return ((InsertIndexResult) NULL);
-
- hitem = _hash_formitem(itup);
-
- res = _hash_doinsert(rel, hitem);
-
- pfree(hitem);
- pfree(itup);
-
- return (res);
+ HashItem hitem;
+ IndexTuple itup;
+ InsertIndexResult res;
+
+
+ /* generate an index tuple */
+ itup = index_formtuple(RelationGetTupleDescriptor(rel), datum, nulls);
+ itup->t_tid = *ht_ctid;
+
+ if (itup->t_info & INDEX_NULL_MASK)
+ return ((InsertIndexResult) NULL);
+
+ hitem = _hash_formitem(itup);
+
+ res = _hash_doinsert(rel, hitem);
+
+ pfree(hitem);
+ pfree(itup);
+
+ return (res);
}
/*
- * hashgettuple() -- Get the next tuple in the scan.
+ * hashgettuple() -- Get the next tuple in the scan.
*/
-char *
+char *
hashgettuple(IndexScanDesc scan, ScanDirection dir)
{
- RetrieveIndexResult res;
-
- /*
- * If we've already initialized this scan, we can just advance it
- * in the appropriate direction. If we haven't done so yet, we
- * call a routine to get the first item in the scan.
- */
-
- if (ItemPointerIsValid(&(scan->currentItemData)))
- res = _hash_next(scan, dir);
- else
- res = _hash_first(scan, dir);
-
- return ((char *) res);
+ RetrieveIndexResult res;
+
+ /*
+ * If we've already initialized this scan, we can just advance it in
+ * the appropriate direction. If we haven't done so yet, we call a
+ * routine to get the first item in the scan.
+ */
+
+ if (ItemPointerIsValid(&(scan->currentItemData)))
+ res = _hash_next(scan, dir);
+ else
+ res = _hash_first(scan, dir);
+
+ return ((char *) res);
}
/*
- * hashbeginscan() -- start a scan on a hash index
+ * hashbeginscan() -- start a scan on a hash index
*/
-char *
+char *
hashbeginscan(Relation rel,
- bool fromEnd,
- uint16 keysz,
- ScanKey scankey)
+ bool fromEnd,
+ uint16 keysz,
+ ScanKey scankey)
{
- IndexScanDesc scan;
- HashScanOpaque so;
-
- scan = RelationGetIndexScan(rel, fromEnd, keysz, scankey);
- so = (HashScanOpaque) palloc(sizeof(HashScanOpaqueData));
- so->hashso_curbuf = so->hashso_mrkbuf = InvalidBuffer;
- scan->opaque = so;
- scan->flags = 0x0;
-
- /* register scan in case we change pages it's using */
- _hash_regscan(scan);
-
- return ((char *) scan);
+ IndexScanDesc scan;
+ HashScanOpaque so;
+
+ scan = RelationGetIndexScan(rel, fromEnd, keysz, scankey);
+ so = (HashScanOpaque) palloc(sizeof(HashScanOpaqueData));
+ so->hashso_curbuf = so->hashso_mrkbuf = InvalidBuffer;
+ scan->opaque = so;
+ scan->flags = 0x0;
+
+ /* register scan in case we change pages it's using */
+ _hash_regscan(scan);
+
+ return ((char *) scan);
}
/*
- * hashrescan() -- rescan an index relation
+ * hashrescan() -- rescan an index relation
*/
void
hashrescan(IndexScanDesc scan, bool fromEnd, ScanKey scankey)
{
- ItemPointer iptr;
- HashScanOpaque so;
-
- so = (HashScanOpaque) scan->opaque;
-
- /* we hold a read lock on the current page in the scan */
- if (ItemPointerIsValid(iptr = &(scan->currentItemData))) {
- _hash_relbuf(scan->relation, so->hashso_curbuf, HASH_READ);
- so->hashso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
- if (ItemPointerIsValid(iptr = &(scan->currentMarkData))) {
- _hash_relbuf(scan->relation, so->hashso_mrkbuf, HASH_READ);
- so->hashso_mrkbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- /* reset the scan key */
- if (scan->numberOfKeys > 0) {
- memmove(scan->keyData,
- scankey,
- scan->numberOfKeys * sizeof(ScanKeyData));
- }
+ ItemPointer iptr;
+ HashScanOpaque so;
+
+ so = (HashScanOpaque) scan->opaque;
+
+ /* we hold a read lock on the current page in the scan */
+ if (ItemPointerIsValid(iptr = &(scan->currentItemData)))
+ {
+ _hash_relbuf(scan->relation, so->hashso_curbuf, HASH_READ);
+ so->hashso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+ if (ItemPointerIsValid(iptr = &(scan->currentMarkData)))
+ {
+ _hash_relbuf(scan->relation, so->hashso_mrkbuf, HASH_READ);
+ so->hashso_mrkbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ /* reset the scan key */
+ if (scan->numberOfKeys > 0)
+ {
+ memmove(scan->keyData,
+ scankey,
+ scan->numberOfKeys * sizeof(ScanKeyData));
+ }
}
/*
- * hashendscan() -- close down a scan
+ * hashendscan() -- close down a scan
*/
void
hashendscan(IndexScanDesc scan)
{
-
- ItemPointer iptr;
- HashScanOpaque so;
-
- so = (HashScanOpaque) scan->opaque;
-
- /* release any locks we still hold */
- if (ItemPointerIsValid(iptr = &(scan->currentItemData))) {
- _hash_relbuf(scan->relation, so->hashso_curbuf, HASH_READ);
- so->hashso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- if (ItemPointerIsValid(iptr = &(scan->currentMarkData))) {
- if (BufferIsValid(so->hashso_mrkbuf))
- _hash_relbuf(scan->relation, so->hashso_mrkbuf, HASH_READ);
- so->hashso_mrkbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- /* don't need scan registered anymore */
- _hash_dropscan(scan);
-
- /* be tidy */
- pfree (scan->opaque);
+
+ ItemPointer iptr;
+ HashScanOpaque so;
+
+ so = (HashScanOpaque) scan->opaque;
+
+ /* release any locks we still hold */
+ if (ItemPointerIsValid(iptr = &(scan->currentItemData)))
+ {
+ _hash_relbuf(scan->relation, so->hashso_curbuf, HASH_READ);
+ so->hashso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ if (ItemPointerIsValid(iptr = &(scan->currentMarkData)))
+ {
+ if (BufferIsValid(so->hashso_mrkbuf))
+ _hash_relbuf(scan->relation, so->hashso_mrkbuf, HASH_READ);
+ so->hashso_mrkbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ /* don't need scan registered anymore */
+ _hash_dropscan(scan);
+
+ /* be tidy */
+ pfree(scan->opaque);
}
/*
- * hashmarkpos() -- save current scan position
+ * hashmarkpos() -- save current scan position
*
*/
void
hashmarkpos(IndexScanDesc scan)
{
- ItemPointer iptr;
- HashScanOpaque so;
-
- /* see if we ever call this code. if we do, then so_mrkbuf a
- * useful element in the scan->opaque structure. if this procedure
- * is never called, so_mrkbuf should be removed from the scan->opaque
- * structure.
- */
- elog(NOTICE, "Hashmarkpos() called.");
-
- so = (HashScanOpaque) scan->opaque;
-
- /* release lock on old marked data, if any */
- if (ItemPointerIsValid(iptr = &(scan->currentMarkData))) {
- _hash_relbuf(scan->relation, so->hashso_mrkbuf, HASH_READ);
- so->hashso_mrkbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- /* bump lock on currentItemData and copy to currentMarkData */
- if (ItemPointerIsValid(&(scan->currentItemData))) {
- so->hashso_mrkbuf = _hash_getbuf(scan->relation,
- BufferGetBlockNumber(so->hashso_curbuf),
- HASH_READ);
- scan->currentMarkData = scan->currentItemData;
- }
+ ItemPointer iptr;
+ HashScanOpaque so;
+
+ /*
+ * see if we ever call this code. if we do, then so_mrkbuf a useful
+ * element in the scan->opaque structure. if this procedure is never
+ * called, so_mrkbuf should be removed from the scan->opaque
+ * structure.
+ */
+ elog(NOTICE, "Hashmarkpos() called.");
+
+ so = (HashScanOpaque) scan->opaque;
+
+ /* release lock on old marked data, if any */
+ if (ItemPointerIsValid(iptr = &(scan->currentMarkData)))
+ {
+ _hash_relbuf(scan->relation, so->hashso_mrkbuf, HASH_READ);
+ so->hashso_mrkbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ /* bump lock on currentItemData and copy to currentMarkData */
+ if (ItemPointerIsValid(&(scan->currentItemData)))
+ {
+ so->hashso_mrkbuf = _hash_getbuf(scan->relation,
+ BufferGetBlockNumber(so->hashso_curbuf),
+ HASH_READ);
+ scan->currentMarkData = scan->currentItemData;
+ }
}
/*
- * hashrestrpos() -- restore scan to last saved position
+ * hashrestrpos() -- restore scan to last saved position
*/
void
hashrestrpos(IndexScanDesc scan)
{
- ItemPointer iptr;
- HashScanOpaque so;
-
- /* see if we ever call this code. if we do, then so_mrkbuf a
- * useful element in the scan->opaque structure. if this procedure
- * is never called, so_mrkbuf should be removed from the scan->opaque
- * structure.
- */
- elog(NOTICE, "Hashrestrpos() called.");
-
- so = (HashScanOpaque) scan->opaque;
-
- /* release lock on current data, if any */
- if (ItemPointerIsValid(iptr = &(scan->currentItemData))) {
- _hash_relbuf(scan->relation, so->hashso_curbuf, HASH_READ);
- so->hashso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- /* bump lock on currentMarkData and copy to currentItemData */
- if (ItemPointerIsValid(&(scan->currentMarkData))) {
- so->hashso_curbuf =
- _hash_getbuf(scan->relation,
- BufferGetBlockNumber(so->hashso_mrkbuf),
- HASH_READ);
-
- scan->currentItemData = scan->currentMarkData;
- }
+ ItemPointer iptr;
+ HashScanOpaque so;
+
+ /*
+ * see if we ever call this code. if we do, then so_mrkbuf a useful
+ * element in the scan->opaque structure. if this procedure is never
+ * called, so_mrkbuf should be removed from the scan->opaque
+ * structure.
+ */
+ elog(NOTICE, "Hashrestrpos() called.");
+
+ so = (HashScanOpaque) scan->opaque;
+
+ /* release lock on current data, if any */
+ if (ItemPointerIsValid(iptr = &(scan->currentItemData)))
+ {
+ _hash_relbuf(scan->relation, so->hashso_curbuf, HASH_READ);
+ so->hashso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ /* bump lock on currentMarkData and copy to currentItemData */
+ if (ItemPointerIsValid(&(scan->currentMarkData)))
+ {
+ so->hashso_curbuf =
+ _hash_getbuf(scan->relation,
+ BufferGetBlockNumber(so->hashso_mrkbuf),
+ HASH_READ);
+
+ scan->currentItemData = scan->currentMarkData;
+ }
}
/* stubs */
void
hashdelete(Relation rel, ItemPointer tid)
{
- /* adjust any active scans that will be affected by this deletion */
- _hash_adjscans(rel, tid);
-
- /* delete the data from the page */
- _hash_pagedel(rel, tid);
-}
+ /* adjust any active scans that will be affected by this deletion */
+ _hash_adjscans(rel, tid);
+ /* delete the data from the page */
+ _hash_pagedel(rel, tid);
+}
diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c
index 5862800b21d..a3cbaa1a94c 100644
--- a/src/backend/access/hash/hashfunc.c
+++ b/src/backend/access/hash/hashfunc.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* hashfunc.c--
- * Comparison functions for hash access method.
+ * Comparison functions for hash access method.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.3 1996/11/10 02:57:40 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.4 1997/09/07 04:37:53 momjian Exp $
*
* NOTES
- * These functions are stored in pg_amproc. For each operator class
- * defined on hash tables, they compute the hash value of the argument.
+ * These functions are stored in pg_amproc. For each operator class
+ * defined on hash tables, they compute the hash value of the argument.
*
*-------------------------------------------------------------------------
*/
@@ -20,206 +20,223 @@
#include "access/hash.h"
-uint32 hashint2(int16 key)
+uint32
+hashint2(int16 key)
{
- return ((uint32) ~key);
+ return ((uint32) ~ key);
}
-uint32 hashint4(uint32 key)
+uint32
+hashint4(uint32 key)
{
- return (~key);
+ return (~key);
}
/* Hash function from Chris Torek. */
-uint32 hashfloat4(float32 keyp)
+uint32
+hashfloat4(float32 keyp)
{
- int len;
- int loop;
- uint32 h;
- char *kp = (char *) keyp;
+ int len;
+ int loop;
+ uint32 h;
+ char *kp = (char *) keyp;
- len = sizeof(float32data);
+ len = sizeof(float32data);
-#define HASH4a h = (h << 5) - h + *kp++;
-#define HASH4b h = (h << 5) + h + *kp++;
+#define HASH4a h = (h << 5) - h + *kp++;
+#define HASH4b h = (h << 5) + h + *kp++;
#define HASH4 HASH4b
- h = 0;
- if (len > 0) {
- loop = (len + 8 - 1) >> 3;
-
- switch (len & (8 - 1)) {
- case 0:
- do { /* All fall throughs */
- HASH4;
- case 7:
- HASH4;
- case 6:
- HASH4;
- case 5:
- HASH4;
- case 4:
- HASH4;
- case 3:
- HASH4;
- case 2:
- HASH4;
- case 1:
- HASH4;
- } while (--loop);
+ h = 0;
+ if (len > 0)
+ {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1))
+ {
+ case 0:
+ do
+ { /* All fall throughs */
+ HASH4;
+ case 7:
+ HASH4;
+ case 6:
+ HASH4;
+ case 5:
+ HASH4;
+ case 4:
+ HASH4;
+ case 3:
+ HASH4;
+ case 2:
+ HASH4;
+ case 1:
+ HASH4;
+ } while (--loop);
+ }
}
- }
- return (h);
-}
+ return (h);
+}
-uint32 hashfloat8(float64 keyp)
+uint32
+hashfloat8(float64 keyp)
{
- int len;
- int loop;
- uint32 h;
- char *kp = (char *) keyp;
+ int len;
+ int loop;
+ uint32 h;
+ char *kp = (char *) keyp;
- len = sizeof(float64data);
+ len = sizeof(float64data);
-#define HASH4a h = (h << 5) - h + *kp++;
-#define HASH4b h = (h << 5) + h + *kp++;
+#define HASH4a h = (h << 5) - h + *kp++;
+#define HASH4b h = (h << 5) + h + *kp++;
#define HASH4 HASH4b
- h = 0;
- if (len > 0) {
- loop = (len + 8 - 1) >> 3;
-
- switch (len & (8 - 1)) {
- case 0:
- do { /* All fall throughs */
- HASH4;
- case 7:
- HASH4;
- case 6:
- HASH4;
- case 5:
- HASH4;
- case 4:
- HASH4;
- case 3:
- HASH4;
- case 2:
- HASH4;
- case 1:
- HASH4;
- } while (--loop);
+ h = 0;
+ if (len > 0)
+ {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (8 - 1))
+ {
+ case 0:
+ do
+ { /* All fall throughs */
+ HASH4;
+ case 7:
+ HASH4;
+ case 6:
+ HASH4;
+ case 5:
+ HASH4;
+ case 4:
+ HASH4;
+ case 3:
+ HASH4;
+ case 2:
+ HASH4;
+ case 1:
+ HASH4;
+ } while (--loop);
+ }
}
- }
- return (h);
-}
+ return (h);
+}
-uint32 hashoid(Oid key)
+uint32
+hashoid(Oid key)
{
- return ((uint32) ~key);
+ return ((uint32) ~ key);
}
-uint32 hashchar(char key)
+uint32
+hashchar(char key)
{
- int len;
- uint32 h;
+ int len;
+ uint32 h;
+
+ len = sizeof(char);
- len = sizeof(char);
+#define PRIME1 37
+#define PRIME2 1048583
-#define PRIME1 37
-#define PRIME2 1048583
+ h = 0;
+ /* Convert char to integer */
+ h = h * PRIME1 ^ (key - ' ');
+ h %= PRIME2;
- h = 0;
- /* Convert char to integer */
- h = h * PRIME1 ^ (key - ' ');
- h %= PRIME2;
-
- return (h);
+ return (h);
}
-uint32 hashchar2(uint16 intkey)
+uint32
+hashchar2(uint16 intkey)
{
- uint32 h;
- int len;
- char *key = (char *) &intkey;
-
- h = 0;
- len = sizeof(uint16);
- /* Convert string to integer */
- while (len--)
- h = h * PRIME1 ^ (*key++ - ' ');
- h %= PRIME2;
-
- return (h);
+ uint32 h;
+ int len;
+ char *key = (char *) &intkey;
+
+ h = 0;
+ len = sizeof(uint16);
+ /* Convert string to integer */
+ while (len--)
+ h = h * PRIME1 ^ (*key++ - ' ');
+ h %= PRIME2;
+
+ return (h);
}
-uint32 hashchar4(uint32 intkey)
+uint32
+hashchar4(uint32 intkey)
{
- uint32 h;
- int len;
- char *key = (char *) &intkey;
-
- h = 0;
- len = sizeof(uint32);
- /* Convert string to integer */
- while (len--)
- h = h * PRIME1 ^ (*key++ - ' ');
- h %= PRIME2;
-
- return (h);
+ uint32 h;
+ int len;
+ char *key = (char *) &intkey;
+
+ h = 0;
+ len = sizeof(uint32);
+ /* Convert string to integer */
+ while (len--)
+ h = h * PRIME1 ^ (*key++ - ' ');
+ h %= PRIME2;
+
+ return (h);
}
-uint32 hashchar8(char *key)
+uint32
+hashchar8(char *key)
{
- uint32 h;
- int len;
-
- h = 0;
- len = sizeof(char8);
- /* Convert string to integer */
- while (len--)
- h = h * PRIME1 ^ (*key++ - ' ');
- h %= PRIME2;
-
- return (h);
+ uint32 h;
+ int len;
+
+ h = 0;
+ len = sizeof(char8);
+ /* Convert string to integer */
+ while (len--)
+ h = h * PRIME1 ^ (*key++ - ' ');
+ h %= PRIME2;
+
+ return (h);
}
-uint32 hashname(NameData *n)
+uint32
+hashname(NameData * n)
{
- uint32 h;
- int len;
- char *key;
-
- key = n->data;
-
- h = 0;
- len = NAMEDATALEN;
- /* Convert string to integer */
- while (len--)
- h = h * PRIME1 ^ (*key++ - ' ');
- h %= PRIME2;
-
- return (h);
+ uint32 h;
+ int len;
+ char *key;
+
+ key = n->data;
+
+ h = 0;
+ len = NAMEDATALEN;
+ /* Convert string to integer */
+ while (len--)
+ h = h * PRIME1 ^ (*key++ - ' ');
+ h %= PRIME2;
+
+ return (h);
}
-uint32 hashchar16(char *key)
+uint32
+hashchar16(char *key)
{
- uint32 h;
- int len;
-
- h = 0;
- len = sizeof(char16);
- /* Convert string to integer */
- while (len--)
- h = h * PRIME1 ^ (*key++ - ' ');
- h %= PRIME2;
-
- return (h);
+ uint32 h;
+ int len;
+
+ h = 0;
+ len = sizeof(char16);
+ /* Convert string to integer */
+ while (len--)
+ h = h * PRIME1 ^ (*key++ - ' ');
+ h %= PRIME2;
+
+ return (h);
}
@@ -234,45 +251,49 @@ uint32 hashchar16(char *key)
*
* "OZ's original sdbm hash"
*/
-uint32 hashtext(struct varlena *key)
+uint32
+hashtext(struct varlena * key)
{
- int keylen;
- char *keydata;
- uint32 n;
- int loop;
-
- keydata = VARDATA(key);
- keylen = VARSIZE(key);
-
- /* keylen includes the four bytes in which string keylength is stored */
- keylen -= sizeof(VARSIZE(key));
-
-#define HASHC n = *keydata++ + 65599 * n
-
- n = 0;
- if (keylen > 0) {
- loop = (keylen + 8 - 1) >> 3;
-
- switch (keylen & (8 - 1)) {
- case 0:
- do { /* All fall throughs */
- HASHC;
- case 7:
- HASHC;
- case 6:
- HASHC;
- case 5:
- HASHC;
- case 4:
- HASHC;
- case 3:
- HASHC;
- case 2:
- HASHC;
- case 1:
- HASHC;
- } while (--loop);
+ int keylen;
+ char *keydata;
+ uint32 n;
+ int loop;
+
+ keydata = VARDATA(key);
+ keylen = VARSIZE(key);
+
+ /* keylen includes the four bytes in which string keylength is stored */
+ keylen -= sizeof(VARSIZE(key));
+
+#define HASHC n = *keydata++ + 65599 * n
+
+ n = 0;
+ if (keylen > 0)
+ {
+ loop = (keylen + 8 - 1) >> 3;
+
+ switch (keylen & (8 - 1))
+ {
+ case 0:
+ do
+ { /* All fall throughs */
+ HASHC;
+ case 7:
+ HASHC;
+ case 6:
+ HASHC;
+ case 5:
+ HASHC;
+ case 4:
+ HASHC;
+ case 3:
+ HASHC;
+ case 2:
+ HASHC;
+ case 1:
+ HASHC;
+ } while (--loop);
+ }
}
- }
- return (n);
-}
+ return (n);
+}
diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index f1233c68b2d..4829093589a 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* hashinsert.c--
- * Item insertion in hash tables for Postgres.
+ * Item insertion in hash tables for Postgres.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hashinsert.c,v 1.8 1997/08/12 22:51:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashinsert.c,v 1.9 1997/09/07 04:37:56 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/hash.h>
#include <storage/bufmgr.h>
#include <utils/memutils.h>
@@ -22,211 +22,221 @@ static InsertIndexResult _hash_insertonpg(Relation rel, Buffer buf, int keysz, S
static OffsetNumber _hash_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, HashItem hitem);
/*
- * _hash_doinsert() -- Handle insertion of a single HashItem in the table.
+ * _hash_doinsert() -- Handle insertion of a single HashItem in the table.
*
- * This routine is called by the public interface routines, hashbuild
- * and hashinsert. By here, hashitem is filled in, and has a unique
- * (xid, seqno) pair. The datum to be used as a "key" is in the
- * hashitem.
+ * This routine is called by the public interface routines, hashbuild
+ * and hashinsert. By here, hashitem is filled in, and has a unique
+ * (xid, seqno) pair. The datum to be used as a "key" is in the
+ * hashitem.
*/
InsertIndexResult
_hash_doinsert(Relation rel, HashItem hitem)
{
- Buffer buf;
- Buffer metabuf;
- BlockNumber blkno;
- HashMetaPage metap;
- IndexTuple itup;
- InsertIndexResult res;
- ScanKey itup_scankey;
- int natts;
- Page page;
-
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- /* we need a scan key to do our search, so build one */
- itup = &(hitem->hash_itup);
- if ((natts = rel->rd_rel->relnatts) != 1)
- elog(WARN, "Hash indices valid for only one index key.");
- itup_scankey = _hash_mkscankey(rel, itup, metap);
-
- /*
- * find the first page in the bucket chain containing this key and
- * place it in buf. _hash_search obtains a read lock for us.
- */
- _hash_search(rel, natts, itup_scankey, &buf, metap);
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE);
-
- /*
- * trade in our read lock for a write lock so that we can do the
- * insertion.
- */
- blkno = BufferGetBlockNumber(buf);
- _hash_relbuf(rel, buf, HASH_READ);
- buf = _hash_getbuf(rel, blkno, HASH_WRITE);
-
-
- /*
- * XXX btree comment (haven't decided what to do in hash): don't
- * think the bucket can be split while we're reading the metapage.
- *
- * If the page was split between the time that we surrendered our
- * read lock and acquired our write lock, then this page may no
- * longer be the right place for the key we want to insert.
- */
-
- /* do the insertion */
- res = _hash_insertonpg(rel, buf, natts, itup_scankey,
- hitem, metabuf);
-
- /* be tidy */
- _hash_freeskey(itup_scankey);
-
- return (res);
+ Buffer buf;
+ Buffer metabuf;
+ BlockNumber blkno;
+ HashMetaPage metap;
+ IndexTuple itup;
+ InsertIndexResult res;
+ ScanKey itup_scankey;
+ int natts;
+ Page page;
+
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ /* we need a scan key to do our search, so build one */
+ itup = &(hitem->hash_itup);
+ if ((natts = rel->rd_rel->relnatts) != 1)
+ elog(WARN, "Hash indices valid for only one index key.");
+ itup_scankey = _hash_mkscankey(rel, itup, metap);
+
+ /*
+ * find the first page in the bucket chain containing this key and
+ * place it in buf. _hash_search obtains a read lock for us.
+ */
+ _hash_search(rel, natts, itup_scankey, &buf, metap);
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE);
+
+ /*
+ * trade in our read lock for a write lock so that we can do the
+ * insertion.
+ */
+ blkno = BufferGetBlockNumber(buf);
+ _hash_relbuf(rel, buf, HASH_READ);
+ buf = _hash_getbuf(rel, blkno, HASH_WRITE);
+
+
+ /*
+ * XXX btree comment (haven't decided what to do in hash): don't think
+ * the bucket can be split while we're reading the metapage.
+ *
+ * If the page was split between the time that we surrendered our read
+ * lock and acquired our write lock, then this page may no longer be
+ * the right place for the key we want to insert.
+ */
+
+ /* do the insertion */
+ res = _hash_insertonpg(rel, buf, natts, itup_scankey,
+ hitem, metabuf);
+
+ /* be tidy */
+ _hash_freeskey(itup_scankey);
+
+ return (res);
}
/*
- * _hash_insertonpg() -- Insert a tuple on a particular page in the table.
+ * _hash_insertonpg() -- Insert a tuple on a particular page in the table.
*
- * This recursive procedure does the following things:
+ * This recursive procedure does the following things:
*
- * + if necessary, splits the target page.
- * + inserts the tuple.
+ * + if necessary, splits the target page.
+ * + inserts the tuple.
*
- * On entry, we must have the right buffer on which to do the
- * insertion, and the buffer must be pinned and locked. On return,
- * we will have dropped both the pin and the write lock on the buffer.
+ * On entry, we must have the right buffer on which to do the
+ * insertion, and the buffer must be pinned and locked. On return,
+ * we will have dropped both the pin and the write lock on the buffer.
*
*/
-static InsertIndexResult
+static InsertIndexResult
_hash_insertonpg(Relation rel,
- Buffer buf,
- int keysz,
- ScanKey scankey,
- HashItem hitem,
- Buffer metabuf)
+ Buffer buf,
+ int keysz,
+ ScanKey scankey,
+ HashItem hitem,
+ Buffer metabuf)
{
- InsertIndexResult res;
- Page page;
- BlockNumber itup_blkno;
- OffsetNumber itup_off;
- int itemsz;
- HashPageOpaque pageopaque;
- bool do_expand = false;
- Buffer ovflbuf;
- HashMetaPage metap;
- Bucket bucket;
-
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
- bucket = pageopaque->hasho_bucket;
-
- itemsz = IndexTupleDSize(hitem->hash_itup)
- + (sizeof(HashItemData) - sizeof(IndexTupleData));
- itemsz = DOUBLEALIGN(itemsz);
-
- while (PageGetFreeSpace(page) < itemsz) {
- /*
- * no space on this page; check for an overflow page
- */
- if (BlockNumberIsValid(pageopaque->hasho_nextblkno)) {
- /*
- * ovfl page exists; go get it. if it doesn't have room,
- * we'll find out next pass through the loop test above.
- */
- ovflbuf = _hash_getbuf(rel, pageopaque->hasho_nextblkno,
- HASH_WRITE);
- _hash_relbuf(rel, buf, HASH_WRITE);
- buf = ovflbuf;
- page = BufferGetPage(buf);
- } else {
- /*
- * we're at the end of the bucket chain and we haven't
- * found a page with enough room. allocate a new overflow
- * page.
- */
- do_expand = true;
- ovflbuf = _hash_addovflpage(rel, &metabuf, buf);
- _hash_relbuf(rel, buf, HASH_WRITE);
- buf = ovflbuf;
- page = BufferGetPage(buf);
-
- if (PageGetFreeSpace(page) < itemsz) {
- /* it doesn't fit on an empty page -- give up */
- elog(WARN, "hash item too large");
- }
- }
- _hash_checkpage(page, LH_OVERFLOW_PAGE);
+ InsertIndexResult res;
+ Page page;
+ BlockNumber itup_blkno;
+ OffsetNumber itup_off;
+ int itemsz;
+ HashPageOpaque pageopaque;
+ bool do_expand = false;
+ Buffer ovflbuf;
+ HashMetaPage metap;
+ Bucket bucket;
+
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
- Assert(pageopaque->hasho_bucket == bucket);
- }
-
- itup_off = _hash_pgaddtup(rel, buf, keysz, scankey, itemsz, hitem);
- itup_blkno = BufferGetBlockNumber(buf);
-
- /* by here, the new tuple is inserted */
- res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
-
- ItemPointerSet(&(res->pointerData), itup_blkno, itup_off);
-
- if (res != NULL) {
- /*
- * Increment the number of keys in the table.
- * We switch lock access type just for a moment
- * to allow greater accessibility to the metapage.
- */
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf,
- HASH_READ, HASH_WRITE);
- metap->hashm_nkeys += 1;
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf,
- HASH_WRITE, HASH_READ);
-
- }
-
- _hash_wrtbuf(rel, buf);
-
- if (do_expand ||
- (metap->hashm_nkeys / (metap->hashm_maxbucket + 1))
- > metap->hashm_ffactor) {
- _hash_expandtable(rel, metabuf);
- }
- _hash_relbuf(rel, metabuf, HASH_READ);
- return (res);
-}
+ bucket = pageopaque->hasho_bucket;
+
+ itemsz = IndexTupleDSize(hitem->hash_itup)
+ + (sizeof(HashItemData) - sizeof(IndexTupleData));
+ itemsz = DOUBLEALIGN(itemsz);
+
+ while (PageGetFreeSpace(page) < itemsz)
+ {
+
+ /*
+ * no space on this page; check for an overflow page
+ */
+ if (BlockNumberIsValid(pageopaque->hasho_nextblkno))
+ {
+
+ /*
+ * ovfl page exists; go get it. if it doesn't have room,
+ * we'll find out next pass through the loop test above.
+ */
+ ovflbuf = _hash_getbuf(rel, pageopaque->hasho_nextblkno,
+ HASH_WRITE);
+ _hash_relbuf(rel, buf, HASH_WRITE);
+ buf = ovflbuf;
+ page = BufferGetPage(buf);
+ }
+ else
+ {
+
+ /*
+ * we're at the end of the bucket chain and we haven't found a
+ * page with enough room. allocate a new overflow page.
+ */
+ do_expand = true;
+ ovflbuf = _hash_addovflpage(rel, &metabuf, buf);
+ _hash_relbuf(rel, buf, HASH_WRITE);
+ buf = ovflbuf;
+ page = BufferGetPage(buf);
+
+ if (PageGetFreeSpace(page) < itemsz)
+ {
+ /* it doesn't fit on an empty page -- give up */
+ elog(WARN, "hash item too large");
+ }
+ }
+ _hash_checkpage(page, LH_OVERFLOW_PAGE);
+ pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+ Assert(pageopaque->hasho_bucket == bucket);
+ }
+
+ itup_off = _hash_pgaddtup(rel, buf, keysz, scankey, itemsz, hitem);
+ itup_blkno = BufferGetBlockNumber(buf);
+
+ /* by here, the new tuple is inserted */
+ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
+
+ ItemPointerSet(&(res->pointerData), itup_blkno, itup_off);
+
+ if (res != NULL)
+ {
+
+ /*
+ * Increment the number of keys in the table. We switch lock
+ * access type just for a moment to allow greater accessibility to
+ * the metapage.
+ */
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf,
+ HASH_READ, HASH_WRITE);
+ metap->hashm_nkeys += 1;
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf,
+ HASH_WRITE, HASH_READ);
+
+ }
+
+ _hash_wrtbuf(rel, buf);
+
+ if (do_expand ||
+ (metap->hashm_nkeys / (metap->hashm_maxbucket + 1))
+ > metap->hashm_ffactor)
+ {
+ _hash_expandtable(rel, metabuf);
+ }
+ _hash_relbuf(rel, metabuf, HASH_READ);
+ return (res);
+}
/*
- * _hash_pgaddtup() -- add a tuple to a particular page in the index.
+ * _hash_pgaddtup() -- add a tuple to a particular page in the index.
*
- * This routine adds the tuple to the page as requested, and keeps the
- * write lock and reference associated with the page's buffer. It is
- * an error to call pgaddtup() without a write lock and reference.
+ * This routine adds the tuple to the page as requested, and keeps the
+ * write lock and reference associated with the page's buffer. It is
+ * an error to call pgaddtup() without a write lock and reference.
*/
-static OffsetNumber
+static OffsetNumber
_hash_pgaddtup(Relation rel,
- Buffer buf,
- int keysz,
- ScanKey itup_scankey,
- Size itemsize,
- HashItem hitem)
+ Buffer buf,
+ int keysz,
+ ScanKey itup_scankey,
+ Size itemsize,
+ HashItem hitem)
{
- OffsetNumber itup_off;
- Page page;
-
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
-
- itup_off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
- PageAddItem(page, (Item) hitem, itemsize, itup_off, LP_USED);
-
- /* write the buffer, but hold our lock */
- _hash_wrtnorelbuf(rel, buf);
-
- return (itup_off);
+ OffsetNumber itup_off;
+ Page page;
+
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+
+ itup_off = OffsetNumberNext(PageGetMaxOffsetNumber(page));
+ PageAddItem(page, (Item) hitem, itemsize, itup_off, LP_USED);
+
+ /* write the buffer, but hold our lock */
+ _hash_wrtnorelbuf(rel, buf);
+
+ return (itup_off);
}
diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c
index d976c4818c8..b6882d4d3e1 100644
--- a/src/backend/access/hash/hashovfl.c
+++ b/src/backend/access/hash/hashovfl.c
@@ -1,400 +1,423 @@
/*-------------------------------------------------------------------------
*
* hashovfl.c--
- * Overflow page management code for the Postgres hash access method
+ * Overflow page management code for the Postgres hash access method
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hashovfl.c,v 1.9 1997/08/12 22:51:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashovfl.c,v 1.10 1997/09/07 04:37:57 momjian Exp $
*
* NOTES
- * Overflow pages look like ordinary relation pages.
+ * Overflow pages look like ordinary relation pages.
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/hash.h>
#include <storage/bufmgr.h>
#include <utils/memutils.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static OverflowPageAddress _hash_getovfladdr(Relation rel, Buffer *metabufp);
-static uint32 _hash_firstfreebit(uint32 map);
+static OverflowPageAddress _hash_getovfladdr(Relation rel, Buffer * metabufp);
+static uint32 _hash_firstfreebit(uint32 map);
/*
- * _hash_addovflpage
+ * _hash_addovflpage
+ *
+ * Add an overflow page to the page currently pointed to by the buffer
+ * argument 'buf'.
*
- * Add an overflow page to the page currently pointed to by the buffer
- * argument 'buf'.
+ * *Metabufp has a read lock upon entering the function; buf has a
+ * write lock.
*
- * *Metabufp has a read lock upon entering the function; buf has a
- * write lock.
- *
*/
Buffer
-_hash_addovflpage(Relation rel, Buffer *metabufp, Buffer buf)
+_hash_addovflpage(Relation rel, Buffer * metabufp, Buffer buf)
{
-
- OverflowPageAddress oaddr;
- BlockNumber ovflblkno;
- Buffer ovflbuf;
- HashMetaPage metap;
- HashPageOpaque ovflopaque;
- HashPageOpaque pageopaque;
- Page page;
- Page ovflpage;
-
- /* this had better be the last page in a bucket chain */
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
- Assert(!BlockNumberIsValid(pageopaque->hasho_nextblkno));
-
- metap = (HashMetaPage) BufferGetPage(*metabufp);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- /* allocate an empty overflow page */
- oaddr = _hash_getovfladdr(rel, metabufp);
- if (oaddr == InvalidOvflAddress) {
- elog(WARN, "_hash_addovflpage: problem with _hash_getovfladdr.");
- }
- ovflblkno = OADDR_TO_BLKNO(OADDR_OF(SPLITNUM(oaddr), OPAGENUM(oaddr)));
- Assert(BlockNumberIsValid(ovflblkno));
- ovflbuf = _hash_getbuf(rel, ovflblkno, HASH_WRITE);
- Assert(BufferIsValid(ovflbuf));
- ovflpage = BufferGetPage(ovflbuf);
-
- /* initialize the new overflow page */
- _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
- ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
- ovflopaque->hasho_prevblkno = BufferGetBlockNumber(buf);
- ovflopaque->hasho_nextblkno = InvalidBlockNumber;
- ovflopaque->hasho_flag = LH_OVERFLOW_PAGE;
- ovflopaque->hasho_oaddr = oaddr;
- ovflopaque->hasho_bucket = pageopaque->hasho_bucket;
- _hash_wrtnorelbuf(rel, ovflbuf);
-
- /* logically chain overflow page to previous page */
- pageopaque->hasho_nextblkno = ovflblkno;
- _hash_wrtnorelbuf(rel, buf);
- return (ovflbuf);
+
+ OverflowPageAddress oaddr;
+ BlockNumber ovflblkno;
+ Buffer ovflbuf;
+ HashMetaPage metap;
+ HashPageOpaque ovflopaque;
+ HashPageOpaque pageopaque;
+ Page page;
+ Page ovflpage;
+
+ /* this had better be the last page in a bucket chain */
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);
+ Assert(!BlockNumberIsValid(pageopaque->hasho_nextblkno));
+
+ metap = (HashMetaPage) BufferGetPage(*metabufp);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ /* allocate an empty overflow page */
+ oaddr = _hash_getovfladdr(rel, metabufp);
+ if (oaddr == InvalidOvflAddress)
+ {
+ elog(WARN, "_hash_addovflpage: problem with _hash_getovfladdr.");
+ }
+ ovflblkno = OADDR_TO_BLKNO(OADDR_OF(SPLITNUM(oaddr), OPAGENUM(oaddr)));
+ Assert(BlockNumberIsValid(ovflblkno));
+ ovflbuf = _hash_getbuf(rel, ovflblkno, HASH_WRITE);
+ Assert(BufferIsValid(ovflbuf));
+ ovflpage = BufferGetPage(ovflbuf);
+
+ /* initialize the new overflow page */
+ _hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));
+ ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
+ ovflopaque->hasho_prevblkno = BufferGetBlockNumber(buf);
+ ovflopaque->hasho_nextblkno = InvalidBlockNumber;
+ ovflopaque->hasho_flag = LH_OVERFLOW_PAGE;
+ ovflopaque->hasho_oaddr = oaddr;
+ ovflopaque->hasho_bucket = pageopaque->hasho_bucket;
+ _hash_wrtnorelbuf(rel, ovflbuf);
+
+ /* logically chain overflow page to previous page */
+ pageopaque->hasho_nextblkno = ovflblkno;
+ _hash_wrtnorelbuf(rel, buf);
+ return (ovflbuf);
}
/*
- * _hash_getovfladdr()
+ * _hash_getovfladdr()
*
- * Find an available overflow page and return its address.
+ * Find an available overflow page and return its address.
*
- * When we enter this function, we have a read lock on *metabufp which
- * we change to a write lock immediately. Before exiting, the write lock
- * is exchanged for a read lock.
+ * When we enter this function, we have a read lock on *metabufp which
+ * we change to a write lock immediately. Before exiting, the write lock
+ * is exchanged for a read lock.
*
*/
-static OverflowPageAddress
-_hash_getovfladdr(Relation rel, Buffer *metabufp)
+static OverflowPageAddress
+_hash_getovfladdr(Relation rel, Buffer * metabufp)
{
- HashMetaPage metap;
- Buffer mapbuf = 0;
- BlockNumber blkno;
- PageOffset offset;
- OverflowPageAddress oaddr;
- SplitNumber splitnum;
- uint32 *freep = NULL;
- uint32 max_free;
- uint32 bit;
- uint32 first_page;
- uint32 free_bit;
- uint32 free_page;
- uint32 in_use_bits;
- uint32 i, j;
-
- metap = (HashMetaPage) _hash_chgbufaccess(rel, metabufp, HASH_READ, HASH_WRITE);
-
- splitnum = metap->OVFL_POINT;
- max_free = metap->SPARES[splitnum];
-
- free_page = (max_free - 1) >> (metap->BSHIFT + BYTE_TO_BIT);
- free_bit = (max_free - 1) & (BMPGSZ_BIT(metap) - 1);
-
- /* Look through all the free maps to find the first free block */
- first_page = metap->LAST_FREED >> (metap->BSHIFT + BYTE_TO_BIT);
- for ( i = first_page; i <= free_page; i++ ) {
- Page mappage;
-
- blkno = metap->hashm_mapp[i];
- mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE);
- mappage = BufferGetPage(mapbuf);
- _hash_checkpage(mappage, LH_BITMAP_PAGE);
- freep = HashPageGetBitmap(mappage);
- Assert(freep);
-
- if (i == free_page)
- in_use_bits = free_bit;
- else
- in_use_bits = BMPGSZ_BIT(metap) - 1;
-
- if (i == first_page) {
- bit = metap->LAST_FREED & (BMPGSZ_BIT(metap) - 1);
- j = bit / BITS_PER_MAP;
- bit = bit & ~(BITS_PER_MAP - 1);
- } else {
- bit = 0;
- j = 0;
+ HashMetaPage metap;
+ Buffer mapbuf = 0;
+ BlockNumber blkno;
+ PageOffset offset;
+ OverflowPageAddress oaddr;
+ SplitNumber splitnum;
+ uint32 *freep = NULL;
+ uint32 max_free;
+ uint32 bit;
+ uint32 first_page;
+ uint32 free_bit;
+ uint32 free_page;
+ uint32 in_use_bits;
+ uint32 i,
+ j;
+
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, metabufp, HASH_READ, HASH_WRITE);
+
+ splitnum = metap->OVFL_POINT;
+ max_free = metap->SPARES[splitnum];
+
+ free_page = (max_free - 1) >> (metap->BSHIFT + BYTE_TO_BIT);
+ free_bit = (max_free - 1) & (BMPGSZ_BIT(metap) - 1);
+
+ /* Look through all the free maps to find the first free block */
+ first_page = metap->LAST_FREED >> (metap->BSHIFT + BYTE_TO_BIT);
+ for (i = first_page; i <= free_page; i++)
+ {
+ Page mappage;
+
+ blkno = metap->hashm_mapp[i];
+ mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE);
+ mappage = BufferGetPage(mapbuf);
+ _hash_checkpage(mappage, LH_BITMAP_PAGE);
+ freep = HashPageGetBitmap(mappage);
+ Assert(freep);
+
+ if (i == free_page)
+ in_use_bits = free_bit;
+ else
+ in_use_bits = BMPGSZ_BIT(metap) - 1;
+
+ if (i == first_page)
+ {
+ bit = metap->LAST_FREED & (BMPGSZ_BIT(metap) - 1);
+ j = bit / BITS_PER_MAP;
+ bit = bit & ~(BITS_PER_MAP - 1);
+ }
+ else
+ {
+ bit = 0;
+ j = 0;
+ }
+ for (; bit <= in_use_bits; j++, bit += BITS_PER_MAP)
+ if (freep[j] != ALL_SET)
+ goto found;
+ }
+
+ /* No Free Page Found - have to allocate a new page */
+ metap->LAST_FREED = metap->SPARES[splitnum];
+ metap->SPARES[splitnum]++;
+ offset = metap->SPARES[splitnum] -
+ (splitnum ? metap->SPARES[splitnum - 1] : 0);
+
+#define OVMSG "HASH: Out of overflow pages. Out of luck.\n"
+
+ if (offset > SPLITMASK)
+ {
+ if (++splitnum >= NCACHED)
+ {
+ elog(WARN, OVMSG);
+ }
+ metap->OVFL_POINT = splitnum;
+ metap->SPARES[splitnum] = metap->SPARES[splitnum - 1];
+ metap->SPARES[splitnum - 1]--;
+ offset = 0;
}
- for (; bit <= in_use_bits; j++, bit += BITS_PER_MAP)
- if (freep[j] != ALL_SET)
- goto found;
- }
-
- /* No Free Page Found - have to allocate a new page */
- metap->LAST_FREED = metap->SPARES[splitnum];
- metap->SPARES[splitnum]++;
- offset = metap->SPARES[splitnum] -
- (splitnum ? metap->SPARES[splitnum - 1] : 0);
-
-#define OVMSG "HASH: Out of overflow pages. Out of luck.\n"
-
- if (offset > SPLITMASK) {
- if (++splitnum >= NCACHED) {
- elog(WARN, OVMSG);
+
+ /* Check if we need to allocate a new bitmap page */
+ if (free_bit == BMPGSZ_BIT(metap) - 1)
+ {
+ /* won't be needing old map page */
+
+ _hash_relbuf(rel, mapbuf, HASH_WRITE);
+
+ free_page++;
+ if (free_page >= NCACHED)
+ {
+ elog(WARN, OVMSG);
+ }
+
+ /*
+ * This is tricky. The 1 indicates that you want the new page
+ * allocated with 1 clear bit. Actually, you are going to
+ * allocate 2 pages from this map. The first is going to be the
+ * map page, the second is the overflow page we were looking for.
+ * The init_bitmap routine automatically, sets the first bit of
+ * itself to indicate that the bitmap itself is in use. We would
+ * explicitly set the second bit, but don't have to if we tell
+ * init_bitmap not to leave it clear in the first place.
+ */
+ if (_hash_initbitmap(rel, metap, OADDR_OF(splitnum, offset),
+ 1, free_page))
+ {
+ elog(WARN, "overflow_page: problem with _hash_initbitmap.");
+ }
+ metap->SPARES[splitnum]++;
+ offset++;
+ if (offset > SPLITMASK)
+ {
+ if (++splitnum >= NCACHED)
+ {
+ elog(WARN, OVMSG);
+ }
+ metap->OVFL_POINT = splitnum;
+ metap->SPARES[splitnum] = metap->SPARES[splitnum - 1];
+ metap->SPARES[splitnum - 1]--;
+ offset = 0;
+ }
}
- metap->OVFL_POINT = splitnum;
- metap->SPARES[splitnum] = metap->SPARES[splitnum-1];
- metap->SPARES[splitnum-1]--;
- offset = 0;
- }
-
- /* Check if we need to allocate a new bitmap page */
- if (free_bit == BMPGSZ_BIT(metap) - 1) {
- /* won't be needing old map page */
-
- _hash_relbuf(rel, mapbuf, HASH_WRITE);
-
- free_page++;
- if (free_page >= NCACHED) {
- elog(WARN, OVMSG);
+ else
+ {
+
+ /*
+ * Free_bit addresses the last used bit. Bump it to address the
+ * first available bit.
+ */
+ free_bit++;
+ SETBIT(freep, free_bit);
+ _hash_wrtbuf(rel, mapbuf);
}
-
+
+ /* Calculate address of the new overflow page */
+ oaddr = OADDR_OF(splitnum, offset);
+ _hash_chgbufaccess(rel, metabufp, HASH_WRITE, HASH_READ);
+ return (oaddr);
+
+found:
+ bit = bit + _hash_firstfreebit(freep[j]);
+ SETBIT(freep, bit);
+ _hash_wrtbuf(rel, mapbuf);
+
/*
- * This is tricky. The 1 indicates that you want the new page
- * allocated with 1 clear bit. Actually, you are going to
- * allocate 2 pages from this map. The first is going to be
- * the map page, the second is the overflow page we were
- * looking for. The init_bitmap routine automatically, sets
- * the first bit of itself to indicate that the bitmap itself
- * is in use. We would explicitly set the second bit, but
- * don't have to if we tell init_bitmap not to leave it clear
- * in the first place.
+ * Bits are addressed starting with 0, but overflow pages are
+ * addressed beginning at 1. Bit is a bit addressnumber, so we need to
+ * increment it to convert it to a page number.
*/
- if (_hash_initbitmap(rel, metap, OADDR_OF(splitnum, offset),
- 1, free_page)) {
- elog(WARN, "overflow_page: problem with _hash_initbitmap.");
+
+ bit = 1 + bit + (i * BMPGSZ_BIT(metap));
+ if (bit >= metap->LAST_FREED)
+ {
+ metap->LAST_FREED = bit - 1;
}
- metap->SPARES[splitnum]++;
- offset++;
- if (offset > SPLITMASK) {
- if (++splitnum >= NCACHED) {
+
+ /* Calculate the split number for this page */
+ for (i = 0; (i < splitnum) && (bit > metap->SPARES[i]); i++)
+ ;
+ offset = (i ? bit - metap->SPARES[i - 1] : bit);
+ if (offset >= SPLITMASK)
+ {
elog(WARN, OVMSG);
- }
- metap->OVFL_POINT = splitnum;
- metap->SPARES[splitnum] = metap->SPARES[splitnum-1];
- metap->SPARES[splitnum-1]--;
- offset = 0;
}
- } else {
-
- /*
- * Free_bit addresses the last used bit. Bump it to address
- * the first available bit.
- */
- free_bit++;
- SETBIT(freep, free_bit);
- _hash_wrtbuf(rel, mapbuf);
- }
-
- /* Calculate address of the new overflow page */
- oaddr = OADDR_OF(splitnum, offset);
- _hash_chgbufaccess(rel, metabufp, HASH_WRITE, HASH_READ);
- return (oaddr);
-
- found:
- bit = bit + _hash_firstfreebit(freep[j]);
- SETBIT(freep, bit);
- _hash_wrtbuf(rel, mapbuf);
-
- /*
- * Bits are addressed starting with 0, but overflow pages are addressed
- * beginning at 1. Bit is a bit addressnumber, so we need to increment
- * it to convert it to a page number.
- */
-
- bit = 1 + bit + (i * BMPGSZ_BIT(metap));
- if (bit >= metap->LAST_FREED) {
- metap->LAST_FREED = bit - 1;
- }
-
- /* Calculate the split number for this page */
- for (i = 0; (i < splitnum) && (bit > metap->SPARES[i]); i++)
- ;
- offset = (i ? bit - metap->SPARES[i - 1] : bit);
- if (offset >= SPLITMASK) {
- elog(WARN, OVMSG);
- }
-
- /* initialize this page */
- oaddr = OADDR_OF(i, offset);
- _hash_chgbufaccess(rel, metabufp, HASH_WRITE, HASH_READ);
- return (oaddr);
+
+ /* initialize this page */
+ oaddr = OADDR_OF(i, offset);
+ _hash_chgbufaccess(rel, metabufp, HASH_WRITE, HASH_READ);
+ return (oaddr);
}
/*
- * _hash_firstfreebit()
+ * _hash_firstfreebit()
+ *
+ * Return the first bit that is not set in the argument 'map'. This
+ * function is used to find an available overflow page within a
+ * splitnumber.
*
- * Return the first bit that is not set in the argument 'map'. This
- * function is used to find an available overflow page within a
- * splitnumber.
- *
*/
-static uint32
+static uint32
_hash_firstfreebit(uint32 map)
{
- uint32 i, mask;
-
- mask = 0x1;
- for (i = 0; i < BITS_PER_MAP; i++) {
- if (!(mask & map))
- return (i);
- mask = mask << 1;
- }
- return (i);
+ uint32 i,
+ mask;
+
+ mask = 0x1;
+ for (i = 0; i < BITS_PER_MAP; i++)
+ {
+ if (!(mask & map))
+ return (i);
+ mask = mask << 1;
+ }
+ return (i);
}
/*
- * _hash_freeovflpage() -
+ * _hash_freeovflpage() -
*
- * Mark this overflow page as free and return a buffer with
- * the page that follows it (which may be defined as
- * InvalidBuffer).
+ * Mark this overflow page as free and return a buffer with
+ * the page that follows it (which may be defined as
+ * InvalidBuffer).
*
*/
Buffer
_hash_freeovflpage(Relation rel, Buffer ovflbuf)
{
- HashMetaPage metap;
- Buffer metabuf;
- Buffer mapbuf;
- BlockNumber prevblkno;
- BlockNumber blkno;
- BlockNumber nextblkno;
- HashPageOpaque ovflopaque;
- Page ovflpage;
- Page mappage;
- OverflowPageAddress addr;
- SplitNumber splitnum;
- uint32 *freep;
- uint32 ovflpgno;
- int32 bitmappage, bitmapbit;
- Bucket bucket;
-
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- ovflpage = BufferGetPage(ovflbuf);
- _hash_checkpage(ovflpage, LH_OVERFLOW_PAGE);
- ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
- addr = ovflopaque->hasho_oaddr;
- nextblkno = ovflopaque->hasho_nextblkno;
- prevblkno = ovflopaque->hasho_prevblkno;
- bucket = ovflopaque->hasho_bucket;
- memset(ovflpage, 0, BufferGetPageSize(ovflbuf));
- _hash_wrtbuf(rel, ovflbuf);
-
- /*
- * fix up the bucket chain. this is a doubly-linked list, so we
- * must fix up the bucket chain members behind and ahead of the
- * overflow page being deleted.
- *
- * XXX this should look like:
- * - lock prev/next
- * - modify/write prev/next (how to do write ordering with a
- * doubly-linked list?)
- * - unlock prev/next
- */
- if (BlockNumberIsValid(prevblkno)) {
- Buffer prevbuf = _hash_getbuf(rel, prevblkno, HASH_WRITE);
- Page prevpage = BufferGetPage(prevbuf);
- HashPageOpaque prevopaque =
- (HashPageOpaque) PageGetSpecialPointer(prevpage);
-
- _hash_checkpage(prevpage, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- Assert(prevopaque->hasho_bucket == bucket);
- prevopaque->hasho_nextblkno = nextblkno;
- _hash_wrtbuf(rel, prevbuf);
- }
- if (BlockNumberIsValid(nextblkno)) {
- Buffer nextbuf = _hash_getbuf(rel, nextblkno, HASH_WRITE);
- Page nextpage = BufferGetPage(nextbuf);
- HashPageOpaque nextopaque =
- (HashPageOpaque) PageGetSpecialPointer(nextpage);
-
- _hash_checkpage(nextpage, LH_OVERFLOW_PAGE);
- Assert(nextopaque->hasho_bucket == bucket);
- nextopaque->hasho_prevblkno = prevblkno;
- _hash_wrtbuf(rel, nextbuf);
- }
-
- /*
- * Fix up the overflow page bitmap that tracks this particular
- * overflow page. The bitmap can be found in the MetaPageData
- * array element hashm_mapp[bitmappage].
- */
- splitnum = (addr >> SPLITSHIFT);
- ovflpgno =
- (splitnum ? metap->SPARES[splitnum - 1] : 0) + (addr & SPLITMASK) - 1;
-
- if (ovflpgno < metap->LAST_FREED) {
- metap->LAST_FREED = ovflpgno;
- }
-
- bitmappage = (ovflpgno >> (metap->BSHIFT + BYTE_TO_BIT));
- bitmapbit = ovflpgno & (BMPGSZ_BIT(metap) - 1);
-
- blkno = metap->hashm_mapp[bitmappage];
- mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE);
- mappage = BufferGetPage(mapbuf);
- _hash_checkpage(mappage, LH_BITMAP_PAGE);
- freep = HashPageGetBitmap(mappage);
- CLRBIT(freep, bitmapbit);
- _hash_wrtbuf(rel, mapbuf);
-
- _hash_relbuf(rel, metabuf, HASH_WRITE);
-
- /*
- * now instantiate the page that replaced this one,
- * if it exists, and return that buffer with a write lock.
- */
- if (BlockNumberIsValid(nextblkno)) {
- return (_hash_getbuf(rel, nextblkno, HASH_WRITE));
- } else {
- return (InvalidBuffer);
- }
+ HashMetaPage metap;
+ Buffer metabuf;
+ Buffer mapbuf;
+ BlockNumber prevblkno;
+ BlockNumber blkno;
+ BlockNumber nextblkno;
+ HashPageOpaque ovflopaque;
+ Page ovflpage;
+ Page mappage;
+ OverflowPageAddress addr;
+ SplitNumber splitnum;
+ uint32 *freep;
+ uint32 ovflpgno;
+ int32 bitmappage,
+ bitmapbit;
+ Bucket bucket;
+
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ ovflpage = BufferGetPage(ovflbuf);
+ _hash_checkpage(ovflpage, LH_OVERFLOW_PAGE);
+ ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);
+ addr = ovflopaque->hasho_oaddr;
+ nextblkno = ovflopaque->hasho_nextblkno;
+ prevblkno = ovflopaque->hasho_prevblkno;
+ bucket = ovflopaque->hasho_bucket;
+ memset(ovflpage, 0, BufferGetPageSize(ovflbuf));
+ _hash_wrtbuf(rel, ovflbuf);
+
+ /*
+ * fix up the bucket chain. this is a doubly-linked list, so we must
+ * fix up the bucket chain members behind and ahead of the overflow
+ * page being deleted.
+ *
+ * XXX this should look like: - lock prev/next - modify/write prev/next
+ * (how to do write ordering with a doubly-linked list?) - unlock
+ * prev/next
+ */
+ if (BlockNumberIsValid(prevblkno))
+ {
+ Buffer prevbuf = _hash_getbuf(rel, prevblkno, HASH_WRITE);
+ Page prevpage = BufferGetPage(prevbuf);
+ HashPageOpaque prevopaque =
+ (HashPageOpaque) PageGetSpecialPointer(prevpage);
+
+ _hash_checkpage(prevpage, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ Assert(prevopaque->hasho_bucket == bucket);
+ prevopaque->hasho_nextblkno = nextblkno;
+ _hash_wrtbuf(rel, prevbuf);
+ }
+ if (BlockNumberIsValid(nextblkno))
+ {
+ Buffer nextbuf = _hash_getbuf(rel, nextblkno, HASH_WRITE);
+ Page nextpage = BufferGetPage(nextbuf);
+ HashPageOpaque nextopaque =
+ (HashPageOpaque) PageGetSpecialPointer(nextpage);
+
+ _hash_checkpage(nextpage, LH_OVERFLOW_PAGE);
+ Assert(nextopaque->hasho_bucket == bucket);
+ nextopaque->hasho_prevblkno = prevblkno;
+ _hash_wrtbuf(rel, nextbuf);
+ }
+
+ /*
+ * Fix up the overflow page bitmap that tracks this particular
+ * overflow page. The bitmap can be found in the MetaPageData array
+ * element hashm_mapp[bitmappage].
+ */
+ splitnum = (addr >> SPLITSHIFT);
+ ovflpgno =
+ (splitnum ? metap->SPARES[splitnum - 1] : 0) + (addr & SPLITMASK) - 1;
+
+ if (ovflpgno < metap->LAST_FREED)
+ {
+ metap->LAST_FREED = ovflpgno;
+ }
+
+ bitmappage = (ovflpgno >> (metap->BSHIFT + BYTE_TO_BIT));
+ bitmapbit = ovflpgno & (BMPGSZ_BIT(metap) - 1);
+
+ blkno = metap->hashm_mapp[bitmappage];
+ mapbuf = _hash_getbuf(rel, blkno, HASH_WRITE);
+ mappage = BufferGetPage(mapbuf);
+ _hash_checkpage(mappage, LH_BITMAP_PAGE);
+ freep = HashPageGetBitmap(mappage);
+ CLRBIT(freep, bitmapbit);
+ _hash_wrtbuf(rel, mapbuf);
+
+ _hash_relbuf(rel, metabuf, HASH_WRITE);
+
+ /*
+ * now instantiate the page that replaced this one, if it exists, and
+ * return that buffer with a write lock.
+ */
+ if (BlockNumberIsValid(nextblkno))
+ {
+ return (_hash_getbuf(rel, nextblkno, HASH_WRITE));
+ }
+ else
+ {
+ return (InvalidBuffer);
+ }
}
/*
- * _hash_initbitmap()
- *
- * Initialize a new bitmap page. The metapage has a write-lock upon
- * entering the function.
+ * _hash_initbitmap()
+ *
+ * Initialize a new bitmap page. The metapage has a write-lock upon
+ * entering the function.
*
* 'pnum' is the OverflowPageAddress of the new bitmap page.
* 'nbits' is how many bits to clear (i.e., make available) in the new
@@ -404,211 +427,219 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf)
* metapage's array of bitmap page OverflowPageAddresses.
*/
-#define INT_MASK ((1 << INT_TO_BIT) -1)
+#define INT_MASK ((1 << INT_TO_BIT) -1)
int32
_hash_initbitmap(Relation rel,
- HashMetaPage metap,
- int32 pnum,
- int32 nbits,
- int32 ndx)
+ HashMetaPage metap,
+ int32 pnum,
+ int32 nbits,
+ int32 ndx)
{
- Buffer buf;
- BlockNumber blkno;
- Page pg;
- HashPageOpaque op;
- uint32 *freep;
- int clearbytes, clearints;
-
- blkno = OADDR_TO_BLKNO(pnum);
- buf = _hash_getbuf(rel, blkno, HASH_WRITE);
- pg = BufferGetPage(buf);
- _hash_pageinit(pg, BufferGetPageSize(buf));
- op = (HashPageOpaque) PageGetSpecialPointer(pg);
- op->hasho_oaddr = InvalidOvflAddress;
- op->hasho_prevblkno = InvalidBlockNumber;
- op->hasho_nextblkno = InvalidBlockNumber;
- op->hasho_flag = LH_BITMAP_PAGE;
- op->hasho_bucket = -1;
-
- freep = HashPageGetBitmap(pg);
-
- /* set all of the bits above 'nbits' to 1 */
- clearints = ((nbits - 1) >> INT_TO_BIT) + 1;
- clearbytes = clearints << INT_TO_BYTE;
- memset((char *) freep, 0, clearbytes);
- memset(((char *) freep) + clearbytes, 0xFF,
- BMPGSZ_BYTE(metap) - clearbytes);
- freep[clearints - 1] = ALL_SET << (nbits & INT_MASK);
-
- /* bit 0 represents the new bitmap page */
- SETBIT(freep, 0);
-
- /* metapage already has a write lock */
- metap->hashm_nmaps++;
- metap->hashm_mapp[ndx] = blkno;
-
- /* write out the new bitmap page (releasing its locks) */
- _hash_wrtbuf(rel, buf);
-
- return (0);
+ Buffer buf;
+ BlockNumber blkno;
+ Page pg;
+ HashPageOpaque op;
+ uint32 *freep;
+ int clearbytes,
+ clearints;
+
+ blkno = OADDR_TO_BLKNO(pnum);
+ buf = _hash_getbuf(rel, blkno, HASH_WRITE);
+ pg = BufferGetPage(buf);
+ _hash_pageinit(pg, BufferGetPageSize(buf));
+ op = (HashPageOpaque) PageGetSpecialPointer(pg);
+ op->hasho_oaddr = InvalidOvflAddress;
+ op->hasho_prevblkno = InvalidBlockNumber;
+ op->hasho_nextblkno = InvalidBlockNumber;
+ op->hasho_flag = LH_BITMAP_PAGE;
+ op->hasho_bucket = -1;
+
+ freep = HashPageGetBitmap(pg);
+
+ /* set all of the bits above 'nbits' to 1 */
+ clearints = ((nbits - 1) >> INT_TO_BIT) + 1;
+ clearbytes = clearints << INT_TO_BYTE;
+ memset((char *) freep, 0, clearbytes);
+ memset(((char *) freep) + clearbytes, 0xFF,
+ BMPGSZ_BYTE(metap) - clearbytes);
+ freep[clearints - 1] = ALL_SET << (nbits & INT_MASK);
+
+ /* bit 0 represents the new bitmap page */
+ SETBIT(freep, 0);
+
+ /* metapage already has a write lock */
+ metap->hashm_nmaps++;
+ metap->hashm_mapp[ndx] = blkno;
+
+ /* write out the new bitmap page (releasing its locks) */
+ _hash_wrtbuf(rel, buf);
+
+ return (0);
}
/*
- * _hash_squeezebucket(rel, bucket)
+ * _hash_squeezebucket(rel, bucket)
*
- * Try to squeeze the tuples onto pages occuring earlier in the
- * bucket chain in an attempt to free overflow pages. When we start
- * the "squeezing", the page from which we start taking tuples (the
- * "read" page) is the last bucket in the bucket chain and the page
- * onto which we start squeezing tuples (the "write" page) is the
- * first page in the bucket chain. The read page works backward and
- * the write page works forward; the procedure terminates when the
- * read page and write page are the same page.
+ * Try to squeeze the tuples onto pages occuring earlier in the
+ * bucket chain in an attempt to free overflow pages. When we start
+ * the "squeezing", the page from which we start taking tuples (the
+ * "read" page) is the last bucket in the bucket chain and the page
+ * onto which we start squeezing tuples (the "write" page) is the
+ * first page in the bucket chain. The read page works backward and
+ * the write page works forward; the procedure terminates when the
+ * read page and write page are the same page.
*/
void
_hash_squeezebucket(Relation rel,
- HashMetaPage metap,
- Bucket bucket)
+ HashMetaPage metap,
+ Bucket bucket)
{
- Buffer wbuf;
- Buffer rbuf = 0;
- BlockNumber wblkno;
- BlockNumber rblkno;
- Page wpage;
- Page rpage;
- HashPageOpaque wopaque;
- HashPageOpaque ropaque;
- OffsetNumber woffnum;
- OffsetNumber roffnum;
- HashItem hitem;
- int itemsz;
-
-/* elog(DEBUG, "_hash_squeezebucket: squeezing bucket %d", bucket); */
-
- /*
- * start squeezing into the base bucket page.
- */
- wblkno = BUCKET_TO_BLKNO(bucket);
- wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
- wpage = BufferGetPage(wbuf);
- _hash_checkpage(wpage, LH_BUCKET_PAGE);
- wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
-
- /*
- * if there aren't any overflow pages, there's nothing to squeeze.
- */
- if (!BlockNumberIsValid(wopaque->hasho_nextblkno)) {
- _hash_relbuf(rel, wbuf, HASH_WRITE);
- return;
- }
-
- /*
- * find the last page in the bucket chain by starting at the base
- * bucket page and working forward.
- *
- * XXX if chains tend to be long, we should probably move forward
- * using HASH_READ and then _hash_chgbufaccess to HASH_WRITE when
- * we reach the end. if they are short we probably don't care
- * very much. if the hash function is working at all, they had
- * better be short..
- */
- ropaque = wopaque;
- do {
- rblkno = ropaque->hasho_nextblkno;
- if (ropaque != wopaque) {
- _hash_relbuf(rel, rbuf, HASH_WRITE);
- }
- rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
- rpage = BufferGetPage(rbuf);
- _hash_checkpage(rpage, LH_OVERFLOW_PAGE);
- Assert(!PageIsEmpty(rpage));
- ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
- Assert(ropaque->hasho_bucket == bucket);
- } while (BlockNumberIsValid(ropaque->hasho_nextblkno));
-
- /*
- * squeeze the tuples.
- */
- roffnum = FirstOffsetNumber;
- for(;;) {
- hitem = (HashItem) PageGetItem(rpage, PageGetItemId(rpage, roffnum));
- itemsz = IndexTupleDSize(hitem->hash_itup)
- + (sizeof(HashItemData) - sizeof(IndexTupleData));
- itemsz = DOUBLEALIGN(itemsz);
-
+ Buffer wbuf;
+ Buffer rbuf = 0;
+ BlockNumber wblkno;
+ BlockNumber rblkno;
+ Page wpage;
+ Page rpage;
+ HashPageOpaque wopaque;
+ HashPageOpaque ropaque;
+ OffsetNumber woffnum;
+ OffsetNumber roffnum;
+ HashItem hitem;
+ int itemsz;
+
+/* elog(DEBUG, "_hash_squeezebucket: squeezing bucket %d", bucket); */
+
/*
- * walk up the bucket chain, looking for a page big enough for
- * this item.
+ * start squeezing into the base bucket page.
*/
- while (PageGetFreeSpace(wpage) < itemsz) {
- wblkno = wopaque->hasho_nextblkno;
+ wblkno = BUCKET_TO_BLKNO(bucket);
+ wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
+ wpage = BufferGetPage(wbuf);
+ _hash_checkpage(wpage, LH_BUCKET_PAGE);
+ wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
- _hash_wrtbuf(rel, wbuf);
-
- if (!BlockNumberIsValid(wblkno) || (rblkno == wblkno)) {
- _hash_wrtbuf(rel, rbuf);
- /* wbuf is already released */
+ /*
+ * if there aren't any overflow pages, there's nothing to squeeze.
+ */
+ if (!BlockNumberIsValid(wopaque->hasho_nextblkno))
+ {
+ _hash_relbuf(rel, wbuf, HASH_WRITE);
return;
- }
-
- wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
- wpage = BufferGetPage(wbuf);
- _hash_checkpage(wpage, LH_OVERFLOW_PAGE);
- Assert(!PageIsEmpty(wpage));
- wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
- Assert(wopaque->hasho_bucket == bucket);
}
-
- /*
- * if we're here, we have found room so insert on the "write"
- * page.
- */
- woffnum = OffsetNumberNext(PageGetMaxOffsetNumber(wpage));
- PageAddItem(wpage, (Item) hitem, itemsz, woffnum, LP_USED);
-
- /*
- * delete the tuple from the "read" page.
- * PageIndexTupleDelete repacks the ItemId array, so 'roffnum'
- * will be "advanced" to the "next" ItemId.
+
+ /*
+ * find the last page in the bucket chain by starting at the base
+ * bucket page and working forward.
+ *
+ * XXX if chains tend to be long, we should probably move forward using
+ * HASH_READ and then _hash_chgbufaccess to HASH_WRITE when we reach
+ * the end. if they are short we probably don't care very much. if
+ * the hash function is working at all, they had better be short..
*/
- PageIndexTupleDelete(rpage, roffnum);
- _hash_wrtnorelbuf(rel, rbuf);
-
+ ropaque = wopaque;
+ do
+ {
+ rblkno = ropaque->hasho_nextblkno;
+ if (ropaque != wopaque)
+ {
+ _hash_relbuf(rel, rbuf, HASH_WRITE);
+ }
+ rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
+ rpage = BufferGetPage(rbuf);
+ _hash_checkpage(rpage, LH_OVERFLOW_PAGE);
+ Assert(!PageIsEmpty(rpage));
+ ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
+ Assert(ropaque->hasho_bucket == bucket);
+ } while (BlockNumberIsValid(ropaque->hasho_nextblkno));
+
/*
- * if the "read" page is now empty because of the deletion,
- * free it.
+ * squeeze the tuples.
*/
- if (PageIsEmpty(rpage) && (ropaque->hasho_flag & LH_OVERFLOW_PAGE)) {
- rblkno = ropaque->hasho_prevblkno;
- Assert(BlockNumberIsValid(rblkno));
-
- /*
- * free this overflow page. the extra _hash_relbuf is
- * because _hash_freeovflpage gratuitously returns the
- * next page (we want the previous page and will get it
- * ourselves later).
- */
- rbuf = _hash_freeovflpage(rel, rbuf);
- if (BufferIsValid(rbuf)) {
- _hash_relbuf(rel, rbuf, HASH_WRITE);
- }
-
- if (rblkno == wblkno) {
- /* rbuf is already released */
- _hash_wrtbuf(rel, wbuf);
- return;
- }
-
- rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
- rpage = BufferGetPage(rbuf);
- _hash_checkpage(rpage, LH_OVERFLOW_PAGE);
- Assert(!PageIsEmpty(rpage));
- ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
- Assert(ropaque->hasho_bucket == bucket);
-
- roffnum = FirstOffsetNumber;
+ roffnum = FirstOffsetNumber;
+ for (;;)
+ {
+ hitem = (HashItem) PageGetItem(rpage, PageGetItemId(rpage, roffnum));
+ itemsz = IndexTupleDSize(hitem->hash_itup)
+ + (sizeof(HashItemData) - sizeof(IndexTupleData));
+ itemsz = DOUBLEALIGN(itemsz);
+
+ /*
+ * walk up the bucket chain, looking for a page big enough for
+ * this item.
+ */
+ while (PageGetFreeSpace(wpage) < itemsz)
+ {
+ wblkno = wopaque->hasho_nextblkno;
+
+ _hash_wrtbuf(rel, wbuf);
+
+ if (!BlockNumberIsValid(wblkno) || (rblkno == wblkno))
+ {
+ _hash_wrtbuf(rel, rbuf);
+ /* wbuf is already released */
+ return;
+ }
+
+ wbuf = _hash_getbuf(rel, wblkno, HASH_WRITE);
+ wpage = BufferGetPage(wbuf);
+ _hash_checkpage(wpage, LH_OVERFLOW_PAGE);
+ Assert(!PageIsEmpty(wpage));
+ wopaque = (HashPageOpaque) PageGetSpecialPointer(wpage);
+ Assert(wopaque->hasho_bucket == bucket);
+ }
+
+ /*
+ * if we're here, we have found room so insert on the "write"
+ * page.
+ */
+ woffnum = OffsetNumberNext(PageGetMaxOffsetNumber(wpage));
+ PageAddItem(wpage, (Item) hitem, itemsz, woffnum, LP_USED);
+
+ /*
+ * delete the tuple from the "read" page. PageIndexTupleDelete
+ * repacks the ItemId array, so 'roffnum' will be "advanced" to
+ * the "next" ItemId.
+ */
+ PageIndexTupleDelete(rpage, roffnum);
+ _hash_wrtnorelbuf(rel, rbuf);
+
+ /*
+ * if the "read" page is now empty because of the deletion, free
+ * it.
+ */
+ if (PageIsEmpty(rpage) && (ropaque->hasho_flag & LH_OVERFLOW_PAGE))
+ {
+ rblkno = ropaque->hasho_prevblkno;
+ Assert(BlockNumberIsValid(rblkno));
+
+ /*
+ * free this overflow page. the extra _hash_relbuf is because
+ * _hash_freeovflpage gratuitously returns the next page (we
+ * want the previous page and will get it ourselves later).
+ */
+ rbuf = _hash_freeovflpage(rel, rbuf);
+ if (BufferIsValid(rbuf))
+ {
+ _hash_relbuf(rel, rbuf, HASH_WRITE);
+ }
+
+ if (rblkno == wblkno)
+ {
+ /* rbuf is already released */
+ _hash_wrtbuf(rel, wbuf);
+ return;
+ }
+
+ rbuf = _hash_getbuf(rel, rblkno, HASH_WRITE);
+ rpage = BufferGetPage(rbuf);
+ _hash_checkpage(rpage, LH_OVERFLOW_PAGE);
+ Assert(!PageIsEmpty(rpage));
+ ropaque = (HashPageOpaque) PageGetSpecialPointer(rpage);
+ Assert(ropaque->hasho_bucket == bucket);
+
+ roffnum = FirstOffsetNumber;
+ }
}
- }
}
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 49c8f03f524..6c819b652d2 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -1,30 +1,30 @@
/*-------------------------------------------------------------------------
*
* hashpage.c--
- * Hash table page management code for the Postgres hash access method
+ * Hash table page management code for the Postgres hash access method
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.9 1997/08/18 20:51:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.10 1997/09/07 04:38:00 momjian Exp $
*
* NOTES
- * Postgres hash pages look like ordinary relation pages. The opaque
- * data at high addresses includes information about the page including
- * whether a page is an overflow page or a true bucket, the block
- * numbers of the preceding and following pages, and the overflow
- * address of the page if it is an overflow page.
+ * Postgres hash pages look like ordinary relation pages. The opaque
+ * data at high addresses includes information about the page including
+ * whether a page is an overflow page or a true bucket, the block
+ * numbers of the preceding and following pages, and the overflow
+ * address of the page if it is an overflow page.
*
- * The first page in a hash relation, page zero, is special -- it stores
- * information describing the hash table; it is referred to as teh
- * "meta page." Pages one and higher store the actual data.
+ * The first page in a hash relation, page zero, is special -- it stores
+ * information describing the hash table; it is referred to as teh
+ * "meta page." Pages one and higher store the actual data.
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/hash.h>
#include <storage/bufmgr.h>
#include <miscadmin.h>
@@ -33,411 +33,429 @@
#include <access/genam.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static void _hash_setpagelock(Relation rel, BlockNumber blkno, int access);
-static void _hash_unsetpagelock(Relation rel, BlockNumber blkno, int access);
-static void _hash_splitpage(Relation rel, Buffer metabuf, Bucket obucket, Bucket nbucket);
-
-/*
- * We use high-concurrency locking on hash indices. There are two cases in
- * which we don't do locking. One is when we're building the index.
- * Since the creating transaction has not committed, no one can see
- * the index, and there's no reason to share locks. The second case
- * is when we're just starting up the database system. We use some
- * special-purpose initialization code in the relation cache manager
- * (see utils/cache/relcache.c) to allow us to do indexed scans on
- * the system catalogs before we'd normally be able to. This happens
- * before the lock table is fully initialized, so we can't use it.
- * Strictly speaking, this violates 2pl, but we don't do 2pl on the
- * system catalogs anyway.
+static void _hash_setpagelock(Relation rel, BlockNumber blkno, int access);
+static void _hash_unsetpagelock(Relation rel, BlockNumber blkno, int access);
+static void _hash_splitpage(Relation rel, Buffer metabuf, Bucket obucket, Bucket nbucket);
+
+/*
+ * We use high-concurrency locking on hash indices. There are two cases in
+ * which we don't do locking. One is when we're building the index.
+ * Since the creating transaction has not committed, no one can see
+ * the index, and there's no reason to share locks. The second case
+ * is when we're just starting up the database system. We use some
+ * special-purpose initialization code in the relation cache manager
+ * (see utils/cache/relcache.c) to allow us to do indexed scans on
+ * the system catalogs before we'd normally be able to. This happens
+ * before the lock table is fully initialized, so we can't use it.
+ * Strictly speaking, this violates 2pl, but we don't do 2pl on the
+ * system catalogs anyway.
*/
-#define USELOCKING (!BuildingHash && !IsInitProcessingMode())
+#define USELOCKING (!BuildingHash && !IsInitProcessingMode())
/*
- * _hash_metapinit() -- Initialize the metadata page of a hash index,
- * the two buckets that we begin with and the initial
- * bitmap page.
+ * _hash_metapinit() -- Initialize the metadata page of a hash index,
+ * the two buckets that we begin with and the initial
+ * bitmap page.
*/
void
_hash_metapinit(Relation rel)
{
- HashMetaPage metap;
- HashPageOpaque pageopaque;
- Buffer metabuf;
- Buffer buf;
- Page pg;
- int nbuckets;
- uint32 nelem; /* number elements */
- uint32 lg2nelem; /* _hash_log2(nelem) */
- uint32 nblocks;
- uint16 i;
-
- /* can't be sharing this with anyone, now... */
- if (USELOCKING)
- RelationSetLockForWrite(rel);
-
- if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0) {
- elog(WARN, "Cannot initialize non-empty hash table %s",
- RelationGetRelationName(rel));
- }
-
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
- pg = BufferGetPage(metabuf);
- metap = (HashMetaPage) pg;
- _hash_pageinit(pg, BufferGetPageSize(metabuf));
-
- metap->hashm_magic = HASH_MAGIC;
- metap->hashm_version = HASH_VERSION;
- metap->hashm_nkeys = 0;
- metap->hashm_nmaps = 0;
- metap->hashm_ffactor = DEFAULT_FFACTOR;
- metap->hashm_bsize = BufferGetPageSize(metabuf);
- metap->hashm_bshift = _hash_log2(metap->hashm_bsize);
- for (i = metap->hashm_bshift; i > 0; --i) {
- if ((1 << i) < (metap->hashm_bsize -
- (DOUBLEALIGN(sizeof(PageHeaderData)) +
- DOUBLEALIGN(sizeof(HashPageOpaqueData))))) {
- break;
+ HashMetaPage metap;
+ HashPageOpaque pageopaque;
+ Buffer metabuf;
+ Buffer buf;
+ Page pg;
+ int nbuckets;
+ uint32 nelem; /* number elements */
+ uint32 lg2nelem; /* _hash_log2(nelem) */
+ uint32 nblocks;
+ uint16 i;
+
+ /* can't be sharing this with anyone, now... */
+ if (USELOCKING)
+ RelationSetLockForWrite(rel);
+
+ if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0)
+ {
+ elog(WARN, "Cannot initialize non-empty hash table %s",
+ RelationGetRelationName(rel));
+ }
+
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
+ pg = BufferGetPage(metabuf);
+ metap = (HashMetaPage) pg;
+ _hash_pageinit(pg, BufferGetPageSize(metabuf));
+
+ metap->hashm_magic = HASH_MAGIC;
+ metap->hashm_version = HASH_VERSION;
+ metap->hashm_nkeys = 0;
+ metap->hashm_nmaps = 0;
+ metap->hashm_ffactor = DEFAULT_FFACTOR;
+ metap->hashm_bsize = BufferGetPageSize(metabuf);
+ metap->hashm_bshift = _hash_log2(metap->hashm_bsize);
+ for (i = metap->hashm_bshift; i > 0; --i)
+ {
+ if ((1 << i) < (metap->hashm_bsize -
+ (DOUBLEALIGN(sizeof(PageHeaderData)) +
+ DOUBLEALIGN(sizeof(HashPageOpaqueData)))))
+ {
+ break;
+ }
}
- }
- Assert(i);
- metap->hashm_bmsize = 1 << i;
- metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);
-
- /*
- * Make nelem = 2 rather than 0 so that we end up allocating space
- * for the next greater power of two number of buckets.
- */
- nelem = 2;
- lg2nelem = 1; /*_hash_log2(MAX(nelem, 2)) */
- nbuckets = 2; /*1 << lg2nelem */
-
- memset((char *) metap->hashm_spares, 0, sizeof(metap->hashm_spares));
- memset((char *) metap->hashm_mapp, 0, sizeof(metap->hashm_mapp));
-
- metap->hashm_spares[lg2nelem] = 2; /* lg2nelem + 1 */
- metap->hashm_spares[lg2nelem + 1] = 2; /* lg2nelem + 1 */
- metap->hashm_ovflpoint = 1; /* lg2nelem */
- metap->hashm_lastfreed = 2;
-
- metap->hashm_maxbucket = metap->hashm_lowmask = 1; /* nbuckets - 1 */
- metap->hashm_highmask = 3; /* (nbuckets << 1) - 1 */
-
- pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
- pageopaque->hasho_oaddr = InvalidOvflAddress;
- pageopaque->hasho_prevblkno = InvalidBlockNumber;
- pageopaque->hasho_nextblkno = InvalidBlockNumber;
- pageopaque->hasho_flag = LH_META_PAGE;
- pageopaque->hasho_bucket = -1;
-
- /*
- * First bitmap page is at: splitpoint lg2nelem page offset 1 which
- * turns out to be page 3. Couldn't initialize page 3 until we created
- * the first two buckets above.
- */
- if (_hash_initbitmap(rel, metap, OADDR_OF(lg2nelem, 1), lg2nelem + 1, 0))
- elog(WARN, "Problem with _hash_initbitmap.");
-
- /* all done */
- _hash_wrtnorelbuf(rel, metabuf);
-
- /*
- * initialize the first two buckets
- */
- for (i = 0; i <= 1; i++) {
- buf = _hash_getbuf(rel, BUCKET_TO_BLKNO(i), HASH_WRITE);
- pg = BufferGetPage(buf);
- _hash_pageinit(pg, BufferGetPageSize(buf));
+ Assert(i);
+ metap->hashm_bmsize = 1 << i;
+ metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);
+
+ /*
+ * Make nelem = 2 rather than 0 so that we end up allocating space for
+ * the next greater power of two number of buckets.
+ */
+ nelem = 2;
+ lg2nelem = 1; /* _hash_log2(MAX(nelem, 2)) */
+ nbuckets = 2; /* 1 << lg2nelem */
+
+ memset((char *) metap->hashm_spares, 0, sizeof(metap->hashm_spares));
+ memset((char *) metap->hashm_mapp, 0, sizeof(metap->hashm_mapp));
+
+ metap->hashm_spares[lg2nelem] = 2; /* lg2nelem + 1 */
+ metap->hashm_spares[lg2nelem + 1] = 2; /* lg2nelem + 1 */
+ metap->hashm_ovflpoint = 1; /* lg2nelem */
+ metap->hashm_lastfreed = 2;
+
+ metap->hashm_maxbucket = metap->hashm_lowmask = 1; /* nbuckets - 1 */
+ metap->hashm_highmask = 3; /* (nbuckets << 1) - 1 */
+
pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
pageopaque->hasho_oaddr = InvalidOvflAddress;
pageopaque->hasho_prevblkno = InvalidBlockNumber;
pageopaque->hasho_nextblkno = InvalidBlockNumber;
- pageopaque->hasho_flag = LH_BUCKET_PAGE;
- pageopaque->hasho_bucket = i;
- _hash_wrtbuf(rel, buf);
- }
-
- _hash_relbuf(rel, metabuf, HASH_WRITE);
-
- if (USELOCKING)
- RelationUnsetLockForWrite(rel);
+ pageopaque->hasho_flag = LH_META_PAGE;
+ pageopaque->hasho_bucket = -1;
+
+ /*
+ * First bitmap page is at: splitpoint lg2nelem page offset 1 which
+ * turns out to be page 3. Couldn't initialize page 3 until we
+ * created the first two buckets above.
+ */
+ if (_hash_initbitmap(rel, metap, OADDR_OF(lg2nelem, 1), lg2nelem + 1, 0))
+ elog(WARN, "Problem with _hash_initbitmap.");
+
+ /* all done */
+ _hash_wrtnorelbuf(rel, metabuf);
+
+ /*
+ * initialize the first two buckets
+ */
+ for (i = 0; i <= 1; i++)
+ {
+ buf = _hash_getbuf(rel, BUCKET_TO_BLKNO(i), HASH_WRITE);
+ pg = BufferGetPage(buf);
+ _hash_pageinit(pg, BufferGetPageSize(buf));
+ pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
+ pageopaque->hasho_oaddr = InvalidOvflAddress;
+ pageopaque->hasho_prevblkno = InvalidBlockNumber;
+ pageopaque->hasho_nextblkno = InvalidBlockNumber;
+ pageopaque->hasho_flag = LH_BUCKET_PAGE;
+ pageopaque->hasho_bucket = i;
+ _hash_wrtbuf(rel, buf);
+ }
+
+ _hash_relbuf(rel, metabuf, HASH_WRITE);
+
+ if (USELOCKING)
+ RelationUnsetLockForWrite(rel);
}
/*
- * _hash_getbuf() -- Get a buffer by block number for read or write.
+ * _hash_getbuf() -- Get a buffer by block number for read or write.
*
- * When this routine returns, the appropriate lock is set on the
- * requested buffer its reference count is correct.
+ * When this routine returns, the appropriate lock is set on the
+ * requested buffer its reference count is correct.
*
- * XXX P_NEW is not used because, unlike the tree structures, we
- * need the bucket blocks to be at certain block numbers. we must
- * depend on the caller to call _hash_pageinit on the block if it
- * knows that this is a new block.
+ * XXX P_NEW is not used because, unlike the tree structures, we
+ * need the bucket blocks to be at certain block numbers. we must
+ * depend on the caller to call _hash_pageinit on the block if it
+ * knows that this is a new block.
*/
Buffer
_hash_getbuf(Relation rel, BlockNumber blkno, int access)
{
- Buffer buf;
-
- if (blkno == P_NEW) {
- elog(WARN, "_hash_getbuf: internal error: hash AM does not use P_NEW");
- }
- switch (access) {
- case HASH_WRITE:
- case HASH_READ:
- _hash_setpagelock(rel, blkno, access);
- break;
- default:
- elog(WARN, "_hash_getbuf: invalid access (%d) on new blk: %s",
- access, RelationGetRelationName(rel));
- break;
- }
- buf = ReadBuffer(rel, blkno);
-
- /* ref count and lock type are correct */
- return (buf);
+ Buffer buf;
+
+ if (blkno == P_NEW)
+ {
+ elog(WARN, "_hash_getbuf: internal error: hash AM does not use P_NEW");
+ }
+ switch (access)
+ {
+ case HASH_WRITE:
+ case HASH_READ:
+ _hash_setpagelock(rel, blkno, access);
+ break;
+ default:
+ elog(WARN, "_hash_getbuf: invalid access (%d) on new blk: %s",
+ access, RelationGetRelationName(rel));
+ break;
+ }
+ buf = ReadBuffer(rel, blkno);
+
+ /* ref count and lock type are correct */
+ return (buf);
}
/*
- * _hash_relbuf() -- release a locked buffer.
+ * _hash_relbuf() -- release a locked buffer.
*/
void
_hash_relbuf(Relation rel, Buffer buf, int access)
{
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(buf);
-
- switch (access) {
- case HASH_WRITE:
- case HASH_READ:
- _hash_unsetpagelock(rel, blkno, access);
- break;
- default:
- elog(WARN, "_hash_relbuf: invalid access (%d) on blk %x: %s",
- access, blkno, RelationGetRelationName(rel));
- }
-
- ReleaseBuffer(buf);
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(buf);
+
+ switch (access)
+ {
+ case HASH_WRITE:
+ case HASH_READ:
+ _hash_unsetpagelock(rel, blkno, access);
+ break;
+ default:
+ elog(WARN, "_hash_relbuf: invalid access (%d) on blk %x: %s",
+ access, blkno, RelationGetRelationName(rel));
+ }
+
+ ReleaseBuffer(buf);
}
/*
- * _hash_wrtbuf() -- write a hash page to disk.
+ * _hash_wrtbuf() -- write a hash page to disk.
*
- * This routine releases the lock held on the buffer and our reference
- * to it. It is an error to call _hash_wrtbuf() without a write lock
- * or a reference to the buffer.
+ * This routine releases the lock held on the buffer and our reference
+ * to it. It is an error to call _hash_wrtbuf() without a write lock
+ * or a reference to the buffer.
*/
void
_hash_wrtbuf(Relation rel, Buffer buf)
{
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(buf);
- WriteBuffer(buf);
- _hash_unsetpagelock(rel, blkno, HASH_WRITE);
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(buf);
+ WriteBuffer(buf);
+ _hash_unsetpagelock(rel, blkno, HASH_WRITE);
}
/*
- * _hash_wrtnorelbuf() -- write a hash page to disk, but do not release
- * our reference or lock.
+ * _hash_wrtnorelbuf() -- write a hash page to disk, but do not release
+ * our reference or lock.
*
- * It is an error to call _hash_wrtnorelbuf() without a write lock
- * or a reference to the buffer.
+ * It is an error to call _hash_wrtnorelbuf() without a write lock
+ * or a reference to the buffer.
*/
void
_hash_wrtnorelbuf(Relation rel, Buffer buf)
{
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(buf);
- WriteNoReleaseBuffer(buf);
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(buf);
+ WriteNoReleaseBuffer(buf);
}
Page
_hash_chgbufaccess(Relation rel,
- Buffer *bufp,
- int from_access,
- int to_access)
+ Buffer * bufp,
+ int from_access,
+ int to_access)
{
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(*bufp);
-
- switch (from_access) {
- case HASH_WRITE:
- _hash_wrtbuf(rel, *bufp);
- break;
- case HASH_READ:
- _hash_relbuf(rel, *bufp, from_access);
- break;
- default:
- elog(WARN, "_hash_chgbufaccess: invalid access (%d) on blk %x: %s",
- from_access, blkno, RelationGetRelationName(rel));
- break;
- }
- *bufp = _hash_getbuf(rel, blkno, to_access);
- return (BufferGetPage(*bufp));
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(*bufp);
+
+ switch (from_access)
+ {
+ case HASH_WRITE:
+ _hash_wrtbuf(rel, *bufp);
+ break;
+ case HASH_READ:
+ _hash_relbuf(rel, *bufp, from_access);
+ break;
+ default:
+ elog(WARN, "_hash_chgbufaccess: invalid access (%d) on blk %x: %s",
+ from_access, blkno, RelationGetRelationName(rel));
+ break;
+ }
+ *bufp = _hash_getbuf(rel, blkno, to_access);
+ return (BufferGetPage(*bufp));
}
/*
- * _hash_pageinit() -- Initialize a new page.
+ * _hash_pageinit() -- Initialize a new page.
*/
void
_hash_pageinit(Page page, Size size)
{
- Assert(((PageHeader) page)->pd_lower == 0);
- Assert(((PageHeader) page)->pd_upper == 0);
- Assert(((PageHeader) page)->pd_special == 0);
-
- /*
- * Cargo-cult programming -- don't really need this to be zero, but
- * creating new pages is an infrequent occurrence and it makes me feel
- * good when I know they're empty.
- */
- memset(page, 0, size);
-
- PageInit(page, size, sizeof(HashPageOpaqueData));
+ Assert(((PageHeader) page)->pd_lower == 0);
+ Assert(((PageHeader) page)->pd_upper == 0);
+ Assert(((PageHeader) page)->pd_special == 0);
+
+ /*
+ * Cargo-cult programming -- don't really need this to be zero, but
+ * creating new pages is an infrequent occurrence and it makes me feel
+ * good when I know they're empty.
+ */
+ memset(page, 0, size);
+
+ PageInit(page, size, sizeof(HashPageOpaqueData));
}
static void
_hash_setpagelock(Relation rel,
- BlockNumber blkno,
- int access)
+ BlockNumber blkno,
+ int access)
{
- ItemPointerData iptr;
-
- if (USELOCKING) {
- ItemPointerSet(&iptr, blkno, 1);
-
- switch (access) {
- case HASH_WRITE:
- RelationSetSingleWLockPage(rel, &iptr);
- break;
- case HASH_READ:
- RelationSetSingleRLockPage(rel, &iptr);
- break;
- default:
- elog(WARN, "_hash_setpagelock: invalid access (%d) on blk %x: %s",
- access, blkno, RelationGetRelationName(rel));
- break;
+ ItemPointerData iptr;
+
+ if (USELOCKING)
+ {
+ ItemPointerSet(&iptr, blkno, 1);
+
+ switch (access)
+ {
+ case HASH_WRITE:
+ RelationSetSingleWLockPage(rel, &iptr);
+ break;
+ case HASH_READ:
+ RelationSetSingleRLockPage(rel, &iptr);
+ break;
+ default:
+ elog(WARN, "_hash_setpagelock: invalid access (%d) on blk %x: %s",
+ access, blkno, RelationGetRelationName(rel));
+ break;
+ }
}
- }
}
static void
_hash_unsetpagelock(Relation rel,
- BlockNumber blkno,
- int access)
+ BlockNumber blkno,
+ int access)
{
- ItemPointerData iptr;
-
- if (USELOCKING) {
- ItemPointerSet(&iptr, blkno, 1);
-
- switch (access) {
- case HASH_WRITE:
- RelationUnsetSingleWLockPage(rel, &iptr);
- break;
- case HASH_READ:
- RelationUnsetSingleRLockPage(rel, &iptr);
- break;
- default:
- elog(WARN, "_hash_unsetpagelock: invalid access (%d) on blk %x: %s",
- access, blkno, RelationGetRelationName(rel));
- break;
+ ItemPointerData iptr;
+
+ if (USELOCKING)
+ {
+ ItemPointerSet(&iptr, blkno, 1);
+
+ switch (access)
+ {
+ case HASH_WRITE:
+ RelationUnsetSingleWLockPage(rel, &iptr);
+ break;
+ case HASH_READ:
+ RelationUnsetSingleRLockPage(rel, &iptr);
+ break;
+ default:
+ elog(WARN, "_hash_unsetpagelock: invalid access (%d) on blk %x: %s",
+ access, blkno, RelationGetRelationName(rel));
+ break;
+ }
}
- }
}
void
_hash_pagedel(Relation rel, ItemPointer tid)
{
- Buffer buf;
- Buffer metabuf;
- Page page;
- BlockNumber blkno;
- OffsetNumber offno;
- HashMetaPage metap;
- HashPageOpaque opaque;
-
- blkno = ItemPointerGetBlockNumber(tid);
- offno = ItemPointerGetOffsetNumber(tid);
-
- buf = _hash_getbuf(rel, blkno, HASH_WRITE);
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- opaque = (HashPageOpaque) PageGetSpecialPointer(page);
-
- PageIndexTupleDelete(page, offno);
- _hash_wrtnorelbuf(rel, buf);
-
- if (PageIsEmpty(page) && (opaque->hasho_flag & LH_OVERFLOW_PAGE)) {
- buf = _hash_freeovflpage(rel, buf);
- if (BufferIsValid(buf)) {
- _hash_relbuf(rel, buf, HASH_WRITE);
+ Buffer buf;
+ Buffer metabuf;
+ Page page;
+ BlockNumber blkno;
+ OffsetNumber offno;
+ HashMetaPage metap;
+ HashPageOpaque opaque;
+
+ blkno = ItemPointerGetBlockNumber(tid);
+ offno = ItemPointerGetOffsetNumber(tid);
+
+ buf = _hash_getbuf(rel, blkno, HASH_WRITE);
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+
+ PageIndexTupleDelete(page, offno);
+ _hash_wrtnorelbuf(rel, buf);
+
+ if (PageIsEmpty(page) && (opaque->hasho_flag & LH_OVERFLOW_PAGE))
+ {
+ buf = _hash_freeovflpage(rel, buf);
+ if (BufferIsValid(buf))
+ {
+ _hash_relbuf(rel, buf, HASH_WRITE);
+ }
}
- } else {
- _hash_relbuf(rel, buf, HASH_WRITE);
- }
-
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
- ++metap->hashm_nkeys;
- _hash_wrtbuf(rel, metabuf);
+ else
+ {
+ _hash_relbuf(rel, buf, HASH_WRITE);
+ }
+
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE);
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+ ++metap->hashm_nkeys;
+ _hash_wrtbuf(rel, metabuf);
}
void
_hash_expandtable(Relation rel, Buffer metabuf)
{
- HashMetaPage metap;
- Bucket old_bucket;
- Bucket new_bucket;
- uint32 spare_ndx;
-
-/* elog(DEBUG, "_hash_expandtable: expanding..."); */
-
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_READ, HASH_WRITE);
- new_bucket = ++metap->MAX_BUCKET;
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_WRITE, HASH_READ);
- old_bucket = (metap->MAX_BUCKET & metap->LOW_MASK);
-
- /*
- * If the split point is increasing (MAX_BUCKET's log base 2
- * * increases), we need to copy the current contents of the spare
- * split bucket to the next bucket.
- */
- spare_ndx = _hash_log2(metap->MAX_BUCKET + 1);
- if (spare_ndx > metap->OVFL_POINT) {
-
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_READ, HASH_WRITE);
- metap->SPARES[spare_ndx] = metap->SPARES[metap->OVFL_POINT];
- metap->OVFL_POINT = spare_ndx;
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_WRITE, HASH_READ);
- }
-
- if (new_bucket > metap->HIGH_MASK) {
-
- /* Starting a new doubling */
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_READ, HASH_WRITE);
- metap->LOW_MASK = metap->HIGH_MASK;
- metap->HIGH_MASK = new_bucket | metap->LOW_MASK;
- metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_WRITE, HASH_READ);
-
- }
- /* Relocate records to the new bucket */
- _hash_splitpage(rel, metabuf, old_bucket, new_bucket);
+ HashMetaPage metap;
+ Bucket old_bucket;
+ Bucket new_bucket;
+ uint32 spare_ndx;
+
+/* elog(DEBUG, "_hash_expandtable: expanding..."); */
+
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_READ, HASH_WRITE);
+ new_bucket = ++metap->MAX_BUCKET;
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_WRITE, HASH_READ);
+ old_bucket = (metap->MAX_BUCKET & metap->LOW_MASK);
+
+ /*
+ * If the split point is increasing (MAX_BUCKET's log base 2 *
+ * increases), we need to copy the current contents of the spare split
+ * bucket to the next bucket.
+ */
+ spare_ndx = _hash_log2(metap->MAX_BUCKET + 1);
+ if (spare_ndx > metap->OVFL_POINT)
+ {
+
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_READ, HASH_WRITE);
+ metap->SPARES[spare_ndx] = metap->SPARES[metap->OVFL_POINT];
+ metap->OVFL_POINT = spare_ndx;
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_WRITE, HASH_READ);
+ }
+
+ if (new_bucket > metap->HIGH_MASK)
+ {
+
+ /* Starting a new doubling */
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_READ, HASH_WRITE);
+ metap->LOW_MASK = metap->HIGH_MASK;
+ metap->HIGH_MASK = new_bucket | metap->LOW_MASK;
+ metap = (HashMetaPage) _hash_chgbufaccess(rel, &metabuf, HASH_WRITE, HASH_READ);
+
+ }
+ /* Relocate records to the new bucket */
+ _hash_splitpage(rel, metabuf, old_bucket, new_bucket);
}
@@ -450,224 +468,243 @@ _hash_expandtable(Relation rel, Buffer metabuf)
*/
static void
_hash_splitpage(Relation rel,
- Buffer metabuf,
- Bucket obucket,
- Bucket nbucket)
+ Buffer metabuf,
+ Bucket obucket,
+ Bucket nbucket)
{
- Bucket bucket;
- Buffer obuf;
- Buffer nbuf;
- Buffer ovflbuf;
- BlockNumber oblkno;
- BlockNumber nblkno;
- bool null;
- Datum datum;
- HashItem hitem;
- HashPageOpaque oopaque;
- HashPageOpaque nopaque;
- HashMetaPage metap;
- IndexTuple itup;
- int itemsz;
- OffsetNumber ooffnum;
- OffsetNumber noffnum;
- OffsetNumber omaxoffnum;
- Page opage;
- Page npage;
- TupleDesc itupdesc;
-
-/* elog(DEBUG, "_hash_splitpage: splitting %d into %d,%d",
- obucket, obucket, nbucket);
+ Bucket bucket;
+ Buffer obuf;
+ Buffer nbuf;
+ Buffer ovflbuf;
+ BlockNumber oblkno;
+ BlockNumber nblkno;
+ bool null;
+ Datum datum;
+ HashItem hitem;
+ HashPageOpaque oopaque;
+ HashPageOpaque nopaque;
+ HashMetaPage metap;
+ IndexTuple itup;
+ int itemsz;
+ OffsetNumber ooffnum;
+ OffsetNumber noffnum;
+ OffsetNumber omaxoffnum;
+ Page opage;
+ Page npage;
+ TupleDesc itupdesc;
+
+/* elog(DEBUG, "_hash_splitpage: splitting %d into %d,%d",
+ obucket, obucket, nbucket);
*/
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- /* get the buffers & pages */
- oblkno = BUCKET_TO_BLKNO(obucket);
- nblkno = BUCKET_TO_BLKNO(nbucket);
- obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
- nbuf = _hash_getbuf(rel, nblkno, HASH_WRITE);
- opage = BufferGetPage(obuf);
- npage = BufferGetPage(nbuf);
-
- /* initialize the new bucket */
- _hash_pageinit(npage, BufferGetPageSize(nbuf));
- nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
- nopaque->hasho_prevblkno = InvalidBlockNumber;
- nopaque->hasho_nextblkno = InvalidBlockNumber;
- nopaque->hasho_flag = LH_BUCKET_PAGE;
- nopaque->hasho_oaddr = InvalidOvflAddress;
- nopaque->hasho_bucket = nbucket;
- _hash_wrtnorelbuf(rel, nbuf);
-
- /*
- * make sure the old bucket isn't empty. advance 'opage' and
- * friends through the overflow bucket chain until we find a
- * non-empty page.
- *
- * XXX we should only need this once, if we are careful to
- * preserve the invariant that overflow pages are never empty.
- */
- _hash_checkpage(opage, LH_BUCKET_PAGE);
- oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
- if (PageIsEmpty(opage)) {
- oblkno = oopaque->hasho_nextblkno;
- _hash_relbuf(rel, obuf, HASH_WRITE);
- if (!BlockNumberIsValid(oblkno)) {
- /*
- * the old bucket is completely empty; of course, the new
- * bucket will be as well, but since it's a base bucket
- * page we don't care.
- */
- _hash_relbuf(rel, nbuf, HASH_WRITE);
- return;
- }
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ /* get the buffers & pages */
+ oblkno = BUCKET_TO_BLKNO(obucket);
+ nblkno = BUCKET_TO_BLKNO(nbucket);
obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
+ nbuf = _hash_getbuf(rel, nblkno, HASH_WRITE);
opage = BufferGetPage(obuf);
- _hash_checkpage(opage, LH_OVERFLOW_PAGE);
- if (PageIsEmpty(opage)) {
- elog(WARN, "_hash_splitpage: empty overflow page %d", oblkno);
- }
- oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
- }
-
- /*
- * we are now guaranteed that 'opage' is not empty. partition the
- * tuples in the old bucket between the old bucket and the new
- * bucket, advancing along their respective overflow bucket chains
- * and adding overflow pages as needed.
- */
- ooffnum = FirstOffsetNumber;
- omaxoffnum = PageGetMaxOffsetNumber(opage);
- for (;;) {
+ npage = BufferGetPage(nbuf);
+
+ /* initialize the new bucket */
+ _hash_pageinit(npage, BufferGetPageSize(nbuf));
+ nopaque = (HashPageOpaque) PageGetSpecialPointer(npage);
+ nopaque->hasho_prevblkno = InvalidBlockNumber;
+ nopaque->hasho_nextblkno = InvalidBlockNumber;
+ nopaque->hasho_flag = LH_BUCKET_PAGE;
+ nopaque->hasho_oaddr = InvalidOvflAddress;
+ nopaque->hasho_bucket = nbucket;
+ _hash_wrtnorelbuf(rel, nbuf);
+
/*
- * at each iteration through this loop, each of these variables
- * should be up-to-date: obuf opage oopaque ooffnum omaxoffnum
+ * make sure the old bucket isn't empty. advance 'opage' and friends
+ * through the overflow bucket chain until we find a non-empty page.
+ *
+ * XXX we should only need this once, if we are careful to preserve the
+ * invariant that overflow pages are never empty.
*/
+ _hash_checkpage(opage, LH_BUCKET_PAGE);
+ oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+ if (PageIsEmpty(opage))
+ {
+ oblkno = oopaque->hasho_nextblkno;
+ _hash_relbuf(rel, obuf, HASH_WRITE);
+ if (!BlockNumberIsValid(oblkno))
+ {
- /* check if we're at the end of the page */
- if (ooffnum > omaxoffnum) {
- /* at end of page, but check for overflow page */
- oblkno = oopaque->hasho_nextblkno;
- if (BlockNumberIsValid(oblkno)) {
- /*
- * we ran out of tuples on this particular page, but
- * we have more overflow pages; re-init values.
- */
- _hash_wrtbuf(rel, obuf);
+ /*
+ * the old bucket is completely empty; of course, the new
+ * bucket will be as well, but since it's a base bucket page
+ * we don't care.
+ */
+ _hash_relbuf(rel, nbuf, HASH_WRITE);
+ return;
+ }
obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
opage = BufferGetPage(obuf);
_hash_checkpage(opage, LH_OVERFLOW_PAGE);
- oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
-
- /* we're guaranteed that an ovfl page has at least 1 tuple */
- if (PageIsEmpty(opage)) {
- elog(WARN, "_hash_splitpage: empty ovfl page %d!",
- oblkno);
+ if (PageIsEmpty(opage))
+ {
+ elog(WARN, "_hash_splitpage: empty overflow page %d", oblkno);
}
- ooffnum = FirstOffsetNumber;
- omaxoffnum = PageGetMaxOffsetNumber(opage);
- } else {
+ oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+ }
+
+ /*
+ * we are now guaranteed that 'opage' is not empty. partition the
+ * tuples in the old bucket between the old bucket and the new bucket,
+ * advancing along their respective overflow bucket chains and adding
+ * overflow pages as needed.
+ */
+ ooffnum = FirstOffsetNumber;
+ omaxoffnum = PageGetMaxOffsetNumber(opage);
+ for (;;)
+ {
+
/*
- * we're at the end of the bucket chain, so now we're
- * really done with everything. before quitting, call
- * _hash_squeezebucket to ensure the tuples in the
- * bucket (including the overflow pages) are packed as
- * tightly as possible.
+ * at each iteration through this loop, each of these variables
+ * should be up-to-date: obuf opage oopaque ooffnum omaxoffnum
*/
- _hash_wrtbuf(rel, obuf);
- _hash_wrtbuf(rel, nbuf);
- _hash_squeezebucket(rel, metap, obucket);
- return;
- }
- }
-
- /* hash on the tuple */
- hitem = (HashItem) PageGetItem(opage, PageGetItemId(opage, ooffnum));
- itup = &(hitem->hash_itup);
- itupdesc = RelationGetTupleDescriptor(rel);
- datum = index_getattr(itup, 1, itupdesc, &null);
- bucket = _hash_call(rel, metap, datum);
-
- if (bucket == nbucket) {
- /*
- * insert the tuple into the new bucket. if it doesn't
- * fit on the current page in the new bucket, we must
- * allocate a new overflow page and place the tuple on
- * that page instead.
- */
- itemsz = IndexTupleDSize(hitem->hash_itup)
- + (sizeof(HashItemData) - sizeof(IndexTupleData));
-
- itemsz = DOUBLEALIGN(itemsz);
-
- if (PageGetFreeSpace(npage) < itemsz) {
- ovflbuf = _hash_addovflpage(rel, &metabuf, nbuf);
- _hash_wrtbuf(rel, nbuf);
- nbuf = ovflbuf;
- npage = BufferGetPage(nbuf);
- _hash_checkpage(npage, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- }
-
- noffnum = OffsetNumberNext(PageGetMaxOffsetNumber(npage));
- PageAddItem(npage, (Item) hitem, itemsz, noffnum, LP_USED);
- _hash_wrtnorelbuf(rel, nbuf);
-
- /*
- * now delete the tuple from the old bucket. after this
- * section of code, 'ooffnum' will actually point to the
- * ItemId to which we would point if we had advanced it
- * before the deletion (PageIndexTupleDelete repacks the
- * ItemId array). this also means that 'omaxoffnum' is
- * exactly one less than it used to be, so we really can
- * just decrement it instead of calling
- * PageGetMaxOffsetNumber.
- */
- PageIndexTupleDelete(opage, ooffnum);
- _hash_wrtnorelbuf(rel, obuf);
- omaxoffnum = OffsetNumberPrev(omaxoffnum);
-
- /*
- * tidy up. if the old page was an overflow page and it
- * is now empty, we must free it (we want to preserve the
- * invariant that overflow pages cannot be empty).
- */
- if (PageIsEmpty(opage) &&
- (oopaque->hasho_flag & LH_OVERFLOW_PAGE)) {
- obuf = _hash_freeovflpage(rel, obuf);
-
- /* check that we're not through the bucket chain */
- if (BufferIsInvalid(obuf)) {
- _hash_wrtbuf(rel, nbuf);
- _hash_squeezebucket(rel, metap, obucket);
- return;
+
+ /* check if we're at the end of the page */
+ if (ooffnum > omaxoffnum)
+ {
+ /* at end of page, but check for overflow page */
+ oblkno = oopaque->hasho_nextblkno;
+ if (BlockNumberIsValid(oblkno))
+ {
+
+ /*
+ * we ran out of tuples on this particular page, but we
+ * have more overflow pages; re-init values.
+ */
+ _hash_wrtbuf(rel, obuf);
+ obuf = _hash_getbuf(rel, oblkno, HASH_WRITE);
+ opage = BufferGetPage(obuf);
+ _hash_checkpage(opage, LH_OVERFLOW_PAGE);
+ oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+
+ /* we're guaranteed that an ovfl page has at least 1 tuple */
+ if (PageIsEmpty(opage))
+ {
+ elog(WARN, "_hash_splitpage: empty ovfl page %d!",
+ oblkno);
+ }
+ ooffnum = FirstOffsetNumber;
+ omaxoffnum = PageGetMaxOffsetNumber(opage);
+ }
+ else
+ {
+
+ /*
+ * we're at the end of the bucket chain, so now we're
+ * really done with everything. before quitting, call
+ * _hash_squeezebucket to ensure the tuples in the bucket
+ * (including the overflow pages) are packed as tightly as
+ * possible.
+ */
+ _hash_wrtbuf(rel, obuf);
+ _hash_wrtbuf(rel, nbuf);
+ _hash_squeezebucket(rel, metap, obucket);
+ return;
+ }
}
-
- /*
- * re-init. again, we're guaranteed that an ovfl page
- * has at least one tuple.
- */
- opage = BufferGetPage(obuf);
- _hash_checkpage(opage, LH_OVERFLOW_PAGE);
- oblkno = BufferGetBlockNumber(obuf);
- oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
- if (PageIsEmpty(opage)) {
- elog(WARN, "_hash_splitpage: empty overflow page %d",
- oblkno);
+
+ /* hash on the tuple */
+ hitem = (HashItem) PageGetItem(opage, PageGetItemId(opage, ooffnum));
+ itup = &(hitem->hash_itup);
+ itupdesc = RelationGetTupleDescriptor(rel);
+ datum = index_getattr(itup, 1, itupdesc, &null);
+ bucket = _hash_call(rel, metap, datum);
+
+ if (bucket == nbucket)
+ {
+
+ /*
+ * insert the tuple into the new bucket. if it doesn't fit on
+ * the current page in the new bucket, we must allocate a new
+ * overflow page and place the tuple on that page instead.
+ */
+ itemsz = IndexTupleDSize(hitem->hash_itup)
+ + (sizeof(HashItemData) - sizeof(IndexTupleData));
+
+ itemsz = DOUBLEALIGN(itemsz);
+
+ if (PageGetFreeSpace(npage) < itemsz)
+ {
+ ovflbuf = _hash_addovflpage(rel, &metabuf, nbuf);
+ _hash_wrtbuf(rel, nbuf);
+ nbuf = ovflbuf;
+ npage = BufferGetPage(nbuf);
+ _hash_checkpage(npage, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ }
+
+ noffnum = OffsetNumberNext(PageGetMaxOffsetNumber(npage));
+ PageAddItem(npage, (Item) hitem, itemsz, noffnum, LP_USED);
+ _hash_wrtnorelbuf(rel, nbuf);
+
+ /*
+ * now delete the tuple from the old bucket. after this
+ * section of code, 'ooffnum' will actually point to the
+ * ItemId to which we would point if we had advanced it before
+ * the deletion (PageIndexTupleDelete repacks the ItemId
+ * array). this also means that 'omaxoffnum' is exactly one
+ * less than it used to be, so we really can just decrement it
+ * instead of calling PageGetMaxOffsetNumber.
+ */
+ PageIndexTupleDelete(opage, ooffnum);
+ _hash_wrtnorelbuf(rel, obuf);
+ omaxoffnum = OffsetNumberPrev(omaxoffnum);
+
+ /*
+ * tidy up. if the old page was an overflow page and it is
+ * now empty, we must free it (we want to preserve the
+ * invariant that overflow pages cannot be empty).
+ */
+ if (PageIsEmpty(opage) &&
+ (oopaque->hasho_flag & LH_OVERFLOW_PAGE))
+ {
+ obuf = _hash_freeovflpage(rel, obuf);
+
+ /* check that we're not through the bucket chain */
+ if (BufferIsInvalid(obuf))
+ {
+ _hash_wrtbuf(rel, nbuf);
+ _hash_squeezebucket(rel, metap, obucket);
+ return;
+ }
+
+ /*
+ * re-init. again, we're guaranteed that an ovfl page has
+ * at least one tuple.
+ */
+ opage = BufferGetPage(obuf);
+ _hash_checkpage(opage, LH_OVERFLOW_PAGE);
+ oblkno = BufferGetBlockNumber(obuf);
+ oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
+ if (PageIsEmpty(opage))
+ {
+ elog(WARN, "_hash_splitpage: empty overflow page %d",
+ oblkno);
+ }
+ ooffnum = FirstOffsetNumber;
+ omaxoffnum = PageGetMaxOffsetNumber(opage);
+ }
+ }
+ else
+ {
+
+ /*
+ * the tuple stays on this page. we didn't move anything, so
+ * we didn't delete anything and therefore we don't have to
+ * change 'omaxoffnum'.
+ *
+ * XXX any hash value from [0, nbucket-1] will map to this
+ * bucket, which doesn't make sense to me.
+ */
+ ooffnum = OffsetNumberNext(ooffnum);
}
- ooffnum = FirstOffsetNumber;
- omaxoffnum = PageGetMaxOffsetNumber(opage);
- }
- } else {
- /*
- * the tuple stays on this page. we didn't move anything,
- * so we didn't delete anything and therefore we don't
- * have to change 'omaxoffnum'.
- *
- * XXX any hash value from [0, nbucket-1] will map to this
- * bucket, which doesn't make sense to me.
- */
- ooffnum = OffsetNumberNext(ooffnum);
}
- }
- /*NOTREACHED*/
+ /* NOTREACHED */
}
diff --git a/src/backend/access/hash/hashscan.c b/src/backend/access/hash/hashscan.c
index bd776d68c0d..79fa33f747c 100644
--- a/src/backend/access/hash/hashscan.c
+++ b/src/backend/access/hash/hashscan.c
@@ -1,160 +1,167 @@
/*-------------------------------------------------------------------------
*
* hashscan.c--
- * manage scans on hash tables
+ * manage scans on hash tables
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.8 1996/11/15 18:36:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.9 1997/09/07 04:38:01 momjian Exp $
*
* NOTES
- * Because we can be doing an index scan on a relation while we
- * update it, we need to avoid missing data that moves around in
- * the index. The routines and global variables in this file
- * guarantee that all scans in the local address space stay
- * correctly positioned. This is all we need to worry about, since
- * write locking guarantees that no one else will be on the same
- * page at the same time as we are.
+ * Because we can be doing an index scan on a relation while we
+ * update it, we need to avoid missing data that moves around in
+ * the index. The routines and global variables in this file
+ * guarantee that all scans in the local address space stay
+ * correctly positioned. This is all we need to worry about, since
+ * write locking guarantees that no one else will be on the same
+ * page at the same time as we are.
*
- * The scheme is to manage a list of active scans in the current
- * backend. Whenever we add or remove records from an index, we
- * check the list of active scans to see if any has been affected.
- * A scan is affected only if it is on the same relation, and the
- * same page, as the update.
+ * The scheme is to manage a list of active scans in the current
+ * backend. Whenever we add or remove records from an index, we
+ * check the list of active scans to see if any has been affected.
+ * A scan is affected only if it is on the same relation, and the
+ * same page, as the update.
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/hash.h>
-static void _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
-static bool _hash_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
+static void _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
+static bool _hash_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
-typedef struct HashScanListData {
- IndexScanDesc hashsl_scan;
- struct HashScanListData *hashsl_next;
-} HashScanListData;
+typedef struct HashScanListData
+{
+ IndexScanDesc hashsl_scan;
+ struct HashScanListData *hashsl_next;
+} HashScanListData;
-typedef HashScanListData *HashScanList;
+typedef HashScanListData *HashScanList;
-static HashScanList HashScans = (HashScanList) NULL;
+static HashScanList HashScans = (HashScanList) NULL;
/*
- * _Hash_regscan() -- register a new scan.
+ * _Hash_regscan() -- register a new scan.
*/
void
_hash_regscan(IndexScanDesc scan)
{
- HashScanList new_el;
-
- new_el = (HashScanList) palloc(sizeof(HashScanListData));
- new_el->hashsl_scan = scan;
- new_el->hashsl_next = HashScans;
- HashScans = new_el;
+ HashScanList new_el;
+
+ new_el = (HashScanList) palloc(sizeof(HashScanListData));
+ new_el->hashsl_scan = scan;
+ new_el->hashsl_next = HashScans;
+ HashScans = new_el;
}
/*
- * _hash_dropscan() -- drop a scan from the scan list
+ * _hash_dropscan() -- drop a scan from the scan list
*/
void
_hash_dropscan(IndexScanDesc scan)
{
- HashScanList chk, last;
-
- last = (HashScanList) NULL;
- for (chk = HashScans;
- chk != (HashScanList) NULL && chk->hashsl_scan != scan;
- chk = chk->hashsl_next) {
- last = chk;
- }
-
- if (chk == (HashScanList) NULL)
- elog(WARN, "hash scan list trashed; can't find 0x%lx", scan);
-
- if (last == (HashScanList) NULL)
- HashScans = chk->hashsl_next;
- else
- last->hashsl_next = chk->hashsl_next;
-
- pfree (chk);
+ HashScanList chk,
+ last;
+
+ last = (HashScanList) NULL;
+ for (chk = HashScans;
+ chk != (HashScanList) NULL && chk->hashsl_scan != scan;
+ chk = chk->hashsl_next)
+ {
+ last = chk;
+ }
+
+ if (chk == (HashScanList) NULL)
+ elog(WARN, "hash scan list trashed; can't find 0x%lx", scan);
+
+ if (last == (HashScanList) NULL)
+ HashScans = chk->hashsl_next;
+ else
+ last->hashsl_next = chk->hashsl_next;
+
+ pfree(chk);
}
void
_hash_adjscans(Relation rel, ItemPointer tid)
{
- HashScanList l;
- Oid relid;
-
- relid = rel->rd_id;
- for (l = HashScans; l != (HashScanList) NULL; l = l->hashsl_next) {
- if (relid == l->hashsl_scan->relation->rd_id)
- _hash_scandel(l->hashsl_scan, ItemPointerGetBlockNumber(tid),
- ItemPointerGetOffsetNumber(tid));
- }
+ HashScanList l;
+ Oid relid;
+
+ relid = rel->rd_id;
+ for (l = HashScans; l != (HashScanList) NULL; l = l->hashsl_next)
+ {
+ if (relid == l->hashsl_scan->relation->rd_id)
+ _hash_scandel(l->hashsl_scan, ItemPointerGetBlockNumber(tid),
+ ItemPointerGetOffsetNumber(tid));
+ }
}
static void
_hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
{
- ItemPointer current;
- Buffer buf;
- Buffer metabuf;
- HashScanOpaque so;
-
- if (!_hash_scantouched(scan, blkno, offno))
- return;
-
- metabuf = _hash_getbuf(scan->relation, HASH_METAPAGE, HASH_READ);
-
- so = (HashScanOpaque) scan->opaque;
- buf = so->hashso_curbuf;
-
- current = &(scan->currentItemData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno) {
- _hash_step(scan, &buf, BackwardScanDirection, metabuf);
- so->hashso_curbuf = buf;
- }
-
- current = &(scan->currentMarkData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno) {
- ItemPointerData tmp;
- tmp = *current;
- *current = scan->currentItemData;
- scan->currentItemData = tmp;
- _hash_step(scan, &buf, BackwardScanDirection, metabuf);
- so->hashso_mrkbuf = buf;
- tmp = *current;
- *current = scan->currentItemData;
- scan->currentItemData = tmp;
- }
+ ItemPointer current;
+ Buffer buf;
+ Buffer metabuf;
+ HashScanOpaque so;
+
+ if (!_hash_scantouched(scan, blkno, offno))
+ return;
+
+ metabuf = _hash_getbuf(scan->relation, HASH_METAPAGE, HASH_READ);
+
+ so = (HashScanOpaque) scan->opaque;
+ buf = so->hashso_curbuf;
+
+ current = &(scan->currentItemData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ {
+ _hash_step(scan, &buf, BackwardScanDirection, metabuf);
+ so->hashso_curbuf = buf;
+ }
+
+ current = &(scan->currentMarkData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ {
+ ItemPointerData tmp;
+
+ tmp = *current;
+ *current = scan->currentItemData;
+ scan->currentItemData = tmp;
+ _hash_step(scan, &buf, BackwardScanDirection, metabuf);
+ so->hashso_mrkbuf = buf;
+ tmp = *current;
+ *current = scan->currentItemData;
+ scan->currentItemData = tmp;
+ }
}
-static bool
+static bool
_hash_scantouched(IndexScanDesc scan,
- BlockNumber blkno,
- OffsetNumber offno)
+ BlockNumber blkno,
+ OffsetNumber offno)
{
- ItemPointer current;
-
- current = &(scan->currentItemData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno)
- return (true);
-
- current = &(scan->currentMarkData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno)
- return (true);
-
- return (false);
+ ItemPointer current;
+
+ current = &(scan->currentItemData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ return (true);
+
+ current = &(scan->currentMarkData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ return (true);
+
+ return (false);
}
diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c
index bc67b7f5aac..0a42ad05065 100644
--- a/src/backend/access/hash/hashsearch.c
+++ b/src/backend/access/hash/hashsearch.c
@@ -1,423 +1,467 @@
/*-------------------------------------------------------------------------
*
* hashsearch.c--
- * search code for postgres hash tables
+ * search code for postgres hash tables
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.10 1997/06/28 05:45:40 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.11 1997/09/07 04:38:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/hash.h>
#include <storage/bufmgr.h>
#ifndef HAVE_MEMMOVE
-# include "regex/utils.h"
+#include "regex/utils.h"
#else
-# include <string.h>
-#endif
+#include <string.h>
+#endif
/*
- * _hash_search() -- Finds the page/bucket that the contains the
- * scankey and loads it into *bufP. the buffer has a read lock.
+ * _hash_search() -- Finds the page/bucket that the contains the
+ * scankey and loads it into *bufP. the buffer has a read lock.
*/
void
_hash_search(Relation rel,
- int keysz,
- ScanKey scankey,
- Buffer *bufP,
- HashMetaPage metap)
+ int keysz,
+ ScanKey scankey,
+ Buffer * bufP,
+ HashMetaPage metap)
{
- BlockNumber blkno;
- Datum keyDatum;
- Bucket bucket;
-
- if (scankey == (ScanKey) NULL ||
- (keyDatum = scankey[0].sk_argument) == (Datum) NULL) {
- /*
- * If the scankey argument is NULL, all tuples will satisfy
- * the scan so we start the scan at the first bucket (bucket
- * 0).
- */
- bucket = 0;
- } else {
- bucket = _hash_call(rel, metap, keyDatum);
- }
-
- blkno = BUCKET_TO_BLKNO(bucket);
-
- *bufP = _hash_getbuf(rel, blkno, HASH_READ);
+ BlockNumber blkno;
+ Datum keyDatum;
+ Bucket bucket;
+
+ if (scankey == (ScanKey) NULL ||
+ (keyDatum = scankey[0].sk_argument) == (Datum) NULL)
+ {
+
+ /*
+ * If the scankey argument is NULL, all tuples will satisfy the
+ * scan so we start the scan at the first bucket (bucket 0).
+ */
+ bucket = 0;
+ }
+ else
+ {
+ bucket = _hash_call(rel, metap, keyDatum);
+ }
+
+ blkno = BUCKET_TO_BLKNO(bucket);
+
+ *bufP = _hash_getbuf(rel, blkno, HASH_READ);
}
/*
- * _hash_next() -- Get the next item in a scan.
+ * _hash_next() -- Get the next item in a scan.
*
- * On entry, we have a valid currentItemData in the scan, and a
- * read lock on the page that contains that item. We do not have
- * the page pinned. We return the next item in the scan. On
- * exit, we have the page containing the next item locked but not
- * pinned.
+ * On entry, we have a valid currentItemData in the scan, and a
+ * read lock on the page that contains that item. We do not have
+ * the page pinned. We return the next item in the scan. On
+ * exit, we have the page containing the next item locked but not
+ * pinned.
*/
RetrieveIndexResult
_hash_next(IndexScanDesc scan, ScanDirection dir)
{
- Relation rel;
- Buffer buf;
- Buffer metabuf;
- Page page;
- OffsetNumber offnum;
- RetrieveIndexResult res;
- ItemPointer current;
- HashItem hitem;
- IndexTuple itup;
- HashScanOpaque so;
-
- rel = scan->relation;
- so = (HashScanOpaque) scan->opaque;
- current = &(scan->currentItemData);
-
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
-
- /*
- * XXX 10 may 91: somewhere there's a bug in our management of the
- * cached buffer for this scan. wei discovered it. the following
- * is a workaround so he can work until i figure out what's going on.
- */
-
- if (!BufferIsValid(so->hashso_curbuf)) {
- so->hashso_curbuf = _hash_getbuf(rel,
- ItemPointerGetBlockNumber(current),
- HASH_READ);
- }
-
- /* we still have the buffer pinned and locked */
- buf = so->hashso_curbuf;
-
- /*
- * step to next valid tuple. note that _hash_step releases our
- * lock on 'metabuf'; if we switch to a new 'buf' while looking
- * for the next tuple, we come back with a lock on that buffer.
- */
- if (!_hash_step(scan, &buf, dir, metabuf)) {
- return ((RetrieveIndexResult) NULL);
- }
-
- /* if we're here, _hash_step found a valid tuple */
- current = &(scan->currentItemData);
- offnum = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &hitem->hash_itup;
- res = FormRetrieveIndexResult(current, &(itup->t_tid));
-
- return (res);
+ Relation rel;
+ Buffer buf;
+ Buffer metabuf;
+ Page page;
+ OffsetNumber offnum;
+ RetrieveIndexResult res;
+ ItemPointer current;
+ HashItem hitem;
+ IndexTuple itup;
+ HashScanOpaque so;
+
+ rel = scan->relation;
+ so = (HashScanOpaque) scan->opaque;
+ current = &(scan->currentItemData);
+
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
+
+ /*
+ * XXX 10 may 91: somewhere there's a bug in our management of the
+ * cached buffer for this scan. wei discovered it. the following is
+ * a workaround so he can work until i figure out what's going on.
+ */
+
+ if (!BufferIsValid(so->hashso_curbuf))
+ {
+ so->hashso_curbuf = _hash_getbuf(rel,
+ ItemPointerGetBlockNumber(current),
+ HASH_READ);
+ }
+
+ /* we still have the buffer pinned and locked */
+ buf = so->hashso_curbuf;
+
+ /*
+ * step to next valid tuple. note that _hash_step releases our lock
+ * on 'metabuf'; if we switch to a new 'buf' while looking for the
+ * next tuple, we come back with a lock on that buffer.
+ */
+ if (!_hash_step(scan, &buf, dir, metabuf))
+ {
+ return ((RetrieveIndexResult) NULL);
+ }
+
+ /* if we're here, _hash_step found a valid tuple */
+ current = &(scan->currentItemData);
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &hitem->hash_itup;
+ res = FormRetrieveIndexResult(current, &(itup->t_tid));
+
+ return (res);
}
static void
_hash_readnext(Relation rel,
- Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
+ Buffer * bufp, Page * pagep, HashPageOpaque * opaquep)
{
- BlockNumber blkno;
-
- blkno = (*opaquep)->hasho_nextblkno;
- _hash_relbuf(rel, *bufp, HASH_READ);
- *bufp = InvalidBuffer;
- if (BlockNumberIsValid(blkno)) {
- *bufp = _hash_getbuf(rel, blkno, HASH_READ);
- *pagep = BufferGetPage(*bufp);
- _hash_checkpage(*pagep, LH_OVERFLOW_PAGE);
- *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
- Assert(!PageIsEmpty(*pagep));
- }
+ BlockNumber blkno;
+
+ blkno = (*opaquep)->hasho_nextblkno;
+ _hash_relbuf(rel, *bufp, HASH_READ);
+ *bufp = InvalidBuffer;
+ if (BlockNumberIsValid(blkno))
+ {
+ *bufp = _hash_getbuf(rel, blkno, HASH_READ);
+ *pagep = BufferGetPage(*bufp);
+ _hash_checkpage(*pagep, LH_OVERFLOW_PAGE);
+ *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
+ Assert(!PageIsEmpty(*pagep));
+ }
}
static void
_hash_readprev(Relation rel,
- Buffer *bufp, Page *pagep, HashPageOpaque *opaquep)
+ Buffer * bufp, Page * pagep, HashPageOpaque * opaquep)
{
- BlockNumber blkno;
-
- blkno = (*opaquep)->hasho_prevblkno;
- _hash_relbuf(rel, *bufp, HASH_READ);
- *bufp = InvalidBuffer;
- if (BlockNumberIsValid(blkno)) {
- *bufp = _hash_getbuf(rel, blkno, HASH_READ);
- *pagep = BufferGetPage(*bufp);
- _hash_checkpage(*pagep, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
- if (PageIsEmpty(*pagep)) {
- Assert((*opaquep)->hasho_flag & LH_BUCKET_PAGE);
- _hash_relbuf(rel, *bufp, HASH_READ);
- *bufp = InvalidBuffer;
+ BlockNumber blkno;
+
+ blkno = (*opaquep)->hasho_prevblkno;
+ _hash_relbuf(rel, *bufp, HASH_READ);
+ *bufp = InvalidBuffer;
+ if (BlockNumberIsValid(blkno))
+ {
+ *bufp = _hash_getbuf(rel, blkno, HASH_READ);
+ *pagep = BufferGetPage(*bufp);
+ _hash_checkpage(*pagep, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ *opaquep = (HashPageOpaque) PageGetSpecialPointer(*pagep);
+ if (PageIsEmpty(*pagep))
+ {
+ Assert((*opaquep)->hasho_flag & LH_BUCKET_PAGE);
+ _hash_relbuf(rel, *bufp, HASH_READ);
+ *bufp = InvalidBuffer;
+ }
}
- }
}
/*
- * _hash_first() -- Find the first item in a scan.
+ * _hash_first() -- Find the first item in a scan.
*
- * Return the RetrieveIndexResult of the first item in the tree that
- * satisfies the qualificatin associated with the scan descriptor. On
- * exit, the page containing the current index tuple is read locked
- * and pinned, and the scan's opaque data entry is updated to
- * include the buffer.
+ * Return the RetrieveIndexResult of the first item in the tree that
+ * satisfies the qualificatin associated with the scan descriptor. On
+ * exit, the page containing the current index tuple is read locked
+ * and pinned, and the scan's opaque data entry is updated to
+ * include the buffer.
*/
RetrieveIndexResult
_hash_first(IndexScanDesc scan, ScanDirection dir)
{
- Relation rel;
- Buffer buf;
- Buffer metabuf;
- Page page;
- HashPageOpaque opaque;
- HashMetaPage metap;
- HashItem hitem;
- IndexTuple itup;
- ItemPointer current;
- OffsetNumber offnum;
- RetrieveIndexResult res;
- HashScanOpaque so;
-
- rel = scan->relation;
- so = (HashScanOpaque) scan->opaque;
- current = &(scan->currentItemData);
-
- metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- /*
- * XXX -- The attribute number stored in the scan key is the attno
- * in the heap relation. We need to transmogrify this into
- * the index relation attno here. For the moment, we have
- * hardwired attno == 1.
- */
-
- /* find the correct bucket page and load it into buf */
- _hash_search(rel, 1, scan->keyData, &buf, metap);
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE);
- opaque = (HashPageOpaque) PageGetSpecialPointer(page);
-
- /*
- * if we are scanning forward, we need to find the first non-empty
- * page (if any) in the bucket chain. since overflow pages are
- * never empty, this had better be either the bucket page or the
- * first overflow page.
- *
- * if we are scanning backward, we always go all the way to the
- * end of the bucket chain.
- */
- if (PageIsEmpty(page)) {
- if (BlockNumberIsValid(opaque->hasho_nextblkno)) {
- _hash_readnext(rel, &buf, &page, &opaque);
- } else {
- ItemPointerSetInvalid(current);
- so->hashso_curbuf = InvalidBuffer;
- /*
- * If there is no scankeys, all tuples will satisfy
- * the scan - so we continue in _hash_step to get
- * tuples from all buckets. - vadim 04/29/97
- */
- if ( scan->numberOfKeys >= 1 )
- {
- _hash_relbuf(rel, buf, HASH_READ);
- _hash_relbuf(rel, metabuf, HASH_READ);
- return ((RetrieveIndexResult) NULL);
- }
+ Relation rel;
+ Buffer buf;
+ Buffer metabuf;
+ Page page;
+ HashPageOpaque opaque;
+ HashMetaPage metap;
+ HashItem hitem;
+ IndexTuple itup;
+ ItemPointer current;
+ OffsetNumber offnum;
+ RetrieveIndexResult res;
+ HashScanOpaque so;
+
+ rel = scan->relation;
+ so = (HashScanOpaque) scan->opaque;
+ current = &(scan->currentItemData);
+
+ metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ /*
+ * XXX -- The attribute number stored in the scan key is the attno in
+ * the heap relation. We need to transmogrify this into the index
+ * relation attno here. For the moment, we have hardwired attno == 1.
+ */
+
+ /* find the correct bucket page and load it into buf */
+ _hash_search(rel, 1, scan->keyData, &buf, metap);
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE);
+ opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+
+ /*
+ * if we are scanning forward, we need to find the first non-empty
+ * page (if any) in the bucket chain. since overflow pages are never
+ * empty, this had better be either the bucket page or the first
+ * overflow page.
+ *
+ * if we are scanning backward, we always go all the way to the end of
+ * the bucket chain.
+ */
+ if (PageIsEmpty(page))
+ {
+ if (BlockNumberIsValid(opaque->hasho_nextblkno))
+ {
+ _hash_readnext(rel, &buf, &page, &opaque);
+ }
+ else
+ {
+ ItemPointerSetInvalid(current);
+ so->hashso_curbuf = InvalidBuffer;
+
+ /*
+ * If there is no scankeys, all tuples will satisfy the scan -
+ * so we continue in _hash_step to get tuples from all
+ * buckets. - vadim 04/29/97
+ */
+ if (scan->numberOfKeys >= 1)
+ {
+ _hash_relbuf(rel, buf, HASH_READ);
+ _hash_relbuf(rel, metabuf, HASH_READ);
+ return ((RetrieveIndexResult) NULL);
+ }
+ }
}
- }
- if (ScanDirectionIsBackward(dir)) {
- while (BlockNumberIsValid(opaque->hasho_nextblkno)) {
- _hash_readnext(rel, &buf, &page, &opaque);
+ if (ScanDirectionIsBackward(dir))
+ {
+ while (BlockNumberIsValid(opaque->hasho_nextblkno))
+ {
+ _hash_readnext(rel, &buf, &page, &opaque);
+ }
+ }
+
+ if (!_hash_step(scan, &buf, dir, metabuf))
+ {
+ return ((RetrieveIndexResult) NULL);
}
- }
-
- if (!_hash_step(scan, &buf, dir, metabuf)) {
- return ((RetrieveIndexResult) NULL);
- }
-
- /* if we're here, _hash_step found a valid tuple */
- current = &(scan->currentItemData);
- offnum = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &hitem->hash_itup;
- res = FormRetrieveIndexResult(current, &(itup->t_tid));
-
- return (res);
+
+ /* if we're here, _hash_step found a valid tuple */
+ current = &(scan->currentItemData);
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &hitem->hash_itup;
+ res = FormRetrieveIndexResult(current, &(itup->t_tid));
+
+ return (res);
}
/*
- * _hash_step() -- step to the next valid item in a scan in the bucket.
+ * _hash_step() -- step to the next valid item in a scan in the bucket.
*
- * If no valid record exists in the requested direction, return
- * false. Else, return true and set the CurrentItemData for the
- * scan to the right thing.
- *
- * 'bufP' points to the buffer which contains the current page
- * that we'll step through.
+ * If no valid record exists in the requested direction, return
+ * false. Else, return true and set the CurrentItemData for the
+ * scan to the right thing.
*
- * 'metabuf' is released when this returns.
+ * 'bufP' points to the buffer which contains the current page
+ * that we'll step through.
+ *
+ * 'metabuf' is released when this returns.
*/
bool
-_hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir, Buffer metabuf)
+_hash_step(IndexScanDesc scan, Buffer * bufP, ScanDirection dir, Buffer metabuf)
{
- Relation rel;
- ItemPointer current;
- HashScanOpaque so;
- int allbuckets;
- HashMetaPage metap;
- Buffer buf;
- Page page;
- HashPageOpaque opaque;
- OffsetNumber maxoff;
- OffsetNumber offnum;
- Bucket bucket;
- BlockNumber blkno;
- HashItem hitem;
- IndexTuple itup;
-
- rel = scan->relation;
- current = &(scan->currentItemData);
- so = (HashScanOpaque) scan->opaque;
- allbuckets = (scan->numberOfKeys < 1);
-
- metap = (HashMetaPage) BufferGetPage(metabuf);
- _hash_checkpage((Page) metap, LH_META_PAGE);
-
- buf = *bufP;
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE|LH_OVERFLOW_PAGE);
- opaque = (HashPageOpaque) PageGetSpecialPointer(page);
-
- /*
- * If _hash_step is called from _hash_first, current will not be
- * valid, so we can't dereference it. However, in that case, we
- * presumably want to start at the beginning/end of the page...
- */
- maxoff = PageGetMaxOffsetNumber(page);
- if (ItemPointerIsValid(current)) {
- offnum = ItemPointerGetOffsetNumber(current);
- } else {
- offnum = InvalidOffsetNumber;
- }
-
- /*
- * 'offnum' now points to the last tuple we have seen (if any).
- *
- * continue to step through tuples until:
- * 1) we get to the end of the bucket chain or
- * 2) we find a valid tuple.
- */
- do {
- bucket = opaque->hasho_bucket;
-
- switch (dir) {
- case ForwardScanDirection:
- if (offnum != InvalidOffsetNumber) {
- offnum = OffsetNumberNext(offnum); /* move forward */
- } else {
- offnum = FirstOffsetNumber; /* new page */
- }
- while (offnum > maxoff) {
- /*
- * either this page is empty (maxoff ==
- * InvalidOffsetNumber) or we ran off the end.
- */
- _hash_readnext(rel, &buf, &page, &opaque);
- if (BufferIsInvalid(buf)) { /* end of chain */
- if (allbuckets && bucket < metap->hashm_maxbucket) {
- ++bucket;
- blkno = BUCKET_TO_BLKNO(bucket);
- buf = _hash_getbuf(rel, blkno, HASH_READ);
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE);
- opaque = (HashPageOpaque) PageGetSpecialPointer(page);
- Assert(opaque->hasho_bucket == bucket);
- while (PageIsEmpty(page) &&
- BlockNumberIsValid(opaque->hasho_nextblkno)) {
- _hash_readnext(rel, &buf, &page, &opaque);
+ Relation rel;
+ ItemPointer current;
+ HashScanOpaque so;
+ int allbuckets;
+ HashMetaPage metap;
+ Buffer buf;
+ Page page;
+ HashPageOpaque opaque;
+ OffsetNumber maxoff;
+ OffsetNumber offnum;
+ Bucket bucket;
+ BlockNumber blkno;
+ HashItem hitem;
+ IndexTuple itup;
+
+ rel = scan->relation;
+ current = &(scan->currentItemData);
+ so = (HashScanOpaque) scan->opaque;
+ allbuckets = (scan->numberOfKeys < 1);
+
+ metap = (HashMetaPage) BufferGetPage(metabuf);
+ _hash_checkpage((Page) metap, LH_META_PAGE);
+
+ buf = *bufP;
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
+ opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+
+ /*
+ * If _hash_step is called from _hash_first, current will not be
+ * valid, so we can't dereference it. However, in that case, we
+ * presumably want to start at the beginning/end of the page...
+ */
+ maxoff = PageGetMaxOffsetNumber(page);
+ if (ItemPointerIsValid(current))
+ {
+ offnum = ItemPointerGetOffsetNumber(current);
+ }
+ else
+ {
+ offnum = InvalidOffsetNumber;
+ }
+
+ /*
+ * 'offnum' now points to the last tuple we have seen (if any).
+ *
+ * continue to step through tuples until: 1) we get to the end of the
+ * bucket chain or 2) we find a valid tuple.
+ */
+ do
+ {
+ bucket = opaque->hasho_bucket;
+
+ switch (dir)
+ {
+ case ForwardScanDirection:
+ if (offnum != InvalidOffsetNumber)
+ {
+ offnum = OffsetNumberNext(offnum); /* move forward */
}
- maxoff = PageGetMaxOffsetNumber(page);
- offnum = FirstOffsetNumber;
- } else {
- maxoff = offnum = InvalidOffsetNumber;
- break; /* while */
- }
- } else {
- /* _hash_readnext never returns an empty page */
- maxoff = PageGetMaxOffsetNumber(page);
- offnum = FirstOffsetNumber;
- }
- }
- break;
- case BackwardScanDirection:
- if (offnum != InvalidOffsetNumber) {
- offnum = OffsetNumberPrev(offnum); /* move back */
- } else {
- offnum = maxoff; /* new page */
- }
- while (offnum < FirstOffsetNumber) {
- /*
- * either this page is empty (offnum ==
- * InvalidOffsetNumber) or we ran off the end.
- */
- _hash_readprev(rel, &buf, &page, &opaque);
- if (BufferIsInvalid(buf)) { /* end of chain */
- if (allbuckets && bucket > 0) {
- --bucket;
- blkno = BUCKET_TO_BLKNO(bucket);
- buf = _hash_getbuf(rel, blkno, HASH_READ);
- page = BufferGetPage(buf);
- _hash_checkpage(page, LH_BUCKET_PAGE);
- opaque = (HashPageOpaque) PageGetSpecialPointer(page);
- Assert(opaque->hasho_bucket == bucket);
- while (BlockNumberIsValid(opaque->hasho_nextblkno)) {
- _hash_readnext(rel, &buf, &page, &opaque);
+ else
+ {
+ offnum = FirstOffsetNumber; /* new page */
+ }
+ while (offnum > maxoff)
+ {
+
+ /*
+ * either this page is empty (maxoff ==
+ * InvalidOffsetNumber) or we ran off the end.
+ */
+ _hash_readnext(rel, &buf, &page, &opaque);
+ if (BufferIsInvalid(buf))
+ { /* end of chain */
+ if (allbuckets && bucket < metap->hashm_maxbucket)
+ {
+ ++bucket;
+ blkno = BUCKET_TO_BLKNO(bucket);
+ buf = _hash_getbuf(rel, blkno, HASH_READ);
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE);
+ opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+ Assert(opaque->hasho_bucket == bucket);
+ while (PageIsEmpty(page) &&
+ BlockNumberIsValid(opaque->hasho_nextblkno))
+ {
+ _hash_readnext(rel, &buf, &page, &opaque);
+ }
+ maxoff = PageGetMaxOffsetNumber(page);
+ offnum = FirstOffsetNumber;
+ }
+ else
+ {
+ maxoff = offnum = InvalidOffsetNumber;
+ break; /* while */
+ }
+ }
+ else
+ {
+ /* _hash_readnext never returns an empty page */
+ maxoff = PageGetMaxOffsetNumber(page);
+ offnum = FirstOffsetNumber;
+ }
+ }
+ break;
+ case BackwardScanDirection:
+ if (offnum != InvalidOffsetNumber)
+ {
+ offnum = OffsetNumberPrev(offnum); /* move back */
+ }
+ else
+ {
+ offnum = maxoff;/* new page */
}
- maxoff = offnum = PageGetMaxOffsetNumber(page);
- } else {
- maxoff = offnum = InvalidOffsetNumber;
- break; /* while */
- }
- } else {
- /* _hash_readprev never returns an empty page */
- maxoff = offnum = PageGetMaxOffsetNumber(page);
+ while (offnum < FirstOffsetNumber)
+ {
+
+ /*
+ * either this page is empty (offnum ==
+ * InvalidOffsetNumber) or we ran off the end.
+ */
+ _hash_readprev(rel, &buf, &page, &opaque);
+ if (BufferIsInvalid(buf))
+ { /* end of chain */
+ if (allbuckets && bucket > 0)
+ {
+ --bucket;
+ blkno = BUCKET_TO_BLKNO(bucket);
+ buf = _hash_getbuf(rel, blkno, HASH_READ);
+ page = BufferGetPage(buf);
+ _hash_checkpage(page, LH_BUCKET_PAGE);
+ opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+ Assert(opaque->hasho_bucket == bucket);
+ while (BlockNumberIsValid(opaque->hasho_nextblkno))
+ {
+ _hash_readnext(rel, &buf, &page, &opaque);
+ }
+ maxoff = offnum = PageGetMaxOffsetNumber(page);
+ }
+ else
+ {
+ maxoff = offnum = InvalidOffsetNumber;
+ break; /* while */
+ }
+ }
+ else
+ {
+ /* _hash_readprev never returns an empty page */
+ maxoff = offnum = PageGetMaxOffsetNumber(page);
+ }
+ }
+ break;
+ default:
+ /* NoMovementScanDirection */
+ /* this should not be reached */
+ break;
}
- }
- break;
- default:
- /* NoMovementScanDirection */
- /* this should not be reached */
- break;
- }
- /* we ran off the end of the world without finding a match */
- if (offnum == InvalidOffsetNumber) {
- _hash_relbuf(rel, metabuf, HASH_READ);
- *bufP = so->hashso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(current);
- return(false);
- }
-
- /* get ready to check this tuple */
- hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &hitem->hash_itup;
- } while (!_hash_checkqual(scan, itup));
-
- /* if we made it to here, we've found a valid tuple */
- _hash_relbuf(rel, metabuf, HASH_READ);
- blkno = BufferGetBlockNumber(buf);
- *bufP = so->hashso_curbuf = buf;
- ItemPointerSet(current, blkno, offnum);
- return(true);
+ /* we ran off the end of the world without finding a match */
+ if (offnum == InvalidOffsetNumber)
+ {
+ _hash_relbuf(rel, metabuf, HASH_READ);
+ *bufP = so->hashso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(current);
+ return (false);
+ }
+
+ /* get ready to check this tuple */
+ hitem = (HashItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &hitem->hash_itup;
+ } while (!_hash_checkqual(scan, itup));
+
+ /* if we made it to here, we've found a valid tuple */
+ _hash_relbuf(rel, metabuf, HASH_READ);
+ blkno = BufferGetBlockNumber(buf);
+ *bufP = so->hashso_curbuf = buf;
+ ItemPointerSet(current, blkno, offnum);
+ return (true);
}
diff --git a/src/backend/access/hash/hashstrat.c b/src/backend/access/hash/hashstrat.c
index d2f1e513c38..f1bdbdb8a3a 100644
--- a/src/backend/access/hash/hashstrat.c
+++ b/src/backend/access/hash/hashstrat.c
@@ -1,80 +1,83 @@
/*-------------------------------------------------------------------------
*
* btstrat.c--
- * Srategy map entries for the btree indexed access method
+ * Srategy map entries for the btree indexed access method
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/Attic/hashstrat.c,v 1.9 1997/08/20 02:01:42 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/Attic/hashstrat.c,v 1.10 1997/09/07 04:38:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/hash.h>
#include <access/istrat.h>
-/*
- * only one valid strategy for hash tables: equality.
+/*
+ * only one valid strategy for hash tables: equality.
*/
#ifdef NOT_USED
-static StrategyNumber HTNegate[1] = {
- InvalidStrategy
+static StrategyNumber HTNegate[1] = {
+ InvalidStrategy
};
-static StrategyNumber HTCommute[1] = {
- HTEqualStrategyNumber
+static StrategyNumber HTCommute[1] = {
+ HTEqualStrategyNumber
};
-static StrategyNumber HTNegateCommute[1] = {
- InvalidStrategy
+static StrategyNumber HTNegateCommute[1] = {
+ InvalidStrategy
};
-static StrategyEvaluationData HTEvaluationData = {
- /* XXX static for simplicity */
+static StrategyEvaluationData HTEvaluationData = {
+ /* XXX static for simplicity */
- HTMaxStrategyNumber,
- (StrategyTransformMap)HTNegate,
- (StrategyTransformMap)HTCommute,
- (StrategyTransformMap)HTNegateCommute,
- {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+ HTMaxStrategyNumber,
+ (StrategyTransformMap) HTNegate,
+ (StrategyTransformMap) HTCommute,
+ (StrategyTransformMap) HTNegateCommute,
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
+
#endif
/* ----------------------------------------------------------------
- * RelationGetHashStrategy
+ * RelationGetHashStrategy
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
-static StrategyNumber
+static StrategyNumber
_hash_getstrat(Relation rel,
- AttrNumber attno,
- RegProcedure proc)
+ AttrNumber attno,
+ RegProcedure proc)
{
- StrategyNumber strat;
+ StrategyNumber strat;
- strat = RelationGetStrategy(rel, attno, &HTEvaluationData, proc);
+ strat = RelationGetStrategy(rel, attno, &HTEvaluationData, proc);
- Assert(StrategyNumberIsValid(strat));
+ Assert(StrategyNumberIsValid(strat));
- return (strat);
+ return (strat);
}
+
#endif
#ifdef NOT_USED
-static bool
+static bool
_hash_invokestrat(Relation rel,
- AttrNumber attno,
- StrategyNumber strat,
- Datum left,
- Datum right)
+ AttrNumber attno,
+ StrategyNumber strat,
+ Datum left,
+ Datum right)
{
- return (RelationInvokeStrategy(rel, &HTEvaluationData, attno, strat,
- left, right));
+ return (RelationInvokeStrategy(rel, &HTEvaluationData, attno, strat,
+ left, right));
}
+
#endif
diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c
index dd0b4737454..f9fbe0e2d17 100644
--- a/src/backend/access/hash/hashutil.c
+++ b/src/backend/access/hash/hashutil.c
@@ -1,109 +1,110 @@
/*-------------------------------------------------------------------------
*
* btutils.c--
- * Utility code for Postgres btree implementation.
+ * Utility code for Postgres btree implementation.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hashutil.c,v 1.9 1997/08/14 05:01:32 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hashutil.c,v 1.10 1997/09/07 04:38:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <access/hash.h>
#include <fmgr.h>
#include <utils/memutils.h>
#include <access/iqual.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
ScanKey
_hash_mkscankey(Relation rel, IndexTuple itup, HashMetaPage metap)
{
- ScanKey skey;
- TupleDesc itupdesc;
- int natts;
- AttrNumber i;
- Datum arg;
- RegProcedure proc;
- bool null;
-
- natts = rel->rd_rel->relnatts;
- itupdesc = RelationGetTupleDescriptor(rel);
-
- skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
-
- for (i = 0; i < natts; i++) {
- arg = index_getattr(itup, i + 1, itupdesc, &null);
- proc = metap->hashm_procid;
- ScanKeyEntryInitialize(&skey[i],
- 0x0, (AttrNumber) (i + 1), proc, arg);
- }
-
- return (skey);
-}
+ ScanKey skey;
+ TupleDesc itupdesc;
+ int natts;
+ AttrNumber i;
+ Datum arg;
+ RegProcedure proc;
+ bool null;
+
+ natts = rel->rd_rel->relnatts;
+ itupdesc = RelationGetTupleDescriptor(rel);
+
+ skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
+
+ for (i = 0; i < natts; i++)
+ {
+ arg = index_getattr(itup, i + 1, itupdesc, &null);
+ proc = metap->hashm_procid;
+ ScanKeyEntryInitialize(&skey[i],
+ 0x0, (AttrNumber) (i + 1), proc, arg);
+ }
+
+ return (skey);
+}
void
_hash_freeskey(ScanKey skey)
{
- pfree(skey);
+ pfree(skey);
}
bool
_hash_checkqual(IndexScanDesc scan, IndexTuple itup)
{
- if (scan->numberOfKeys > 0)
- return (index_keytest(itup,
- RelationGetTupleDescriptor(scan->relation),
- scan->numberOfKeys, scan->keyData));
- else
- return (true);
+ if (scan->numberOfKeys > 0)
+ return (index_keytest(itup,
+ RelationGetTupleDescriptor(scan->relation),
+ scan->numberOfKeys, scan->keyData));
+ else
+ return (true);
}
HashItem
_hash_formitem(IndexTuple itup)
{
- int nbytes_hitem;
- HashItem hitem;
- Size tuplen;
-
- /* disallow nulls in hash keys */
- if (itup->t_info & INDEX_NULL_MASK)
- elog(WARN, "hash indices cannot include null keys");
-
- /* make a copy of the index tuple with room for the sequence number */
- tuplen = IndexTupleSize(itup);
- nbytes_hitem = tuplen +
- (sizeof(HashItemData) - sizeof(IndexTupleData));
-
- hitem = (HashItem) palloc(nbytes_hitem);
- memmove((char *) &(hitem->hash_itup), (char *) itup, tuplen);
-
- return (hitem);
+ int nbytes_hitem;
+ HashItem hitem;
+ Size tuplen;
+
+ /* disallow nulls in hash keys */
+ if (itup->t_info & INDEX_NULL_MASK)
+ elog(WARN, "hash indices cannot include null keys");
+
+ /* make a copy of the index tuple with room for the sequence number */
+ tuplen = IndexTupleSize(itup);
+ nbytes_hitem = tuplen +
+ (sizeof(HashItemData) - sizeof(IndexTupleData));
+
+ hitem = (HashItem) palloc(nbytes_hitem);
+ memmove((char *) &(hitem->hash_itup), (char *) itup, tuplen);
+
+ return (hitem);
}
Bucket
_hash_call(Relation rel, HashMetaPage metap, Datum key)
{
- uint32 n;
- Bucket bucket;
- RegProcedure proc;
-
- proc = metap->hashm_procid;
- n = (uint32) fmgr(proc, key);
- bucket = n & metap->hashm_highmask;
- if (bucket > metap->hashm_maxbucket)
- bucket = bucket & metap->hashm_lowmask;
- return (bucket);
+ uint32 n;
+ Bucket bucket;
+ RegProcedure proc;
+
+ proc = metap->hashm_procid;
+ n = (uint32) fmgr(proc, key);
+ bucket = n & metap->hashm_highmask;
+ if (bucket > metap->hashm_maxbucket)
+ bucket = bucket & metap->hashm_lowmask;
+ return (bucket);
}
/*
@@ -112,12 +113,13 @@ _hash_call(Relation rel, HashMetaPage metap, Datum key)
uint32
_hash_log2(uint32 num)
{
- uint32 i, limit;
-
- limit = 1;
- for (i = 0; limit < num; limit = limit << 1, i++)
- ;
- return (i);
+ uint32 i,
+ limit;
+
+ limit = 1;
+ for (i = 0; limit < num; limit = limit << 1, i++)
+ ;
+ return (i);
}
/*
@@ -126,19 +128,20 @@ _hash_log2(uint32 num)
void
_hash_checkpage(Page page, int flags)
{
- HashPageOpaque opaque;
+ HashPageOpaque opaque;
- Assert(page);
- Assert(((PageHeader)(page))->pd_lower >= (sizeof(PageHeaderData) - sizeof(ItemIdData)));
+ Assert(page);
+ Assert(((PageHeader) (page))->pd_lower >= (sizeof(PageHeaderData) - sizeof(ItemIdData)));
#if 1
- Assert(((PageHeader)(page))->pd_upper <=
- (BLCKSZ - DOUBLEALIGN(sizeof(HashPageOpaqueData))));
- Assert(((PageHeader)(page))->pd_special ==
- (BLCKSZ - DOUBLEALIGN(sizeof(HashPageOpaqueData))));
- Assert(((PageHeader)(page))->pd_opaque.od_pagesize == BLCKSZ);
+ Assert(((PageHeader) (page))->pd_upper <=
+ (BLCKSZ - DOUBLEALIGN(sizeof(HashPageOpaqueData))));
+ Assert(((PageHeader) (page))->pd_special ==
+ (BLCKSZ - DOUBLEALIGN(sizeof(HashPageOpaqueData))));
+ Assert(((PageHeader) (page))->pd_opaque.od_pagesize == BLCKSZ);
#endif
- if (flags) {
- opaque = (HashPageOpaque) PageGetSpecialPointer(page);
- Assert(opaque->hasho_flag & flags);
- }
+ if (flags)
+ {
+ opaque = (HashPageOpaque) PageGetSpecialPointer(page);
+ Assert(opaque->hasho_flag & flags);
+ }
}
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index f199803a711..b7ab8625140 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1,74 +1,74 @@
/*-------------------------------------------------------------------------
*
* heapam.c--
- * heap access method code
+ * heap access method code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.15 1997/08/27 09:00:20 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.16 1997/09/07 04:38:09 momjian Exp $
*
*
* INTERFACE ROUTINES
- * heapgettup - fetch next heap tuple from a scan
- * heap_open - open a heap relation by relationId
- * heap_openr - open a heap relation by name
- * heap_close - close a heap relation
- * heap_beginscan - begin relation scan
- * heap_rescan - restart a relation scan
- * heap_endscan - end relation scan
- * heap_getnext - retrieve next tuple in scan
- * heap_fetch - retrive tuple with tid
- * heap_insert - insert tuple into a relation
- * heap_delete - delete a tuple from a relation
- * heap_replace - replace a tuple in a relation with another tuple
- * heap_markpos - mark scan position
- * heap_restrpos - restore position to marked location
- *
+ * heapgettup - fetch next heap tuple from a scan
+ * heap_open - open a heap relation by relationId
+ * heap_openr - open a heap relation by name
+ * heap_close - close a heap relation
+ * heap_beginscan - begin relation scan
+ * heap_rescan - restart a relation scan
+ * heap_endscan - end relation scan
+ * heap_getnext - retrieve next tuple in scan
+ * heap_fetch - retrive tuple with tid
+ * heap_insert - insert tuple into a relation
+ * heap_delete - delete a tuple from a relation
+ * heap_replace - replace a tuple in a relation with another tuple
+ * heap_markpos - mark scan position
+ * heap_restrpos - restore position to marked location
+ *
* NOTES
- * This file contains the heap_ routines which implement
- * the POSTGRES heap access method used for all POSTGRES
- * relations.
+ * This file contains the heap_ routines which implement
+ * the POSTGRES heap access method used for all POSTGRES
+ * relations.
*
* OLD COMMENTS
- * struct relscan hints: (struct should be made AM independent?)
+ * struct relscan hints: (struct should be made AM independent?)
*
- * rs_ctid is the tid of the last tuple returned by getnext.
- * rs_ptid and rs_ntid are the tids of the previous and next tuples
- * returned by getnext, respectively. NULL indicates an end of
- * scan (either direction); NON indicates an unknow value.
+ * rs_ctid is the tid of the last tuple returned by getnext.
+ * rs_ptid and rs_ntid are the tids of the previous and next tuples
+ * returned by getnext, respectively. NULL indicates an end of
+ * scan (either direction); NON indicates an unknow value.
*
- * possible combinations:
- * rs_p rs_c rs_n interpretation
- * NULL NULL NULL empty scan
- * NULL NULL NON at begining of scan
- * NULL NULL t1 at begining of scan (with cached tid)
- * NON NULL NULL at end of scan
- * t1 NULL NULL at end of scan (with cached tid)
- * NULL t1 NULL just returned only tuple
- * NULL t1 NON just returned first tuple
- * NULL t1 t2 returned first tuple (with cached tid)
- * NON t1 NULL just returned last tuple
- * t2 t1 NULL returned last tuple (with cached tid)
- * t1 t2 NON in the middle of a forward scan
- * NON t2 t1 in the middle of a reverse scan
- * ti tj tk in the middle of a scan (w cached tid)
+ * possible combinations:
+ * rs_p rs_c rs_n interpretation
+ * NULL NULL NULL empty scan
+ * NULL NULL NON at begining of scan
+ * NULL NULL t1 at begining of scan (with cached tid)
+ * NON NULL NULL at end of scan
+ * t1 NULL NULL at end of scan (with cached tid)
+ * NULL t1 NULL just returned only tuple
+ * NULL t1 NON just returned first tuple
+ * NULL t1 t2 returned first tuple (with cached tid)
+ * NON t1 NULL just returned last tuple
+ * t2 t1 NULL returned last tuple (with cached tid)
+ * t1 t2 NON in the middle of a forward scan
+ * NON t2 t1 in the middle of a reverse scan
+ * ti tj tk in the middle of a scan (w cached tid)
*
- * Here NULL is ...tup == NULL && ...buf == InvalidBuffer,
- * and NON is ...tup == NULL && ...buf == UnknownBuffer.
+ * Here NULL is ...tup == NULL && ...buf == InvalidBuffer,
+ * and NON is ...tup == NULL && ...buf == UnknownBuffer.
*
- * Currently, the NONTID values are not cached with their actual
- * values by getnext. Values may be cached by markpos since it stores
- * all three tids.
+ * Currently, the NONTID values are not cached with their actual
+ * values by getnext. Values may be cached by markpos since it stores
+ * all three tids.
*
- * NOTE: the calls to elog() must stop. Should decide on an interface
- * between the general and specific AM calls.
+ * NOTE: the calls to elog() must stop. Should decide on an interface
+ * between the general and specific AM calls.
*
- * XXX probably do not need a free tuple routine for heaps.
- * Huh? Free tuple is not necessary for tuples returned by scans, but
- * is necessary for tuples which are returned by
- * RelationGetTupleByItemPointer. -hirohama
+ * XXX probably do not need a free tuple routine for heaps.
+ * Huh? Free tuple is not necessary for tuples returned by scans, but
+ * is necessary for tuples which are returned by
+ * RelationGetTupleByItemPointer. -hirohama
*
*-------------------------------------------------------------------------
*/
@@ -91,644 +91,706 @@
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static bool ImmediateInvalidation;
+static bool ImmediateInvalidation;
/* ----------------------------------------------------------------
- * heap support routines
+ * heap support routines
* ----------------------------------------------------------------
*/
/* ----------------
- * initsdesc - sdesc code common to heap_beginscan and heap_rescan
+ * initsdesc - sdesc code common to heap_beginscan and heap_rescan
* ----------------
*/
static void
initsdesc(HeapScanDesc sdesc,
- Relation relation,
- int atend,
- unsigned nkeys,
- ScanKey key)
+ Relation relation,
+ int atend,
+ unsigned nkeys,
+ ScanKey key)
{
- if (!RelationGetNumberOfBlocks(relation)) {
- /* ----------------
- * relation is empty
- * ----------------
- */
- sdesc->rs_ntup = sdesc->rs_ctup = sdesc->rs_ptup = NULL;
- sdesc->rs_nbuf = sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer;
- } else if (atend) {
- /* ----------------
- * reverse scan
- * ----------------
- */
- sdesc->rs_ntup = sdesc->rs_ctup = NULL;
- sdesc->rs_nbuf = sdesc->rs_cbuf = InvalidBuffer;
- sdesc->rs_ptup = NULL;
- sdesc->rs_pbuf = UnknownBuffer;
- } else {
+ if (!RelationGetNumberOfBlocks(relation))
+ {
+ /* ----------------
+ * relation is empty
+ * ----------------
+ */
+ sdesc->rs_ntup = sdesc->rs_ctup = sdesc->rs_ptup = NULL;
+ sdesc->rs_nbuf = sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer;
+ }
+ else if (atend)
+ {
+ /* ----------------
+ * reverse scan
+ * ----------------
+ */
+ sdesc->rs_ntup = sdesc->rs_ctup = NULL;
+ sdesc->rs_nbuf = sdesc->rs_cbuf = InvalidBuffer;
+ sdesc->rs_ptup = NULL;
+ sdesc->rs_pbuf = UnknownBuffer;
+ }
+ else
+ {
+ /* ----------------
+ * forward scan
+ * ----------------
+ */
+ sdesc->rs_ctup = sdesc->rs_ptup = NULL;
+ sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer;
+ sdesc->rs_ntup = NULL;
+ sdesc->rs_nbuf = UnknownBuffer;
+ } /* invalid too */
+
+ /* we don't have a marked position... */
+ ItemPointerSetInvalid(&(sdesc->rs_mptid));
+ ItemPointerSetInvalid(&(sdesc->rs_mctid));
+ ItemPointerSetInvalid(&(sdesc->rs_mntid));
+ ItemPointerSetInvalid(&(sdesc->rs_mcd));
+
/* ----------------
- * forward scan
+ * copy the scan key, if appropriate
* ----------------
*/
- sdesc->rs_ctup = sdesc->rs_ptup = NULL;
- sdesc->rs_cbuf = sdesc->rs_pbuf = InvalidBuffer;
- sdesc->rs_ntup = NULL;
- sdesc->rs_nbuf = UnknownBuffer;
- } /* invalid too */
-
- /* we don't have a marked position... */
- ItemPointerSetInvalid(&(sdesc->rs_mptid));
- ItemPointerSetInvalid(&(sdesc->rs_mctid));
- ItemPointerSetInvalid(&(sdesc->rs_mntid));
- ItemPointerSetInvalid(&(sdesc->rs_mcd));
-
- /* ----------------
- * copy the scan key, if appropriate
- * ----------------
- */
- if (key != NULL)
- memmove(sdesc->rs_key, key, nkeys * sizeof(ScanKeyData));
+ if (key != NULL)
+ memmove(sdesc->rs_key, key, nkeys * sizeof(ScanKeyData));
}
/* ----------------
- * unpinsdesc - code common to heap_rescan and heap_endscan
+ * unpinsdesc - code common to heap_rescan and heap_endscan
* ----------------
*/
static void
unpinsdesc(HeapScanDesc sdesc)
{
- if (BufferIsValid(sdesc->rs_pbuf)) {
- ReleaseBuffer(sdesc->rs_pbuf);
- }
-
- /* ------------------------------------
- * Scan will pin buffer one for each non-NULL tuple pointer
- * (ptup, ctup, ntup), so they have to be unpinned multiple
- * times.
- * ------------------------------------
- */
- if (BufferIsValid(sdesc->rs_cbuf)) {
- ReleaseBuffer(sdesc->rs_cbuf);
- }
-
- if (BufferIsValid(sdesc->rs_nbuf)) {
- ReleaseBuffer(sdesc->rs_nbuf);
- }
+ if (BufferIsValid(sdesc->rs_pbuf))
+ {
+ ReleaseBuffer(sdesc->rs_pbuf);
+ }
+
+ /* ------------------------------------
+ * Scan will pin buffer one for each non-NULL tuple pointer
+ * (ptup, ctup, ntup), so they have to be unpinned multiple
+ * times.
+ * ------------------------------------
+ */
+ if (BufferIsValid(sdesc->rs_cbuf))
+ {
+ ReleaseBuffer(sdesc->rs_cbuf);
+ }
+
+ if (BufferIsValid(sdesc->rs_nbuf))
+ {
+ ReleaseBuffer(sdesc->rs_nbuf);
+ }
}
/* ------------------------------------------
- * nextpage
+ * nextpage
*
- * figure out the next page to scan after the current page
- * taking into account of possible adjustment of degrees of
- * parallelism
+ * figure out the next page to scan after the current page
+ * taking into account of possible adjustment of degrees of
+ * parallelism
* ------------------------------------------
*/
static int
nextpage(int page, int dir)
{
- return((dir<0)?page-1:page+1);
+ return ((dir < 0) ? page - 1 : page + 1);
}
/* ----------------
- * heapgettup - fetch next heap tuple
+ * heapgettup - fetch next heap tuple
*
- * routine used by heap_getnext() which does most of the
- * real work in scanning tuples.
+ * routine used by heap_getnext() which does most of the
+ * real work in scanning tuples.
* ----------------
*/
-static HeapTuple
+static HeapTuple
heapgettup(Relation relation,
- ItemPointer tid,
- int dir,
- Buffer *b,
- TimeQual timeQual,
- int nkeys,
- ScanKey key)
+ ItemPointer tid,
+ int dir,
+ Buffer * b,
+ TimeQual timeQual,
+ int nkeys,
+ ScanKey key)
{
- ItemId lpp;
- Page dp;
- int page;
- int pages;
- int lines;
- HeapTuple rtup;
- OffsetNumber lineoff;
- int linesleft;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_heapgettup);
- IncrHeapAccessStat(global_heapgettup);
-
- /* ----------------
- * debugging stuff
- *
- * check validity of arguments, here and for other functions too
- * Note: no locking manipulations needed--this is a local function
- * ----------------
- */
-#ifdef HEAPDEBUGALL
- if (ItemPointerIsValid(tid)) {
- elog(DEBUG, "heapgettup(%.16s, tid=0x%x[%d,%d], dir=%d, ...)",
- RelationGetRelationName(relation), tid, tid->ip_blkid,
- tid->ip_posid, dir);
- } else {
- elog(DEBUG, "heapgettup(%.16s, tid=0x%x, dir=%d, ...)",
- RelationGetRelationName(relation), tid, dir);
- }
- elog(DEBUG, "heapgettup(..., b=0x%x, timeQ=0x%x, nkeys=%d, key=0x%x",
- b, timeQual, nkeys, key);
- if (timeQual == SelfTimeQual) {
- elog(DEBUG, "heapgettup: relation(%c)=`%.16s', SelfTimeQual",
- relation->rd_rel->relkind, &relation->rd_rel->relname);
- } else {
- elog(DEBUG, "heapgettup: relation(%c)=`%.16s', timeQual=%d",
- relation->rd_rel->relkind, &relation->rd_rel->relname,
- timeQual);
- }
-#endif /* !defined(HEAPDEBUGALL) */
-
- if (!ItemPointerIsValid(tid)) {
- Assert(!PointerIsValid(tid));
- }
-
- /* ----------------
- * return null immediately if relation is empty
- * ----------------
- */
- if (!(pages = relation->rd_nblocks))
- return (NULL);
-
- /* ----------------
- * calculate next starting lineoff, given scan direction
- * ----------------
- */
- if (!dir) {
+ ItemId lpp;
+ Page dp;
+ int page;
+ int pages;
+ int lines;
+ HeapTuple rtup;
+ OffsetNumber lineoff;
+ int linesleft;
+
/* ----------------
- * ``no movement'' scan direction
+ * increment access statistics
* ----------------
*/
- /* assume it is a valid TID XXX */
- if (ItemPointerIsValid(tid) == false) {
- *b = InvalidBuffer;
- return (NULL);
- }
- *b = RelationGetBufferWithBuffer(relation,
- ItemPointerGetBlockNumber(tid),
- *b);
-
-#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(*b)) {
- elog(WARN, "heapgettup: failed ReadBuffer");
- }
-#endif
-
- dp = (Page) BufferGetPage(*b);
- lineoff = ItemPointerGetOffsetNumber(tid);
- lpp = PageGetItemId(dp, lineoff);
-
- rtup = (HeapTuple)PageGetItem((Page) dp, lpp);
- return (rtup);
-
- } else if (dir < 0) {
+ IncrHeapAccessStat(local_heapgettup);
+ IncrHeapAccessStat(global_heapgettup);
+
/* ----------------
- * reverse scan direction
+ * debugging stuff
+ *
+ * check validity of arguments, here and for other functions too
+ * Note: no locking manipulations needed--this is a local function
* ----------------
*/
- if (ItemPointerIsValid(tid) == false) {
- tid = NULL;
+#ifdef HEAPDEBUGALL
+ if (ItemPointerIsValid(tid))
+ {
+ elog(DEBUG, "heapgettup(%.16s, tid=0x%x[%d,%d], dir=%d, ...)",
+ RelationGetRelationName(relation), tid, tid->ip_blkid,
+ tid->ip_posid, dir);
}
- if (tid == NULL) {
- page = pages - 1; /* final page */
- } else {
- page = ItemPointerGetBlockNumber(tid); /* current page */
+ else
+ {
+ elog(DEBUG, "heapgettup(%.16s, tid=0x%x, dir=%d, ...)",
+ RelationGetRelationName(relation), tid, dir);
}
- if (page < 0) {
- *b = InvalidBuffer;
- return (NULL);
+ elog(DEBUG, "heapgettup(..., b=0x%x, timeQ=0x%x, nkeys=%d, key=0x%x",
+ b, timeQual, nkeys, key);
+ if (timeQual == SelfTimeQual)
+ {
+ elog(DEBUG, "heapgettup: relation(%c)=`%.16s', SelfTimeQual",
+ relation->rd_rel->relkind, &relation->rd_rel->relname);
}
-
- *b = RelationGetBufferWithBuffer(relation, page, *b);
-#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(*b)) {
- elog(WARN, "heapgettup: failed ReadBuffer");
+ else
+ {
+ elog(DEBUG, "heapgettup: relation(%c)=`%.16s', timeQual=%d",
+ relation->rd_rel->relkind, &relation->rd_rel->relname,
+ timeQual);
}
-#endif
-
- dp = (Page) BufferGetPage(*b);
- lines = PageGetMaxOffsetNumber(dp);
- if (tid == NULL) {
- lineoff = lines; /* final offnum */
- } else {
- lineoff = /* previous offnum */
- OffsetNumberPrev(ItemPointerGetOffsetNumber(tid));
+#endif /* !defined(HEAPDEBUGALL) */
+
+ if (!ItemPointerIsValid(tid))
+ {
+ Assert(!PointerIsValid(tid));
}
- /* page and lineoff now reference the physically previous tid */
- } else {
/* ----------------
- * forward scan direction
+ * return null immediately if relation is empty
* ----------------
*/
- if (ItemPointerIsValid(tid) == false) {
- page = 0; /* first page */
- lineoff = FirstOffsetNumber; /* first offnum */
- } else {
- page = ItemPointerGetBlockNumber(tid); /* current page */
- lineoff = /* next offnum */
- OffsetNumberNext(ItemPointerGetOffsetNumber(tid));
- }
-
- if (page >= pages) {
- *b = InvalidBuffer;
- return (NULL);
- }
- /* page and lineoff now reference the physically next tid */
+ if (!(pages = relation->rd_nblocks))
+ return (NULL);
+
+ /* ----------------
+ * calculate next starting lineoff, given scan direction
+ * ----------------
+ */
+ if (!dir)
+ {
+ /* ----------------
+ * ``no movement'' scan direction
+ * ----------------
+ */
+ /* assume it is a valid TID XXX */
+ if (ItemPointerIsValid(tid) == false)
+ {
+ *b = InvalidBuffer;
+ return (NULL);
+ }
+ *b = RelationGetBufferWithBuffer(relation,
+ ItemPointerGetBlockNumber(tid),
+ *b);
- *b = RelationGetBufferWithBuffer(relation, page, *b);
#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(*b)) {
- elog(WARN, "heapgettup: failed ReadBuffer");
+ if (!BufferIsValid(*b))
+ {
+ elog(WARN, "heapgettup: failed ReadBuffer");
+ }
+#endif
+
+ dp = (Page) BufferGetPage(*b);
+ lineoff = ItemPointerGetOffsetNumber(tid);
+ lpp = PageGetItemId(dp, lineoff);
+
+ rtup = (HeapTuple) PageGetItem((Page) dp, lpp);
+ return (rtup);
+
}
+ else if (dir < 0)
+ {
+ /* ----------------
+ * reverse scan direction
+ * ----------------
+ */
+ if (ItemPointerIsValid(tid) == false)
+ {
+ tid = NULL;
+ }
+ if (tid == NULL)
+ {
+ page = pages - 1; /* final page */
+ }
+ else
+ {
+ page = ItemPointerGetBlockNumber(tid); /* current page */
+ }
+ if (page < 0)
+ {
+ *b = InvalidBuffer;
+ return (NULL);
+ }
+
+ *b = RelationGetBufferWithBuffer(relation, page, *b);
+#ifndef NO_BUFFERISVALID
+ if (!BufferIsValid(*b))
+ {
+ elog(WARN, "heapgettup: failed ReadBuffer");
+ }
#endif
-
- dp = (Page) BufferGetPage(*b);
- lines = PageGetMaxOffsetNumber(dp);
- }
-
- /* 'dir' is now non-zero */
-
- /* ----------------
- * calculate line pointer and number of remaining items
- * to check on this page.
- * ----------------
- */
- lpp = PageGetItemId(dp, lineoff);
- if (dir < 0) {
- linesleft = lineoff - 1;
- } else {
- linesleft = lines - lineoff;
- }
-
- /* ----------------
- * advance the scan until we find a qualifying tuple or
- * run out of stuff to scan
- * ----------------
- */
- for (;;) {
- while (linesleft >= 0) {
- /* ----------------
- * if current tuple qualifies, return it.
- * ----------------
- */
- if ((rtup = heap_tuple_satisfies(lpp, relation, *b, (PageHeader) dp,
- timeQual, nkeys, key)) != NULL) {
- ItemPointer iptr = &(rtup->t_ctid);
- if (ItemPointerGetBlockNumber(iptr) != page) {
- /*
- * set block id to the correct page number
- * --- this is a hack to support the virtual fragment
- * concept
- */
- ItemPointerSetBlockNumber(iptr, page);
+
+ dp = (Page) BufferGetPage(*b);
+ lines = PageGetMaxOffsetNumber(dp);
+ if (tid == NULL)
+ {
+ lineoff = lines; /* final offnum */
}
- return (rtup);
- }
-
- /* ----------------
- * otherwise move to the next item on the page
- * ----------------
- */
- --linesleft;
- if (dir < 0) {
- --lpp; /* move back in this page's ItemId array */
- } else {
- ++lpp; /* move forward in this page's ItemId array */
- }
+ else
+ {
+ lineoff = /* previous offnum */
+ OffsetNumberPrev(ItemPointerGetOffsetNumber(tid));
+ }
+ /* page and lineoff now reference the physically previous tid */
+
+ }
+ else
+ {
+ /* ----------------
+ * forward scan direction
+ * ----------------
+ */
+ if (ItemPointerIsValid(tid) == false)
+ {
+ page = 0; /* first page */
+ lineoff = FirstOffsetNumber; /* first offnum */
+ }
+ else
+ {
+ page = ItemPointerGetBlockNumber(tid); /* current page */
+ lineoff = /* next offnum */
+ OffsetNumberNext(ItemPointerGetOffsetNumber(tid));
+ }
+
+ if (page >= pages)
+ {
+ *b = InvalidBuffer;
+ return (NULL);
+ }
+ /* page and lineoff now reference the physically next tid */
+
+ *b = RelationGetBufferWithBuffer(relation, page, *b);
+#ifndef NO_BUFFERISVALID
+ if (!BufferIsValid(*b))
+ {
+ elog(WARN, "heapgettup: failed ReadBuffer");
+ }
+#endif
+
+ dp = (Page) BufferGetPage(*b);
+ lines = PageGetMaxOffsetNumber(dp);
}
-
+
+ /* 'dir' is now non-zero */
+
/* ----------------
- * if we get here, it means we've exhausted the items on
- * this page and it's time to move to the next..
+ * calculate line pointer and number of remaining items
+ * to check on this page.
* ----------------
*/
- page = nextpage(page, dir);
-
+ lpp = PageGetItemId(dp, lineoff);
+ if (dir < 0)
+ {
+ linesleft = lineoff - 1;
+ }
+ else
+ {
+ linesleft = lines - lineoff;
+ }
+
/* ----------------
- * return NULL if we've exhausted all the pages..
+ * advance the scan until we find a qualifying tuple or
+ * run out of stuff to scan
* ----------------
*/
- if (page < 0 || page >= pages) {
- if (BufferIsValid(*b))
- ReleaseBuffer(*b);
- *b = InvalidBuffer;
- return (NULL);
- }
-
- *b = ReleaseAndReadBuffer(*b, relation, page);
-
+ for (;;)
+ {
+ while (linesleft >= 0)
+ {
+ /* ----------------
+ * if current tuple qualifies, return it.
+ * ----------------
+ */
+ if ((rtup = heap_tuple_satisfies(lpp, relation, *b, (PageHeader) dp,
+ timeQual, nkeys, key)) != NULL)
+ {
+ ItemPointer iptr = &(rtup->t_ctid);
+
+ if (ItemPointerGetBlockNumber(iptr) != page)
+ {
+
+ /*
+ * set block id to the correct page number --- this is
+ * a hack to support the virtual fragment concept
+ */
+ ItemPointerSetBlockNumber(iptr, page);
+ }
+ return (rtup);
+ }
+
+ /* ----------------
+ * otherwise move to the next item on the page
+ * ----------------
+ */
+ --linesleft;
+ if (dir < 0)
+ {
+ --lpp; /* move back in this page's ItemId array */
+ }
+ else
+ {
+ ++lpp; /* move forward in this page's ItemId
+ * array */
+ }
+ }
+
+ /* ----------------
+ * if we get here, it means we've exhausted the items on
+ * this page and it's time to move to the next..
+ * ----------------
+ */
+ page = nextpage(page, dir);
+
+ /* ----------------
+ * return NULL if we've exhausted all the pages..
+ * ----------------
+ */
+ if (page < 0 || page >= pages)
+ {
+ if (BufferIsValid(*b))
+ ReleaseBuffer(*b);
+ *b = InvalidBuffer;
+ return (NULL);
+ }
+
+ *b = ReleaseAndReadBuffer(*b, relation, page);
+
#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(*b)) {
- elog(WARN, "heapgettup: failed ReadBuffer");
- }
+ if (!BufferIsValid(*b))
+ {
+ elog(WARN, "heapgettup: failed ReadBuffer");
+ }
#endif
- dp = (Page) BufferGetPage(*b);
- lines = lineoff = PageGetMaxOffsetNumber((Page) dp);
- linesleft = lines - 1;
- if (dir < 0) {
- lpp = PageGetItemId(dp, lineoff);
- } else {
- lpp = PageGetItemId(dp, FirstOffsetNumber);
+ dp = (Page) BufferGetPage(*b);
+ lines = lineoff = PageGetMaxOffsetNumber((Page) dp);
+ linesleft = lines - 1;
+ if (dir < 0)
+ {
+ lpp = PageGetItemId(dp, lineoff);
+ }
+ else
+ {
+ lpp = PageGetItemId(dp, FirstOffsetNumber);
+ }
}
- }
}
void
doinsert(Relation relation, HeapTuple tup)
{
- RelationPutHeapTupleAtEnd(relation, tup);
- return;
+ RelationPutHeapTupleAtEnd(relation, tup);
+ return;
}
-/*
- * HeapScanIsValid is now a macro in relscan.h -cim 4/27/91
+/*
+ * HeapScanIsValid is now a macro in relscan.h -cim 4/27/91
*/
#ifdef NOT_USED
/* ----------------
- * SetHeapAccessMethodImmediateInvalidation
+ * SetHeapAccessMethodImmediateInvalidation
* ----------------
*/
void
SetHeapAccessMethodImmediateInvalidation(bool on)
{
- ImmediateInvalidation = on;
+ ImmediateInvalidation = on;
}
+
#endif
/* ----------------------------------------------------------------
- * heap access method interface
+ * heap access method interface
* ----------------------------------------------------------------
*/
/* ----------------
- * heap_open - open a heap relation by relationId
+ * heap_open - open a heap relation by relationId
*
- * presently the relcache routines do all the work we need
- * to open/close heap relations.
+ * presently the relcache routines do all the work we need
+ * to open/close heap relations.
* ----------------
*/
Relation
heap_open(Oid relationId)
{
- Relation r;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_open);
- IncrHeapAccessStat(global_open);
-
- r = (Relation) RelationIdGetRelation(relationId);
-
- if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX) {
- elog(WARN, "%s is an index relation", r->rd_rel->relname.data);
- }
-
- return (r);
+ Relation r;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_open);
+ IncrHeapAccessStat(global_open);
+
+ r = (Relation) RelationIdGetRelation(relationId);
+
+ if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
+ {
+ elog(WARN, "%s is an index relation", r->rd_rel->relname.data);
+ }
+
+ return (r);
}
/* ----------------
- * heap_openr - open a heap relation by name
+ * heap_openr - open a heap relation by name
*
- * presently the relcache routines do all the work we need
- * to open/close heap relations.
+ * presently the relcache routines do all the work we need
+ * to open/close heap relations.
* ----------------
*/
Relation
heap_openr(char *relationName)
{
- Relation r;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_openr);
- IncrHeapAccessStat(global_openr);
-
- r = RelationNameGetRelation(relationName);
-
- if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX) {
- elog(WARN, "%s is an index relation", r->rd_rel->relname.data);
- }
-
- return (r);
+ Relation r;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_openr);
+ IncrHeapAccessStat(global_openr);
+
+ r = RelationNameGetRelation(relationName);
+
+ if (RelationIsValid(r) && r->rd_rel->relkind == RELKIND_INDEX)
+ {
+ elog(WARN, "%s is an index relation", r->rd_rel->relname.data);
+ }
+
+ return (r);
}
/* ----------------
- * heap_close - close a heap relation
+ * heap_close - close a heap relation
*
- * presently the relcache routines do all the work we need
- * to open/close heap relations.
+ * presently the relcache routines do all the work we need
+ * to open/close heap relations.
* ----------------
*/
void
heap_close(Relation relation)
{
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_close);
- IncrHeapAccessStat(global_close);
-
- RelationClose(relation);
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_close);
+ IncrHeapAccessStat(global_close);
+
+ RelationClose(relation);
}
/* ----------------
- * heap_beginscan - begin relation scan
+ * heap_beginscan - begin relation scan
* ----------------
*/
HeapScanDesc
heap_beginscan(Relation relation,
- int atend,
- TimeQual timeQual,
- unsigned nkeys,
- ScanKey key)
+ int atend,
+ TimeQual timeQual,
+ unsigned nkeys,
+ ScanKey key)
{
- HeapScanDesc sdesc;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_beginscan);
- IncrHeapAccessStat(global_beginscan);
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- if (RelationIsValid(relation) == false)
- elog(WARN, "heap_beginscan: !RelationIsValid(relation)");
-
- /* ----------------
- * set relation level read lock
- * ----------------
- */
- RelationSetLockForRead(relation);
-
- /* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */
- if (relation->rd_rel->relkind == RELKIND_UNCATALOGED) {
- timeQual = SelfTimeQual;
- }
-
- /* ----------------
- * increment relation ref count while scanning relation
- * ----------------
- */
- RelationIncrementReferenceCount(relation);
-
- /* ----------------
- * allocate and initialize scan descriptor
- * ----------------
- */
- sdesc = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
-
- relation->rd_nblocks = smgrnblocks(relation->rd_rel->relsmgr, relation);
- sdesc->rs_rd = relation;
-
- if (nkeys) {
- /*
- * we do this here instead of in initsdesc() because heap_rescan also
- * calls initsdesc() and we don't want to allocate memory again
+ HeapScanDesc sdesc;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_beginscan);
+ IncrHeapAccessStat(global_beginscan);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
*/
- sdesc->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
- } else {
- sdesc->rs_key = NULL;
- }
-
- initsdesc(sdesc, relation, atend, nkeys, key);
-
- sdesc->rs_atend = atend;
- sdesc->rs_tr = timeQual;
- sdesc->rs_nkeys = (short)nkeys;
-
- return (sdesc);
+ if (RelationIsValid(relation) == false)
+ elog(WARN, "heap_beginscan: !RelationIsValid(relation)");
+
+ /* ----------------
+ * set relation level read lock
+ * ----------------
+ */
+ RelationSetLockForRead(relation);
+
+ /* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */
+ if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
+ {
+ timeQual = SelfTimeQual;
+ }
+
+ /* ----------------
+ * increment relation ref count while scanning relation
+ * ----------------
+ */
+ RelationIncrementReferenceCount(relation);
+
+ /* ----------------
+ * allocate and initialize scan descriptor
+ * ----------------
+ */
+ sdesc = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
+
+ relation->rd_nblocks = smgrnblocks(relation->rd_rel->relsmgr, relation);
+ sdesc->rs_rd = relation;
+
+ if (nkeys)
+ {
+
+ /*
+ * we do this here instead of in initsdesc() because heap_rescan
+ * also calls initsdesc() and we don't want to allocate memory
+ * again
+ */
+ sdesc->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
+ }
+ else
+ {
+ sdesc->rs_key = NULL;
+ }
+
+ initsdesc(sdesc, relation, atend, nkeys, key);
+
+ sdesc->rs_atend = atend;
+ sdesc->rs_tr = timeQual;
+ sdesc->rs_nkeys = (short) nkeys;
+
+ return (sdesc);
}
/* ----------------
- * heap_rescan - restart a relation scan
+ * heap_rescan - restart a relation scan
* ----------------
*/
void
heap_rescan(HeapScanDesc sdesc,
- bool scanFromEnd,
- ScanKey key)
+ bool scanFromEnd,
+ ScanKey key)
{
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_rescan);
- IncrHeapAccessStat(global_rescan);
-
- /* Note: set relation level read lock is still set */
-
- /* ----------------
- * unpin scan buffers
- * ----------------
- */
- unpinsdesc(sdesc);
-
- /* ----------------
- * reinitialize scan descriptor
- * ----------------
- */
- initsdesc(sdesc, sdesc->rs_rd, scanFromEnd, sdesc->rs_nkeys, key);
- sdesc->rs_atend = (bool) scanFromEnd;
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_rescan);
+ IncrHeapAccessStat(global_rescan);
+
+ /* Note: set relation level read lock is still set */
+
+ /* ----------------
+ * unpin scan buffers
+ * ----------------
+ */
+ unpinsdesc(sdesc);
+
+ /* ----------------
+ * reinitialize scan descriptor
+ * ----------------
+ */
+ initsdesc(sdesc, sdesc->rs_rd, scanFromEnd, sdesc->rs_nkeys, key);
+ sdesc->rs_atend = (bool) scanFromEnd;
}
/* ----------------
- * heap_endscan - end relation scan
+ * heap_endscan - end relation scan
*
- * See how to integrate with index scans.
- * Check handling if reldesc caching.
+ * See how to integrate with index scans.
+ * Check handling if reldesc caching.
* ----------------
*/
void
heap_endscan(HeapScanDesc sdesc)
{
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_endscan);
- IncrHeapAccessStat(global_endscan);
-
- /* Note: no locking manipulations needed */
-
- /* ----------------
- * unpin scan buffers
- * ----------------
- */
- unpinsdesc(sdesc);
-
- /* ----------------
- * decrement relation reference count and free scan descriptor storage
- * ----------------
- */
- RelationDecrementReferenceCount(sdesc->rs_rd);
-
- /* ----------------
- * Non 2-phase read locks on catalog relations
- * ----------------
- */
- if ( IsSystemRelationName(RelationGetRelationName(sdesc->rs_rd)->data) )
-
- RelationUnsetLockForRead(sdesc->rs_rd);
-
- pfree(sdesc); /* XXX */
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_endscan);
+ IncrHeapAccessStat(global_endscan);
+
+ /* Note: no locking manipulations needed */
+
+ /* ----------------
+ * unpin scan buffers
+ * ----------------
+ */
+ unpinsdesc(sdesc);
+
+ /* ----------------
+ * decrement relation reference count and free scan descriptor storage
+ * ----------------
+ */
+ RelationDecrementReferenceCount(sdesc->rs_rd);
+
+ /* ----------------
+ * Non 2-phase read locks on catalog relations
+ * ----------------
+ */
+ if (IsSystemRelationName(RelationGetRelationName(sdesc->rs_rd)->data))
+
+ RelationUnsetLockForRead(sdesc->rs_rd);
+
+ pfree(sdesc); /* XXX */
}
/* ----------------
- * heap_getnext - retrieve next tuple in scan
+ * heap_getnext - retrieve next tuple in scan
*
- * Fix to work with index relations.
+ * Fix to work with index relations.
* ----------------
*/
#ifdef HEAPDEBUGALL
#define HEAPDEBUG_1 \
elog(DEBUG, "heap_getnext([%s,nkeys=%d],backw=%d,0x%x) called", \
- sdesc->rs_rd->rd_rel->relname.data, sdesc->rs_nkeys, backw, b)
-
+ sdesc->rs_rd->rd_rel->relname.data, sdesc->rs_nkeys, backw, b)
+
#define HEAPDEBUG_2 \
- elog(DEBUG, "heap_getnext called with backw (no tracing yet)")
-
+ elog(DEBUG, "heap_getnext called with backw (no tracing yet)")
+
#define HEAPDEBUG_3 \
- elog(DEBUG, "heap_getnext returns NULL at end")
-
+ elog(DEBUG, "heap_getnext returns NULL at end")
+
#define HEAPDEBUG_4 \
- elog(DEBUG, "heap_getnext valid buffer UNPIN'd")
-
+ elog(DEBUG, "heap_getnext valid buffer UNPIN'd")
+
#define HEAPDEBUG_5 \
- elog(DEBUG, "heap_getnext next tuple was cached")
-
+ elog(DEBUG, "heap_getnext next tuple was cached")
+
#define HEAPDEBUG_6 \
- elog(DEBUG, "heap_getnext returning EOS")
-
+ elog(DEBUG, "heap_getnext returning EOS")
+
#define HEAPDEBUG_7 \
- elog(DEBUG, "heap_getnext returning tuple");
+ elog(DEBUG, "heap_getnext returning tuple");
#else
#define HEAPDEBUG_1
#define HEAPDEBUG_2
@@ -737,715 +799,759 @@ elog(DEBUG, "heap_getnext([%s,nkeys=%d],backw=%d,0x%x) called", \
#define HEAPDEBUG_5
#define HEAPDEBUG_6
#define HEAPDEBUG_7
-#endif /* !defined(HEAPDEBUGALL) */
-
-
+#endif /* !defined(HEAPDEBUGALL) */
+
+
HeapTuple
heap_getnext(HeapScanDesc scandesc,
- int backw,
- Buffer *b)
+ int backw,
+ Buffer * b)
{
- register HeapScanDesc sdesc = scandesc;
- Buffer localb;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_getnext);
- IncrHeapAccessStat(global_getnext);
-
- /* Note: no locking manipulations needed */
-
- /* ----------------
- * argument checks
- * ----------------
- */
- if (sdesc == NULL)
- elog(WARN, "heap_getnext: NULL relscan");
-
- /* ----------------
- * initialize return buffer to InvalidBuffer
- * ----------------
- */
- if (! PointerIsValid(b)) b = &localb;
- (*b) = InvalidBuffer;
-
- HEAPDEBUG_1; /* heap_getnext( info ) */
-
- if (backw) {
+ register HeapScanDesc sdesc = scandesc;
+ Buffer localb;
+
/* ----------------
- * handle reverse scan
+ * increment access statistics
* ----------------
*/
- HEAPDEBUG_2; /* heap_getnext called with backw */
-
- if (sdesc->rs_ptup == sdesc->rs_ctup &&
- BufferIsInvalid(sdesc->rs_pbuf))
- {
- if (BufferIsValid(sdesc->rs_nbuf))
- ReleaseBuffer(sdesc->rs_nbuf);
- return (NULL);
- }
-
- /*
- * Copy the "current" tuple/buffer
- * to "next". Pin/unpin the buffers
- * accordingly
+ IncrHeapAccessStat(local_getnext);
+ IncrHeapAccessStat(global_getnext);
+
+ /* Note: no locking manipulations needed */
+
+ /* ----------------
+ * argument checks
+ * ----------------
*/
- if (sdesc->rs_nbuf != sdesc->rs_cbuf) {
- if (BufferIsValid(sdesc->rs_nbuf))
- ReleaseBuffer(sdesc->rs_nbuf);
- if (BufferIsValid(sdesc->rs_cbuf))
- IncrBufferRefCount(sdesc->rs_cbuf);
- }
- sdesc->rs_ntup = sdesc->rs_ctup;
- sdesc->rs_nbuf = sdesc->rs_cbuf;
-
- if (sdesc->rs_ptup != NULL) {
- if (sdesc->rs_cbuf != sdesc->rs_pbuf) {
- if (BufferIsValid(sdesc->rs_cbuf))
- ReleaseBuffer(sdesc->rs_cbuf);
- if (BufferIsValid(sdesc->rs_pbuf))
- IncrBufferRefCount(sdesc->rs_pbuf);
- }
- sdesc->rs_ctup = sdesc->rs_ptup;
- sdesc->rs_cbuf = sdesc->rs_pbuf;
- } else { /* NONTUP */
- ItemPointer iptr;
-
- iptr = (sdesc->rs_ctup != NULL) ?
- &(sdesc->rs_ctup->t_ctid) : (ItemPointer) NULL;
-
- /* Don't release sdesc->rs_cbuf at this point, because
- heapgettup doesn't increase PrivateRefCount if it
- is already set. On a backward scan, both rs_ctup and rs_ntup
- usually point to the same buffer page, so
- PrivateRefCount[rs_cbuf] should be 2 (or more, if for instance
- ctup is stored in a TupleTableSlot). - 01/09/94 */
-
- sdesc->rs_ctup = (HeapTuple)
- heapgettup(sdesc->rs_rd,
- iptr,
- -1,
- &(sdesc->rs_cbuf),
- sdesc->rs_tr,
- sdesc->rs_nkeys,
- sdesc->rs_key);
- }
-
- if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf))
- {
+ if (sdesc == NULL)
+ elog(WARN, "heap_getnext: NULL relscan");
+
+ /* ----------------
+ * initialize return buffer to InvalidBuffer
+ * ----------------
+ */
+ if (!PointerIsValid(b))
+ b = &localb;
+ (*b) = InvalidBuffer;
+
+ HEAPDEBUG_1; /* heap_getnext( info ) */
+
+ if (backw)
+ {
+ /* ----------------
+ * handle reverse scan
+ * ----------------
+ */
+ HEAPDEBUG_2; /* heap_getnext called with backw */
+
+ if (sdesc->rs_ptup == sdesc->rs_ctup &&
+ BufferIsInvalid(sdesc->rs_pbuf))
+ {
+ if (BufferIsValid(sdesc->rs_nbuf))
+ ReleaseBuffer(sdesc->rs_nbuf);
+ return (NULL);
+ }
+
+ /*
+ * Copy the "current" tuple/buffer to "next". Pin/unpin the
+ * buffers accordingly
+ */
+ if (sdesc->rs_nbuf != sdesc->rs_cbuf)
+ {
+ if (BufferIsValid(sdesc->rs_nbuf))
+ ReleaseBuffer(sdesc->rs_nbuf);
+ if (BufferIsValid(sdesc->rs_cbuf))
+ IncrBufferRefCount(sdesc->rs_cbuf);
+ }
+ sdesc->rs_ntup = sdesc->rs_ctup;
+ sdesc->rs_nbuf = sdesc->rs_cbuf;
+
+ if (sdesc->rs_ptup != NULL)
+ {
+ if (sdesc->rs_cbuf != sdesc->rs_pbuf)
+ {
+ if (BufferIsValid(sdesc->rs_cbuf))
+ ReleaseBuffer(sdesc->rs_cbuf);
+ if (BufferIsValid(sdesc->rs_pbuf))
+ IncrBufferRefCount(sdesc->rs_pbuf);
+ }
+ sdesc->rs_ctup = sdesc->rs_ptup;
+ sdesc->rs_cbuf = sdesc->rs_pbuf;
+ }
+ else
+ { /* NONTUP */
+ ItemPointer iptr;
+
+ iptr = (sdesc->rs_ctup != NULL) ?
+ &(sdesc->rs_ctup->t_ctid) : (ItemPointer) NULL;
+
+ /*
+ * Don't release sdesc->rs_cbuf at this point, because
+ * heapgettup doesn't increase PrivateRefCount if it is
+ * already set. On a backward scan, both rs_ctup and rs_ntup
+ * usually point to the same buffer page, so
+ * PrivateRefCount[rs_cbuf] should be 2 (or more, if for
+ * instance ctup is stored in a TupleTableSlot). - 01/09/94
+ */
+
+ sdesc->rs_ctup = (HeapTuple)
+ heapgettup(sdesc->rs_rd,
+ iptr,
+ -1,
+ &(sdesc->rs_cbuf),
+ sdesc->rs_tr,
+ sdesc->rs_nkeys,
+ sdesc->rs_key);
+ }
+
+ if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf))
+ {
+ if (BufferIsValid(sdesc->rs_pbuf))
+ ReleaseBuffer(sdesc->rs_pbuf);
+ sdesc->rs_ptup = NULL;
+ sdesc->rs_pbuf = InvalidBuffer;
+ if (BufferIsValid(sdesc->rs_nbuf))
+ ReleaseBuffer(sdesc->rs_nbuf);
+ sdesc->rs_ntup = NULL;
+ sdesc->rs_nbuf = InvalidBuffer;
+ return (NULL);
+ }
+
if (BufferIsValid(sdesc->rs_pbuf))
- ReleaseBuffer(sdesc->rs_pbuf);
+ ReleaseBuffer(sdesc->rs_pbuf);
sdesc->rs_ptup = NULL;
- sdesc->rs_pbuf = InvalidBuffer;
+ sdesc->rs_pbuf = UnknownBuffer;
+
+ }
+ else
+ {
+ /* ----------------
+ * handle forward scan
+ * ----------------
+ */
+ if (sdesc->rs_ctup == sdesc->rs_ntup &&
+ BufferIsInvalid(sdesc->rs_nbuf))
+ {
+ if (BufferIsValid(sdesc->rs_pbuf))
+ ReleaseBuffer(sdesc->rs_pbuf);
+ HEAPDEBUG_3; /* heap_getnext returns NULL at end */
+ return (NULL);
+ }
+
+ /*
+ * Copy the "current" tuple/buffer to "previous". Pin/unpin the
+ * buffers accordingly
+ */
+ if (sdesc->rs_pbuf != sdesc->rs_cbuf)
+ {
+ if (BufferIsValid(sdesc->rs_pbuf))
+ ReleaseBuffer(sdesc->rs_pbuf);
+ if (BufferIsValid(sdesc->rs_cbuf))
+ IncrBufferRefCount(sdesc->rs_cbuf);
+ }
+ sdesc->rs_ptup = sdesc->rs_ctup;
+ sdesc->rs_pbuf = sdesc->rs_cbuf;
+
+ if (sdesc->rs_ntup != NULL)
+ {
+ if (sdesc->rs_cbuf != sdesc->rs_nbuf)
+ {
+ if (BufferIsValid(sdesc->rs_cbuf))
+ ReleaseBuffer(sdesc->rs_cbuf);
+ if (BufferIsValid(sdesc->rs_nbuf))
+ IncrBufferRefCount(sdesc->rs_nbuf);
+ }
+ sdesc->rs_ctup = sdesc->rs_ntup;
+ sdesc->rs_cbuf = sdesc->rs_nbuf;
+ HEAPDEBUG_5; /* heap_getnext next tuple was cached */
+ }
+ else
+ { /* NONTUP */
+ ItemPointer iptr;
+
+ iptr = (sdesc->rs_ctup != NULL) ?
+ &sdesc->rs_ctup->t_ctid : (ItemPointer) NULL;
+
+ /*
+ * Don't release sdesc->rs_cbuf at this point, because
+ * heapgettup doesn't increase PrivateRefCount if it is
+ * already set. On a forward scan, both rs_ctup and rs_ptup
+ * usually point to the same buffer page, so
+ * PrivateRefCount[rs_cbuf] should be 2 (or more, if for
+ * instance ctup is stored in a TupleTableSlot). - 01/09/93
+ */
+
+ sdesc->rs_ctup = (HeapTuple)
+ heapgettup(sdesc->rs_rd,
+ iptr,
+ 1,
+ &sdesc->rs_cbuf,
+ sdesc->rs_tr,
+ sdesc->rs_nkeys,
+ sdesc->rs_key);
+ }
+
+ if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf))
+ {
+ if (BufferIsValid(sdesc->rs_nbuf))
+ ReleaseBuffer(sdesc->rs_nbuf);
+ sdesc->rs_ntup = NULL;
+ sdesc->rs_nbuf = InvalidBuffer;
+ if (BufferIsValid(sdesc->rs_pbuf))
+ ReleaseBuffer(sdesc->rs_pbuf);
+ sdesc->rs_ptup = NULL;
+ sdesc->rs_pbuf = InvalidBuffer;
+ HEAPDEBUG_6; /* heap_getnext returning EOS */
+ return (NULL);
+ }
+
if (BufferIsValid(sdesc->rs_nbuf))
- ReleaseBuffer(sdesc->rs_nbuf);
+ ReleaseBuffer(sdesc->rs_nbuf);
sdesc->rs_ntup = NULL;
- sdesc->rs_nbuf = InvalidBuffer;
- return (NULL);
- }
-
- if (BufferIsValid(sdesc->rs_pbuf))
- ReleaseBuffer(sdesc->rs_pbuf);
- sdesc->rs_ptup = NULL;
- sdesc->rs_pbuf = UnknownBuffer;
-
- } else {
+ sdesc->rs_nbuf = UnknownBuffer;
+ }
+
/* ----------------
- * handle forward scan
+ * if we get here it means we have a new current scan tuple, so
+ * point to the proper return buffer and return the tuple.
* ----------------
*/
- if (sdesc->rs_ctup == sdesc->rs_ntup &&
- BufferIsInvalid(sdesc->rs_nbuf)) {
- if (BufferIsValid(sdesc->rs_pbuf))
- ReleaseBuffer(sdesc->rs_pbuf);
- HEAPDEBUG_3; /* heap_getnext returns NULL at end */
- return (NULL);
- }
-
- /*
- * Copy the "current" tuple/buffer
- * to "previous". Pin/unpin the buffers
- * accordingly
- */
- if (sdesc->rs_pbuf != sdesc->rs_cbuf) {
- if (BufferIsValid(sdesc->rs_pbuf))
- ReleaseBuffer(sdesc->rs_pbuf);
- if (BufferIsValid(sdesc->rs_cbuf))
- IncrBufferRefCount(sdesc->rs_cbuf);
- }
- sdesc->rs_ptup = sdesc->rs_ctup;
- sdesc->rs_pbuf = sdesc->rs_cbuf;
-
- if (sdesc->rs_ntup != NULL) {
- if (sdesc->rs_cbuf != sdesc->rs_nbuf) {
- if (BufferIsValid(sdesc->rs_cbuf))
- ReleaseBuffer(sdesc->rs_cbuf);
- if (BufferIsValid(sdesc->rs_nbuf))
- IncrBufferRefCount(sdesc->rs_nbuf);
- }
- sdesc->rs_ctup = sdesc->rs_ntup;
- sdesc->rs_cbuf = sdesc->rs_nbuf;
- HEAPDEBUG_5; /* heap_getnext next tuple was cached */
- } else { /* NONTUP */
- ItemPointer iptr;
-
- iptr = (sdesc->rs_ctup != NULL) ?
- &sdesc->rs_ctup->t_ctid : (ItemPointer) NULL;
-
- /* Don't release sdesc->rs_cbuf at this point, because
- heapgettup doesn't increase PrivateRefCount if it
- is already set. On a forward scan, both rs_ctup and rs_ptup
- usually point to the same buffer page, so
- PrivateRefCount[rs_cbuf] should be 2 (or more, if for instance
- ctup is stored in a TupleTableSlot). - 01/09/93 */
-
- sdesc->rs_ctup = (HeapTuple)
- heapgettup(sdesc->rs_rd,
- iptr,
- 1,
- &sdesc->rs_cbuf,
- sdesc->rs_tr,
- sdesc->rs_nkeys,
- sdesc->rs_key);
- }
-
- if (sdesc->rs_ctup == NULL && !BufferIsValid(sdesc->rs_cbuf)) {
- if (BufferIsValid(sdesc->rs_nbuf))
- ReleaseBuffer(sdesc->rs_nbuf);
- sdesc->rs_ntup = NULL;
- sdesc->rs_nbuf = InvalidBuffer;
- if (BufferIsValid(sdesc->rs_pbuf))
- ReleaseBuffer(sdesc->rs_pbuf);
- sdesc->rs_ptup = NULL;
- sdesc->rs_pbuf = InvalidBuffer;
- HEAPDEBUG_6; /* heap_getnext returning EOS */
- return (NULL);
- }
-
- if (BufferIsValid(sdesc->rs_nbuf))
- ReleaseBuffer(sdesc->rs_nbuf);
- sdesc->rs_ntup = NULL;
- sdesc->rs_nbuf = UnknownBuffer;
- }
-
- /* ----------------
- * if we get here it means we have a new current scan tuple, so
- * point to the proper return buffer and return the tuple.
- * ----------------
- */
- (*b) = sdesc->rs_cbuf;
-
- HEAPDEBUG_7; /* heap_getnext returning tuple */
-
- return (sdesc->rs_ctup);
+ (*b) = sdesc->rs_cbuf;
+
+ HEAPDEBUG_7; /* heap_getnext returning tuple */
+
+ return (sdesc->rs_ctup);
}
/* ----------------
- * heap_fetch - retrive tuple with tid
+ * heap_fetch - retrive tuple with tid
*
- * Currently ignores LP_IVALID during processing!
+ * Currently ignores LP_IVALID during processing!
* ----------------
*/
HeapTuple
heap_fetch(Relation relation,
- TimeQual timeQual,
- ItemPointer tid,
- Buffer *b)
+ TimeQual timeQual,
+ ItemPointer tid,
+ Buffer * b)
{
- ItemId lp;
- Buffer buffer;
- PageHeader dp;
- HeapTuple tuple;
- OffsetNumber offnum;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_fetch);
- IncrHeapAccessStat(global_fetch);
-
- /*
- * Note: This is collosally expensive - does two system calls per
- * indexscan tuple fetch. Not good, and since we should be doing
- * page level locking by the scanner anyway, it is commented out.
- */
-
- /* RelationSetLockForTupleRead(relation, tid); */
-
- /* ----------------
- * get the buffer from the relation descriptor
- * Note that this does a buffer pin.
- * ----------------
- */
-
- buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
-
+ ItemId lp;
+ Buffer buffer;
+ PageHeader dp;
+ HeapTuple tuple;
+ OffsetNumber offnum;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_fetch);
+ IncrHeapAccessStat(global_fetch);
+
+ /*
+ * Note: This is collosally expensive - does two system calls per
+ * indexscan tuple fetch. Not good, and since we should be doing page
+ * level locking by the scanner anyway, it is commented out.
+ */
+
+ /* RelationSetLockForTupleRead(relation, tid); */
+
+ /* ----------------
+ * get the buffer from the relation descriptor
+ * Note that this does a buffer pin.
+ * ----------------
+ */
+
+ buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
+
#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(buffer)) {
- elog(WARN, "heap_fetch: %s relation: ReadBuffer(%lx) failed",
- &relation->rd_rel->relname, (long)tid);
- }
+ if (!BufferIsValid(buffer))
+ {
+ elog(WARN, "heap_fetch: %s relation: ReadBuffer(%lx) failed",
+ &relation->rd_rel->relname, (long) tid);
+ }
#endif
-
- /* ----------------
- * get the item line pointer corresponding to the requested tid
- * ----------------
- */
- dp = (PageHeader) BufferGetPage(buffer);
- offnum = ItemPointerGetOffsetNumber(tid);
- lp = PageGetItemId(dp, offnum);
-
- /* ----------------
- * more sanity checks
- * ----------------
- */
-
- Assert(ItemIdIsUsed(lp));
-
- /* ----------------
- * check time qualification of tid
- * ----------------
- */
-
- tuple = heap_tuple_satisfies(lp, relation, buffer, dp,
- timeQual, 0,(ScanKey)NULL);
-
- if (tuple == NULL)
+
+ /* ----------------
+ * get the item line pointer corresponding to the requested tid
+ * ----------------
+ */
+ dp = (PageHeader) BufferGetPage(buffer);
+ offnum = ItemPointerGetOffsetNumber(tid);
+ lp = PageGetItemId(dp, offnum);
+
+ /* ----------------
+ * more sanity checks
+ * ----------------
+ */
+
+ Assert(ItemIdIsUsed(lp));
+
+ /* ----------------
+ * check time qualification of tid
+ * ----------------
+ */
+
+ tuple = heap_tuple_satisfies(lp, relation, buffer, dp,
+ timeQual, 0, (ScanKey) NULL);
+
+ if (tuple == NULL)
{
- ReleaseBuffer(buffer);
- return (NULL);
+ ReleaseBuffer(buffer);
+ return (NULL);
}
-
- /* ----------------
- * all checks passed, now either return a copy of the tuple
- * or pin the buffer page and return a pointer, depending on
- * whether caller gave us a valid b.
- * ----------------
- */
-
- if (PointerIsValid(b)) {
- *b = buffer;
- } else {
- tuple = heap_copytuple(tuple);
- ReleaseBuffer(buffer);
- }
- return (tuple);
+
+ /* ----------------
+ * all checks passed, now either return a copy of the tuple
+ * or pin the buffer page and return a pointer, depending on
+ * whether caller gave us a valid b.
+ * ----------------
+ */
+
+ if (PointerIsValid(b))
+ {
+ *b = buffer;
+ }
+ else
+ {
+ tuple = heap_copytuple(tuple);
+ ReleaseBuffer(buffer);
+ }
+ return (tuple);
}
/* ----------------
- * heap_insert - insert tuple
+ * heap_insert - insert tuple
*
- * The assignment of t_min (and thus the others) should be
- * removed eventually.
+ * The assignment of t_min (and thus the others) should be
+ * removed eventually.
*
- * Currently places the tuple onto the last page. If there is no room,
- * it is placed on new pages. (Heap relations)
- * Note that concurrent inserts during a scan will probably have
- * unexpected results, though this will be fixed eventually.
+ * Currently places the tuple onto the last page. If there is no room,
+ * it is placed on new pages. (Heap relations)
+ * Note that concurrent inserts during a scan will probably have
+ * unexpected results, though this will be fixed eventually.
*
- * Fix to work with indexes.
+ * Fix to work with indexes.
* ----------------
*/
Oid
heap_insert(Relation relation, HeapTuple tup)
{
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_insert);
- IncrHeapAccessStat(global_insert);
-
- /* ----------------
- * set relation level write lock. If this is a "local" relation (not
- * visible to others), we don't need to set a write lock.
- * ----------------
- */
- if (!relation->rd_islocal)
- RelationSetLockForWrite(relation);
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_insert);
+ IncrHeapAccessStat(global_insert);
- /* ----------------
- * If the object id of this tuple has already been assigned, trust
- * the caller. There are a couple of ways this can happen. At initial
- * db creation, the backend program sets oids for tuples. When we
- * define an index, we set the oid. Finally, in the future, we may
- * allow users to set their own object ids in order to support a
- * persistent object store (objects need to contain pointers to one
- * another).
- * ----------------
- */
- if (!OidIsValid(tup->t_oid)) {
- tup->t_oid = newoid();
- LastOidProcessed = tup->t_oid;
- }
- else
- CheckMaxObjectId(tup->t_oid);
-
- TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin));
- tup->t_cmin = GetCurrentCommandId();
- StoreInvalidTransactionId(&(tup->t_xmax));
- tup->t_tmin = INVALID_ABSTIME;
- tup->t_tmax = CURRENT_ABSTIME;
-
- doinsert(relation, tup);
-
- if ( IsSystemRelationName(RelationGetRelationName(relation)->data)) {
- RelationUnsetLockForWrite(relation);
-
/* ----------------
- * invalidate caches (only works for system relations)
+ * set relation level write lock. If this is a "local" relation (not
+ * visible to others), we don't need to set a write lock.
* ----------------
*/
- SetRefreshWhenInvalidate(ImmediateInvalidation);
- RelationInvalidateHeapTuple(relation, tup);
- SetRefreshWhenInvalidate((bool)!ImmediateInvalidation);
- }
-
- return(tup->t_oid);
+ if (!relation->rd_islocal)
+ RelationSetLockForWrite(relation);
+
+ /* ----------------
+ * If the object id of this tuple has already been assigned, trust
+ * the caller. There are a couple of ways this can happen. At initial
+ * db creation, the backend program sets oids for tuples. When we
+ * define an index, we set the oid. Finally, in the future, we may
+ * allow users to set their own object ids in order to support a
+ * persistent object store (objects need to contain pointers to one
+ * another).
+ * ----------------
+ */
+ if (!OidIsValid(tup->t_oid))
+ {
+ tup->t_oid = newoid();
+ LastOidProcessed = tup->t_oid;
+ }
+ else
+ CheckMaxObjectId(tup->t_oid);
+
+ TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin));
+ tup->t_cmin = GetCurrentCommandId();
+ StoreInvalidTransactionId(&(tup->t_xmax));
+ tup->t_tmin = INVALID_ABSTIME;
+ tup->t_tmax = CURRENT_ABSTIME;
+
+ doinsert(relation, tup);
+
+ if (IsSystemRelationName(RelationGetRelationName(relation)->data))
+ {
+ RelationUnsetLockForWrite(relation);
+
+ /* ----------------
+ * invalidate caches (only works for system relations)
+ * ----------------
+ */
+ SetRefreshWhenInvalidate(ImmediateInvalidation);
+ RelationInvalidateHeapTuple(relation, tup);
+ SetRefreshWhenInvalidate((bool) ! ImmediateInvalidation);
+ }
+
+ return (tup->t_oid);
}
/* ----------------
- * heap_delete - delete a tuple
+ * heap_delete - delete a tuple
*
- * Must decide how to handle errors.
+ * Must decide how to handle errors.
* ----------------
*/
int
heap_delete(Relation relation, ItemPointer tid)
{
- ItemId lp;
- HeapTuple tp;
- PageHeader dp;
- Buffer b;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_delete);
- IncrHeapAccessStat(global_delete);
-
- /* ----------------
- * sanity check
- * ----------------
- */
- Assert(ItemPointerIsValid(tid));
-
- /* ----------------
- * set relation level write lock
- * ----------------
- */
- RelationSetLockForWrite(relation);
-
- b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
-
+ ItemId lp;
+ HeapTuple tp;
+ PageHeader dp;
+ Buffer b;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_delete);
+ IncrHeapAccessStat(global_delete);
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ Assert(ItemPointerIsValid(tid));
+
+ /* ----------------
+ * set relation level write lock
+ * ----------------
+ */
+ RelationSetLockForWrite(relation);
+
+ b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
+
#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(b)) { /* XXX L_SH better ??? */
- elog(WARN, "heap_delete: failed ReadBuffer");
- }
-#endif /* NO_BUFFERISVALID */
-
- dp = (PageHeader) BufferGetPage(b);
- lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
-
- /*
- * Just like test against non-functional updates we try to catch
- * non-functional delete attempts. - vadim 05/05/97
- */
- tp = (HeapTuple) PageGetItem((Page)dp, lp);
- Assert(HeapTupleIsValid(tp));
- if (TupleUpdatedByCurXactAndCmd(tp)) {
- elog(NOTICE, "Non-functional delete, tuple already deleted");
- if ( IsSystemRelationName(RelationGetRelationName(relation)->data) )
- RelationUnsetLockForWrite(relation);
- ReleaseBuffer(b);
- return (1);
- }
- /* ----------------
- * check that we're deleteing a valid item
- * ----------------
- */
- if (!(tp = heap_tuple_satisfies(lp, relation, b, dp,
- NowTimeQual, 0, (ScanKey) NULL))) {
-
- /* XXX call something else */
- ReleaseBuffer(b);
-
- elog(WARN, "heap_delete: (am)invalid tid");
- }
-
- /* ----------------
- * get the tuple and lock tell the buffer manager we want
- * exclusive access to the page
- * ----------------
- */
-
- /* ----------------
- * store transaction information of xact deleting the tuple
- * ----------------
- */
- TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax));
- tp->t_cmax = GetCurrentCommandId();
- ItemPointerSetInvalid(&tp->t_chain);
-
- /* ----------------
- * invalidate caches
- * ----------------
- */
- SetRefreshWhenInvalidate(ImmediateInvalidation);
- RelationInvalidateHeapTuple(relation, tp);
- SetRefreshWhenInvalidate((bool)!ImmediateInvalidation);
-
- WriteBuffer(b);
- if ( IsSystemRelationName(RelationGetRelationName(relation)->data) )
- RelationUnsetLockForWrite(relation);
-
- return(0);
+ if (!BufferIsValid(b))
+ { /* XXX L_SH better ??? */
+ elog(WARN, "heap_delete: failed ReadBuffer");
+ }
+#endif /* NO_BUFFERISVALID */
+
+ dp = (PageHeader) BufferGetPage(b);
+ lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));
+
+ /*
+ * Just like test against non-functional updates we try to catch
+ * non-functional delete attempts. - vadim 05/05/97
+ */
+ tp = (HeapTuple) PageGetItem((Page) dp, lp);
+ Assert(HeapTupleIsValid(tp));
+ if (TupleUpdatedByCurXactAndCmd(tp))
+ {
+ elog(NOTICE, "Non-functional delete, tuple already deleted");
+ if (IsSystemRelationName(RelationGetRelationName(relation)->data))
+ RelationUnsetLockForWrite(relation);
+ ReleaseBuffer(b);
+ return (1);
+ }
+ /* ----------------
+ * check that we're deleteing a valid item
+ * ----------------
+ */
+ if (!(tp = heap_tuple_satisfies(lp, relation, b, dp,
+ NowTimeQual, 0, (ScanKey) NULL)))
+ {
+
+ /* XXX call something else */
+ ReleaseBuffer(b);
+
+ elog(WARN, "heap_delete: (am)invalid tid");
+ }
+
+ /* ----------------
+ * get the tuple and lock tell the buffer manager we want
+ * exclusive access to the page
+ * ----------------
+ */
+
+ /* ----------------
+ * store transaction information of xact deleting the tuple
+ * ----------------
+ */
+ TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax));
+ tp->t_cmax = GetCurrentCommandId();
+ ItemPointerSetInvalid(&tp->t_chain);
+
+ /* ----------------
+ * invalidate caches
+ * ----------------
+ */
+ SetRefreshWhenInvalidate(ImmediateInvalidation);
+ RelationInvalidateHeapTuple(relation, tp);
+ SetRefreshWhenInvalidate((bool) ! ImmediateInvalidation);
+
+ WriteBuffer(b);
+ if (IsSystemRelationName(RelationGetRelationName(relation)->data))
+ RelationUnsetLockForWrite(relation);
+
+ return (0);
}
/* ----------------
- * heap_replace - replace a tuple
+ * heap_replace - replace a tuple
+ *
+ * Must decide how to handle errors.
*
- * Must decide how to handle errors.
+ * Fix arguments, work with indexes.
*
- * Fix arguments, work with indexes.
- *
- * 12/30/93 - modified the return value to be 1 when
- * a non-functional update is detected. This
- * prevents the calling routine from updating
- * indices unnecessarily. -kw
+ * 12/30/93 - modified the return value to be 1 when
+ * a non-functional update is detected. This
+ * prevents the calling routine from updating
+ * indices unnecessarily. -kw
*
* ----------------
*/
int
heap_replace(Relation relation, ItemPointer otid, HeapTuple tup)
{
- ItemId lp;
- HeapTuple tp;
- Page dp;
- Buffer buffer;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_replace);
- IncrHeapAccessStat(global_replace);
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(ItemPointerIsValid(otid));
-
- /* ----------------
- * set relation level write lock
- * ----------------
- */
- if (!relation->rd_islocal)
- RelationSetLockForWrite(relation);
-
- buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(otid));
+ ItemId lp;
+ HeapTuple tp;
+ Page dp;
+ Buffer buffer;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_replace);
+ IncrHeapAccessStat(global_replace);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(ItemPointerIsValid(otid));
+
+ /* ----------------
+ * set relation level write lock
+ * ----------------
+ */
+ if (!relation->rd_islocal)
+ RelationSetLockForWrite(relation);
+
+ buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(otid));
#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(buffer)) {
- /* XXX L_SH better ??? */
- elog(WARN, "amreplace: failed ReadBuffer");
- }
-#endif /* NO_BUFFERISVALID */
-
- dp = (Page) BufferGetPage(buffer);
- lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(otid));
-
- /* ----------------
- * logically delete old item
- * ----------------
- */
-
- tp = (HeapTuple) PageGetItem(dp, lp);
- Assert(HeapTupleIsValid(tp));
-
- /* -----------------
- * the following test should be able to catch all non-functional
- * update attempts and shut out all ghost tuples.
- * XXX In the future, Spyros may need to update the rule lock on a tuple
- * more than once within the same command and same transaction.
- * He will have to introduce a new flag to override the following check.
- * -- Wei
- *
- * -----------------
- */
-
- if (TupleUpdatedByCurXactAndCmd(tp)) {
- elog(NOTICE, "Non-functional update, only first update is performed");
- if ( IsSystemRelationName(RelationGetRelationName(relation)->data) )
- RelationUnsetLockForWrite(relation);
- ReleaseBuffer(buffer);
- return(1);
- }
-
- /* ----------------
- * check that we're replacing a valid item -
- *
- * NOTE that this check must follow the non-functional update test
- * above as it can happen that we try to 'replace' the same tuple
- * twice in a single transaction. The second time around the
- * tuple will fail the NowTimeQual. We don't want to abort the
- * xact, we only want to flag the 'non-functional' NOTICE. -mer
- * ----------------
- */
- if (!heap_tuple_satisfies(lp,
- relation,
- buffer,
- (PageHeader)dp,
- NowTimeQual,
- 0,
- (ScanKey)NULL))
- {
- ReleaseBuffer(buffer);
- elog(WARN, "heap_replace: (am)invalid otid");
- }
-
- /* XXX order problems if not atomic assignment ??? */
- tup->t_oid = tp->t_oid;
- TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin));
- tup->t_cmin = GetCurrentCommandId();
- StoreInvalidTransactionId(&(tup->t_xmax));
- tup->t_tmin = INVALID_ABSTIME;
- tup->t_tmax = CURRENT_ABSTIME;
- ItemPointerSetInvalid(&tup->t_chain);
-
- /* ----------------
- * insert new item
- * ----------------
- */
- if ((unsigned)DOUBLEALIGN(tup->t_len) <= PageGetFreeSpace((Page) dp)) {
- RelationPutHeapTuple(relation, BufferGetBlockNumber(buffer), tup);
- } else {
+ if (!BufferIsValid(buffer))
+ {
+ /* XXX L_SH better ??? */
+ elog(WARN, "amreplace: failed ReadBuffer");
+ }
+#endif /* NO_BUFFERISVALID */
+
+ dp = (Page) BufferGetPage(buffer);
+ lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(otid));
+
/* ----------------
- * new item won't fit on same page as old item, have to look
- * for a new place to put it.
+ * logically delete old item
* ----------------
*/
- doinsert(relation, tup);
- }
-
- /* ----------------
- * new item in place, now record transaction information
- * ----------------
- */
- TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax));
- tp->t_cmax = GetCurrentCommandId();
- tp->t_chain = tup->t_ctid;
-
- /* ----------------
- * invalidate caches
- * ----------------
- */
- SetRefreshWhenInvalidate(ImmediateInvalidation);
- RelationInvalidateHeapTuple(relation, tp);
- SetRefreshWhenInvalidate((bool)!ImmediateInvalidation);
-
- WriteBuffer(buffer);
-
- if ( IsSystemRelationName(RelationGetRelationName(relation)->data) )
- RelationUnsetLockForWrite(relation);
-
- return(0);
+
+ tp = (HeapTuple) PageGetItem(dp, lp);
+ Assert(HeapTupleIsValid(tp));
+
+ /* -----------------
+ * the following test should be able to catch all non-functional
+ * update attempts and shut out all ghost tuples.
+ * XXX In the future, Spyros may need to update the rule lock on a tuple
+ * more than once within the same command and same transaction.
+ * He will have to introduce a new flag to override the following check.
+ * -- Wei
+ *
+ * -----------------
+ */
+
+ if (TupleUpdatedByCurXactAndCmd(tp))
+ {
+ elog(NOTICE, "Non-functional update, only first update is performed");
+ if (IsSystemRelationName(RelationGetRelationName(relation)->data))
+ RelationUnsetLockForWrite(relation);
+ ReleaseBuffer(buffer);
+ return (1);
+ }
+
+ /* ----------------
+ * check that we're replacing a valid item -
+ *
+ * NOTE that this check must follow the non-functional update test
+ * above as it can happen that we try to 'replace' the same tuple
+ * twice in a single transaction. The second time around the
+ * tuple will fail the NowTimeQual. We don't want to abort the
+ * xact, we only want to flag the 'non-functional' NOTICE. -mer
+ * ----------------
+ */
+ if (!heap_tuple_satisfies(lp,
+ relation,
+ buffer,
+ (PageHeader) dp,
+ NowTimeQual,
+ 0,
+ (ScanKey) NULL))
+ {
+ ReleaseBuffer(buffer);
+ elog(WARN, "heap_replace: (am)invalid otid");
+ }
+
+ /* XXX order problems if not atomic assignment ??? */
+ tup->t_oid = tp->t_oid;
+ TransactionIdStore(GetCurrentTransactionId(), &(tup->t_xmin));
+ tup->t_cmin = GetCurrentCommandId();
+ StoreInvalidTransactionId(&(tup->t_xmax));
+ tup->t_tmin = INVALID_ABSTIME;
+ tup->t_tmax = CURRENT_ABSTIME;
+ ItemPointerSetInvalid(&tup->t_chain);
+
+ /* ----------------
+ * insert new item
+ * ----------------
+ */
+ if ((unsigned) DOUBLEALIGN(tup->t_len) <= PageGetFreeSpace((Page) dp))
+ {
+ RelationPutHeapTuple(relation, BufferGetBlockNumber(buffer), tup);
+ }
+ else
+ {
+ /* ----------------
+ * new item won't fit on same page as old item, have to look
+ * for a new place to put it.
+ * ----------------
+ */
+ doinsert(relation, tup);
+ }
+
+ /* ----------------
+ * new item in place, now record transaction information
+ * ----------------
+ */
+ TransactionIdStore(GetCurrentTransactionId(), &(tp->t_xmax));
+ tp->t_cmax = GetCurrentCommandId();
+ tp->t_chain = tup->t_ctid;
+
+ /* ----------------
+ * invalidate caches
+ * ----------------
+ */
+ SetRefreshWhenInvalidate(ImmediateInvalidation);
+ RelationInvalidateHeapTuple(relation, tp);
+ SetRefreshWhenInvalidate((bool) ! ImmediateInvalidation);
+
+ WriteBuffer(buffer);
+
+ if (IsSystemRelationName(RelationGetRelationName(relation)->data))
+ RelationUnsetLockForWrite(relation);
+
+ return (0);
}
/* ----------------
- * heap_markpos - mark scan position
+ * heap_markpos - mark scan position
*
- * Note:
- * Should only one mark be maintained per scan at one time.
- * Check if this can be done generally--say calls to get the
- * next/previous tuple and NEVER pass struct scandesc to the
- * user AM's. Now, the mark is sent to the executor for safekeeping.
- * Probably can store this info into a GENERAL scan structure.
+ * Note:
+ * Should only one mark be maintained per scan at one time.
+ * Check if this can be done generally--say calls to get the
+ * next/previous tuple and NEVER pass struct scandesc to the
+ * user AM's. Now, the mark is sent to the executor for safekeeping.
+ * Probably can store this info into a GENERAL scan structure.
*
- * May be best to change this call to store the marked position
- * (up to 2?) in the scan structure itself.
- * Fix to use the proper caching structure.
+ * May be best to change this call to store the marked position
+ * (up to 2?) in the scan structure itself.
+ * Fix to use the proper caching structure.
* ----------------
*/
void
heap_markpos(HeapScanDesc sdesc)
{
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_markpos);
- IncrHeapAccessStat(global_markpos);
-
- /* Note: no locking manipulations needed */
-
- if (sdesc->rs_ptup == NULL &&
- BufferIsUnknown(sdesc->rs_pbuf)) { /* == NONTUP */
- sdesc->rs_ptup = (HeapTuple)
- heapgettup(sdesc->rs_rd,
- (sdesc->rs_ctup == NULL) ?
- (ItemPointer)NULL : &sdesc->rs_ctup->t_ctid,
- -1,
- &sdesc->rs_pbuf,
- sdesc->rs_tr,
- sdesc->rs_nkeys,
- sdesc->rs_key);
-
- } else if (sdesc->rs_ntup == NULL &&
- BufferIsUnknown(sdesc->rs_nbuf)) { /* == NONTUP */
- sdesc->rs_ntup = (HeapTuple)
- heapgettup(sdesc->rs_rd,
- (sdesc->rs_ctup == NULL) ?
- (ItemPointer)NULL : &sdesc->rs_ctup->t_ctid,
- 1,
- &sdesc->rs_nbuf,
- sdesc->rs_tr,
- sdesc->rs_nkeys,
- sdesc->rs_key);
- }
-
- /* ----------------
- * Should not unpin the buffer pages. They may still be in use.
- * ----------------
- */
- if (sdesc->rs_ptup != NULL) {
- sdesc->rs_mptid = sdesc->rs_ptup->t_ctid;
- } else {
- ItemPointerSetInvalid(&sdesc->rs_mptid);
- }
- if (sdesc->rs_ctup != NULL) {
- sdesc->rs_mctid = sdesc->rs_ctup->t_ctid;
- } else {
- ItemPointerSetInvalid(&sdesc->rs_mctid);
- }
- if (sdesc->rs_ntup != NULL) {
- sdesc->rs_mntid = sdesc->rs_ntup->t_ctid;
- } else {
- ItemPointerSetInvalid(&sdesc->rs_mntid);
- }
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_markpos);
+ IncrHeapAccessStat(global_markpos);
+
+ /* Note: no locking manipulations needed */
+
+ if (sdesc->rs_ptup == NULL &&
+ BufferIsUnknown(sdesc->rs_pbuf))
+ { /* == NONTUP */
+ sdesc->rs_ptup = (HeapTuple)
+ heapgettup(sdesc->rs_rd,
+ (sdesc->rs_ctup == NULL) ?
+ (ItemPointer) NULL : &sdesc->rs_ctup->t_ctid,
+ -1,
+ &sdesc->rs_pbuf,
+ sdesc->rs_tr,
+ sdesc->rs_nkeys,
+ sdesc->rs_key);
+
+ }
+ else if (sdesc->rs_ntup == NULL &&
+ BufferIsUnknown(sdesc->rs_nbuf))
+ { /* == NONTUP */
+ sdesc->rs_ntup = (HeapTuple)
+ heapgettup(sdesc->rs_rd,
+ (sdesc->rs_ctup == NULL) ?
+ (ItemPointer) NULL : &sdesc->rs_ctup->t_ctid,
+ 1,
+ &sdesc->rs_nbuf,
+ sdesc->rs_tr,
+ sdesc->rs_nkeys,
+ sdesc->rs_key);
+ }
+
+ /* ----------------
+ * Should not unpin the buffer pages. They may still be in use.
+ * ----------------
+ */
+ if (sdesc->rs_ptup != NULL)
+ {
+ sdesc->rs_mptid = sdesc->rs_ptup->t_ctid;
+ }
+ else
+ {
+ ItemPointerSetInvalid(&sdesc->rs_mptid);
+ }
+ if (sdesc->rs_ctup != NULL)
+ {
+ sdesc->rs_mctid = sdesc->rs_ctup->t_ctid;
+ }
+ else
+ {
+ ItemPointerSetInvalid(&sdesc->rs_mctid);
+ }
+ if (sdesc->rs_ntup != NULL)
+ {
+ sdesc->rs_mntid = sdesc->rs_ntup->t_ctid;
+ }
+ else
+ {
+ ItemPointerSetInvalid(&sdesc->rs_mntid);
+ }
}
/* ----------------
- * heap_restrpos - restore position to marked location
+ * heap_restrpos - restore position to marked location
*
- * Note: there are bad side effects here. If we were past the end
- * of a relation when heapmarkpos is called, then if the relation is
- * extended via insert, then the next call to heaprestrpos will set
- * cause the added tuples to be visible when the scan continues.
- * Problems also arise if the TID's are rearranged!!!
+ * Note: there are bad side effects here. If we were past the end
+ * of a relation when heapmarkpos is called, then if the relation is
+ * extended via insert, then the next call to heaprestrpos will set
+ * cause the added tuples to be visible when the scan continues.
+ * Problems also arise if the TID's are rearranged!!!
*
- * Now pins buffer once for each valid tuple pointer (rs_ptup,
- * rs_ctup, rs_ntup) referencing it.
- * - 01/13/94
+ * Now pins buffer once for each valid tuple pointer (rs_ptup,
+ * rs_ctup, rs_ntup) referencing it.
+ * - 01/13/94
*
* XXX might be better to do direct access instead of
- * using the generality of heapgettup().
+ * using the generality of heapgettup().
*
* XXX It is very possible that when a scan is restored, that a tuple
* XXX which previously qualified may fail for time range purposes, unless
@@ -1455,60 +1561,69 @@ heap_markpos(HeapScanDesc sdesc)
void
heap_restrpos(HeapScanDesc sdesc)
{
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_restrpos);
- IncrHeapAccessStat(global_restrpos);
-
- /* XXX no amrestrpos checking that ammarkpos called */
-
- /* Note: no locking manipulations needed */
-
- unpinsdesc(sdesc);
-
- /* force heapgettup to pin buffer for each loaded tuple */
- sdesc->rs_pbuf = InvalidBuffer;
- sdesc->rs_cbuf = InvalidBuffer;
- sdesc->rs_nbuf = InvalidBuffer;
-
- if (!ItemPointerIsValid(&sdesc->rs_mptid)) {
- sdesc->rs_ptup = NULL;
- } else {
- sdesc->rs_ptup = (HeapTuple)
- heapgettup(sdesc->rs_rd,
- &sdesc->rs_mptid,
- 0,
- &sdesc->rs_pbuf,
- NowTimeQual,
- 0,
- (ScanKey) NULL);
- }
-
- if (!ItemPointerIsValid(&sdesc->rs_mctid)) {
- sdesc->rs_ctup = NULL;
- } else {
- sdesc->rs_ctup = (HeapTuple)
- heapgettup(sdesc->rs_rd,
- &sdesc->rs_mctid,
- 0,
- &sdesc->rs_cbuf,
- NowTimeQual,
- 0,
- (ScanKey) NULL);
- }
-
- if (!ItemPointerIsValid(&sdesc->rs_mntid)) {
- sdesc->rs_ntup = NULL;
- } else {
- sdesc->rs_ntup = (HeapTuple)
- heapgettup(sdesc->rs_rd,
- &sdesc->rs_mntid,
- 0,
- &sdesc->rs_nbuf,
- NowTimeQual,
- 0,
- (ScanKey) NULL);
- }
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_restrpos);
+ IncrHeapAccessStat(global_restrpos);
+
+ /* XXX no amrestrpos checking that ammarkpos called */
+
+ /* Note: no locking manipulations needed */
+
+ unpinsdesc(sdesc);
+
+ /* force heapgettup to pin buffer for each loaded tuple */
+ sdesc->rs_pbuf = InvalidBuffer;
+ sdesc->rs_cbuf = InvalidBuffer;
+ sdesc->rs_nbuf = InvalidBuffer;
+
+ if (!ItemPointerIsValid(&sdesc->rs_mptid))
+ {
+ sdesc->rs_ptup = NULL;
+ }
+ else
+ {
+ sdesc->rs_ptup = (HeapTuple)
+ heapgettup(sdesc->rs_rd,
+ &sdesc->rs_mptid,
+ 0,
+ &sdesc->rs_pbuf,
+ NowTimeQual,
+ 0,
+ (ScanKey) NULL);
+ }
+
+ if (!ItemPointerIsValid(&sdesc->rs_mctid))
+ {
+ sdesc->rs_ctup = NULL;
+ }
+ else
+ {
+ sdesc->rs_ctup = (HeapTuple)
+ heapgettup(sdesc->rs_rd,
+ &sdesc->rs_mctid,
+ 0,
+ &sdesc->rs_cbuf,
+ NowTimeQual,
+ 0,
+ (ScanKey) NULL);
+ }
+
+ if (!ItemPointerIsValid(&sdesc->rs_mntid))
+ {
+ sdesc->rs_ntup = NULL;
+ }
+ else
+ {
+ sdesc->rs_ntup = (HeapTuple)
+ heapgettup(sdesc->rs_rd,
+ &sdesc->rs_mntid,
+ 0,
+ &sdesc->rs_nbuf,
+ NowTimeQual,
+ 0,
+ (ScanKey) NULL);
+ }
}
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index f172a404708..0854b69bf0b 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* hio.c--
- * POSTGRES heap access method input/output code.
+ * POSTGRES heap access method input/output code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Id: hio.c,v 1.9 1996/11/05 09:53:02 scrappy Exp $
+ * $Id: hio.c,v 1.10 1997/09/07 04:38:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,64 +21,65 @@
/*
* amputunique - place tuple at tid
- * Currently on errors, calls elog. Perhaps should return -1?
- * Possible errors include the addition of a tuple to the page
- * between the time the linep is chosen and the page is L_UP'd.
+ * Currently on errors, calls elog. Perhaps should return -1?
+ * Possible errors include the addition of a tuple to the page
+ * between the time the linep is chosen and the page is L_UP'd.
*
- * This should be coordinated with the B-tree code.
- * Probably needs to have an amdelunique to allow for
- * internal index records to be deleted and reordered as needed.
- * For the heap AM, this should never be needed.
+ * This should be coordinated with the B-tree code.
+ * Probably needs to have an amdelunique to allow for
+ * internal index records to be deleted and reordered as needed.
+ * For the heap AM, this should never be needed.
*/
void
RelationPutHeapTuple(Relation relation,
- BlockNumber blockIndex,
- HeapTuple tuple)
+ BlockNumber blockIndex,
+ HeapTuple tuple)
{
- Buffer buffer;
- Page pageHeader;
- BlockNumber numberOfBlocks;
- OffsetNumber offnum;
- unsigned int len;
- ItemId itemId;
- Item item;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_RelationPutHeapTuple);
- IncrHeapAccessStat(global_RelationPutHeapTuple);
-
- Assert(RelationIsValid(relation));
- Assert(HeapTupleIsValid(tuple));
-
- numberOfBlocks = RelationGetNumberOfBlocks(relation);
- Assert(blockIndex < numberOfBlocks);
-
- buffer = ReadBuffer(relation, blockIndex);
+ Buffer buffer;
+ Page pageHeader;
+ BlockNumber numberOfBlocks;
+ OffsetNumber offnum;
+ unsigned int len;
+ ItemId itemId;
+ Item item;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_RelationPutHeapTuple);
+ IncrHeapAccessStat(global_RelationPutHeapTuple);
+
+ Assert(RelationIsValid(relation));
+ Assert(HeapTupleIsValid(tuple));
+
+ numberOfBlocks = RelationGetNumberOfBlocks(relation);
+ Assert(blockIndex < numberOfBlocks);
+
+ buffer = ReadBuffer(relation, blockIndex);
#ifndef NO_BUFFERISVALID
- if (!BufferIsValid(buffer)) {
- elog(WARN, "RelationPutHeapTuple: no buffer for %ld in %s",
- blockIndex, &relation->rd_rel->relname);
- }
+ if (!BufferIsValid(buffer))
+ {
+ elog(WARN, "RelationPutHeapTuple: no buffer for %ld in %s",
+ blockIndex, &relation->rd_rel->relname);
+ }
#endif
-
- pageHeader = (Page)BufferGetPage(buffer);
- len = (unsigned)DOUBLEALIGN(tuple->t_len); /* be conservative */
- Assert((int)len <= PageGetFreeSpace(pageHeader));
-
- offnum = PageAddItem((Page)pageHeader, (Item)tuple,
- tuple->t_len, InvalidOffsetNumber, LP_USED);
-
- itemId = PageGetItemId((Page)pageHeader, offnum);
- item = PageGetItem((Page)pageHeader, itemId);
-
- ItemPointerSet(&((HeapTuple)item)->t_ctid, blockIndex, offnum);
-
- WriteBuffer(buffer);
- /* return an accurate tuple */
- ItemPointerSet(&tuple->t_ctid, blockIndex, offnum);
+
+ pageHeader = (Page) BufferGetPage(buffer);
+ len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */
+ Assert((int) len <= PageGetFreeSpace(pageHeader));
+
+ offnum = PageAddItem((Page) pageHeader, (Item) tuple,
+ tuple->t_len, InvalidOffsetNumber, LP_USED);
+
+ itemId = PageGetItemId((Page) pageHeader, offnum);
+ item = PageGetItem((Page) pageHeader, itemId);
+
+ ItemPointerSet(&((HeapTuple) item)->t_ctid, blockIndex, offnum);
+
+ WriteBuffer(buffer);
+ /* return an accurate tuple */
+ ItemPointerSet(&tuple->t_ctid, blockIndex, offnum);
}
/*
@@ -91,7 +92,7 @@ RelationPutHeapTuple(Relation relation,
* Eventually, we should cache the number of blocks in a relation somewhere.
* Until that time, this code will have to do an lseek to determine the number
* of blocks in a relation.
- *
+ *
* This code should ideally do at most 4 semops, 1 lseek, and possibly 1 write
* to do an append; it's possible to eliminate 2 of the semops if we do direct
* buffer stuff (!); the lseek and the write can go if we get
@@ -107,70 +108,70 @@ RelationPutHeapTuple(Relation relation,
void
RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple)
{
- Buffer buffer;
- Page pageHeader;
- BlockNumber lastblock;
- OffsetNumber offnum;
- unsigned int len;
- ItemId itemId;
- Item item;
-
- Assert(RelationIsValid(relation));
- Assert(HeapTupleIsValid(tuple));
-
- /*
- * XXX This does an lseek - VERY expensive - but at the moment it
- * is the only way to accurately determine how many blocks are in
- * a relation. A good optimization would be to get this to actually
- * work properly.
- */
-
- lastblock = RelationGetNumberOfBlocks(relation);
-
- if (lastblock == 0)
+ Buffer buffer;
+ Page pageHeader;
+ BlockNumber lastblock;
+ OffsetNumber offnum;
+ unsigned int len;
+ ItemId itemId;
+ Item item;
+
+ Assert(RelationIsValid(relation));
+ Assert(HeapTupleIsValid(tuple));
+
+ /*
+ * XXX This does an lseek - VERY expensive - but at the moment it is
+ * the only way to accurately determine how many blocks are in a
+ * relation. A good optimization would be to get this to actually
+ * work properly.
+ */
+
+ lastblock = RelationGetNumberOfBlocks(relation);
+
+ if (lastblock == 0)
{
- buffer = ReadBuffer(relation, lastblock);
- pageHeader = (Page)BufferGetPage(buffer);
- if (PageIsNew((PageHeader) pageHeader))
+ buffer = ReadBuffer(relation, lastblock);
+ pageHeader = (Page) BufferGetPage(buffer);
+ if (PageIsNew((PageHeader) pageHeader))
{
- buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
- pageHeader = (Page)BufferGetPage(buffer);
- PageInit(pageHeader, BufferGetPageSize(buffer), 0);
+ buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
+ pageHeader = (Page) BufferGetPage(buffer);
+ PageInit(pageHeader, BufferGetPageSize(buffer), 0);
}
}
- else
- buffer = ReadBuffer(relation, lastblock - 1);
-
- pageHeader = (Page)BufferGetPage(buffer);
- len = (unsigned)DOUBLEALIGN(tuple->t_len); /* be conservative */
-
- /*
- * Note that this is true if the above returned a bogus page, which
- * it will do for a completely empty relation.
- */
-
- if (len > PageGetFreeSpace(pageHeader))
+ else
+ buffer = ReadBuffer(relation, lastblock - 1);
+
+ pageHeader = (Page) BufferGetPage(buffer);
+ len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */
+
+ /*
+ * Note that this is true if the above returned a bogus page, which it
+ * will do for a completely empty relation.
+ */
+
+ if (len > PageGetFreeSpace(pageHeader))
{
- buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
- pageHeader = (Page)BufferGetPage(buffer);
- PageInit(pageHeader, BufferGetPageSize(buffer), 0);
-
- if (len > PageGetFreeSpace(pageHeader))
- elog(WARN, "Tuple is too big: size %d", len);
+ buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW);
+ pageHeader = (Page) BufferGetPage(buffer);
+ PageInit(pageHeader, BufferGetPageSize(buffer), 0);
+
+ if (len > PageGetFreeSpace(pageHeader))
+ elog(WARN, "Tuple is too big: size %d", len);
}
-
- offnum = PageAddItem((Page)pageHeader, (Item)tuple,
- tuple->t_len, InvalidOffsetNumber, LP_USED);
-
- itemId = PageGetItemId((Page)pageHeader, offnum);
- item = PageGetItem((Page)pageHeader, itemId);
-
- lastblock = BufferGetBlockNumber(buffer);
-
- ItemPointerSet(&((HeapTuple)item)->t_ctid, lastblock, offnum);
-
- /* return an accurate tuple */
- ItemPointerSet(&tuple->t_ctid, lastblock, offnum);
-
- WriteBuffer(buffer);
+
+ offnum = PageAddItem((Page) pageHeader, (Item) tuple,
+ tuple->t_len, InvalidOffsetNumber, LP_USED);
+
+ itemId = PageGetItemId((Page) pageHeader, offnum);
+ item = PageGetItem((Page) pageHeader, itemId);
+
+ lastblock = BufferGetBlockNumber(buffer);
+
+ ItemPointerSet(&((HeapTuple) item)->t_ctid, lastblock, offnum);
+
+ /* return an accurate tuple */
+ ItemPointerSet(&tuple->t_ctid, lastblock, offnum);
+
+ WriteBuffer(buffer);
}
diff --git a/src/backend/access/heap/stats.c b/src/backend/access/heap/stats.c
index ae8273ac81c..aa16803779c 100644
--- a/src/backend/access/heap/stats.c
+++ b/src/backend/access/heap/stats.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* stats.c--
- * heap access method debugging statistic collection routines
+ * heap access method debugging statistic collection routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.11 1997/08/19 21:29:21 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.12 1997/09/07 04:38:13 momjian Exp $
*
* NOTES
- * initam should be moved someplace else.
+ * initam should be moved someplace else.
*
*-------------------------------------------------------------------------
*/
@@ -23,322 +23,327 @@
#include <utils/mcxt.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static void InitHeapAccessStatistics(void);
+static void InitHeapAccessStatistics(void);
/* ----------------
- * InitHeapAccessStatistics
+ * InitHeapAccessStatistics
* ----------------
*/
HeapAccessStatistics heap_access_stats = (HeapAccessStatistics) NULL;
-
+
static void
-InitHeapAccessStatistics()
+InitHeapAccessStatistics()
{
- MemoryContext oldContext;
- HeapAccessStatistics stats;
-
- /* ----------------
- * make sure we don't initialize things twice
- * ----------------
- */
- if (heap_access_stats != NULL)
- return;
-
- /* ----------------
- * allocate statistics structure from the top memory context
- * ----------------
- */
- oldContext = MemoryContextSwitchTo(TopMemoryContext);
-
- stats = (HeapAccessStatistics)
- palloc(sizeof(HeapAccessStatisticsData));
-
- /* ----------------
- * initialize fields to default values
- * ----------------
- */
- stats->global_open = 0;
- stats->global_openr = 0;
- stats->global_close = 0;
- stats->global_beginscan = 0;
- stats->global_rescan = 0;
- stats->global_endscan = 0;
- stats->global_getnext = 0;
- stats->global_fetch = 0;
- stats->global_insert = 0;
- stats->global_delete = 0;
- stats->global_replace = 0;
- stats->global_markpos = 0;
- stats->global_restrpos = 0;
- stats->global_BufferGetRelation = 0;
- stats->global_RelationIdGetRelation = 0;
- stats->global_RelationIdGetRelation_Buf = 0;
- stats->global_getreldesc = 0;
- stats->global_heapgettup = 0;
- stats->global_RelationPutHeapTuple = 0;
- stats->global_RelationPutLongHeapTuple = 0;
-
- stats->local_open = 0;
- stats->local_openr = 0;
- stats->local_close = 0;
- stats->local_beginscan = 0;
- stats->local_rescan = 0;
- stats->local_endscan = 0;
- stats->local_getnext = 0;
- stats->local_fetch = 0;
- stats->local_insert = 0;
- stats->local_delete = 0;
- stats->local_replace = 0;
- stats->local_markpos = 0;
- stats->local_restrpos = 0;
- stats->local_BufferGetRelation = 0;
- stats->local_RelationIdGetRelation = 0;
- stats->local_RelationIdGetRelation_Buf = 0;
- stats->local_getreldesc = 0;
- stats->local_heapgettup = 0;
- stats->local_RelationPutHeapTuple = 0;
- stats->local_RelationPutLongHeapTuple = 0;
- stats->local_RelationNameGetRelation = 0;
- stats->global_RelationNameGetRelation = 0;
-
- /* ----------------
- * record init times
- * ----------------
- */
- time(&stats->init_global_timestamp);
- time(&stats->local_reset_timestamp);
- time(&stats->last_request_timestamp);
-
- /* ----------------
- * return to old memory context
- * ----------------
- */
- MemoryContextSwitchTo(oldContext);
-
- heap_access_stats = stats;
+ MemoryContext oldContext;
+ HeapAccessStatistics stats;
+
+ /* ----------------
+ * make sure we don't initialize things twice
+ * ----------------
+ */
+ if (heap_access_stats != NULL)
+ return;
+
+ /* ----------------
+ * allocate statistics structure from the top memory context
+ * ----------------
+ */
+ oldContext = MemoryContextSwitchTo(TopMemoryContext);
+
+ stats = (HeapAccessStatistics)
+ palloc(sizeof(HeapAccessStatisticsData));
+
+ /* ----------------
+ * initialize fields to default values
+ * ----------------
+ */
+ stats->global_open = 0;
+ stats->global_openr = 0;
+ stats->global_close = 0;
+ stats->global_beginscan = 0;
+ stats->global_rescan = 0;
+ stats->global_endscan = 0;
+ stats->global_getnext = 0;
+ stats->global_fetch = 0;
+ stats->global_insert = 0;
+ stats->global_delete = 0;
+ stats->global_replace = 0;
+ stats->global_markpos = 0;
+ stats->global_restrpos = 0;
+ stats->global_BufferGetRelation = 0;
+ stats->global_RelationIdGetRelation = 0;
+ stats->global_RelationIdGetRelation_Buf = 0;
+ stats->global_getreldesc = 0;
+ stats->global_heapgettup = 0;
+ stats->global_RelationPutHeapTuple = 0;
+ stats->global_RelationPutLongHeapTuple = 0;
+
+ stats->local_open = 0;
+ stats->local_openr = 0;
+ stats->local_close = 0;
+ stats->local_beginscan = 0;
+ stats->local_rescan = 0;
+ stats->local_endscan = 0;
+ stats->local_getnext = 0;
+ stats->local_fetch = 0;
+ stats->local_insert = 0;
+ stats->local_delete = 0;
+ stats->local_replace = 0;
+ stats->local_markpos = 0;
+ stats->local_restrpos = 0;
+ stats->local_BufferGetRelation = 0;
+ stats->local_RelationIdGetRelation = 0;
+ stats->local_RelationIdGetRelation_Buf = 0;
+ stats->local_getreldesc = 0;
+ stats->local_heapgettup = 0;
+ stats->local_RelationPutHeapTuple = 0;
+ stats->local_RelationPutLongHeapTuple = 0;
+ stats->local_RelationNameGetRelation = 0;
+ stats->global_RelationNameGetRelation = 0;
+
+ /* ----------------
+ * record init times
+ * ----------------
+ */
+ time(&stats->init_global_timestamp);
+ time(&stats->local_reset_timestamp);
+ time(&stats->last_request_timestamp);
+
+ /* ----------------
+ * return to old memory context
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldContext);
+
+ heap_access_stats = stats;
}
#ifdef NOT_USED
/* ----------------
- * ResetHeapAccessStatistics
+ * ResetHeapAccessStatistics
* ----------------
*/
void
-ResetHeapAccessStatistics()
+ResetHeapAccessStatistics()
{
- HeapAccessStatistics stats;
-
- /* ----------------
- * do nothing if stats aren't initialized
- * ----------------
- */
- if (heap_access_stats == NULL)
- return;
-
- stats = heap_access_stats;
-
- /* ----------------
- * reset local counts
- * ----------------
- */
- stats->local_open = 0;
- stats->local_openr = 0;
- stats->local_close = 0;
- stats->local_beginscan = 0;
- stats->local_rescan = 0;
- stats->local_endscan = 0;
- stats->local_getnext = 0;
- stats->local_fetch = 0;
- stats->local_insert = 0;
- stats->local_delete = 0;
- stats->local_replace = 0;
- stats->local_markpos = 0;
- stats->local_restrpos = 0;
- stats->local_BufferGetRelation = 0;
- stats->local_RelationIdGetRelation = 0;
- stats->local_RelationIdGetRelation_Buf = 0;
- stats->local_getreldesc = 0;
- stats->local_heapgettup = 0;
- stats->local_RelationPutHeapTuple = 0;
- stats->local_RelationPutLongHeapTuple = 0;
-
- /* ----------------
- * reset local timestamps
- * ----------------
- */
- time(&stats->local_reset_timestamp);
- time(&stats->last_request_timestamp);
+ HeapAccessStatistics stats;
+
+ /* ----------------
+ * do nothing if stats aren't initialized
+ * ----------------
+ */
+ if (heap_access_stats == NULL)
+ return;
+
+ stats = heap_access_stats;
+
+ /* ----------------
+ * reset local counts
+ * ----------------
+ */
+ stats->local_open = 0;
+ stats->local_openr = 0;
+ stats->local_close = 0;
+ stats->local_beginscan = 0;
+ stats->local_rescan = 0;
+ stats->local_endscan = 0;
+ stats->local_getnext = 0;
+ stats->local_fetch = 0;
+ stats->local_insert = 0;
+ stats->local_delete = 0;
+ stats->local_replace = 0;
+ stats->local_markpos = 0;
+ stats->local_restrpos = 0;
+ stats->local_BufferGetRelation = 0;
+ stats->local_RelationIdGetRelation = 0;
+ stats->local_RelationIdGetRelation_Buf = 0;
+ stats->local_getreldesc = 0;
+ stats->local_heapgettup = 0;
+ stats->local_RelationPutHeapTuple = 0;
+ stats->local_RelationPutLongHeapTuple = 0;
+
+ /* ----------------
+ * reset local timestamps
+ * ----------------
+ */
+ time(&stats->local_reset_timestamp);
+ time(&stats->last_request_timestamp);
}
+
#endif
#ifdef NOT_USED
/* ----------------
- * GetHeapAccessStatistics
+ * GetHeapAccessStatistics
* ----------------
*/
-HeapAccessStatistics GetHeapAccessStatistics()
+HeapAccessStatistics
+GetHeapAccessStatistics()
{
- HeapAccessStatistics stats;
-
- /* ----------------
- * return nothing if stats aren't initialized
- * ----------------
- */
- if (heap_access_stats == NULL)
- return NULL;
-
- /* ----------------
- * record the current request time
- * ----------------
- */
- time(&heap_access_stats->last_request_timestamp);
-
- /* ----------------
- * allocate a copy of the stats and return it to the caller.
- * ----------------
- */
- stats = (HeapAccessStatistics)
- palloc(sizeof(HeapAccessStatisticsData));
-
- memmove(stats,
- heap_access_stats,
- sizeof(HeapAccessStatisticsData));
-
- return stats;
+ HeapAccessStatistics stats;
+
+ /* ----------------
+ * return nothing if stats aren't initialized
+ * ----------------
+ */
+ if (heap_access_stats == NULL)
+ return NULL;
+
+ /* ----------------
+ * record the current request time
+ * ----------------
+ */
+ time(&heap_access_stats->last_request_timestamp);
+
+ /* ----------------
+ * allocate a copy of the stats and return it to the caller.
+ * ----------------
+ */
+ stats = (HeapAccessStatistics)
+ palloc(sizeof(HeapAccessStatisticsData));
+
+ memmove(stats,
+ heap_access_stats,
+ sizeof(HeapAccessStatisticsData));
+
+ return stats;
}
+
#endif
#ifdef NOT_USED
/* ----------------
- * PrintHeapAccessStatistics
+ * PrintHeapAccessStatistics
* ----------------
*/
void
PrintHeapAccessStatistics(HeapAccessStatistics stats)
{
- /* ----------------
- * return nothing if stats aren't valid
- * ----------------
- */
- if (stats == NULL)
- return;
-
- printf("======== heap am statistics ========\n");
- printf("init_global_timestamp: %s",
- ctime(&(stats->init_global_timestamp)));
-
- printf("local_reset_timestamp: %s",
- ctime(&(stats->local_reset_timestamp)));
-
- printf("last_request_timestamp: %s",
- ctime(&(stats->last_request_timestamp)));
-
- printf("local/global_open: %6d/%6d\n",
- stats->local_open, stats->global_open);
-
- printf("local/global_openr: %6d/%6d\n",
- stats->local_openr, stats->global_openr);
-
- printf("local/global_close: %6d/%6d\n",
- stats->local_close, stats->global_close);
-
- printf("local/global_beginscan: %6d/%6d\n",
- stats->local_beginscan, stats->global_beginscan);
-
- printf("local/global_rescan: %6d/%6d\n",
- stats->local_rescan, stats->global_rescan);
-
- printf("local/global_endscan: %6d/%6d\n",
- stats->local_endscan, stats->global_endscan);
-
- printf("local/global_getnext: %6d/%6d\n",
- stats->local_getnext, stats->global_getnext);
-
- printf("local/global_fetch: %6d/%6d\n",
- stats->local_fetch, stats->global_fetch);
-
- printf("local/global_insert: %6d/%6d\n",
- stats->local_insert, stats->global_insert);
-
- printf("local/global_delete: %6d/%6d\n",
- stats->local_delete, stats->global_delete);
-
- printf("local/global_replace: %6d/%6d\n",
- stats->local_replace, stats->global_replace);
-
- printf("local/global_markpos: %6d/%6d\n",
- stats->local_markpos, stats->global_markpos);
-
- printf("local/global_restrpos: %6d/%6d\n",
- stats->local_restrpos, stats->global_restrpos);
-
- printf("================\n");
-
- printf("local/global_BufferGetRelation: %6d/%6d\n",
- stats->local_BufferGetRelation,
- stats->global_BufferGetRelation);
-
- printf("local/global_RelationIdGetRelation: %6d/%6d\n",
- stats->local_RelationIdGetRelation,
- stats->global_RelationIdGetRelation);
-
- printf("local/global_RelationIdGetRelation_Buf: %6d/%6d\n",
- stats->local_RelationIdGetRelation_Buf,
- stats->global_RelationIdGetRelation_Buf);
-
- printf("local/global_getreldesc: %6d/%6d\n",
- stats->local_getreldesc, stats->global_getreldesc);
-
- printf("local/global_heapgettup: %6d/%6d\n",
- stats->local_heapgettup, stats->global_heapgettup);
-
- printf("local/global_RelationPutHeapTuple: %6d/%6d\n",
- stats->local_RelationPutHeapTuple,
- stats->global_RelationPutHeapTuple);
-
- printf("local/global_RelationPutLongHeapTuple: %6d/%6d\n",
- stats->local_RelationPutLongHeapTuple,
- stats->global_RelationPutLongHeapTuple);
-
- printf("===================================\n");
-
- printf("\n");
+ /* ----------------
+ * return nothing if stats aren't valid
+ * ----------------
+ */
+ if (stats == NULL)
+ return;
+
+ printf("======== heap am statistics ========\n");
+ printf("init_global_timestamp: %s",
+ ctime(&(stats->init_global_timestamp)));
+
+ printf("local_reset_timestamp: %s",
+ ctime(&(stats->local_reset_timestamp)));
+
+ printf("last_request_timestamp: %s",
+ ctime(&(stats->last_request_timestamp)));
+
+ printf("local/global_open: %6d/%6d\n",
+ stats->local_open, stats->global_open);
+
+ printf("local/global_openr: %6d/%6d\n",
+ stats->local_openr, stats->global_openr);
+
+ printf("local/global_close: %6d/%6d\n",
+ stats->local_close, stats->global_close);
+
+ printf("local/global_beginscan: %6d/%6d\n",
+ stats->local_beginscan, stats->global_beginscan);
+
+ printf("local/global_rescan: %6d/%6d\n",
+ stats->local_rescan, stats->global_rescan);
+
+ printf("local/global_endscan: %6d/%6d\n",
+ stats->local_endscan, stats->global_endscan);
+
+ printf("local/global_getnext: %6d/%6d\n",
+ stats->local_getnext, stats->global_getnext);
+
+ printf("local/global_fetch: %6d/%6d\n",
+ stats->local_fetch, stats->global_fetch);
+
+ printf("local/global_insert: %6d/%6d\n",
+ stats->local_insert, stats->global_insert);
+
+ printf("local/global_delete: %6d/%6d\n",
+ stats->local_delete, stats->global_delete);
+
+ printf("local/global_replace: %6d/%6d\n",
+ stats->local_replace, stats->global_replace);
+
+ printf("local/global_markpos: %6d/%6d\n",
+ stats->local_markpos, stats->global_markpos);
+
+ printf("local/global_restrpos: %6d/%6d\n",
+ stats->local_restrpos, stats->global_restrpos);
+
+ printf("================\n");
+
+ printf("local/global_BufferGetRelation: %6d/%6d\n",
+ stats->local_BufferGetRelation,
+ stats->global_BufferGetRelation);
+
+ printf("local/global_RelationIdGetRelation: %6d/%6d\n",
+ stats->local_RelationIdGetRelation,
+ stats->global_RelationIdGetRelation);
+
+ printf("local/global_RelationIdGetRelation_Buf: %6d/%6d\n",
+ stats->local_RelationIdGetRelation_Buf,
+ stats->global_RelationIdGetRelation_Buf);
+
+ printf("local/global_getreldesc: %6d/%6d\n",
+ stats->local_getreldesc, stats->global_getreldesc);
+
+ printf("local/global_heapgettup: %6d/%6d\n",
+ stats->local_heapgettup, stats->global_heapgettup);
+
+ printf("local/global_RelationPutHeapTuple: %6d/%6d\n",
+ stats->local_RelationPutHeapTuple,
+ stats->global_RelationPutHeapTuple);
+
+ printf("local/global_RelationPutLongHeapTuple: %6d/%6d\n",
+ stats->local_RelationPutLongHeapTuple,
+ stats->global_RelationPutLongHeapTuple);
+
+ printf("===================================\n");
+
+ printf("\n");
}
+
#endif
#ifdef NOT_USED
/* ----------------
- * PrintAndFreeHeapAccessStatistics
+ * PrintAndFreeHeapAccessStatistics
* ----------------
*/
void
PrintAndFreeHeapAccessStatistics(HeapAccessStatistics stats)
{
- PrintHeapAccessStatistics(stats);
- if (stats != NULL)
- pfree(stats);
+ PrintHeapAccessStatistics(stats);
+ if (stats != NULL)
+ pfree(stats);
}
+
#endif
/* ----------------------------------------------------------------
- * access method initialization
+ * access method initialization
* ----------------------------------------------------------------
*/
/* ----------------
- * initam should someday be moved someplace else.
+ * initam should someday be moved someplace else.
* ----------------
*/
void
initam(void)
{
- /* ----------------
- * initialize heap statistics.
- * ----------------
- */
- InitHeapAccessStatistics();
+ /* ----------------
+ * initialize heap statistics.
+ * ----------------
+ */
+ InitHeapAccessStatistics();
}
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 52b7b1473bf..da7fc0dc09f 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* genam.c--
- * general index access method routines
+ * general index access method routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.7 1997/08/19 21:29:26 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.8 1997/09/07 04:38:17 momjian Exp $
*
* NOTES
- * many of the old access method routines have been turned into
- * macros and moved to genam.h -cim 4/30/91
+ * many of the old access method routines have been turned into
+ * macros and moved to genam.h -cim 4/30/91
*
*-------------------------------------------------------------------------
*/
@@ -29,18 +29,18 @@
* previous, current, next. Note that the case of reverse scans works
* identically.
*
- * State Result
- * (1) + + - + 0 0 (if the next item pointer is invalid)
- * (2) + X - (otherwise)
- * (3) * 0 0 * 0 0 (no change)
- * (4) + X 0 X 0 0 (shift)
- * (5) * + X + X - (shift, add unknown)
+ * State Result
+ * (1) + + - + 0 0 (if the next item pointer is invalid)
+ * (2) + X - (otherwise)
+ * (3) * 0 0 * 0 0 (no change)
+ * (4) + X 0 X 0 0 (shift)
+ * (5) * + X + X - (shift, add unknown)
*
* All other states cannot occur.
*
* Note:
*It would be possible to cache the status of the previous and
- * next item pointer using the flags.
+ * next item pointer using the flags.
* ----------------------------------------------------------------
*/
@@ -51,220 +51,234 @@
#include <storage/bufmgr.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/* ----------------------------------------------------------------
- * general access method routines
+ * general access method routines
*
- * All indexed access methods use an identical scan structure.
- * We don't know how the various AMs do locking, however, so we don't
- * do anything about that here.
+ * All indexed access methods use an identical scan structure.
+ * We don't know how the various AMs do locking, however, so we don't
+ * do anything about that here.
*
- * The intent is that an AM implementor will define a front-end routine
- * that calls this one, to fill in the scan, and then does whatever kind
- * of locking he wants.
+ * The intent is that an AM implementor will define a front-end routine
+ * that calls this one, to fill in the scan, and then does whatever kind
+ * of locking he wants.
* ----------------------------------------------------------------
*/
/* ----------------
- * RelationGetIndexScan -- Create and fill an IndexScanDesc.
+ * RelationGetIndexScan -- Create and fill an IndexScanDesc.
*
- * This routine creates an index scan structure and sets its contents
- * up correctly. This routine calls AMrescan to set up the scan with
- * the passed key.
+ * This routine creates an index scan structure and sets its contents
+ * up correctly. This routine calls AMrescan to set up the scan with
+ * the passed key.
*
- * Parameters:
- * relation -- index relation for scan.
- * scanFromEnd -- if true, begin scan at one of the index's
- * endpoints.
- * numberOfKeys -- count of scan keys (more than one won't
- * necessarily do anything useful, yet).
- * key -- the ScanKey for the starting position of the scan.
+ * Parameters:
+ * relation -- index relation for scan.
+ * scanFromEnd -- if true, begin scan at one of the index's
+ * endpoints.
+ * numberOfKeys -- count of scan keys (more than one won't
+ * necessarily do anything useful, yet).
+ * key -- the ScanKey for the starting position of the scan.
*
- * Returns:
- * An initialized IndexScanDesc.
+ * Returns:
+ * An initialized IndexScanDesc.
+ *
+ * Side Effects:
+ * Bumps the ref count on the relation to keep it in the cache.
*
- * Side Effects:
- * Bumps the ref count on the relation to keep it in the cache.
- *
* ----------------
*/
IndexScanDesc
RelationGetIndexScan(Relation relation,
- bool scanFromEnd,
- uint16 numberOfKeys,
- ScanKey key)
+ bool scanFromEnd,
+ uint16 numberOfKeys,
+ ScanKey key)
{
- IndexScanDesc scan;
-
- if (! RelationIsValid(relation))
- elog(WARN, "RelationGetIndexScan: relation invalid");
-
- scan = (IndexScanDesc) palloc(sizeof(IndexScanDescData));
-
- scan->relation = relation;
- scan->opaque = NULL;
- scan->numberOfKeys = numberOfKeys;
-
- ItemPointerSetInvalid(&scan->previousItemData);
- ItemPointerSetInvalid(&scan->currentItemData);
- ItemPointerSetInvalid(&scan->nextItemData);
- ItemPointerSetInvalid(&scan->previousMarkData);
- ItemPointerSetInvalid(&scan->currentMarkData);
- ItemPointerSetInvalid(&scan->nextMarkData);
+ IndexScanDesc scan;
+
+ if (!RelationIsValid(relation))
+ elog(WARN, "RelationGetIndexScan: relation invalid");
+
+ scan = (IndexScanDesc) palloc(sizeof(IndexScanDescData));
- if (numberOfKeys > 0) {
- scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * numberOfKeys);
- } else {
- scan->keyData = NULL;
- }
+ scan->relation = relation;
+ scan->opaque = NULL;
+ scan->numberOfKeys = numberOfKeys;
+
+ ItemPointerSetInvalid(&scan->previousItemData);
+ ItemPointerSetInvalid(&scan->currentItemData);
+ ItemPointerSetInvalid(&scan->nextItemData);
+ ItemPointerSetInvalid(&scan->previousMarkData);
+ ItemPointerSetInvalid(&scan->currentMarkData);
+ ItemPointerSetInvalid(&scan->nextMarkData);
+
+ if (numberOfKeys > 0)
+ {
+ scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * numberOfKeys);
+ }
+ else
+ {
+ scan->keyData = NULL;
+ }
- index_rescan(scan, scanFromEnd, key);
-
- return (scan);
+ index_rescan(scan, scanFromEnd, key);
+
+ return (scan);
}
#ifdef NOT_USED
/* ----------------
- * IndexScanRestart -- Restart an index scan.
+ * IndexScanRestart -- Restart an index scan.
*
- * This routine isn't used by any existing access method. It's
- * appropriate if relation level locks are what you want.
+ * This routine isn't used by any existing access method. It's
+ * appropriate if relation level locks are what you want.
*
- * Returns:
- * None.
+ * Returns:
+ * None.
*
- * Side Effects:
- * None.
+ * Side Effects:
+ * None.
* ----------------
*/
void
IndexScanRestart(IndexScanDesc scan,
- bool scanFromEnd,
- ScanKey key)
+ bool scanFromEnd,
+ ScanKey key)
{
- if (! IndexScanIsValid(scan))
- elog(WARN, "IndexScanRestart: invalid scan");
-
- ItemPointerSetInvalid(&scan->previousItemData);
- ItemPointerSetInvalid(&scan->currentItemData);
- ItemPointerSetInvalid(&scan->nextItemData);
-
- if (RelationGetNumberOfBlocks(scan->relation) == 0)
- scan->flags = ScanUnmarked;
- else if (scanFromEnd)
- scan->flags = ScanUnmarked | ScanUncheckedPrevious;
- else
- scan->flags = ScanUnmarked | ScanUncheckedNext;
-
- scan->scanFromEnd = (bool) scanFromEnd;
-
- if (scan->numberOfKeys > 0)
- memmove(scan->keyData,
- key,
- scan->numberOfKeys * sizeof(ScanKeyData));
+ if (!IndexScanIsValid(scan))
+ elog(WARN, "IndexScanRestart: invalid scan");
+
+ ItemPointerSetInvalid(&scan->previousItemData);
+ ItemPointerSetInvalid(&scan->currentItemData);
+ ItemPointerSetInvalid(&scan->nextItemData);
+
+ if (RelationGetNumberOfBlocks(scan->relation) == 0)
+ scan->flags = ScanUnmarked;
+ else if (scanFromEnd)
+ scan->flags = ScanUnmarked | ScanUncheckedPrevious;
+ else
+ scan->flags = ScanUnmarked | ScanUncheckedNext;
+
+ scan->scanFromEnd = (bool) scanFromEnd;
+
+ if (scan->numberOfKeys > 0)
+ memmove(scan->keyData,
+ key,
+ scan->numberOfKeys * sizeof(ScanKeyData));
}
+
#endif
#ifdef NOT_USED
/* ----------------
- * IndexScanEnd -- End and index scan.
+ * IndexScanEnd -- End and index scan.
*
- * This routine is not used by any existing access method, but is
- * suitable for use if you don't want to do sophisticated locking.
+ * This routine is not used by any existing access method, but is
+ * suitable for use if you don't want to do sophisticated locking.
*
- * Returns:
- * None.
+ * Returns:
+ * None.
*
- * Side Effects:
- * None.
+ * Side Effects:
+ * None.
* ----------------
*/
void
IndexScanEnd(IndexScanDesc scan)
{
- if (! IndexScanIsValid(scan))
- elog(WARN, "IndexScanEnd: invalid scan");
-
- pfree(scan);
+ if (!IndexScanIsValid(scan))
+ elog(WARN, "IndexScanEnd: invalid scan");
+
+ pfree(scan);
}
+
#endif
/* ----------------
- * IndexScanMarkPosition -- Mark current position in a scan.
+ * IndexScanMarkPosition -- Mark current position in a scan.
*
- * This routine isn't used by any existing access method, but is the
- * one that AM implementors should use, if they don't want to do any
- * special locking. If relation-level locking is sufficient, this is
- * the routine for you.
+ * This routine isn't used by any existing access method, but is the
+ * one that AM implementors should use, if they don't want to do any
+ * special locking. If relation-level locking is sufficient, this is
+ * the routine for you.
*
- * Returns:
- * None.
+ * Returns:
+ * None.
*
- * Side Effects:
- * None.
+ * Side Effects:
+ * None.
* ----------------
*/
void
IndexScanMarkPosition(IndexScanDesc scan)
{
- RetrieveIndexResult result;
-
- if (scan->flags & ScanUncheckedPrevious) {
- result =
- index_getnext(scan, BackwardScanDirection);
-
- if (result != NULL) {
- scan->previousItemData = result->index_iptr;
- } else {
- ItemPointerSetInvalid(&scan->previousItemData);
+ RetrieveIndexResult result;
+
+ if (scan->flags & ScanUncheckedPrevious)
+ {
+ result =
+ index_getnext(scan, BackwardScanDirection);
+
+ if (result != NULL)
+ {
+ scan->previousItemData = result->index_iptr;
+ }
+ else
+ {
+ ItemPointerSetInvalid(&scan->previousItemData);
+ }
+
}
-
- } else if (scan->flags & ScanUncheckedNext) {
- result = (RetrieveIndexResult)
- index_getnext(scan, ForwardScanDirection);
-
- if (result != NULL) {
- scan->nextItemData = result->index_iptr;
- } else {
- ItemPointerSetInvalid(&scan->nextItemData);
+ else if (scan->flags & ScanUncheckedNext)
+ {
+ result = (RetrieveIndexResult)
+ index_getnext(scan, ForwardScanDirection);
+
+ if (result != NULL)
+ {
+ scan->nextItemData = result->index_iptr;
+ }
+ else
+ {
+ ItemPointerSetInvalid(&scan->nextItemData);
+ }
}
- }
-
- scan->previousMarkData = scan->previousItemData;
- scan->currentMarkData = scan->currentItemData;
- scan->nextMarkData = scan->nextItemData;
-
- scan->flags = 0x0; /* XXX should have a symbolic name */
+
+ scan->previousMarkData = scan->previousItemData;
+ scan->currentMarkData = scan->currentItemData;
+ scan->nextMarkData = scan->nextItemData;
+
+ scan->flags = 0x0; /* XXX should have a symbolic name */
}
/* ----------------
- * IndexScanRestorePosition -- Restore position on a marked scan.
+ * IndexScanRestorePosition -- Restore position on a marked scan.
*
- * This routine isn't used by any existing access method, but is the
- * one that AM implementors should use if they don't want to do any
- * special locking. If relation-level locking is sufficient, then
- * this is the one you want.
+ * This routine isn't used by any existing access method, but is the
+ * one that AM implementors should use if they don't want to do any
+ * special locking. If relation-level locking is sufficient, then
+ * this is the one you want.
*
- * Returns:
- * None.
+ * Returns:
+ * None.
*
- * Side Effects:
- * None.
+ * Side Effects:
+ * None.
* ----------------
*/
void
IndexScanRestorePosition(IndexScanDesc scan)
-{
- if (scan->flags & ScanUnmarked)
- elog(WARN, "IndexScanRestorePosition: no mark to restore");
-
- scan->previousItemData = scan->previousMarkData;
- scan->currentItemData = scan->currentMarkData;
- scan->nextItemData = scan->nextMarkData;
-
- scan->flags = 0x0; /* XXX should have a symbolic name */
+{
+ if (scan->flags & ScanUnmarked)
+ elog(WARN, "IndexScanRestorePosition: no mark to restore");
+
+ scan->previousItemData = scan->previousMarkData;
+ scan->currentItemData = scan->currentMarkData;
+ scan->nextItemData = scan->nextMarkData;
+
+ scan->flags = 0x0; /* XXX should have a symbolic name */
}
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 3068f7cceed..6841899fa39 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -1,80 +1,80 @@
/*-------------------------------------------------------------------------
*
* indexam.c--
- * general index access method routines
+ * general index access method routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.13 1997/08/26 23:31:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.14 1997/09/07 04:38:26 momjian Exp $
*
* INTERFACE ROUTINES
- * index_open - open an index relation by relationId
- * index_openr - open a index relation by name
- * index_close - close a index relation
- * index_beginscan - start a scan of an index
- * index_rescan - restart a scan of an index
- * index_endscan - end a scan
- * index_insert - insert an index tuple into a relation
- * index_delete - delete an item from an index relation
- * index_markpos - mark a scan position
- * index_restrpos - restore a scan position
- * index_getnext - get the next tuple from a scan
- * ** index_fetch - retrieve tuple with tid
+ * index_open - open an index relation by relationId
+ * index_openr - open a index relation by name
+ * index_close - close a index relation
+ * index_beginscan - start a scan of an index
+ * index_rescan - restart a scan of an index
+ * index_endscan - end a scan
+ * index_insert - insert an index tuple into a relation
+ * index_delete - delete an item from an index relation
+ * index_markpos - mark a scan position
+ * index_restrpos - restore a scan position
+ * index_getnext - get the next tuple from a scan
+ * ** index_fetch - retrieve tuple with tid
* ** index_replace - replace a tuple
* ** index_getattr - get an attribute from an index tuple
- * index_getprocid - get a support procedure id from the rel tuple
- *
- * IndexScanIsValid - check index scan
+ * index_getprocid - get a support procedure id from the rel tuple
+ *
+ * IndexScanIsValid - check index scan
*
* NOTES
- * This file contains the index_ routines which used
- * to be a scattered collection of stuff in access/genam.
+ * This file contains the index_ routines which used
+ * to be a scattered collection of stuff in access/genam.
*
- * The ** routines: index_fetch, index_replace, and index_getattr
- * have not yet been implemented. They may not be needed.
+ * The ** routines: index_fetch, index_replace, and index_getattr
+ * have not yet been implemented. They may not be needed.
*
* old comments
- * Scans are implemented as follows:
+ * Scans are implemented as follows:
*
- * `0' represents an invalid item pointer.
- * `-' represents an unknown item pointer.
- * `X' represents a known item pointers.
- * `+' represents known or invalid item pointers.
- * `*' represents any item pointers.
+ * `0' represents an invalid item pointer.
+ * `-' represents an unknown item pointer.
+ * `X' represents a known item pointers.
+ * `+' represents known or invalid item pointers.
+ * `*' represents any item pointers.
*
- * State is represented by a triple of these symbols in the order of
- * previous, current, next. Note that the case of reverse scans works
- * identically.
+ * State is represented by a triple of these symbols in the order of
+ * previous, current, next. Note that the case of reverse scans works
+ * identically.
*
- * State Result
- * (1) + + - + 0 0 (if the next item pointer is invalid)
- * (2) + X - (otherwise)
- * (3) * 0 0 * 0 0 (no change)
- * (4) + X 0 X 0 0 (shift)
- * (5) * + X + X - (shift, add unknown)
+ * State Result
+ * (1) + + - + 0 0 (if the next item pointer is invalid)
+ * (2) + X - (otherwise)
+ * (3) * 0 0 * 0 0 (no change)
+ * (4) + X 0 X 0 0 (shift)
+ * (5) * + X + X - (shift, add unknown)
*
- * All other states cannot occur.
+ * All other states cannot occur.
*
- * Note: It would be possible to cache the status of the previous and
- * next item pointer using the flags.
+ * Note: It would be possible to cache the status of the previous and
+ * next item pointer using the flags.
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
-#include <access/genam.h>
+
+#include <access/genam.h>
#include <utils/relcache.h>
#include <fmgr.h>
#include <storage/lmgr.h>
#include <access/heapam.h>
/* ----------------
- * undefine macros we aren't going to use that would otherwise
- * get in our way.. delete is defined in c.h and the am's are
- * defined in heapam.h
+ * undefine macros we aren't going to use that would otherwise
+ * get in our way.. delete is defined in c.h and the am's are
+ * defined in heapam.h
* ----------------
*/
#undef delete
@@ -88,314 +88,320 @@
#undef amgettuple
/* ----------------------------------------------------------------
- * macros used in index_ routines
+ * macros used in index_ routines
* ----------------------------------------------------------------
*/
#define RELATION_CHECKS \
Assert(RelationIsValid(relation)); \
- Assert(PointerIsValid(relation->rd_am))
-
+ Assert(PointerIsValid(relation->rd_am))
+
#define SCAN_CHECKS \
- Assert(IndexScanIsValid(scan)); \
- Assert(RelationIsValid(scan->relation)); \
- Assert(PointerIsValid(scan->relation->rd_am))
-
+ Assert(IndexScanIsValid(scan)); \
+ Assert(RelationIsValid(scan->relation)); \
+ Assert(PointerIsValid(scan->relation->rd_am))
+
#define GET_REL_PROCEDURE(x,y) \
- procedure = relation->rd_am->y; \
- if (! RegProcedureIsValid(procedure)) \
- elog(WARN, "index_%s: invalid %s regproc", \
- CppAsString(x), CppAsString(y))
-
+ procedure = relation->rd_am->y; \
+ if (! RegProcedureIsValid(procedure)) \
+ elog(WARN, "index_%s: invalid %s regproc", \
+ CppAsString(x), CppAsString(y))
+
#define GET_SCAN_PROCEDURE(x,y) \
- procedure = scan->relation->rd_am->y; \
- if (! RegProcedureIsValid(procedure)) \
- elog(WARN, "index_%s: invalid %s regproc", \
- CppAsString(x), CppAsString(y))
-
-
+ procedure = scan->relation->rd_am->y; \
+ if (! RegProcedureIsValid(procedure)) \
+ elog(WARN, "index_%s: invalid %s regproc", \
+ CppAsString(x), CppAsString(y))
+
+
/* ----------------------------------------------------------------
- * index_ interface functions
+ * index_ interface functions
* ----------------------------------------------------------------
*/
/* ----------------
- * index_open - open an index relation by relationId
+ * index_open - open an index relation by relationId
*
- * presently the relcache routines do all the work we need
- * to open/close index relations.
+ * presently the relcache routines do all the work we need
+ * to open/close index relations.
* ----------------
*/
Relation
index_open(Oid relationId)
{
- return RelationIdGetRelation(relationId);
+ return RelationIdGetRelation(relationId);
}
/* ----------------
- * index_openr - open a index relation by name
+ * index_openr - open a index relation by name
*
- * presently the relcache routines do all the work we need
- * to open/close index relations.
+ * presently the relcache routines do all the work we need
+ * to open/close index relations.
* ----------------
*/
Relation
index_openr(char *relationName)
{
- return RelationNameGetRelation(relationName);
+ return RelationNameGetRelation(relationName);
}
/* ----------------
- * index_close - close a index relation
+ * index_close - close a index relation
*
- * presently the relcache routines do all the work we need
- * to open/close index relations.
+ * presently the relcache routines do all the work we need
+ * to open/close index relations.
* ----------------
*/
void
index_close(Relation relation)
{
- RelationClose(relation);
+ RelationClose(relation);
}
/* ----------------
- * index_insert - insert an index tuple into a relation
+ * index_insert - insert an index tuple into a relation
* ----------------
*/
InsertIndexResult
index_insert(Relation relation,
- Datum *datum,
- char *nulls,
- ItemPointer heap_t_ctid,
- Relation heapRel)
+ Datum * datum,
+ char *nulls,
+ ItemPointer heap_t_ctid,
+ Relation heapRel)
{
- RegProcedure procedure;
- InsertIndexResult specificResult;
-
- RELATION_CHECKS;
- GET_REL_PROCEDURE(insert,aminsert);
-
- /* ----------------
- * have the am's insert proc do all the work.
- * ----------------
- */
- specificResult = (InsertIndexResult)
- fmgr(procedure, relation, datum, nulls, heap_t_ctid, heapRel, NULL);
-
- /* ----------------
- * the insert proc is supposed to return a "specific result" and
- * this routine has to return a "general result" so after we get
- * something back from the insert proc, we allocate a
- * "general result" and copy some crap between the two.
- *
- * As far as I'm concerned all this result shit is needlessly c
- * omplicated and should be eliminated. -cim 1/19/91
- *
- * mao concurs. regardless of how we feel here, however, it is
- * important to free memory we don't intend to return to anyone.
- * 2/28/91
- *
- * this "general result" crap is now gone. -ay 3/6/95
- * ----------------
- */
-
- return (specificResult);
+ RegProcedure procedure;
+ InsertIndexResult specificResult;
+
+ RELATION_CHECKS;
+ GET_REL_PROCEDURE(insert, aminsert);
+
+ /* ----------------
+ * have the am's insert proc do all the work.
+ * ----------------
+ */
+ specificResult = (InsertIndexResult)
+ fmgr(procedure, relation, datum, nulls, heap_t_ctid, heapRel, NULL);
+
+ /* ----------------
+ * the insert proc is supposed to return a "specific result" and
+ * this routine has to return a "general result" so after we get
+ * something back from the insert proc, we allocate a
+ * "general result" and copy some crap between the two.
+ *
+ * As far as I'm concerned all this result shit is needlessly c
+ * omplicated and should be eliminated. -cim 1/19/91
+ *
+ * mao concurs. regardless of how we feel here, however, it is
+ * important to free memory we don't intend to return to anyone.
+ * 2/28/91
+ *
+ * this "general result" crap is now gone. -ay 3/6/95
+ * ----------------
+ */
+
+ return (specificResult);
}
/* ----------------
- * index_delete - delete an item from an index relation
+ * index_delete - delete an item from an index relation
* ----------------
*/
void
index_delete(Relation relation, ItemPointer indexItem)
{
- RegProcedure procedure;
-
- RELATION_CHECKS;
- GET_REL_PROCEDURE(delete,amdelete);
-
- fmgr(procedure, relation, indexItem);
+ RegProcedure procedure;
+
+ RELATION_CHECKS;
+ GET_REL_PROCEDURE(delete, amdelete);
+
+ fmgr(procedure, relation, indexItem);
}
/* ----------------
- * index_beginscan - start a scan of an index
+ * index_beginscan - start a scan of an index
* ----------------
*/
IndexScanDesc
index_beginscan(Relation relation,
- bool scanFromEnd,
- uint16 numberOfKeys,
- ScanKey key)
+ bool scanFromEnd,
+ uint16 numberOfKeys,
+ ScanKey key)
{
- IndexScanDesc scandesc;
- RegProcedure procedure;
-
- RELATION_CHECKS;
- GET_REL_PROCEDURE(beginscan,ambeginscan);
-
- RelationSetRIntentLock(relation);
-
- scandesc = (IndexScanDesc)
- fmgr(procedure, relation, scanFromEnd, numberOfKeys, key);
-
- return scandesc;
+ IndexScanDesc scandesc;
+ RegProcedure procedure;
+
+ RELATION_CHECKS;
+ GET_REL_PROCEDURE(beginscan, ambeginscan);
+
+ RelationSetRIntentLock(relation);
+
+ scandesc = (IndexScanDesc)
+ fmgr(procedure, relation, scanFromEnd, numberOfKeys, key);
+
+ return scandesc;
}
/* ----------------
- * index_rescan - restart a scan of an index
+ * index_rescan - restart a scan of an index
* ----------------
*/
void
index_rescan(IndexScanDesc scan, bool scanFromEnd, ScanKey key)
{
- RegProcedure procedure;
-
- SCAN_CHECKS;
- GET_SCAN_PROCEDURE(rescan,amrescan);
-
- fmgr(procedure, scan, scanFromEnd, key);
+ RegProcedure procedure;
+
+ SCAN_CHECKS;
+ GET_SCAN_PROCEDURE(rescan, amrescan);
+
+ fmgr(procedure, scan, scanFromEnd, key);
}
/* ----------------
- * index_endscan - end a scan
+ * index_endscan - end a scan
* ----------------
*/
void
index_endscan(IndexScanDesc scan)
{
- RegProcedure procedure;
-
- SCAN_CHECKS;
- GET_SCAN_PROCEDURE(endscan,amendscan);
-
- fmgr(procedure, scan);
-
- RelationUnsetRIntentLock(scan->relation);
+ RegProcedure procedure;
+
+ SCAN_CHECKS;
+ GET_SCAN_PROCEDURE(endscan, amendscan);
+
+ fmgr(procedure, scan);
+
+ RelationUnsetRIntentLock(scan->relation);
}
#ifdef NOT_USED
/* ----------------
- * index_markpos - mark a scan position
+ * index_markpos - mark a scan position
* ----------------
*/
void
index_markpos(IndexScanDesc scan)
{
- RegProcedure procedure;
-
- SCAN_CHECKS;
- GET_SCAN_PROCEDURE(markpos,ammarkpos);
-
- fmgr(procedure, scan);
+ RegProcedure procedure;
+
+ SCAN_CHECKS;
+ GET_SCAN_PROCEDURE(markpos, ammarkpos);
+
+ fmgr(procedure, scan);
}
+
#endif
#ifdef NOT_USED
/* ----------------
- * index_restrpos - restore a scan position
+ * index_restrpos - restore a scan position
* ----------------
*/
void
index_restrpos(IndexScanDesc scan)
{
- RegProcedure procedure;
-
- SCAN_CHECKS;
- GET_SCAN_PROCEDURE(restrpos,amrestrpos);
-
- fmgr(procedure, scan);
+ RegProcedure procedure;
+
+ SCAN_CHECKS;
+ GET_SCAN_PROCEDURE(restrpos, amrestrpos);
+
+ fmgr(procedure, scan);
}
+
#endif
/* ----------------
- * index_getnext - get the next tuple from a scan
+ * index_getnext - get the next tuple from a scan
*
- * A RetrieveIndexResult is a index tuple/heap tuple pair
+ * A RetrieveIndexResult is a index tuple/heap tuple pair
* ----------------
*/
RetrieveIndexResult
index_getnext(IndexScanDesc scan,
- ScanDirection direction)
+ ScanDirection direction)
{
- RegProcedure procedure;
- RetrieveIndexResult result;
-
- SCAN_CHECKS;
- GET_SCAN_PROCEDURE(getnext,amgettuple);
-
- /* ----------------
- * have the am's gettuple proc do all the work.
- * ----------------
- */
- result = (RetrieveIndexResult)
- fmgr(procedure, scan, direction);
-
- return result;
+ RegProcedure procedure;
+ RetrieveIndexResult result;
+
+ SCAN_CHECKS;
+ GET_SCAN_PROCEDURE(getnext, amgettuple);
+
+ /* ----------------
+ * have the am's gettuple proc do all the work.
+ * ----------------
+ */
+ result = (RetrieveIndexResult)
+ fmgr(procedure, scan, direction);
+
+ return result;
}
/* ----------------
- * index_getprocid
+ * index_getprocid
*
- * Some indexed access methods may require support routines that are
- * not in the operator class/operator model imposed by pg_am. These
- * access methods may store the OIDs of registered procedures they
- * need in pg_amproc. These registered procedure OIDs are ordered in
- * a way that makes sense to the access method, and used only by the
- * access method. The general index code doesn't know anything about
- * the routines involved; it just builds an ordered list of them for
- * each attribute on which an index is defined.
+ * Some indexed access methods may require support routines that are
+ * not in the operator class/operator model imposed by pg_am. These
+ * access methods may store the OIDs of registered procedures they
+ * need in pg_amproc. These registered procedure OIDs are ordered in
+ * a way that makes sense to the access method, and used only by the
+ * access method. The general index code doesn't know anything about
+ * the routines involved; it just builds an ordered list of them for
+ * each attribute on which an index is defined.
*
- * This routine returns the requested procedure OID for a particular
- * indexed attribute.
+ * This routine returns the requested procedure OID for a particular
+ * indexed attribute.
* ----------------
*/
RegProcedure
index_getprocid(Relation irel,
- AttrNumber attnum,
- uint16 procnum)
+ AttrNumber attnum,
+ uint16 procnum)
{
- RegProcedure *loc;
- int natts;
-
- natts = irel->rd_rel->relnatts;
-
- loc = irel->rd_support;
-
- Assert(loc != NULL);
-
- return (loc[(natts * (procnum - 1)) + (attnum - 1)]);
+ RegProcedure *loc;
+ int natts;
+
+ natts = irel->rd_rel->relnatts;
+
+ loc = irel->rd_support;
+
+ Assert(loc != NULL);
+
+ return (loc[(natts * (procnum - 1)) + (attnum - 1)]);
}
Datum
GetIndexValue(HeapTuple tuple,
- TupleDesc hTupDesc,
- int attOff,
- AttrNumber attrNums[],
- FuncIndexInfo *fInfo,
- bool *attNull,
- Buffer buffer)
+ TupleDesc hTupDesc,
+ int attOff,
+ AttrNumber attrNums[],
+ FuncIndexInfo * fInfo,
+ bool * attNull,
+ Buffer buffer)
{
- Datum returnVal;
- bool isNull;
-
- if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid) {
- int i;
- Datum *attData = (Datum *)palloc(FIgetnArgs(fInfo)*sizeof(Datum));
-
- for (i = 0; i < FIgetnArgs(fInfo); i++) {
- attData[i] = (Datum) heap_getattr(tuple,
- buffer,
- attrNums[i],
- hTupDesc,
- attNull);
+ Datum returnVal;
+ bool isNull;
+
+ if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid)
+ {
+ int i;
+ Datum *attData = (Datum *) palloc(FIgetnArgs(fInfo) * sizeof(Datum));
+
+ for (i = 0; i < FIgetnArgs(fInfo); i++)
+ {
+ attData[i] = (Datum) heap_getattr(tuple,
+ buffer,
+ attrNums[i],
+ hTupDesc,
+ attNull);
+ }
+ returnVal = (Datum) fmgr_array_args(FIgetProcOid(fInfo),
+ FIgetnArgs(fInfo),
+ (char **) attData,
+ &isNull);
+ pfree(attData);
+ *attNull = FALSE;
+ }
+ else
+ {
+ returnVal = (Datum) heap_getattr(tuple, buffer, attrNums[attOff],
+ hTupDesc, attNull);
}
- returnVal = (Datum)fmgr_array_args(FIgetProcOid(fInfo),
- FIgetnArgs(fInfo),
- (char **) attData,
- &isNull);
- pfree(attData);
- *attNull = FALSE;
- }else {
- returnVal = (Datum) heap_getattr(tuple, buffer, attrNums[attOff],
- hTupDesc, attNull);
- }
- return returnVal;
+ return returnVal;
}
diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c
index 5c143f0aa5f..35158c22170 100644
--- a/src/backend/access/index/istrat.c
+++ b/src/backend/access/index/istrat.c
@@ -1,689 +1,730 @@
/*-------------------------------------------------------------------------
*
* istrat.c--
- * index scan strategy manipulation code and index strategy manipulation
- * operator code.
+ * index scan strategy manipulation code and index strategy manipulation
+ * operator code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.9 1997/08/22 16:48:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.10 1997/09/07 04:38:32 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <catalog/pg_proc.h>
#include <catalog/pg_operator.h>
#include <catalog/catname.h>
#include <catalog/pg_index.h>
#include <catalog/pg_amop.h>
#include <catalog/pg_amproc.h>
-#include <utils/memutils.h> /* could have been access/itup.h */
+#include <utils/memutils.h> /* could have been access/itup.h */
#include <access/heapam.h>
#include <access/istrat.h>
#include <fmgr.h>
-#ifndef NO_ASSERT_CHECKING
-static bool StrategyEvaluationIsValid(StrategyEvaluation evaluation);
-static bool StrategyExpressionIsValid(StrategyExpression expression,
- StrategyNumber maxStrategy);
-static ScanKey StrategyMapGetScanKeyEntry(StrategyMap map,
- StrategyNumber strategyNumber);
-static bool StrategyOperatorIsValid(StrategyOperator operator,
- StrategyNumber maxStrategy);
-static bool StrategyTermIsValid(StrategyTerm term,
- StrategyNumber maxStrategy);
+#ifndef NO_ASSERT_CHECKING
+static bool StrategyEvaluationIsValid(StrategyEvaluation evaluation);
+static bool
+StrategyExpressionIsValid(StrategyExpression expression,
+ StrategyNumber maxStrategy);
+static ScanKey
+StrategyMapGetScanKeyEntry(StrategyMap map,
+ StrategyNumber strategyNumber);
+static bool
+StrategyOperatorIsValid(StrategyOperator operator,
+ StrategyNumber maxStrategy);
+static bool
+StrategyTermIsValid(StrategyTerm term,
+ StrategyNumber maxStrategy);
+
#endif
/* ----------------------------------------------------------------
- * misc strategy support routines
+ * misc strategy support routines
* ----------------------------------------------------------------
*/
-
-/*
- * StrategyNumberIsValid
- * StrategyNumberIsInBounds
- * StrategyMapIsValid
- * StrategyTransformMapIsValid
- * IndexStrategyIsValid
+
+/*
+ * StrategyNumberIsValid
+ * StrategyNumberIsInBounds
+ * StrategyMapIsValid
+ * StrategyTransformMapIsValid
+ * IndexStrategyIsValid
*
- * ... are now macros in istrat.h -cim 4/27/91
+ * ... are now macros in istrat.h -cim 4/27/91
*/
-
+
/*
* StrategyMapGetScanKeyEntry --
- * Returns a scan key entry of a index strategy mapping member.
+ * Returns a scan key entry of a index strategy mapping member.
*
* Note:
- * Assumes that the index strategy mapping is valid.
- * Assumes that the index strategy number is valid.
- * Bounds checking should be done outside this routine.
+ * Assumes that the index strategy mapping is valid.
+ * Assumes that the index strategy number is valid.
+ * Bounds checking should be done outside this routine.
*/
-static ScanKey
+static ScanKey
StrategyMapGetScanKeyEntry(StrategyMap map,
- StrategyNumber strategyNumber)
+ StrategyNumber strategyNumber)
{
- Assert(StrategyMapIsValid(map));
- Assert(StrategyNumberIsValid(strategyNumber));
- return (&map->entry[strategyNumber - 1]);
+ Assert(StrategyMapIsValid(map));
+ Assert(StrategyNumberIsValid(strategyNumber));
+ return (&map->entry[strategyNumber - 1]);
}
/*
* IndexStrategyGetStrategyMap --
- * Returns an index strategy mapping of an index strategy.
+ * Returns an index strategy mapping of an index strategy.
*
* Note:
- * Assumes that the index strategy is valid.
- * Assumes that the number of index strategies is valid.
- * Bounds checking should be done outside this routine.
+ * Assumes that the index strategy is valid.
+ * Assumes that the number of index strategies is valid.
+ * Bounds checking should be done outside this routine.
*/
StrategyMap
IndexStrategyGetStrategyMap(IndexStrategy indexStrategy,
- StrategyNumber maxStrategyNum,
- AttrNumber attrNum)
+ StrategyNumber maxStrategyNum,
+ AttrNumber attrNum)
{
- Assert(IndexStrategyIsValid(indexStrategy));
- Assert(StrategyNumberIsValid(maxStrategyNum));
- Assert(AttributeNumberIsValid(attrNum));
-
- maxStrategyNum = AMStrategies(maxStrategyNum); /* XXX */
- return
- &indexStrategy->strategyMapData[maxStrategyNum * (attrNum - 1)];
+ Assert(IndexStrategyIsValid(indexStrategy));
+ Assert(StrategyNumberIsValid(maxStrategyNum));
+ Assert(AttributeNumberIsValid(attrNum));
+
+ maxStrategyNum = AMStrategies(maxStrategyNum); /* XXX */
+ return
+ &indexStrategy->strategyMapData[maxStrategyNum * (attrNum - 1)];
}
/*
* AttributeNumberGetIndexStrategySize --
- * Computes the size of an index strategy.
+ * Computes the size of an index strategy.
*/
Size
AttributeNumberGetIndexStrategySize(AttrNumber maxAttributeNumber,
- StrategyNumber maxStrategyNumber)
+ StrategyNumber maxStrategyNumber)
{
- maxStrategyNumber = AMStrategies(maxStrategyNumber); /* XXX */
- return
- maxAttributeNumber * maxStrategyNumber * sizeof (ScanKeyData);
+ maxStrategyNumber = AMStrategies(maxStrategyNumber); /* XXX */
+ return
+ maxAttributeNumber * maxStrategyNumber * sizeof(ScanKeyData);
}
-#ifndef NO_ASSERT_CHECKING
-/*
+#ifndef NO_ASSERT_CHECKING
+/*
* StrategyTransformMapIsValid is now a macro in istrat.h -cim 4/27/91
*/
/* ----------------
- * StrategyOperatorIsValid
+ * StrategyOperatorIsValid
* ----------------
*/
-static bool
+static bool
StrategyOperatorIsValid(StrategyOperator operator,
- StrategyNumber maxStrategy)
+ StrategyNumber maxStrategy)
{
- return (bool)
+ return (bool)
(PointerIsValid(operator) &&
StrategyNumberIsInBounds(operator->strategy, maxStrategy) &&
!(operator->flags & ~(SK_NEGATE | SK_COMMUTE)));
}
/* ----------------
- * StrategyTermIsValid
+ * StrategyTermIsValid
* ----------------
*/
-static bool
+static bool
StrategyTermIsValid(StrategyTerm term,
- StrategyNumber maxStrategy)
+ StrategyNumber maxStrategy)
{
- Index index;
-
- if (! PointerIsValid(term) || term->degree == 0)
- return false;
-
- for (index = 0; index < term->degree; index += 1) {
- if (! StrategyOperatorIsValid(&term->operatorData[index],
- maxStrategy)) {
-
- return false;
+ Index index;
+
+ if (!PointerIsValid(term) || term->degree == 0)
+ return false;
+
+ for (index = 0; index < term->degree; index += 1)
+ {
+ if (!StrategyOperatorIsValid(&term->operatorData[index],
+ maxStrategy))
+ {
+
+ return false;
+ }
}
- }
-
- return true;
+
+ return true;
}
/* ----------------
- * StrategyExpressionIsValid
+ * StrategyExpressionIsValid
* ----------------
*/
-static bool
+static bool
StrategyExpressionIsValid(StrategyExpression expression,
- StrategyNumber maxStrategy)
+ StrategyNumber maxStrategy)
{
- StrategyTerm *termP;
-
- if (!PointerIsValid(expression))
- return true;
-
- if (!StrategyTermIsValid(expression->term[0], maxStrategy))
- return false;
-
- termP = &expression->term[1];
- while (StrategyTermIsValid(*termP, maxStrategy))
- termP += 1;
-
- return (bool)
- (! PointerIsValid(*termP));
+ StrategyTerm *termP;
+
+ if (!PointerIsValid(expression))
+ return true;
+
+ if (!StrategyTermIsValid(expression->term[0], maxStrategy))
+ return false;
+
+ termP = &expression->term[1];
+ while (StrategyTermIsValid(*termP, maxStrategy))
+ termP += 1;
+
+ return (bool)
+ (!PointerIsValid(*termP));
}
/* ----------------
- * StrategyEvaluationIsValid
+ * StrategyEvaluationIsValid
* ----------------
*/
-static bool
+static bool
StrategyEvaluationIsValid(StrategyEvaluation evaluation)
{
- Index index;
-
- if (! PointerIsValid(evaluation) ||
- ! StrategyNumberIsValid(evaluation->maxStrategy) ||
- ! StrategyTransformMapIsValid(evaluation->negateTransform) ||
- ! StrategyTransformMapIsValid(evaluation->commuteTransform) ||
- ! StrategyTransformMapIsValid(evaluation->negateCommuteTransform)) {
-
- return false;
- }
-
- for (index = 0; index < evaluation->maxStrategy; index += 1) {
- if (! StrategyExpressionIsValid(evaluation->expression[index],
- evaluation->maxStrategy)) {
-
- return false;
+ Index index;
+
+ if (!PointerIsValid(evaluation) ||
+ !StrategyNumberIsValid(evaluation->maxStrategy) ||
+ !StrategyTransformMapIsValid(evaluation->negateTransform) ||
+ !StrategyTransformMapIsValid(evaluation->commuteTransform) ||
+ !StrategyTransformMapIsValid(evaluation->negateCommuteTransform))
+ {
+
+ return false;
}
- }
- return true;
+
+ for (index = 0; index < evaluation->maxStrategy; index += 1)
+ {
+ if (!StrategyExpressionIsValid(evaluation->expression[index],
+ evaluation->maxStrategy))
+ {
+
+ return false;
+ }
+ }
+ return true;
}
+
#endif
/* ----------------
- * StrategyTermEvaluate
+ * StrategyTermEvaluate
* ----------------
*/
-static bool
+static bool
StrategyTermEvaluate(StrategyTerm term,
- StrategyMap map,
- Datum left,
- Datum right)
+ StrategyMap map,
+ Datum left,
+ Datum right)
{
- Index index;
- long tmpres = 0;
- bool result = 0;
- StrategyOperator operator;
- ScanKey entry;
-
- for (index = 0, operator = &term->operatorData[0];
- index < term->degree; index += 1, operator += 1) {
-
- entry = &map->entry[operator->strategy - 1];
-
- Assert(RegProcedureIsValid(entry->sk_procedure));
-
- switch (operator->flags ^ entry->sk_flags) {
- case 0x0:
- tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
- left, right);
- break;
-
- case SK_NEGATE:
- tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure,
- left, right);
- break;
-
- case SK_COMMUTE:
- tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
- right, left);
- break;
-
- case SK_NEGATE | SK_COMMUTE:
- tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure,
- right, left);
- break;
-
- default:
- elog(FATAL, "StrategyTermEvaluate: impossible case %d",
- operator->flags ^ entry->sk_flags);
+ Index index;
+ long tmpres = 0;
+ bool result = 0;
+ StrategyOperator operator;
+ ScanKey entry;
+
+ for (index = 0, operator = &term->operatorData[0];
+ index < term->degree; index += 1, operator += 1)
+ {
+
+ entry = &map->entry[operator->strategy - 1];
+
+ Assert(RegProcedureIsValid(entry->sk_procedure));
+
+ switch (operator->flags ^ entry->sk_flags)
+ {
+ case 0x0:
+ tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
+ left, right);
+ break;
+
+ case SK_NEGATE:
+ tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure,
+ left, right);
+ break;
+
+ case SK_COMMUTE:
+ tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
+ right, left);
+ break;
+
+ case SK_NEGATE | SK_COMMUTE:
+ tmpres = (long) !FMGR_PTR2(entry->sk_func, entry->sk_procedure,
+ right, left);
+ break;
+
+ default:
+ elog(FATAL, "StrategyTermEvaluate: impossible case %d",
+ operator->flags ^ entry->sk_flags);
+ }
+
+ result = (bool) tmpres;
+ if (!result)
+ return result;
}
-
- result = (bool) tmpres;
- if (!result)
- return result;
- }
-
- return result;
+
+ return result;
}
/* ----------------
- * RelationGetStrategy
+ * RelationGetStrategy
* ----------------
*/
StrategyNumber
RelationGetStrategy(Relation relation,
- AttrNumber attributeNumber,
- StrategyEvaluation evaluation,
- RegProcedure procedure)
+ AttrNumber attributeNumber,
+ StrategyEvaluation evaluation,
+ RegProcedure procedure)
{
- StrategyNumber strategy;
- StrategyMap strategyMap;
- ScanKey entry;
- Index index;
- int numattrs;
-
- Assert(RelationIsValid(relation));
- numattrs = RelationGetNumberOfAttributes(relation);
-
- Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
- Assert(AttributeNumberIsValid(attributeNumber));
- Assert( (attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
-
- Assert(StrategyEvaluationIsValid(evaluation));
- Assert(RegProcedureIsValid(procedure));
-
- strategyMap =
- IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
- evaluation->maxStrategy,
- attributeNumber);
-
- /* get a strategy number for the procedure ignoring flags for now */
- for (index = 0; index < evaluation->maxStrategy; index += 1) {
- if (strategyMap->entry[index].sk_procedure == procedure) {
- break;
+ StrategyNumber strategy;
+ StrategyMap strategyMap;
+ ScanKey entry;
+ Index index;
+ int numattrs;
+
+ Assert(RelationIsValid(relation));
+ numattrs = RelationGetNumberOfAttributes(relation);
+
+ Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
+ Assert(AttributeNumberIsValid(attributeNumber));
+ Assert((attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
+
+ Assert(StrategyEvaluationIsValid(evaluation));
+ Assert(RegProcedureIsValid(procedure));
+
+ strategyMap =
+ IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
+ evaluation->maxStrategy,
+ attributeNumber);
+
+ /* get a strategy number for the procedure ignoring flags for now */
+ for (index = 0; index < evaluation->maxStrategy; index += 1)
+ {
+ if (strategyMap->entry[index].sk_procedure == procedure)
+ {
+ break;
+ }
}
- }
-
- if (index == evaluation->maxStrategy)
- return InvalidStrategy;
-
- strategy = 1 + index;
- entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
-
- Assert(!(entry->sk_flags & ~(SK_NEGATE | SK_COMMUTE)));
-
- switch (entry->sk_flags & (SK_NEGATE | SK_COMMUTE)) {
- case 0x0:
- return strategy;
-
- case SK_NEGATE:
- strategy = evaluation->negateTransform->strategy[strategy - 1];
- break;
-
- case SK_COMMUTE:
- strategy = evaluation->commuteTransform->strategy[strategy - 1];
- break;
-
- case SK_NEGATE | SK_COMMUTE:
- strategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
- break;
-
- default:
- elog(FATAL, "RelationGetStrategy: impossible case %d", entry->sk_flags);
- }
-
-
- if (! StrategyNumberIsInBounds(strategy, evaluation->maxStrategy)) {
- if (! StrategyNumberIsValid(strategy)) {
- elog(WARN, "RelationGetStrategy: corrupted evaluation");
+
+ if (index == evaluation->maxStrategy)
+ return InvalidStrategy;
+
+ strategy = 1 + index;
+ entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
+
+ Assert(!(entry->sk_flags & ~(SK_NEGATE | SK_COMMUTE)));
+
+ switch (entry->sk_flags & (SK_NEGATE | SK_COMMUTE))
+ {
+ case 0x0:
+ return strategy;
+
+ case SK_NEGATE:
+ strategy = evaluation->negateTransform->strategy[strategy - 1];
+ break;
+
+ case SK_COMMUTE:
+ strategy = evaluation->commuteTransform->strategy[strategy - 1];
+ break;
+
+ case SK_NEGATE | SK_COMMUTE:
+ strategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
+ break;
+
+ default:
+ elog(FATAL, "RelationGetStrategy: impossible case %d", entry->sk_flags);
}
- }
-
- return strategy;
+
+
+ if (!StrategyNumberIsInBounds(strategy, evaluation->maxStrategy))
+ {
+ if (!StrategyNumberIsValid(strategy))
+ {
+ elog(WARN, "RelationGetStrategy: corrupted evaluation");
+ }
+ }
+
+ return strategy;
}
/* ----------------
- * RelationInvokeStrategy
+ * RelationInvokeStrategy
* ----------------
*/
-bool /* XXX someday, this may return Datum */
+bool /* XXX someday, this may return Datum */
RelationInvokeStrategy(Relation relation,
- StrategyEvaluation evaluation,
- AttrNumber attributeNumber,
- StrategyNumber strategy,
- Datum left,
- Datum right)
+ StrategyEvaluation evaluation,
+ AttrNumber attributeNumber,
+ StrategyNumber strategy,
+ Datum left,
+ Datum right)
{
- StrategyNumber newStrategy;
- StrategyMap strategyMap;
- ScanKey entry;
- StrategyTermData termData;
- int numattrs;
-
- Assert(RelationIsValid(relation));
- Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
- numattrs = RelationGetNumberOfAttributes(relation);
-
- Assert(StrategyEvaluationIsValid(evaluation));
- Assert(AttributeNumberIsValid(attributeNumber));
- Assert( (attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
-
- Assert(StrategyNumberIsInBounds(strategy, evaluation->maxStrategy));
-
- termData.degree = 1;
-
- strategyMap =
- IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
- evaluation->maxStrategy,
- attributeNumber);
-
- entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
-
- if (RegProcedureIsValid(entry->sk_procedure)) {
- termData.operatorData[0].strategy = strategy;
- termData.operatorData[0].flags = 0x0;
-
- return
- StrategyTermEvaluate(&termData, strategyMap, left, right);
- }
-
-
- newStrategy = evaluation->negateTransform->strategy[strategy - 1];
- if (newStrategy != strategy && StrategyNumberIsValid(newStrategy)) {
-
- entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
-
- if (RegProcedureIsValid(entry->sk_procedure)) {
- termData.operatorData[0].strategy = newStrategy;
- termData.operatorData[0].flags = SK_NEGATE;
-
- return
- StrategyTermEvaluate(&termData, strategyMap, left, right);
+ StrategyNumber newStrategy;
+ StrategyMap strategyMap;
+ ScanKey entry;
+ StrategyTermData termData;
+ int numattrs;
+
+ Assert(RelationIsValid(relation));
+ Assert(relation->rd_rel->relkind == RELKIND_INDEX); /* XXX use accessor */
+ numattrs = RelationGetNumberOfAttributes(relation);
+
+ Assert(StrategyEvaluationIsValid(evaluation));
+ Assert(AttributeNumberIsValid(attributeNumber));
+ Assert((attributeNumber >= 1) && (attributeNumber < 1 + numattrs));
+
+ Assert(StrategyNumberIsInBounds(strategy, evaluation->maxStrategy));
+
+ termData.degree = 1;
+
+ strategyMap =
+ IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
+ evaluation->maxStrategy,
+ attributeNumber);
+
+ entry = StrategyMapGetScanKeyEntry(strategyMap, strategy);
+
+ if (RegProcedureIsValid(entry->sk_procedure))
+ {
+ termData.operatorData[0].strategy = strategy;
+ termData.operatorData[0].flags = 0x0;
+
+ return
+ StrategyTermEvaluate(&termData, strategyMap, left, right);
}
- }
-
- newStrategy = evaluation->commuteTransform->strategy[strategy - 1];
- if (newStrategy != strategy && StrategyNumberIsValid(newStrategy)) {
-
- entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
-
- if (RegProcedureIsValid(entry->sk_procedure)) {
- termData.operatorData[0].strategy = newStrategy;
- termData.operatorData[0].flags = SK_COMMUTE;
-
- return
- StrategyTermEvaluate(&termData, strategyMap, left, right);
+
+
+ newStrategy = evaluation->negateTransform->strategy[strategy - 1];
+ if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
+ {
+
+ entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
+
+ if (RegProcedureIsValid(entry->sk_procedure))
+ {
+ termData.operatorData[0].strategy = newStrategy;
+ termData.operatorData[0].flags = SK_NEGATE;
+
+ return
+ StrategyTermEvaluate(&termData, strategyMap, left, right);
+ }
}
- }
-
- newStrategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
- if (newStrategy != strategy && StrategyNumberIsValid(newStrategy)) {
-
- entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
-
- if (RegProcedureIsValid(entry->sk_procedure)) {
- termData.operatorData[0].strategy = newStrategy;
- termData.operatorData[0].flags = SK_NEGATE | SK_COMMUTE;
-
- return
- StrategyTermEvaluate(&termData, strategyMap, left, right);
+
+ newStrategy = evaluation->commuteTransform->strategy[strategy - 1];
+ if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
+ {
+
+ entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
+
+ if (RegProcedureIsValid(entry->sk_procedure))
+ {
+ termData.operatorData[0].strategy = newStrategy;
+ termData.operatorData[0].flags = SK_COMMUTE;
+
+ return
+ StrategyTermEvaluate(&termData, strategyMap, left, right);
+ }
}
- }
-
- if (PointerIsValid(evaluation->expression[strategy - 1])) {
- StrategyTerm *termP;
-
- termP = &evaluation->expression[strategy - 1]->term[0];
- while (PointerIsValid(*termP)) {
- Index index;
-
- for (index = 0; index < (*termP)->degree; index += 1) {
- entry = StrategyMapGetScanKeyEntry(strategyMap,
- (*termP)->operatorData[index].strategy);
-
- if (! RegProcedureIsValid(entry->sk_procedure)) {
- break;
+
+ newStrategy = evaluation->negateCommuteTransform->strategy[strategy - 1];
+ if (newStrategy != strategy && StrategyNumberIsValid(newStrategy))
+ {
+
+ entry = StrategyMapGetScanKeyEntry(strategyMap, newStrategy);
+
+ if (RegProcedureIsValid(entry->sk_procedure))
+ {
+ termData.operatorData[0].strategy = newStrategy;
+ termData.operatorData[0].flags = SK_NEGATE | SK_COMMUTE;
+
+ return
+ StrategyTermEvaluate(&termData, strategyMap, left, right);
}
- }
-
- if (index == (*termP)->degree) {
- return
- StrategyTermEvaluate(*termP, strategyMap, left, right);
- }
-
- termP += 1;
}
- }
-
- elog(WARN, "RelationInvokeStrategy: cannot evaluate strategy %d",
- strategy);
- /* not reached, just to make compiler happy */
- return FALSE;
+ if (PointerIsValid(evaluation->expression[strategy - 1]))
+ {
+ StrategyTerm *termP;
+
+ termP = &evaluation->expression[strategy - 1]->term[0];
+ while (PointerIsValid(*termP))
+ {
+ Index index;
+
+ for (index = 0; index < (*termP)->degree; index += 1)
+ {
+ entry = StrategyMapGetScanKeyEntry(strategyMap,
+ (*termP)->operatorData[index].strategy);
+
+ if (!RegProcedureIsValid(entry->sk_procedure))
+ {
+ break;
+ }
+ }
+
+ if (index == (*termP)->degree)
+ {
+ return
+ StrategyTermEvaluate(*termP, strategyMap, left, right);
+ }
+
+ termP += 1;
+ }
+ }
+
+ elog(WARN, "RelationInvokeStrategy: cannot evaluate strategy %d",
+ strategy);
+
+ /* not reached, just to make compiler happy */
+ return FALSE;
}
/* ----------------
- * OperatorRelationFillScanKeyEntry
+ * OperatorRelationFillScanKeyEntry
* ----------------
*/
static void
OperatorRelationFillScanKeyEntry(Relation operatorRelation,
- Oid operatorObjectId,
- ScanKey entry)
+ Oid operatorObjectId,
+ ScanKey entry)
{
- HeapScanDesc scan;
- ScanKeyData scanKeyData;
- HeapTuple tuple;
-
- ScanKeyEntryInitialize(&scanKeyData, 0,
- ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(operatorObjectId));
-
- scan = heap_beginscan(operatorRelation, false, NowTimeQual,
- 1, &scanKeyData);
-
- tuple = heap_getnext(scan, false, (Buffer *)NULL);
- if (! HeapTupleIsValid(tuple)) {
- elog(WARN, "OperatorObjectIdFillScanKeyEntry: unknown operator %lu",
- (uint32) operatorObjectId);
- }
-
- entry->sk_flags = 0;
- entry->sk_procedure =
- ((OperatorTupleForm) GETSTRUCT(tuple))->oprcode;
- fmgr_info(entry->sk_procedure, &entry->sk_func, &entry->sk_nargs);
-
- if (! RegProcedureIsValid(entry->sk_procedure)) {
- elog(WARN,
- "OperatorObjectIdFillScanKeyEntry: no procedure for operator %lu",
- (uint32) operatorObjectId);
- }
-
- heap_endscan(scan);
+ HeapScanDesc scan;
+ ScanKeyData scanKeyData;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&scanKeyData, 0,
+ ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(operatorObjectId));
+
+ scan = heap_beginscan(operatorRelation, false, NowTimeQual,
+ 1, &scanKeyData);
+
+ tuple = heap_getnext(scan, false, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "OperatorObjectIdFillScanKeyEntry: unknown operator %lu",
+ (uint32) operatorObjectId);
+ }
+
+ entry->sk_flags = 0;
+ entry->sk_procedure =
+ ((OperatorTupleForm) GETSTRUCT(tuple))->oprcode;
+ fmgr_info(entry->sk_procedure, &entry->sk_func, &entry->sk_nargs);
+
+ if (!RegProcedureIsValid(entry->sk_procedure))
+ {
+ elog(WARN,
+ "OperatorObjectIdFillScanKeyEntry: no procedure for operator %lu",
+ (uint32) operatorObjectId);
+ }
+
+ heap_endscan(scan);
}
/*
* IndexSupportInitialize --
- * Initializes an index strategy and associated support procedures.
+ * Initializes an index strategy and associated support procedures.
*/
void
IndexSupportInitialize(IndexStrategy indexStrategy,
- RegProcedure *indexSupport,
- Oid indexObjectId,
- Oid accessMethodObjectId,
- StrategyNumber maxStrategyNumber,
- StrategyNumber maxSupportNumber,
- AttrNumber maxAttributeNumber)
+ RegProcedure * indexSupport,
+ Oid indexObjectId,
+ Oid accessMethodObjectId,
+ StrategyNumber maxStrategyNumber,
+ StrategyNumber maxSupportNumber,
+ AttrNumber maxAttributeNumber)
{
- Relation relation;
- Relation operatorRelation;
- HeapScanDesc scan;
- HeapTuple tuple;
- ScanKeyData entry[2];
- StrategyMap map;
- AttrNumber attributeNumber;
- int attributeIndex;
- Oid operatorClassObjectId[ MaxIndexAttributeNumber ];
-
- maxStrategyNumber = AMStrategies(maxStrategyNumber);
-
- ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(indexObjectId));
-
- relation = heap_openr(IndexRelationName);
- scan = heap_beginscan(relation, false, NowTimeQual, 1, entry);
- tuple = heap_getnext(scan, 0, (Buffer *)NULL);
- if (! HeapTupleIsValid(tuple))
- elog(WARN, "IndexSupportInitialize: corrupted catalogs");
-
- /*
- * XXX note that the following assumes the INDEX tuple is well formed and
- * that the key[] and class[] are 0 terminated.
- */
- for (attributeIndex=0; attributeIndex<maxAttributeNumber; attributeIndex++)
+ Relation relation;
+ Relation operatorRelation;
+ HeapScanDesc scan;
+ HeapTuple tuple;
+ ScanKeyData entry[2];
+ StrategyMap map;
+ AttrNumber attributeNumber;
+ int attributeIndex;
+ Oid operatorClassObjectId[MaxIndexAttributeNumber];
+
+ maxStrategyNumber = AMStrategies(maxStrategyNumber);
+
+ ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_index_indexrelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(indexObjectId));
+
+ relation = heap_openr(IndexRelationName);
+ scan = heap_beginscan(relation, false, NowTimeQual, 1, entry);
+ tuple = heap_getnext(scan, 0, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ elog(WARN, "IndexSupportInitialize: corrupted catalogs");
+
+ /*
+ * XXX note that the following assumes the INDEX tuple is well formed
+ * and that the key[] and class[] are 0 terminated.
+ */
+ for (attributeIndex = 0; attributeIndex < maxAttributeNumber; attributeIndex++)
{
- IndexTupleForm iform;
-
- iform = (IndexTupleForm) GETSTRUCT(tuple);
-
- if (!OidIsValid(iform->indkey[attributeIndex])) {
- if (attributeIndex == 0) {
- elog(WARN, "IndexSupportInitialize: no pg_index tuple");
+ IndexTupleForm iform;
+
+ iform = (IndexTupleForm) GETSTRUCT(tuple);
+
+ if (!OidIsValid(iform->indkey[attributeIndex]))
+ {
+ if (attributeIndex == 0)
+ {
+ elog(WARN, "IndexSupportInitialize: no pg_index tuple");
+ }
+ break;
}
- break;
- }
-
- operatorClassObjectId[attributeIndex]
- = iform->indclass[attributeIndex];
+
+ operatorClassObjectId[attributeIndex]
+ = iform->indclass[attributeIndex];
}
-
- heap_endscan(scan);
- heap_close(relation);
-
- /* if support routines exist for this access method, load them */
- if (maxSupportNumber > 0) {
-
- ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_amproc_amid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(accessMethodObjectId));
-
- ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
- ObjectIdEqualRegProcedure, 0);
-
-/* relation = heap_openr(Name_pg_amproc); */
- relation = heap_openr(AccessMethodProcedureRelationName);
-
-
+
+ heap_endscan(scan);
+ heap_close(relation);
+
+ /* if support routines exist for this access method, load them */
+ if (maxSupportNumber > 0)
+ {
+
+ ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_amproc_amid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(accessMethodObjectId));
+
+ ScanKeyEntryInitialize(&entry[1], 0, Anum_pg_amproc_amopclaid,
+ ObjectIdEqualRegProcedure, 0);
+
+/* relation = heap_openr(Name_pg_amproc); */
+ relation = heap_openr(AccessMethodProcedureRelationName);
+
+
+ for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
+ attributeNumber--)
+ {
+
+ int16 support;
+ Form_pg_amproc form;
+ RegProcedure *loc;
+
+ loc = &indexSupport[((attributeNumber - 1) * maxSupportNumber)];
+
+ for (support = maxSupportNumber; --support >= 0;)
+ {
+ loc[support] = InvalidOid;
+ }
+
+ entry[1].sk_argument =
+ ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
+
+ scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
+
+ while (tuple = heap_getnext(scan, 0, (Buffer *) NULL),
+ HeapTupleIsValid(tuple))
+ {
+
+ form = (Form_pg_amproc) GETSTRUCT(tuple);
+ loc[(form->amprocnum - 1)] = form->amproc;
+ }
+
+ heap_endscan(scan);
+ }
+ heap_close(relation);
+ }
+
+ ScanKeyEntryInitialize(&entry[0], 0,
+ Anum_pg_amop_amopid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(accessMethodObjectId));
+
+ ScanKeyEntryInitialize(&entry[1], 0,
+ Anum_pg_amop_amopclaid,
+ ObjectIdEqualRegProcedure, 0);
+
+ relation = heap_openr(AccessMethodOperatorRelationName);
+ operatorRelation = heap_openr(OperatorRelationName);
+
for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
- attributeNumber--) {
-
- int16 support;
- Form_pg_amproc form;
- RegProcedure *loc;
-
- loc = &indexSupport[((attributeNumber - 1) * maxSupportNumber)];
-
- for (support = maxSupportNumber; --support >= 0; ) {
- loc[support] = InvalidOid;
- }
-
- entry[1].sk_argument =
- ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
-
- scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
-
- while (tuple = heap_getnext(scan, 0, (Buffer *)NULL),
- HeapTupleIsValid(tuple)) {
-
- form = (Form_pg_amproc) GETSTRUCT(tuple);
- loc[(form->amprocnum - 1)] = form->amproc;
- }
-
- heap_endscan(scan);
+ attributeNumber--)
+ {
+
+ StrategyNumber strategy;
+
+ entry[1].sk_argument =
+ ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
+
+ map = IndexStrategyGetStrategyMap(indexStrategy,
+ maxStrategyNumber,
+ attributeNumber);
+
+ for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
+ ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));
+
+ scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
+
+ while (tuple = heap_getnext(scan, 0, (Buffer *) NULL),
+ HeapTupleIsValid(tuple))
+ {
+ Form_pg_amop form;
+
+ form = (Form_pg_amop) GETSTRUCT(tuple);
+
+ OperatorRelationFillScanKeyEntry(operatorRelation,
+ form->amopopr,
+ StrategyMapGetScanKeyEntry(map, form->amopstrategy));
+ }
+
+ heap_endscan(scan);
}
+
+ heap_close(operatorRelation);
heap_close(relation);
- }
-
- ScanKeyEntryInitialize(&entry[0], 0,
- Anum_pg_amop_amopid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(accessMethodObjectId));
-
- ScanKeyEntryInitialize(&entry[1], 0,
- Anum_pg_amop_amopclaid,
- ObjectIdEqualRegProcedure, 0);
-
- relation = heap_openr(AccessMethodOperatorRelationName);
- operatorRelation = heap_openr(OperatorRelationName);
-
- for (attributeNumber = maxAttributeNumber; attributeNumber > 0;
- attributeNumber--) {
-
- StrategyNumber strategy;
-
- entry[1].sk_argument =
- ObjectIdGetDatum(operatorClassObjectId[attributeNumber - 1]);
-
- map = IndexStrategyGetStrategyMap(indexStrategy,
- maxStrategyNumber,
- attributeNumber);
-
- for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
- ScanKeyEntrySetIllegal(StrategyMapGetScanKeyEntry(map, strategy));
-
- scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
-
- while (tuple = heap_getnext(scan, 0, (Buffer *)NULL),
- HeapTupleIsValid(tuple)) {
- Form_pg_amop form;
-
- form = (Form_pg_amop) GETSTRUCT(tuple);
-
- OperatorRelationFillScanKeyEntry(operatorRelation,
- form->amopopr,
- StrategyMapGetScanKeyEntry(map, form->amopstrategy));
- }
-
- heap_endscan(scan);
- }
-
- heap_close(operatorRelation);
- heap_close(relation);
}
/* ----------------
- * IndexStrategyDisplay
+ * IndexStrategyDisplay
* ----------------
*/
#ifdef ISTRATDEBUG
int
IndexStrategyDisplay(IndexStrategy indexStrategy,
- StrategyNumber numberOfStrategies,
- int numberOfAttributes)
+ StrategyNumber numberOfStrategies,
+ int numberOfAttributes)
{
- StrategyMap strategyMap;
- AttrNumber attributeNumber;
- StrategyNumber strategyNumber;
-
- for (attributeNumber = 1; attributeNumber <= numberOfAttributes;
- attributeNumber += 1) {
-
- strategyMap = IndexStrategyGetStrategyMap(indexStrategy,
- numberOfStrategies,
- attributeNumber);
-
- for (strategyNumber = 1;
- strategyNumber <= AMStrategies(numberOfStrategies);
- strategyNumber += 1) {
-
- printf(":att %d\t:str %d\t:opr 0x%x(%d)\n",
- attributeNumber, strategyNumber,
- strategyMap->entry[strategyNumber - 1].sk_procedure,
- strategyMap->entry[strategyNumber - 1].sk_procedure);
+ StrategyMap strategyMap;
+ AttrNumber attributeNumber;
+ StrategyNumber strategyNumber;
+
+ for (attributeNumber = 1; attributeNumber <= numberOfAttributes;
+ attributeNumber += 1)
+ {
+
+ strategyMap = IndexStrategyGetStrategyMap(indexStrategy,
+ numberOfStrategies,
+ attributeNumber);
+
+ for (strategyNumber = 1;
+ strategyNumber <= AMStrategies(numberOfStrategies);
+ strategyNumber += 1)
+ {
+
+ printf(":att %d\t:str %d\t:opr 0x%x(%d)\n",
+ attributeNumber, strategyNumber,
+ strategyMap->entry[strategyNumber - 1].sk_procedure,
+ strategyMap->entry[strategyNumber - 1].sk_procedure);
+ }
}
- }
}
-#endif /* defined(ISTRATDEBUG) */
-
+#endif /* defined(ISTRATDEBUG) */
diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c
index f005509be07..0312bbb69d7 100644
--- a/src/backend/access/nbtree/nbtcompare.c
+++ b/src/backend/access/nbtree/nbtcompare.c
@@ -1,22 +1,22 @@
/*-------------------------------------------------------------------------
*
* nbtcompare.c--
- * Comparison functions for btree access method.
+ * Comparison functions for btree access method.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.10 1997/06/11 05:20:05 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.11 1997/09/07 04:38:39 momjian Exp $
*
- * NOTES
- * These functions are stored in pg_amproc. For each operator class
- * defined on btrees, they compute
+ * NOTES
+ * These functions are stored in pg_amproc. For each operator class
+ * defined on btrees, they compute
*
- * compare(a, b):
- * < 0 if a < b,
- * = 0 if a == b,
- * > 0 if a > b.
+ * compare(a, b):
+ * < 0 if a < b,
+ * = 0 if a == b,
+ * > 0 if a > b.
*-------------------------------------------------------------------------
*/
@@ -30,168 +30,171 @@
int32
btint2cmp(int16 a, int16 b)
{
- return ((int32) (a - b));
+ return ((int32) (a - b));
}
int32
btint4cmp(int32 a, int32 b)
{
- return (a - b);
+ return (a - b);
}
int32
btint24cmp(int16 a, int32 b)
{
- return (((int32) a) - b);
+ return (((int32) a) - b);
}
int32
btint42cmp(int32 a, int16 b)
{
- return (a - ((int32) b));
+ return (a - ((int32) b));
}
int32
btfloat4cmp(float32 a, float32 b)
{
- if (*a > *b)
- return (1);
- else if (*a == *b)
- return (0);
- else
- return (-1);
+ if (*a > *b)
+ return (1);
+ else if (*a == *b)
+ return (0);
+ else
+ return (-1);
}
int32
btfloat8cmp(float64 a, float64 b)
{
- if (*a > *b)
- return (1);
- else if (*a == *b)
- return (0);
- else
- return (-1);
+ if (*a > *b)
+ return (1);
+ else if (*a == *b)
+ return (0);
+ else
+ return (-1);
}
int32
btoidcmp(Oid a, Oid b)
{
- if (a > b)
- return (1);
- else if (a == b)
- return (0);
- else
- return (-1);
+ if (a > b)
+ return (1);
+ else if (a == b)
+ return (0);
+ else
+ return (-1);
}
int32
btabstimecmp(AbsoluteTime a, AbsoluteTime b)
{
- if (AbsoluteTimeIsBefore(a, b))
- return (-1);
- else if (AbsoluteTimeIsBefore(b, a))
- return (1);
- else
- return (0);
+ if (AbsoluteTimeIsBefore(a, b))
+ return (-1);
+ else if (AbsoluteTimeIsBefore(b, a))
+ return (1);
+ else
+ return (0);
}
int32
btcharcmp(char a, char b)
{
- return ((int32) ((uint8)a - (uint8)b));
+ return ((int32) ((uint8) a - (uint8) b));
}
int32
btchar2cmp(uint16 a, uint16 b)
{
- return (strncmp((char *) &a, (char *) &b, 2));
+ return (strncmp((char *) &a, (char *) &b, 2));
}
int32
btchar4cmp(uint32 a, uint32 b)
{
- return (strncmp((char *) &a, (char *) &b, 4));
+ return (strncmp((char *) &a, (char *) &b, 4));
}
int32
btchar8cmp(char *a, char *b)
{
- return (strncmp(a, b, 8));
+ return (strncmp(a, b, 8));
}
int32
btchar16cmp(char *a, char *b)
{
- return (strncmp(a, b, 16));
+ return (strncmp(a, b, 16));
}
int32
-btnamecmp(NameData *a, NameData *b)
+btnamecmp(NameData * a, NameData * b)
{
- return (strncmp(a->data, b->data, NAMEDATALEN));
+ return (strncmp(a->data, b->data, NAMEDATALEN));
}
int32
-bttextcmp(struct varlena *a, struct varlena *b)
+bttextcmp(struct varlena * a, struct varlena * b)
{
- int res;
- unsigned char *ap, *bp;
+ int res;
+ unsigned char *ap,
+ *bp;
#ifdef USE_LOCALE
- int la = VARSIZE(a) - VARHDRSZ;
- int lb = VARSIZE(b) - VARHDRSZ;
-
- ap = (unsigned char *) palloc (la + 1);
- bp = (unsigned char *) palloc (lb + 1);
-
- memcpy(ap, VARDATA(a), la);
- *(ap + la) = '\0';
- memcpy(bp, VARDATA(b), lb);
- *(bp + lb) = '\0';
-
- res = strcoll (ap, bp);
-
- pfree (ap);
- pfree (bp);
+ int la = VARSIZE(a) - VARHDRSZ;
+ int lb = VARSIZE(b) - VARHDRSZ;
+
+ ap = (unsigned char *) palloc(la + 1);
+ bp = (unsigned char *) palloc(lb + 1);
+
+ memcpy(ap, VARDATA(a), la);
+ *(ap + la) = '\0';
+ memcpy(bp, VARDATA(b), lb);
+ *(bp + lb) = '\0';
+
+ res = strcoll(ap, bp);
+
+ pfree(ap);
+ pfree(bp);
#else
- int len = VARSIZE(a);
-
- /* len is the length of the shorter of the two strings */
- if ( len > VARSIZE(b) )
- len = VARSIZE(b);
-
- len -= VARHDRSZ;
-
- ap = (unsigned char *) VARDATA(a);
- bp = (unsigned char *) VARDATA(b);
-
- /*
- * If the two strings differ in the first len bytes, or if they're
- * the same in the first len bytes and they're both len bytes long,
- * we're done.
- */
-
- res = 0;
- if (len > 0) {
- do {
- res = (int) (*ap++ - *bp++);
- len--;
- } while (res == 0 && len != 0);
- }
+ int len = VARSIZE(a);
+
+ /* len is the length of the shorter of the two strings */
+ if (len > VARSIZE(b))
+ len = VARSIZE(b);
+
+ len -= VARHDRSZ;
+
+ ap = (unsigned char *) VARDATA(a);
+ bp = (unsigned char *) VARDATA(b);
+
+ /*
+ * If the two strings differ in the first len bytes, or if they're the
+ * same in the first len bytes and they're both len bytes long, we're
+ * done.
+ */
+
+ res = 0;
+ if (len > 0)
+ {
+ do
+ {
+ res = (int) (*ap++ - *bp++);
+ len--;
+ } while (res == 0 && len != 0);
+ }
#endif
-
- if (res != 0 || VARSIZE(a) == VARSIZE(b))
- return (res);
-
- /*
- * The two strings are the same in the first len bytes, and they
- * are of different lengths.
- */
-
- if (VARSIZE(a) < VARSIZE(b))
- return (-1);
- else
- return (1);
+
+ if (res != 0 || VARSIZE(a) == VARSIZE(b))
+ return (res);
+
+ /*
+ * The two strings are the same in the first len bytes, and they are
+ * of different lengths.
+ */
+
+ if (VARSIZE(a) < VARSIZE(b))
+ return (-1);
+ else
+ return (1);
}
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 4dfa6fd2558..4bafbc2ddbb 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* btinsert.c--
- * Item insertion in Lehman and Yao btrees for Postgres.
+ * Item insertion in Lehman and Yao btrees for Postgres.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.17 1997/08/20 14:53:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.18 1997/09/07 04:38:45 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,1386 +22,1437 @@
#include <fmgr.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
static InsertIndexResult _bt_insertonpg(Relation rel, Buffer buf, BTStack stack, int keysz, ScanKey scankey, BTItem btitem, BTItem afteritem);
-static Buffer _bt_split(Relation rel, Buffer buf, OffsetNumber firstright);
+static Buffer _bt_split(Relation rel, Buffer buf, OffsetNumber firstright);
static OffsetNumber _bt_findsplitloc(Relation rel, Page page, OffsetNumber start, OffsetNumber maxoff, Size llimit);
-static void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
+static void _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf);
static OffsetNumber _bt_pgaddtup(Relation rel, Buffer buf, int keysz, ScanKey itup_scankey, Size itemsize, BTItem btitem, BTItem afteritem);
-static bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey, BTItem afteritem);
-static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, BTItem oldItem, BTItem newItem);
-static bool _bt_isequal (TupleDesc itupdesc, Page page, OffsetNumber offnum, int keysz, ScanKey scankey);
+static bool _bt_goesonpg(Relation rel, Buffer buf, Size keysz, ScanKey scankey, BTItem afteritem);
+static void _bt_updateitem(Relation rel, Size keysz, Buffer buf, BTItem oldItem, BTItem newItem);
+static bool _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum, int keysz, ScanKey scankey);
/*
- * _bt_doinsert() -- Handle insertion of a single btitem in the tree.
+ * _bt_doinsert() -- Handle insertion of a single btitem in the tree.
*
- * This routine is called by the public interface routines, btbuild
- * and btinsert. By here, btitem is filled in, and has a unique
- * (xid, seqno) pair.
+ * This routine is called by the public interface routines, btbuild
+ * and btinsert. By here, btitem is filled in, and has a unique
+ * (xid, seqno) pair.
*/
InsertIndexResult
_bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel)
{
- ScanKey itup_scankey;
- IndexTuple itup;
- BTStack stack;
- Buffer buf;
- BlockNumber blkno;
- int natts = rel->rd_rel->relnatts;
- InsertIndexResult res;
-
- itup = &(btitem->bti_itup);
-
- /* we need a scan key to do our search, so build one */
- itup_scankey = _bt_mkscankey(rel, itup);
-
- /* find the page containing this key */
- stack = _bt_search(rel, natts, itup_scankey, &buf);
-
- blkno = BufferGetBlockNumber(buf);
-
- /* trade in our read lock for a write lock */
- _bt_relbuf(rel, buf, BT_READ);
- buf = _bt_getbuf(rel, blkno, BT_WRITE);
-
- /*
- * If the page was split between the time that we surrendered our
- * read lock and acquired our write lock, then this page may no
- * longer be the right place for the key we want to insert. In this
- * case, we need to move right in the tree. See Lehman and Yao for
- * an excruciatingly precise description.
- */
-
- buf = _bt_moveright(rel, buf, natts, itup_scankey, BT_WRITE);
-
- /* if we're not allowing duplicates, make sure the key isn't */
- /* already in the node */
- if ( index_is_unique )
- {
- OffsetNumber offset, maxoff;
- Page page;
+ ScanKey itup_scankey;
+ IndexTuple itup;
+ BTStack stack;
+ Buffer buf;
+ BlockNumber blkno;
+ int natts = rel->rd_rel->relnatts;
+ InsertIndexResult res;
- page = BufferGetPage(buf);
- maxoff = PageGetMaxOffsetNumber (page);
+ itup = &(btitem->bti_itup);
+
+ /* we need a scan key to do our search, so build one */
+ itup_scankey = _bt_mkscankey(rel, itup);
+
+ /* find the page containing this key */
+ stack = _bt_search(rel, natts, itup_scankey, &buf);
- offset = _bt_binsrch(rel, buf, natts, itup_scankey, BT_DESCENT);
+ blkno = BufferGetBlockNumber(buf);
- /* make sure the offset we're given points to an actual */
- /* key on the page before trying to compare it */
- if ( !PageIsEmpty (page) && offset <= maxoff )
+ /* trade in our read lock for a write lock */
+ _bt_relbuf(rel, buf, BT_READ);
+ buf = _bt_getbuf(rel, blkno, BT_WRITE);
+
+ /*
+ * If the page was split between the time that we surrendered our read
+ * lock and acquired our write lock, then this page may no longer be
+ * the right place for the key we want to insert. In this case, we
+ * need to move right in the tree. See Lehman and Yao for an
+ * excruciatingly precise description.
+ */
+
+ buf = _bt_moveright(rel, buf, natts, itup_scankey, BT_WRITE);
+
+ /* if we're not allowing duplicates, make sure the key isn't */
+ /* already in the node */
+ if (index_is_unique)
{
- TupleDesc itupdesc;
- BTItem btitem;
- IndexTuple itup;
- HeapTuple htup;
- BTPageOpaque opaque;
- Buffer nbuf;
- BlockNumber blkno;
-
- itupdesc = RelationGetTupleDescriptor(rel);
- nbuf = InvalidBuffer;
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- /*
- * _bt_compare returns 0 for (1,NULL) and (1,NULL) -
- * this's how we handling NULLs - and so we must not use
- * _bt_compare in real comparison, but only for
- * ordering/finding items on pages. - vadim 03/24/97
-
- while ( !_bt_compare (rel, itupdesc, page,
- natts, itup_scankey, offset) )
- */
- while ( _bt_isequal (itupdesc, page, offset, natts, itup_scankey) )
- { /* they're equal */
- btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offset));
- itup = &(btitem->bti_itup);
- htup = heap_fetch (heapRel, SelfTimeQual, &(itup->t_tid), NULL);
- if ( htup != (HeapTuple) NULL )
- { /* it is a duplicate */
- elog(WARN, "Cannot insert a duplicate key into a unique index.");
- }
- /* get next offnum */
- if ( offset < maxoff )
- {
- offset = OffsetNumberNext(offset);
- }
- else
- { /* move right ? */
- if ( P_RIGHTMOST (opaque) )
- break;
- if ( !_bt_isequal (itupdesc, page, P_HIKEY,
- natts, itup_scankey) )
- break;
- /*
- * min key of the right page is the same,
- * ooh - so many dead duplicates...
- */
- blkno = opaque->btpo_next;
- if ( nbuf != InvalidBuffer )
- _bt_relbuf (rel, nbuf, BT_READ);
- for (nbuf = InvalidBuffer; ; )
- {
- nbuf = _bt_getbuf (rel, blkno, BT_READ);
- page = BufferGetPage (nbuf);
- maxoff = PageGetMaxOffsetNumber(page);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- offset = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
- if ( ! PageIsEmpty (page) && offset <= maxoff )
- { /* Found some key */
- break;
- }
- else
- { /* Empty or "pseudo"-empty page - get next */
- blkno = opaque->btpo_next;
- _bt_relbuf (rel, nbuf, BT_READ);
- nbuf = InvalidBuffer;
- if ( blkno == P_NONE )
- break;
+ OffsetNumber offset,
+ maxoff;
+ Page page;
+
+ page = BufferGetPage(buf);
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ offset = _bt_binsrch(rel, buf, natts, itup_scankey, BT_DESCENT);
+
+ /* make sure the offset we're given points to an actual */
+ /* key on the page before trying to compare it */
+ if (!PageIsEmpty(page) && offset <= maxoff)
+ {
+ TupleDesc itupdesc;
+ BTItem btitem;
+ IndexTuple itup;
+ HeapTuple htup;
+ BTPageOpaque opaque;
+ Buffer nbuf;
+ BlockNumber blkno;
+
+ itupdesc = RelationGetTupleDescriptor(rel);
+ nbuf = InvalidBuffer;
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ /*
+ * _bt_compare returns 0 for (1,NULL) and (1,NULL) - this's
+ * how we handling NULLs - and so we must not use _bt_compare
+ * in real comparison, but only for ordering/finding items on
+ * pages. - vadim 03/24/97
+ *
+ * while ( !_bt_compare (rel, itupdesc, page, natts,
+ * itup_scankey, offset) )
+ */
+ while (_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
+ { /* they're equal */
+ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offset));
+ itup = &(btitem->bti_itup);
+ htup = heap_fetch(heapRel, SelfTimeQual, &(itup->t_tid), NULL);
+ if (htup != (HeapTuple) NULL)
+ { /* it is a duplicate */
+ elog(WARN, "Cannot insert a duplicate key into a unique index.");
+ }
+ /* get next offnum */
+ if (offset < maxoff)
+ {
+ offset = OffsetNumberNext(offset);
+ }
+ else
+ { /* move right ? */
+ if (P_RIGHTMOST(opaque))
+ break;
+ if (!_bt_isequal(itupdesc, page, P_HIKEY,
+ natts, itup_scankey))
+ break;
+
+ /*
+ * min key of the right page is the same, ooh - so
+ * many dead duplicates...
+ */
+ blkno = opaque->btpo_next;
+ if (nbuf != InvalidBuffer)
+ _bt_relbuf(rel, nbuf, BT_READ);
+ for (nbuf = InvalidBuffer;;)
+ {
+ nbuf = _bt_getbuf(rel, blkno, BT_READ);
+ page = BufferGetPage(nbuf);
+ maxoff = PageGetMaxOffsetNumber(page);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ offset = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+ if (!PageIsEmpty(page) && offset <= maxoff)
+ { /* Found some key */
+ break;
+ }
+ else
+ { /* Empty or "pseudo"-empty page - get next */
+ blkno = opaque->btpo_next;
+ _bt_relbuf(rel, nbuf, BT_READ);
+ nbuf = InvalidBuffer;
+ if (blkno == P_NONE)
+ break;
+ }
+ }
+ if (nbuf == InvalidBuffer)
+ break;
+ }
}
- }
- if ( nbuf == InvalidBuffer )
- break;
- }
- }
- if ( nbuf != InvalidBuffer )
- _bt_relbuf(rel, nbuf, BT_READ);
+ if (nbuf != InvalidBuffer)
+ _bt_relbuf(rel, nbuf, BT_READ);
+ }
}
- }
-
- /* do the insertion */
- res = _bt_insertonpg(rel, buf, stack, natts, itup_scankey,
- btitem, (BTItem) NULL);
-
- /* be tidy */
- _bt_freestack(stack);
- _bt_freeskey(itup_scankey);
-
- return (res);
+
+ /* do the insertion */
+ res = _bt_insertonpg(rel, buf, stack, natts, itup_scankey,
+ btitem, (BTItem) NULL);
+
+ /* be tidy */
+ _bt_freestack(stack);
+ _bt_freeskey(itup_scankey);
+
+ return (res);
}
/*
- * _bt_insertonpg() -- Insert a tuple on a particular page in the index.
+ * _bt_insertonpg() -- Insert a tuple on a particular page in the index.
*
- * This recursive procedure does the following things:
+ * This recursive procedure does the following things:
*
- * + if necessary, splits the target page.
- * + finds the right place to insert the tuple (taking into
- * account any changes induced by a split).
- * + inserts the tuple.
- * + if the page was split, pops the parent stack, and finds the
- * right place to insert the new child pointer (by walking
- * right using information stored in the parent stack).
- * + invoking itself with the appropriate tuple for the right
- * child page on the parent.
+ * + if necessary, splits the target page.
+ * + finds the right place to insert the tuple (taking into
+ * account any changes induced by a split).
+ * + inserts the tuple.
+ * + if the page was split, pops the parent stack, and finds the
+ * right place to insert the new child pointer (by walking
+ * right using information stored in the parent stack).
+ * + invoking itself with the appropriate tuple for the right
+ * child page on the parent.
*
- * On entry, we must have the right buffer on which to do the
- * insertion, and the buffer must be pinned and locked. On return,
- * we will have dropped both the pin and the write lock on the buffer.
+ * On entry, we must have the right buffer on which to do the
+ * insertion, and the buffer must be pinned and locked. On return,
+ * we will have dropped both the pin and the write lock on the buffer.
*
- * The locking interactions in this code are critical. You should
- * grok Lehman and Yao's paper before making any changes. In addition,
- * you need to understand how we disambiguate duplicate keys in this
- * implementation, in order to be able to find our location using
- * L&Y "move right" operations. Since we may insert duplicate user
- * keys, and since these dups may propogate up the tree, we use the
- * 'afteritem' parameter to position ourselves correctly for the
- * insertion on internal pages.
+ * The locking interactions in this code are critical. You should
+ * grok Lehman and Yao's paper before making any changes. In addition,
+ * you need to understand how we disambiguate duplicate keys in this
+ * implementation, in order to be able to find our location using
+ * L&Y "move right" operations. Since we may insert duplicate user
+ * keys, and since these dups may propogate up the tree, we use the
+ * 'afteritem' parameter to position ourselves correctly for the
+ * insertion on internal pages.
*/
-static InsertIndexResult
+static InsertIndexResult
_bt_insertonpg(Relation rel,
- Buffer buf,
- BTStack stack,
- int keysz,
- ScanKey scankey,
- BTItem btitem,
- BTItem afteritem)
+ Buffer buf,
+ BTStack stack,
+ int keysz,
+ ScanKey scankey,
+ BTItem btitem,
+ BTItem afteritem)
{
- InsertIndexResult res;
- Page page;
- BTPageOpaque lpageop;
- BlockNumber itup_blkno;
- OffsetNumber itup_off;
- OffsetNumber firstright = InvalidOffsetNumber;
- int itemsz;
- bool do_split = false;
- bool keys_equal = false;
-
- page = BufferGetPage(buf);
- lpageop = (BTPageOpaque) PageGetSpecialPointer(page);
-
- itemsz = IndexTupleDSize(btitem->bti_itup)
- + (sizeof(BTItemData) - sizeof(IndexTupleData));
-
- itemsz = DOUBLEALIGN(itemsz); /* be safe, PageAddItem will do this
- but we need to be consistent */
- /*
- * If we have to insert item on the leftmost page which is the first
- * page in the chain of duplicates then:
- * 1. if scankey == hikey (i.e. - new duplicate item) then
- * insert it here;
- * 2. if scankey < hikey then:
- * 2.a if there is duplicate key(s) here - we force splitting;
- * 2.b else - we may "eat" this page from duplicates chain.
- */
- if ( lpageop->btpo_flags & BTP_CHAIN )
- {
- OffsetNumber maxoff = PageGetMaxOffsetNumber (page);
- ItemId hitemid;
- BTItem hitem;
-
- Assert ( !P_RIGHTMOST(lpageop) );
- hitemid = PageGetItemId(page, P_HIKEY);
- hitem = (BTItem) PageGetItem(page, hitemid);
- if ( maxoff > P_HIKEY &&
- !_bt_itemcmp (rel, keysz, hitem,
- (BTItem) PageGetItem(page, PageGetItemId(page, P_FIRSTKEY)),
- BTEqualStrategyNumber) )
- elog (FATAL, "btree: bad key on the page in the chain of duplicates");
-
- if ( !_bt_skeycmp (rel, keysz, scankey, page, hitemid,
- BTEqualStrategyNumber) )
- {
- if ( !P_LEFTMOST(lpageop) )
- elog (FATAL, "btree: attempt to insert bad key on the non-leftmost page in the chain of duplicates");
- if ( !_bt_skeycmp (rel, keysz, scankey, page, hitemid,
- BTLessStrategyNumber) )
- elog (FATAL, "btree: attempt to insert higher key on the leftmost page in the chain of duplicates");
- if ( maxoff > P_HIKEY ) /* have duplicate(s) */
- {
- firstright = P_FIRSTKEY;
- do_split = true;
- }
- else /* "eat" page */
- {
- Buffer pbuf;
- Page ppage;
-
- itup_blkno = BufferGetBlockNumber(buf);
- itup_off = PageAddItem(page, (Item) btitem, itemsz,
- P_FIRSTKEY, LP_USED);
- if ( itup_off == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add item");
- lpageop->btpo_flags &= ~BTP_CHAIN;
- pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
- ppage = BufferGetPage(pbuf);
- PageIndexTupleDelete(ppage, stack->bts_offset);
- pfree(stack->bts_btitem);
- stack->bts_btitem = _bt_formitem(&(btitem->bti_itup));
- ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
- itup_blkno, P_HIKEY);
- _bt_wrtbuf(rel, buf);
- res = _bt_insertonpg(rel, pbuf, stack->bts_parent,
- keysz, scankey, stack->bts_btitem,
- NULL);
- ItemPointerSet(&(res->pointerData), itup_blkno, itup_off);
- return (res);
- }
- }
- else
- {
- keys_equal = true;
- if ( PageGetFreeSpace(page) < itemsz )
- do_split = true;
- }
- }
- else if ( PageGetFreeSpace(page) < itemsz )
- do_split = true;
- else if ( PageGetFreeSpace(page) < 3*itemsz + 2*sizeof(ItemIdData) )
- {
- OffsetNumber offnum = (P_RIGHTMOST(lpageop)) ? P_HIKEY : P_FIRSTKEY;
- OffsetNumber maxoff = PageGetMaxOffsetNumber (page);
- ItemId itid;
- BTItem previtem, chkitem;
- Size maxsize;
- Size currsize;
-
- itid = PageGetItemId(page, offnum);
- previtem = (BTItem) PageGetItem(page, itid);
- maxsize = currsize = (ItemIdGetLength(itid) + sizeof(ItemIdData));
- for (offnum = OffsetNumberNext(offnum);
- offnum <= maxoff; offnum = OffsetNumberNext(offnum) )
- {
- itid = PageGetItemId(page, offnum);
- chkitem = (BTItem) PageGetItem(page, itid);
- if ( !_bt_itemcmp (rel, keysz, previtem, chkitem,
- BTEqualStrategyNumber) )
- {
- if ( currsize > maxsize )
- maxsize = currsize;
- currsize = 0;
- previtem = chkitem;
- }
- currsize += (ItemIdGetLength(itid) + sizeof(ItemIdData));
- }
- if ( currsize > maxsize )
- maxsize = currsize;
- maxsize += sizeof (PageHeaderData) +
- DOUBLEALIGN (sizeof (BTPageOpaqueData));
- if ( maxsize >= PageGetPageSize (page) / 2 )
- do_split = true;
- }
-
- if ( do_split )
- {
- Buffer rbuf;
- Page rpage;
- BTItem ritem;
- BlockNumber rbknum;
- BTPageOpaque rpageop;
- Buffer pbuf;
- Page ppage;
- BTPageOpaque ppageop;
- BlockNumber bknum = BufferGetBlockNumber(buf);
- BTItem lowLeftItem;
- OffsetNumber maxoff;
- bool shifted = false;
- bool left_chained = ( lpageop->btpo_flags & BTP_CHAIN ) ? true : false;
-
- /*
- * If we have to split leaf page in the chain of duplicates by
- * new duplicate then we try to look at our right sibling first.
- */
- if ( ( lpageop->btpo_flags & BTP_CHAIN ) &&
- ( lpageop->btpo_flags & BTP_LEAF ) && keys_equal )
- {
- bool use_left = true;
-
- rbuf = _bt_getbuf(rel, lpageop->btpo_next, BT_WRITE);
- rpage = BufferGetPage(rbuf);
- rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage);
- if ( !P_RIGHTMOST (rpageop) ) /* non-rightmost page */
- { /*
- * If we have the same hikey here then it's
- * yet another page in chain.
- */
- if ( _bt_skeycmp (rel, keysz, scankey, rpage,
- PageGetItemId(rpage, P_HIKEY),
- BTEqualStrategyNumber) )
- {
- if ( !( rpageop->btpo_flags & BTP_CHAIN ) )
- elog (FATAL, "btree: lost page in the chain of duplicates");
- }
- else if ( _bt_skeycmp (rel, keysz, scankey, rpage,
- PageGetItemId(rpage, P_HIKEY),
- BTGreaterStrategyNumber) )
- elog (FATAL, "btree: hikey is out of order");
- else if ( rpageop->btpo_flags & BTP_CHAIN )
- /*
- * If hikey > scankey then it's last page in chain and
- * BTP_CHAIN must be OFF
- */
- elog (FATAL, "btree: lost last page in the chain of duplicates");
-
- /* if there is room here then we use this page. */
- if ( PageGetFreeSpace (rpage) > itemsz )
- use_left = false;
- }
- else /* rightmost page */
- {
- Assert ( !( rpageop->btpo_flags & BTP_CHAIN ) );
- /* if there is room here then we use this page. */
- if ( PageGetFreeSpace (rpage) > itemsz )
- use_left = false;
- }
- if ( !use_left ) /* insert on the right page */
- {
- _bt_relbuf(rel, buf, BT_WRITE);
- return ( _bt_insertonpg(rel, rbuf, stack, keysz,
- scankey, btitem, afteritem) );
- }
- _bt_relbuf(rel, rbuf, BT_WRITE);
- }
+ InsertIndexResult res;
+ Page page;
+ BTPageOpaque lpageop;
+ BlockNumber itup_blkno;
+ OffsetNumber itup_off;
+ OffsetNumber firstright = InvalidOffsetNumber;
+ int itemsz;
+ bool do_split = false;
+ bool keys_equal = false;
+
+ page = BufferGetPage(buf);
+ lpageop = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ itemsz = IndexTupleDSize(btitem->bti_itup)
+ + (sizeof(BTItemData) - sizeof(IndexTupleData));
+
+ itemsz = DOUBLEALIGN(itemsz); /* be safe, PageAddItem will do
+ * this but we need to be
+ * consistent */
+
/*
- * If after splitting un-chained page we'll got chain of pages
- * with duplicates then we want to know
- * 1. on which of two pages new btitem will go (current
- * _bt_findsplitloc is quite bad);
- * 2. what parent (if there's one) thinking about it
- * (remember about deletions)
+ * If we have to insert item on the leftmost page which is the first
+ * page in the chain of duplicates then: 1. if scankey == hikey (i.e.
+ * - new duplicate item) then insert it here; 2. if scankey < hikey
+ * then: 2.a if there is duplicate key(s) here - we force splitting;
+ * 2.b else - we may "eat" this page from duplicates chain.
*/
- else if ( !( lpageop->btpo_flags & BTP_CHAIN ) )
+ if (lpageop->btpo_flags & BTP_CHAIN)
{
- OffsetNumber start = ( P_RIGHTMOST(lpageop) ) ? P_HIKEY : P_FIRSTKEY;
- Size llimit;
-
- maxoff = PageGetMaxOffsetNumber (page);
- llimit = PageGetPageSize(page) - sizeof (PageHeaderData) -
- DOUBLEALIGN (sizeof (BTPageOpaqueData))
- + sizeof(ItemIdData);
- llimit /= 2;
- firstright = _bt_findsplitloc(rel, page, start, maxoff, llimit);
-
- if ( _bt_itemcmp (rel, keysz,
- (BTItem) PageGetItem(page, PageGetItemId(page, start)),
- (BTItem) PageGetItem(page, PageGetItemId(page, firstright)),
- BTEqualStrategyNumber) )
- {
- if ( _bt_skeycmp (rel, keysz, scankey, page,
- PageGetItemId(page, firstright),
- BTLessStrategyNumber) )
- /*
- * force moving current items to the new page:
- * new item will go on the current page.
- */
- firstright = start;
- else
- /*
- * new btitem >= firstright, start item == firstright -
- * new chain of duplicates: if this non-leftmost leaf
- * page and parent item < start item then force moving
- * all items to the new page - current page will be
- * "empty" after it.
- */
- {
- if ( !P_LEFTMOST (lpageop) &&
- ( lpageop->btpo_flags & BTP_LEAF ) )
- {
- ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
- bknum, P_HIKEY);
- pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
- if ( _bt_itemcmp (rel, keysz, stack->bts_btitem,
- (BTItem) PageGetItem(page,
- PageGetItemId(page, start)),
- BTLessStrategyNumber) )
- {
- firstright = start;
- shifted = true;
- }
- _bt_relbuf(rel, pbuf, BT_WRITE);
- }
- }
- } /* else - no new chain if start item < firstright one */
- }
-
- /* split the buffer into left and right halves */
- rbuf = _bt_split(rel, buf, firstright);
-
- /* which new page (left half or right half) gets the tuple? */
- if (_bt_goesonpg(rel, buf, keysz, scankey, afteritem)) {
- /* left page */
- itup_off = _bt_pgaddtup(rel, buf, keysz, scankey,
- itemsz, btitem, afteritem);
- itup_blkno = BufferGetBlockNumber(buf);
- } else {
- /* right page */
- itup_off = _bt_pgaddtup(rel, rbuf, keysz, scankey,
- itemsz, btitem, afteritem);
- itup_blkno = BufferGetBlockNumber(rbuf);
+ OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
+ ItemId hitemid;
+ BTItem hitem;
+
+ Assert(!P_RIGHTMOST(lpageop));
+ hitemid = PageGetItemId(page, P_HIKEY);
+ hitem = (BTItem) PageGetItem(page, hitemid);
+ if (maxoff > P_HIKEY &&
+ !_bt_itemcmp(rel, keysz, hitem,
+ (BTItem) PageGetItem(page, PageGetItemId(page, P_FIRSTKEY)),
+ BTEqualStrategyNumber))
+ elog(FATAL, "btree: bad key on the page in the chain of duplicates");
+
+ if (!_bt_skeycmp(rel, keysz, scankey, page, hitemid,
+ BTEqualStrategyNumber))
+ {
+ if (!P_LEFTMOST(lpageop))
+ elog(FATAL, "btree: attempt to insert bad key on the non-leftmost page in the chain of duplicates");
+ if (!_bt_skeycmp(rel, keysz, scankey, page, hitemid,
+ BTLessStrategyNumber))
+ elog(FATAL, "btree: attempt to insert higher key on the leftmost page in the chain of duplicates");
+ if (maxoff > P_HIKEY) /* have duplicate(s) */
+ {
+ firstright = P_FIRSTKEY;
+ do_split = true;
+ }
+ else
+/* "eat" page */
+ {
+ Buffer pbuf;
+ Page ppage;
+
+ itup_blkno = BufferGetBlockNumber(buf);
+ itup_off = PageAddItem(page, (Item) btitem, itemsz,
+ P_FIRSTKEY, LP_USED);
+ if (itup_off == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add item");
+ lpageop->btpo_flags &= ~BTP_CHAIN;
+ pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
+ ppage = BufferGetPage(pbuf);
+ PageIndexTupleDelete(ppage, stack->bts_offset);
+ pfree(stack->bts_btitem);
+ stack->bts_btitem = _bt_formitem(&(btitem->bti_itup));
+ ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
+ itup_blkno, P_HIKEY);
+ _bt_wrtbuf(rel, buf);
+ res = _bt_insertonpg(rel, pbuf, stack->bts_parent,
+ keysz, scankey, stack->bts_btitem,
+ NULL);
+ ItemPointerSet(&(res->pointerData), itup_blkno, itup_off);
+ return (res);
+ }
+ }
+ else
+ {
+ keys_equal = true;
+ if (PageGetFreeSpace(page) < itemsz)
+ do_split = true;
+ }
}
-
- maxoff = PageGetMaxOffsetNumber (page);
- if ( shifted )
- {
- if ( maxoff > P_FIRSTKEY )
- elog (FATAL, "btree: shifted page is not empty");
- lowLeftItem = (BTItem) NULL;
- }
- else
- {
- if ( maxoff < P_FIRSTKEY )
- elog (FATAL, "btree: un-shifted page is empty");
- lowLeftItem = (BTItem) PageGetItem(page,
- PageGetItemId(page, P_FIRSTKEY));
- if ( _bt_itemcmp (rel, keysz, lowLeftItem,
- (BTItem) PageGetItem(page, PageGetItemId(page, P_HIKEY)),
- BTEqualStrategyNumber) )
- lpageop->btpo_flags |= BTP_CHAIN;
+ else if (PageGetFreeSpace(page) < itemsz)
+ do_split = true;
+ else if (PageGetFreeSpace(page) < 3 * itemsz + 2 * sizeof(ItemIdData))
+ {
+ OffsetNumber offnum = (P_RIGHTMOST(lpageop)) ? P_HIKEY : P_FIRSTKEY;
+ OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
+ ItemId itid;
+ BTItem previtem,
+ chkitem;
+ Size maxsize;
+ Size currsize;
+
+ itid = PageGetItemId(page, offnum);
+ previtem = (BTItem) PageGetItem(page, itid);
+ maxsize = currsize = (ItemIdGetLength(itid) + sizeof(ItemIdData));
+ for (offnum = OffsetNumberNext(offnum);
+ offnum <= maxoff; offnum = OffsetNumberNext(offnum))
+ {
+ itid = PageGetItemId(page, offnum);
+ chkitem = (BTItem) PageGetItem(page, itid);
+ if (!_bt_itemcmp(rel, keysz, previtem, chkitem,
+ BTEqualStrategyNumber))
+ {
+ if (currsize > maxsize)
+ maxsize = currsize;
+ currsize = 0;
+ previtem = chkitem;
+ }
+ currsize += (ItemIdGetLength(itid) + sizeof(ItemIdData));
+ }
+ if (currsize > maxsize)
+ maxsize = currsize;
+ maxsize += sizeof(PageHeaderData) +
+ DOUBLEALIGN(sizeof(BTPageOpaqueData));
+ if (maxsize >= PageGetPageSize(page) / 2)
+ do_split = true;
}
- /*
- * By here,
- *
- * + our target page has been split;
- * + the original tuple has been inserted;
- * + we have write locks on both the old (left half) and new
- * (right half) buffers, after the split; and
- * + we have the key we want to insert into the parent.
- *
- * Do the parent insertion. We need to hold onto the locks for
- * the child pages until we locate the parent, but we can release
- * them before doing the actual insertion (see Lehman and Yao for
- * the reasoning).
- */
-
- if (stack == (BTStack) NULL) {
-
- /* create a new root node and release the split buffers */
- _bt_newroot(rel, buf, rbuf);
- _bt_relbuf(rel, buf, BT_WRITE);
- _bt_relbuf(rel, rbuf, BT_WRITE);
-
- } else {
- ScanKey newskey;
- InsertIndexResult newres;
- BTItem new_item;
- OffsetNumber upditem_offset = P_HIKEY;
- bool do_update = false;
- bool update_in_place = true;
- bool parent_chained;
-
- /* form a index tuple that points at the new right page */
- rbknum = BufferGetBlockNumber(rbuf);
- rpage = BufferGetPage(rbuf);
- rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage);
-
- /*
- * By convention, the first entry (1) on every
- * non-rightmost page is the high key for that page. In
- * order to get the lowest key on the new right page, we
- * actually look at its second (2) entry.
- */
-
- if (! P_RIGHTMOST(rpageop))
- {
- ritem = (BTItem) PageGetItem(rpage,
- PageGetItemId(rpage, P_FIRSTKEY));
- if ( _bt_itemcmp (rel, keysz, ritem,
- (BTItem) PageGetItem(rpage,
- PageGetItemId(rpage, P_HIKEY)),
- BTEqualStrategyNumber) )
- rpageop->btpo_flags |= BTP_CHAIN;
- }
- else
- ritem = (BTItem) PageGetItem(rpage,
- PageGetItemId(rpage, P_HIKEY));
-
- /* get a unique btitem for this key */
- new_item = _bt_formitem(&(ritem->bti_itup));
-
- ItemPointerSet(&(new_item->bti_itup.t_tid), rbknum, P_HIKEY);
-
- /*
- * Find the parent buffer and get the parent page.
- *
- * Oops - if we were moved right then we need to
- * change stack item! We want to find parent pointing to
- * where we are, right ? - vadim 05/27/97
- */
- ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
- bknum, P_HIKEY);
- pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
- ppage = BufferGetPage(pbuf);
- ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
- parent_chained = (( ppageop->btpo_flags & BTP_CHAIN )) ? true : false;
-
- if ( parent_chained && !left_chained )
- elog (FATAL, "nbtree: unexpected chained parent of unchained page");
-
- /*
- * If the key of new_item is < than the key of the item
- * in the parent page pointing to the left page
- * (stack->bts_btitem), we have to update the latter key;
- * otherwise the keys on the parent page wouldn't be
- * monotonically increasing after we inserted the new
- * pointer to the right page (new_item). This only
- * happens if our left page is the leftmost page and a
- * new minimum key had been inserted before, which is not
- * reflected in the parent page but didn't matter so
- * far. If there are duplicate keys and this new minimum
- * key spills over to our new right page, we get an
- * inconsistency if we don't update the left key in the
- * parent page.
- *
- * Also, new duplicates handling code require us to update
- * parent item if some smaller items left on the left page
- * (which is possible in splitting leftmost page) and
- * current parent item == new_item. - vadim 05/27/97
- */
- if ( _bt_itemcmp (rel, keysz, stack->bts_btitem, new_item,
- BTGreaterStrategyNumber) ||
- ( !shifted &&
- _bt_itemcmp(rel, keysz, stack->bts_btitem,
- new_item, BTEqualStrategyNumber) &&
- _bt_itemcmp(rel, keysz, lowLeftItem,
- new_item, BTLessStrategyNumber) ) )
- {
- do_update = true;
- /*
- * figure out which key is leftmost (if the parent page
- * is rightmost, too, it must be the root)
+ if (do_split)
+ {
+ Buffer rbuf;
+ Page rpage;
+ BTItem ritem;
+ BlockNumber rbknum;
+ BTPageOpaque rpageop;
+ Buffer pbuf;
+ Page ppage;
+ BTPageOpaque ppageop;
+ BlockNumber bknum = BufferGetBlockNumber(buf);
+ BTItem lowLeftItem;
+ OffsetNumber maxoff;
+ bool shifted = false;
+ bool left_chained = (lpageop->btpo_flags & BTP_CHAIN) ? true : false;
+
+ /*
+ * If we have to split leaf page in the chain of duplicates by new
+ * duplicate then we try to look at our right sibling first.
*/
- if(P_RIGHTMOST(ppageop))
- upditem_offset = P_HIKEY;
+ if ((lpageop->btpo_flags & BTP_CHAIN) &&
+ (lpageop->btpo_flags & BTP_LEAF) && keys_equal)
+ {
+ bool use_left = true;
+
+ rbuf = _bt_getbuf(rel, lpageop->btpo_next, BT_WRITE);
+ rpage = BufferGetPage(rbuf);
+ rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage);
+ if (!P_RIGHTMOST(rpageop)) /* non-rightmost page */
+ { /* If we have the same hikey here then
+ * it's yet another page in chain. */
+ if (_bt_skeycmp(rel, keysz, scankey, rpage,
+ PageGetItemId(rpage, P_HIKEY),
+ BTEqualStrategyNumber))
+ {
+ if (!(rpageop->btpo_flags & BTP_CHAIN))
+ elog(FATAL, "btree: lost page in the chain of duplicates");
+ }
+ else if (_bt_skeycmp(rel, keysz, scankey, rpage,
+ PageGetItemId(rpage, P_HIKEY),
+ BTGreaterStrategyNumber))
+ elog(FATAL, "btree: hikey is out of order");
+ else if (rpageop->btpo_flags & BTP_CHAIN)
+
+ /*
+ * If hikey > scankey then it's last page in chain and
+ * BTP_CHAIN must be OFF
+ */
+ elog(FATAL, "btree: lost last page in the chain of duplicates");
+
+ /* if there is room here then we use this page. */
+ if (PageGetFreeSpace(rpage) > itemsz)
+ use_left = false;
+ }
+ else
+/* rightmost page */
+ {
+ Assert(!(rpageop->btpo_flags & BTP_CHAIN));
+ /* if there is room here then we use this page. */
+ if (PageGetFreeSpace(rpage) > itemsz)
+ use_left = false;
+ }
+ if (!use_left) /* insert on the right page */
+ {
+ _bt_relbuf(rel, buf, BT_WRITE);
+ return (_bt_insertonpg(rel, rbuf, stack, keysz,
+ scankey, btitem, afteritem));
+ }
+ _bt_relbuf(rel, rbuf, BT_WRITE);
+ }
+
+ /*
+ * If after splitting un-chained page we'll got chain of pages
+ * with duplicates then we want to know 1. on which of two pages
+ * new btitem will go (current _bt_findsplitloc is quite bad); 2.
+ * what parent (if there's one) thinking about it (remember about
+ * deletions)
+ */
+ else if (!(lpageop->btpo_flags & BTP_CHAIN))
+ {
+ OffsetNumber start = (P_RIGHTMOST(lpageop)) ? P_HIKEY : P_FIRSTKEY;
+ Size llimit;
+
+ maxoff = PageGetMaxOffsetNumber(page);
+ llimit = PageGetPageSize(page) - sizeof(PageHeaderData) -
+ DOUBLEALIGN(sizeof(BTPageOpaqueData))
+ + sizeof(ItemIdData);
+ llimit /= 2;
+ firstright = _bt_findsplitloc(rel, page, start, maxoff, llimit);
+
+ if (_bt_itemcmp(rel, keysz,
+ (BTItem) PageGetItem(page, PageGetItemId(page, start)),
+ (BTItem) PageGetItem(page, PageGetItemId(page, firstright)),
+ BTEqualStrategyNumber))
+ {
+ if (_bt_skeycmp(rel, keysz, scankey, page,
+ PageGetItemId(page, firstright),
+ BTLessStrategyNumber))
+
+ /*
+ * force moving current items to the new page: new
+ * item will go on the current page.
+ */
+ firstright = start;
+ else
+
+ /*
+ * new btitem >= firstright, start item == firstright
+ * - new chain of duplicates: if this non-leftmost
+ * leaf page and parent item < start item then force
+ * moving all items to the new page - current page
+ * will be "empty" after it.
+ */
+ {
+ if (!P_LEFTMOST(lpageop) &&
+ (lpageop->btpo_flags & BTP_LEAF))
+ {
+ ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
+ bknum, P_HIKEY);
+ pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
+ if (_bt_itemcmp(rel, keysz, stack->bts_btitem,
+ (BTItem) PageGetItem(page,
+ PageGetItemId(page, start)),
+ BTLessStrategyNumber))
+ {
+ firstright = start;
+ shifted = true;
+ }
+ _bt_relbuf(rel, pbuf, BT_WRITE);
+ }
+ }
+ } /* else - no new chain if start item <
+ * firstright one */
+ }
+
+ /* split the buffer into left and right halves */
+ rbuf = _bt_split(rel, buf, firstright);
+
+ /* which new page (left half or right half) gets the tuple? */
+ if (_bt_goesonpg(rel, buf, keysz, scankey, afteritem))
+ {
+ /* left page */
+ itup_off = _bt_pgaddtup(rel, buf, keysz, scankey,
+ itemsz, btitem, afteritem);
+ itup_blkno = BufferGetBlockNumber(buf);
+ }
else
- upditem_offset = P_FIRSTKEY;
- if ( !P_LEFTMOST(lpageop) ||
- stack->bts_offset != upditem_offset )
- elog (FATAL, "btree: items are out of order (leftmost %d, stack %u, update %u)",
- P_LEFTMOST(lpageop), stack->bts_offset, upditem_offset);
- }
-
- if ( do_update )
- {
- if ( shifted )
- elog (FATAL, "btree: attempt to update parent for shifted page");
- /*
- * Try to update in place. If out parent page is chained
- * then we must forse insertion.
+ {
+ /* right page */
+ itup_off = _bt_pgaddtup(rel, rbuf, keysz, scankey,
+ itemsz, btitem, afteritem);
+ itup_blkno = BufferGetBlockNumber(rbuf);
+ }
+
+ maxoff = PageGetMaxOffsetNumber(page);
+ if (shifted)
+ {
+ if (maxoff > P_FIRSTKEY)
+ elog(FATAL, "btree: shifted page is not empty");
+ lowLeftItem = (BTItem) NULL;
+ }
+ else
+ {
+ if (maxoff < P_FIRSTKEY)
+ elog(FATAL, "btree: un-shifted page is empty");
+ lowLeftItem = (BTItem) PageGetItem(page,
+ PageGetItemId(page, P_FIRSTKEY));
+ if (_bt_itemcmp(rel, keysz, lowLeftItem,
+ (BTItem) PageGetItem(page, PageGetItemId(page, P_HIKEY)),
+ BTEqualStrategyNumber))
+ lpageop->btpo_flags |= BTP_CHAIN;
+ }
+
+ /*
+ * By here,
+ *
+ * + our target page has been split; + the original tuple has been
+ * inserted; + we have write locks on both the old (left half)
+ * and new (right half) buffers, after the split; and + we have
+ * the key we want to insert into the parent.
+ *
+ * Do the parent insertion. We need to hold onto the locks for the
+ * child pages until we locate the parent, but we can release them
+ * before doing the actual insertion (see Lehman and Yao for the
+ * reasoning).
*/
- if ( !parent_chained &&
- DOUBLEALIGN (IndexTupleDSize (lowLeftItem->bti_itup)) ==
- DOUBLEALIGN (IndexTupleDSize (stack->bts_btitem->bti_itup)) )
- {
- _bt_updateitem(rel, keysz, pbuf,
- stack->bts_btitem, lowLeftItem);
- _bt_relbuf(rel, buf, BT_WRITE);
- _bt_relbuf(rel, rbuf, BT_WRITE);
+
+ if (stack == (BTStack) NULL)
+ {
+
+ /* create a new root node and release the split buffers */
+ _bt_newroot(rel, buf, rbuf);
+ _bt_relbuf(rel, buf, BT_WRITE);
+ _bt_relbuf(rel, rbuf, BT_WRITE);
+
}
else
{
- update_in_place = false;
- PageIndexTupleDelete(ppage, upditem_offset);
-
- /*
- * don't write anything out yet--we still have the write
- * lock, and now we call another _bt_insertonpg to
- * insert the correct key.
- * First, make a new item, using the tuple data from
- * lowLeftItem. Point it to the left child.
- * Update it on the stack at the same time.
- */
- pfree(stack->bts_btitem);
- stack->bts_btitem = _bt_formitem(&(lowLeftItem->bti_itup));
- ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
- bknum, P_HIKEY);
-
- /*
- * Unlock the children before doing this
- *
- * Mmm ... I foresee problems here. - vadim 06/10/97
- */
- _bt_relbuf(rel, buf, BT_WRITE);
- _bt_relbuf(rel, rbuf, BT_WRITE);
-
- /*
- * A regular _bt_binsrch should find the right place to
- * put the new entry, since it should be lower than any
- * other key on the page.
- * Therefore set afteritem to NULL.
- */
- newskey = _bt_mkscankey(rel, &(stack->bts_btitem->bti_itup));
- newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
- keysz, newskey, stack->bts_btitem,
- NULL);
-
- pfree(newres);
- pfree(newskey);
-
- /*
- * we have now lost our lock on the parent buffer, and
- * need to get it back.
- */
- pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
+ ScanKey newskey;
+ InsertIndexResult newres;
+ BTItem new_item;
+ OffsetNumber upditem_offset = P_HIKEY;
+ bool do_update = false;
+ bool update_in_place = true;
+ bool parent_chained;
+
+ /* form a index tuple that points at the new right page */
+ rbknum = BufferGetBlockNumber(rbuf);
+ rpage = BufferGetPage(rbuf);
+ rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage);
+
+ /*
+ * By convention, the first entry (1) on every non-rightmost
+ * page is the high key for that page. In order to get the
+ * lowest key on the new right page, we actually look at its
+ * second (2) entry.
+ */
+
+ if (!P_RIGHTMOST(rpageop))
+ {
+ ritem = (BTItem) PageGetItem(rpage,
+ PageGetItemId(rpage, P_FIRSTKEY));
+ if (_bt_itemcmp(rel, keysz, ritem,
+ (BTItem) PageGetItem(rpage,
+ PageGetItemId(rpage, P_HIKEY)),
+ BTEqualStrategyNumber))
+ rpageop->btpo_flags |= BTP_CHAIN;
+ }
+ else
+ ritem = (BTItem) PageGetItem(rpage,
+ PageGetItemId(rpage, P_HIKEY));
+
+ /* get a unique btitem for this key */
+ new_item = _bt_formitem(&(ritem->bti_itup));
+
+ ItemPointerSet(&(new_item->bti_itup.t_tid), rbknum, P_HIKEY);
+
+ /*
+ * Find the parent buffer and get the parent page.
+ *
+ * Oops - if we were moved right then we need to change stack
+ * item! We want to find parent pointing to where we are,
+ * right ? - vadim 05/27/97
+ */
+ ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
+ bknum, P_HIKEY);
+ pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
+ ppage = BufferGetPage(pbuf);
+ ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
+ parent_chained = ((ppageop->btpo_flags & BTP_CHAIN)) ? true : false;
+
+ if (parent_chained && !left_chained)
+ elog(FATAL, "nbtree: unexpected chained parent of unchained page");
+
+ /*
+ * If the key of new_item is < than the key of the item in the
+ * parent page pointing to the left page (stack->bts_btitem),
+ * we have to update the latter key; otherwise the keys on the
+ * parent page wouldn't be monotonically increasing after we
+ * inserted the new pointer to the right page (new_item). This
+ * only happens if our left page is the leftmost page and a
+ * new minimum key had been inserted before, which is not
+ * reflected in the parent page but didn't matter so far. If
+ * there are duplicate keys and this new minimum key spills
+ * over to our new right page, we get an inconsistency if we
+ * don't update the left key in the parent page.
+ *
+ * Also, new duplicates handling code require us to update parent
+ * item if some smaller items left on the left page (which is
+ * possible in splitting leftmost page) and current parent
+ * item == new_item. - vadim 05/27/97
+ */
+ if (_bt_itemcmp(rel, keysz, stack->bts_btitem, new_item,
+ BTGreaterStrategyNumber) ||
+ (!shifted &&
+ _bt_itemcmp(rel, keysz, stack->bts_btitem,
+ new_item, BTEqualStrategyNumber) &&
+ _bt_itemcmp(rel, keysz, lowLeftItem,
+ new_item, BTLessStrategyNumber)))
+ {
+ do_update = true;
+
+ /*
+ * figure out which key is leftmost (if the parent page is
+ * rightmost, too, it must be the root)
+ */
+ if (P_RIGHTMOST(ppageop))
+ upditem_offset = P_HIKEY;
+ else
+ upditem_offset = P_FIRSTKEY;
+ if (!P_LEFTMOST(lpageop) ||
+ stack->bts_offset != upditem_offset)
+ elog(FATAL, "btree: items are out of order (leftmost %d, stack %u, update %u)",
+ P_LEFTMOST(lpageop), stack->bts_offset, upditem_offset);
+ }
+
+ if (do_update)
+ {
+ if (shifted)
+ elog(FATAL, "btree: attempt to update parent for shifted page");
+
+ /*
+ * Try to update in place. If out parent page is chained
+ * then we must forse insertion.
+ */
+ if (!parent_chained &&
+ DOUBLEALIGN(IndexTupleDSize(lowLeftItem->bti_itup)) ==
+ DOUBLEALIGN(IndexTupleDSize(stack->bts_btitem->bti_itup)))
+ {
+ _bt_updateitem(rel, keysz, pbuf,
+ stack->bts_btitem, lowLeftItem);
+ _bt_relbuf(rel, buf, BT_WRITE);
+ _bt_relbuf(rel, rbuf, BT_WRITE);
+ }
+ else
+ {
+ update_in_place = false;
+ PageIndexTupleDelete(ppage, upditem_offset);
+
+ /*
+ * don't write anything out yet--we still have the
+ * write lock, and now we call another _bt_insertonpg
+ * to insert the correct key. First, make a new item,
+ * using the tuple data from lowLeftItem. Point it to
+ * the left child. Update it on the stack at the same
+ * time.
+ */
+ pfree(stack->bts_btitem);
+ stack->bts_btitem = _bt_formitem(&(lowLeftItem->bti_itup));
+ ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
+ bknum, P_HIKEY);
+
+ /*
+ * Unlock the children before doing this
+ *
+ * Mmm ... I foresee problems here. - vadim 06/10/97
+ */
+ _bt_relbuf(rel, buf, BT_WRITE);
+ _bt_relbuf(rel, rbuf, BT_WRITE);
+
+ /*
+ * A regular _bt_binsrch should find the right place
+ * to put the new entry, since it should be lower than
+ * any other key on the page. Therefore set afteritem
+ * to NULL.
+ */
+ newskey = _bt_mkscankey(rel, &(stack->bts_btitem->bti_itup));
+ newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
+ keysz, newskey, stack->bts_btitem,
+ NULL);
+
+ pfree(newres);
+ pfree(newskey);
+
+ /*
+ * we have now lost our lock on the parent buffer, and
+ * need to get it back.
+ */
+ pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
+ }
+ }
+ else
+ {
+ _bt_relbuf(rel, buf, BT_WRITE);
+ _bt_relbuf(rel, rbuf, BT_WRITE);
+ }
+
+ newskey = _bt_mkscankey(rel, &(new_item->bti_itup));
+
+ afteritem = stack->bts_btitem;
+ if (parent_chained && !update_in_place)
+ {
+ ppage = BufferGetPage(pbuf);
+ ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
+ if (ppageop->btpo_flags & BTP_CHAIN)
+ elog(FATAL, "btree: unexpected BTP_CHAIN flag in parent after update");
+ if (P_RIGHTMOST(ppageop))
+ elog(FATAL, "btree: chained parent is RIGHTMOST after update");
+ maxoff = PageGetMaxOffsetNumber(ppage);
+ if (maxoff != P_FIRSTKEY)
+ elog(FATAL, "btree: FIRSTKEY was unexpected in parent after update");
+ if (_bt_skeycmp(rel, keysz, newskey, ppage,
+ PageGetItemId(ppage, P_FIRSTKEY),
+ BTLessEqualStrategyNumber))
+ elog(FATAL, "btree: parent FIRSTKEY is >= duplicate key after update");
+ if (!_bt_skeycmp(rel, keysz, newskey, ppage,
+ PageGetItemId(ppage, P_HIKEY),
+ BTEqualStrategyNumber))
+ elog(FATAL, "btree: parent HIGHKEY is not equal duplicate key after update");
+ afteritem = (BTItem) NULL;
+ }
+ else if (left_chained && !update_in_place)
+ {
+ ppage = BufferGetPage(pbuf);
+ ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
+ if (!P_RIGHTMOST(ppageop) &&
+ _bt_skeycmp(rel, keysz, newskey, ppage,
+ PageGetItemId(ppage, P_HIKEY),
+ BTGreaterStrategyNumber))
+ afteritem = (BTItem) NULL;
+ }
+ if (afteritem == (BTItem) NULL)
+ {
+ rbuf = _bt_getbuf(rel, ppageop->btpo_next, BT_WRITE);
+ _bt_relbuf(rel, pbuf, BT_WRITE);
+ pbuf = rbuf;
+ }
+
+ newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
+ keysz, newskey, new_item,
+ afteritem);
+
+ /* be tidy */
+ pfree(newres);
+ pfree(newskey);
+ pfree(new_item);
}
- }
- else
- {
- _bt_relbuf(rel, buf, BT_WRITE);
- _bt_relbuf(rel, rbuf, BT_WRITE);
- }
-
- newskey = _bt_mkscankey(rel, &(new_item->bti_itup));
-
- afteritem = stack->bts_btitem;
- if ( parent_chained && !update_in_place )
- {
- ppage = BufferGetPage(pbuf);
- ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
- if ( ppageop->btpo_flags & BTP_CHAIN )
- elog (FATAL, "btree: unexpected BTP_CHAIN flag in parent after update");
- if ( P_RIGHTMOST (ppageop) )
- elog (FATAL, "btree: chained parent is RIGHTMOST after update");
- maxoff = PageGetMaxOffsetNumber (ppage);
- if ( maxoff != P_FIRSTKEY )
- elog (FATAL, "btree: FIRSTKEY was unexpected in parent after update");
- if ( _bt_skeycmp (rel, keysz, newskey, ppage,
- PageGetItemId(ppage, P_FIRSTKEY),
- BTLessEqualStrategyNumber) )
- elog (FATAL, "btree: parent FIRSTKEY is >= duplicate key after update");
- if ( !_bt_skeycmp (rel, keysz, newskey, ppage,
- PageGetItemId(ppage, P_HIKEY),
- BTEqualStrategyNumber) )
- elog (FATAL, "btree: parent HIGHKEY is not equal duplicate key after update");
- afteritem = (BTItem) NULL;
- }
- else if ( left_chained && !update_in_place )
- {
- ppage = BufferGetPage(pbuf);
- ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
- if ( !P_RIGHTMOST (ppageop) &&
- _bt_skeycmp (rel, keysz, newskey, ppage,
- PageGetItemId(ppage, P_HIKEY),
- BTGreaterStrategyNumber) )
- afteritem = (BTItem) NULL;
- }
- if ( afteritem == (BTItem) NULL)
- {
- rbuf = _bt_getbuf(rel, ppageop->btpo_next, BT_WRITE);
- _bt_relbuf(rel, pbuf, BT_WRITE);
- pbuf = rbuf;
- }
-
- newres = _bt_insertonpg(rel, pbuf, stack->bts_parent,
- keysz, newskey, new_item,
- afteritem);
-
- /* be tidy */
- pfree(newres);
- pfree(newskey);
- pfree(new_item);
}
- } else {
- itup_off = _bt_pgaddtup(rel, buf, keysz, scankey,
- itemsz, btitem, afteritem);
- itup_blkno = BufferGetBlockNumber(buf);
-
- _bt_relbuf(rel, buf, BT_WRITE);
- }
-
- /* by here, the new tuple is inserted */
- res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
- ItemPointerSet(&(res->pointerData), itup_blkno, itup_off);
-
- return (res);
+ else
+ {
+ itup_off = _bt_pgaddtup(rel, buf, keysz, scankey,
+ itemsz, btitem, afteritem);
+ itup_blkno = BufferGetBlockNumber(buf);
+
+ _bt_relbuf(rel, buf, BT_WRITE);
+ }
+
+ /* by here, the new tuple is inserted */
+ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
+ ItemPointerSet(&(res->pointerData), itup_blkno, itup_off);
+
+ return (res);
}
/*
- * _bt_split() -- split a page in the btree.
+ * _bt_split() -- split a page in the btree.
*
- * On entry, buf is the page to split, and is write-locked and pinned.
- * Returns the new right sibling of buf, pinned and write-locked. The
- * pin and lock on buf are maintained.
+ * On entry, buf is the page to split, and is write-locked and pinned.
+ * Returns the new right sibling of buf, pinned and write-locked. The
+ * pin and lock on buf are maintained.
*/
-static Buffer
+static Buffer
_bt_split(Relation rel, Buffer buf, OffsetNumber firstright)
{
- Buffer rbuf;
- Page origpage;
- Page leftpage, rightpage;
- BTPageOpaque ropaque, lopaque, oopaque;
- Buffer sbuf;
- Page spage;
- BTPageOpaque sopaque;
- Size itemsz;
- ItemId itemid;
- BTItem item;
- OffsetNumber leftoff, rightoff;
- OffsetNumber start;
- OffsetNumber maxoff;
- OffsetNumber i;
-
- rbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
- origpage = BufferGetPage(buf);
- leftpage = PageGetTempPage(origpage, sizeof(BTPageOpaqueData));
- rightpage = BufferGetPage(rbuf);
-
- _bt_pageinit(rightpage, BufferGetPageSize(rbuf));
- _bt_pageinit(leftpage, BufferGetPageSize(buf));
-
- /* init btree private data */
- oopaque = (BTPageOpaque) PageGetSpecialPointer(origpage);
- lopaque = (BTPageOpaque) PageGetSpecialPointer(leftpage);
- ropaque = (BTPageOpaque) PageGetSpecialPointer(rightpage);
-
- /* if we're splitting this page, it won't be the root when we're done */
- oopaque->btpo_flags &= ~BTP_ROOT;
- oopaque->btpo_flags &= ~BTP_CHAIN;
- lopaque->btpo_flags = ropaque->btpo_flags = oopaque->btpo_flags;
- lopaque->btpo_prev = oopaque->btpo_prev;
- ropaque->btpo_prev = BufferGetBlockNumber(buf);
- lopaque->btpo_next = BufferGetBlockNumber(rbuf);
- ropaque->btpo_next = oopaque->btpo_next;
-
- /*
- * If the page we're splitting is not the rightmost page at its
- * level in the tree, then the first (0) entry on the page is the
- * high key for the page. We need to copy that to the right
- * half. Otherwise (meaning the rightmost page case), we should
- * treat the line pointers beginning at zero as user data.
- *
- * We leave a blank space at the start of the line table for the
- * left page. We'll come back later and fill it in with the high
- * key item we get from the right key.
- */
-
- leftoff = P_FIRSTKEY;
- ropaque->btpo_next = oopaque->btpo_next;
- if (! P_RIGHTMOST(oopaque)) {
- /* splitting a non-rightmost page, start at the first data item */
- start = P_FIRSTKEY;
-
- itemid = PageGetItemId(origpage, P_HIKEY);
- itemsz = ItemIdGetLength(itemid);
- item = (BTItem) PageGetItem(origpage, itemid);
- if ( PageAddItem(rightpage, (Item) item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add hikey to the right sibling");
- rightoff = P_FIRSTKEY;
- } else {
- /* splitting a rightmost page, "high key" is the first data item */
- start = P_HIKEY;
-
- /* the new rightmost page will not have a high key */
- rightoff = P_HIKEY;
- }
- maxoff = PageGetMaxOffsetNumber(origpage);
- if ( firstright == InvalidOffsetNumber )
- {
- Size llimit = PageGetFreeSpace(leftpage) / 2;
- firstright = _bt_findsplitloc(rel, origpage, start, maxoff, llimit);
- }
-
- for (i = start; i <= maxoff; i = OffsetNumberNext(i)) {
- itemid = PageGetItemId(origpage, i);
+ Buffer rbuf;
+ Page origpage;
+ Page leftpage,
+ rightpage;
+ BTPageOpaque ropaque,
+ lopaque,
+ oopaque;
+ Buffer sbuf;
+ Page spage;
+ BTPageOpaque sopaque;
+ Size itemsz;
+ ItemId itemid;
+ BTItem item;
+ OffsetNumber leftoff,
+ rightoff;
+ OffsetNumber start;
+ OffsetNumber maxoff;
+ OffsetNumber i;
+
+ rbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
+ origpage = BufferGetPage(buf);
+ leftpage = PageGetTempPage(origpage, sizeof(BTPageOpaqueData));
+ rightpage = BufferGetPage(rbuf);
+
+ _bt_pageinit(rightpage, BufferGetPageSize(rbuf));
+ _bt_pageinit(leftpage, BufferGetPageSize(buf));
+
+ /* init btree private data */
+ oopaque = (BTPageOpaque) PageGetSpecialPointer(origpage);
+ lopaque = (BTPageOpaque) PageGetSpecialPointer(leftpage);
+ ropaque = (BTPageOpaque) PageGetSpecialPointer(rightpage);
+
+ /* if we're splitting this page, it won't be the root when we're done */
+ oopaque->btpo_flags &= ~BTP_ROOT;
+ oopaque->btpo_flags &= ~BTP_CHAIN;
+ lopaque->btpo_flags = ropaque->btpo_flags = oopaque->btpo_flags;
+ lopaque->btpo_prev = oopaque->btpo_prev;
+ ropaque->btpo_prev = BufferGetBlockNumber(buf);
+ lopaque->btpo_next = BufferGetBlockNumber(rbuf);
+ ropaque->btpo_next = oopaque->btpo_next;
+
+ /*
+ * If the page we're splitting is not the rightmost page at its level
+ * in the tree, then the first (0) entry on the page is the high key
+ * for the page. We need to copy that to the right half. Otherwise
+ * (meaning the rightmost page case), we should treat the line
+ * pointers beginning at zero as user data.
+ *
+ * We leave a blank space at the start of the line table for the left
+ * page. We'll come back later and fill it in with the high key item
+ * we get from the right key.
+ */
+
+ leftoff = P_FIRSTKEY;
+ ropaque->btpo_next = oopaque->btpo_next;
+ if (!P_RIGHTMOST(oopaque))
+ {
+ /* splitting a non-rightmost page, start at the first data item */
+ start = P_FIRSTKEY;
+
+ itemid = PageGetItemId(origpage, P_HIKEY);
+ itemsz = ItemIdGetLength(itemid);
+ item = (BTItem) PageGetItem(origpage, itemid);
+ if (PageAddItem(rightpage, (Item) item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add hikey to the right sibling");
+ rightoff = P_FIRSTKEY;
+ }
+ else
+ {
+ /* splitting a rightmost page, "high key" is the first data item */
+ start = P_HIKEY;
+
+ /* the new rightmost page will not have a high key */
+ rightoff = P_HIKEY;
+ }
+ maxoff = PageGetMaxOffsetNumber(origpage);
+ if (firstright == InvalidOffsetNumber)
+ {
+ Size llimit = PageGetFreeSpace(leftpage) / 2;
+
+ firstright = _bt_findsplitloc(rel, origpage, start, maxoff, llimit);
+ }
+
+ for (i = start; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ itemid = PageGetItemId(origpage, i);
+ itemsz = ItemIdGetLength(itemid);
+ item = (BTItem) PageGetItem(origpage, itemid);
+
+ /* decide which page to put it on */
+ if (i < firstright)
+ {
+ if (PageAddItem(leftpage, (Item) item, itemsz, leftoff,
+ LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add item to the left sibling");
+ leftoff = OffsetNumberNext(leftoff);
+ }
+ else
+ {
+ if (PageAddItem(rightpage, (Item) item, itemsz, rightoff,
+ LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add item to the right sibling");
+ rightoff = OffsetNumberNext(rightoff);
+ }
+ }
+
+ /*
+ * Okay, page has been split, high key on right page is correct. Now
+ * set the high key on the left page to be the min key on the right
+ * page.
+ */
+
+ if (P_RIGHTMOST(ropaque))
+ {
+ itemid = PageGetItemId(rightpage, P_HIKEY);
+ }
+ else
+ {
+ itemid = PageGetItemId(rightpage, P_FIRSTKEY);
+ }
itemsz = ItemIdGetLength(itemid);
- item = (BTItem) PageGetItem(origpage, itemid);
-
- /* decide which page to put it on */
- if (i < firstright) {
- if ( PageAddItem(leftpage, (Item) item, itemsz, leftoff,
- LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add item to the left sibling");
- leftoff = OffsetNumberNext(leftoff);
- } else {
- if ( PageAddItem(rightpage, (Item) item, itemsz, rightoff,
- LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add item to the right sibling");
- rightoff = OffsetNumberNext(rightoff);
+ item = (BTItem) PageGetItem(rightpage, itemid);
+
+ /*
+ * We left a hole for the high key on the left page; fill it. The
+ * modal crap is to tell the page manager to put the new item on the
+ * page and not screw around with anything else. Whoever designed
+ * this interface has presumably crawled back into the dung heap they
+ * came from. No one here will admit to it.
+ */
+
+ PageManagerModeSet(OverwritePageManagerMode);
+ if (PageAddItem(leftpage, (Item) item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add hikey to the left sibling");
+ PageManagerModeSet(ShufflePageManagerMode);
+
+ /*
+ * By here, the original data page has been split into two new halves,
+ * and these are correct. The algorithm requires that the left page
+ * never move during a split, so we copy the new left page back on top
+ * of the original. Note that this is not a waste of time, since we
+ * also require (in the page management code) that the center of a
+ * page always be clean, and the most efficient way to guarantee this
+ * is just to compact the data by reinserting it into a new left page.
+ */
+
+ PageRestoreTempPage(leftpage, origpage);
+
+ /* write these guys out */
+ _bt_wrtnorelbuf(rel, rbuf);
+ _bt_wrtnorelbuf(rel, buf);
+
+ /*
+ * Finally, we need to grab the right sibling (if any) and fix the
+ * prev pointer there. We are guaranteed that this is deadlock-free
+ * since no other writer will be moving holding a lock on that page
+ * and trying to move left, and all readers release locks on a page
+ * before trying to fetch its neighbors.
+ */
+
+ if (!P_RIGHTMOST(ropaque))
+ {
+ sbuf = _bt_getbuf(rel, ropaque->btpo_next, BT_WRITE);
+ spage = BufferGetPage(sbuf);
+ sopaque = (BTPageOpaque) PageGetSpecialPointer(spage);
+ sopaque->btpo_prev = BufferGetBlockNumber(rbuf);
+
+ /* write and release the old right sibling */
+ _bt_wrtbuf(rel, sbuf);
}
- }
-
- /*
- * Okay, page has been split, high key on right page is correct. Now
- * set the high key on the left page to be the min key on the right
- * page.
- */
-
- if (P_RIGHTMOST(ropaque)) {
- itemid = PageGetItemId(rightpage, P_HIKEY);
- } else {
- itemid = PageGetItemId(rightpage, P_FIRSTKEY);
- }
- itemsz = ItemIdGetLength(itemid);
- item = (BTItem) PageGetItem(rightpage, itemid);
-
- /*
- * We left a hole for the high key on the left page; fill it. The
- * modal crap is to tell the page manager to put the new item on the
- * page and not screw around with anything else. Whoever designed
- * this interface has presumably crawled back into the dung heap they
- * came from. No one here will admit to it.
- */
-
- PageManagerModeSet(OverwritePageManagerMode);
- if ( PageAddItem(leftpage, (Item) item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add hikey to the left sibling");
- PageManagerModeSet(ShufflePageManagerMode);
-
- /*
- * By here, the original data page has been split into two new halves,
- * and these are correct. The algorithm requires that the left page
- * never move during a split, so we copy the new left page back on top
- * of the original. Note that this is not a waste of time, since we
- * also require (in the page management code) that the center of a
- * page always be clean, and the most efficient way to guarantee this
- * is just to compact the data by reinserting it into a new left page.
- */
-
- PageRestoreTempPage(leftpage, origpage);
-
- /* write these guys out */
- _bt_wrtnorelbuf(rel, rbuf);
- _bt_wrtnorelbuf(rel, buf);
-
- /*
- * Finally, we need to grab the right sibling (if any) and fix the
- * prev pointer there. We are guaranteed that this is deadlock-free
- * since no other writer will be moving holding a lock on that page
- * and trying to move left, and all readers release locks on a page
- * before trying to fetch its neighbors.
- */
-
- if (! P_RIGHTMOST(ropaque)) {
- sbuf = _bt_getbuf(rel, ropaque->btpo_next, BT_WRITE);
- spage = BufferGetPage(sbuf);
- sopaque = (BTPageOpaque) PageGetSpecialPointer(spage);
- sopaque->btpo_prev = BufferGetBlockNumber(rbuf);
-
- /* write and release the old right sibling */
- _bt_wrtbuf(rel, sbuf);
- }
-
- /* split's done */
- return (rbuf);
+
+ /* split's done */
+ return (rbuf);
}
/*
- * _bt_findsplitloc() -- find a safe place to split a page.
+ * _bt_findsplitloc() -- find a safe place to split a page.
*
- * In order to guarantee the proper handling of searches for duplicate
- * keys, the first duplicate in the chain must either be the first
- * item on the page after the split, or the entire chain must be on
- * one of the two pages. That is,
- * [1 2 2 2 3 4 5]
- * must become
- * [1] [2 2 2 3 4 5]
- * or
- * [1 2 2 2] [3 4 5]
- * but not
- * [1 2 2] [2 3 4 5].
- * However,
- * [2 2 2 2 2 3 4]
- * may be split as
- * [2 2 2 2] [2 3 4].
+ * In order to guarantee the proper handling of searches for duplicate
+ * keys, the first duplicate in the chain must either be the first
+ * item on the page after the split, or the entire chain must be on
+ * one of the two pages. That is,
+ * [1 2 2 2 3 4 5]
+ * must become
+ * [1] [2 2 2 3 4 5]
+ * or
+ * [1 2 2 2] [3 4 5]
+ * but not
+ * [1 2 2] [2 3 4 5].
+ * However,
+ * [2 2 2 2 2 3 4]
+ * may be split as
+ * [2 2 2 2] [2 3 4].
*/
-static OffsetNumber
+static OffsetNumber
_bt_findsplitloc(Relation rel,
- Page page,
- OffsetNumber start,
- OffsetNumber maxoff,
- Size llimit)
+ Page page,
+ OffsetNumber start,
+ OffsetNumber maxoff,
+ Size llimit)
{
- OffsetNumber i;
- OffsetNumber saferight;
- ItemId nxtitemid, safeitemid;
- BTItem safeitem, nxtitem;
- Size nbytes;
- int natts;
-
- if ( start >= maxoff )
- elog (FATAL, "btree: cannot split if start (%d) >= maxoff (%d)",
- start, maxoff);
- natts = rel->rd_rel->relnatts;
- saferight = start;
- safeitemid = PageGetItemId(page, saferight);
- nbytes = ItemIdGetLength(safeitemid) + sizeof(ItemIdData);
- safeitem = (BTItem) PageGetItem(page, safeitemid);
-
- i = OffsetNumberNext(start);
-
- while (nbytes < llimit)
- {
- /* check the next item on the page */
- nxtitemid = PageGetItemId(page, i);
- nbytes += (ItemIdGetLength(nxtitemid) + sizeof(ItemIdData));
- nxtitem = (BTItem) PageGetItem(page, nxtitemid);
-
- /*
- * Test against last known safe item:
- * if the tuple we're looking at isn't equal to the last safe
- * one we saw, then it's our new safe tuple.
- */
- if ( !_bt_itemcmp (rel, natts,
- safeitem, nxtitem, BTEqualStrategyNumber) )
+ OffsetNumber i;
+ OffsetNumber saferight;
+ ItemId nxtitemid,
+ safeitemid;
+ BTItem safeitem,
+ nxtitem;
+ Size nbytes;
+ int natts;
+
+ if (start >= maxoff)
+ elog(FATAL, "btree: cannot split if start (%d) >= maxoff (%d)",
+ start, maxoff);
+ natts = rel->rd_rel->relnatts;
+ saferight = start;
+ safeitemid = PageGetItemId(page, saferight);
+ nbytes = ItemIdGetLength(safeitemid) + sizeof(ItemIdData);
+ safeitem = (BTItem) PageGetItem(page, safeitemid);
+
+ i = OffsetNumberNext(start);
+
+ while (nbytes < llimit)
{
- safeitem = nxtitem;
- saferight = i;
+ /* check the next item on the page */
+ nxtitemid = PageGetItemId(page, i);
+ nbytes += (ItemIdGetLength(nxtitemid) + sizeof(ItemIdData));
+ nxtitem = (BTItem) PageGetItem(page, nxtitemid);
+
+ /*
+ * Test against last known safe item: if the tuple we're looking
+ * at isn't equal to the last safe one we saw, then it's our new
+ * safe tuple.
+ */
+ if (!_bt_itemcmp(rel, natts,
+ safeitem, nxtitem, BTEqualStrategyNumber))
+ {
+ safeitem = nxtitem;
+ saferight = i;
+ }
+ if (i < maxoff)
+ i = OffsetNumberNext(i);
+ else
+ break;
}
- if ( i < maxoff )
- i = OffsetNumberNext(i);
- else
- break;
- }
-
- /*
- * If the chain of dups starts at the beginning of the page and extends
- * past the halfway mark, we can split it in the middle.
- */
-
- if (saferight == start)
- saferight = i;
-
- if ( saferight == maxoff && ( maxoff - start ) > 1 )
- saferight = start + ( maxoff - start ) / 2;
-
- return (saferight);
+
+ /*
+ * If the chain of dups starts at the beginning of the page and
+ * extends past the halfway mark, we can split it in the middle.
+ */
+
+ if (saferight == start)
+ saferight = i;
+
+ if (saferight == maxoff && (maxoff - start) > 1)
+ saferight = start + (maxoff - start) / 2;
+
+ return (saferight);
}
/*
- * _bt_newroot() -- Create a new root page for the index.
+ * _bt_newroot() -- Create a new root page for the index.
*
- * We've just split the old root page and need to create a new one.
- * In order to do this, we add a new root page to the file, then lock
- * the metadata page and update it. This is guaranteed to be deadlock-
- * free, because all readers release their locks on the metadata page
- * before trying to lock the root, and all writers lock the root before
- * trying to lock the metadata page. We have a write lock on the old
- * root page, so we have not introduced any cycles into the waits-for
- * graph.
+ * We've just split the old root page and need to create a new one.
+ * In order to do this, we add a new root page to the file, then lock
+ * the metadata page and update it. This is guaranteed to be deadlock-
+ * free, because all readers release their locks on the metadata page
+ * before trying to lock the root, and all writers lock the root before
+ * trying to lock the metadata page. We have a write lock on the old
+ * root page, so we have not introduced any cycles into the waits-for
+ * graph.
*
- * On entry, lbuf (the old root) and rbuf (its new peer) are write-
- * locked. We don't drop the locks in this routine; that's done by
- * the caller. On exit, a new root page exists with entries for the
- * two new children. The new root page is neither pinned nor locked.
+ * On entry, lbuf (the old root) and rbuf (its new peer) are write-
+ * locked. We don't drop the locks in this routine; that's done by
+ * the caller. On exit, a new root page exists with entries for the
+ * two new children. The new root page is neither pinned nor locked.
*/
static void
_bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
{
- Buffer rootbuf;
- Page lpage, rpage, rootpage;
- BlockNumber lbkno, rbkno;
- BlockNumber rootbknum;
- BTPageOpaque rootopaque;
- ItemId itemid;
- BTItem item;
- Size itemsz;
- BTItem new_item;
-
- /* get a new root page */
- rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
- rootpage = BufferGetPage(rootbuf);
- _bt_pageinit(rootpage, BufferGetPageSize(rootbuf));
-
- /* set btree special data */
- rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
- rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
- rootopaque->btpo_flags |= BTP_ROOT;
-
- /*
- * Insert the internal tuple pointers.
- */
-
- lbkno = BufferGetBlockNumber(lbuf);
- rbkno = BufferGetBlockNumber(rbuf);
- lpage = BufferGetPage(lbuf);
- rpage = BufferGetPage(rbuf);
-
- /*
- * step over the high key on the left page while building the
- * left page pointer.
- */
- itemid = PageGetItemId(lpage, P_FIRSTKEY);
- itemsz = ItemIdGetLength(itemid);
- item = (BTItem) PageGetItem(lpage, itemid);
- new_item = _bt_formitem(&(item->bti_itup));
- ItemPointerSet(&(new_item->bti_itup.t_tid), lbkno, P_HIKEY);
-
- /*
- * insert the left page pointer into the new root page. the root
- * page is the rightmost page on its level so the "high key" item
- * is the first data item.
- */
- if ( PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add leftkey to new root page");
- pfree(new_item);
-
- /*
- * the right page is the rightmost page on the second level, so
- * the "high key" item is the first data item on that page as well.
- */
- itemid = PageGetItemId(rpage, P_HIKEY);
- itemsz = ItemIdGetLength(itemid);
- item = (BTItem) PageGetItem(rpage, itemid);
- new_item = _bt_formitem(&(item->bti_itup));
- ItemPointerSet(&(new_item->bti_itup.t_tid), rbkno, P_HIKEY);
-
- /*
- * insert the right page pointer into the new root page.
- */
- if ( PageAddItem(rootpage, (Item) new_item, itemsz, P_FIRSTKEY, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add rightkey to new root page");
- pfree(new_item);
-
- /* write and let go of the root buffer */
- rootbknum = BufferGetBlockNumber(rootbuf);
- _bt_wrtbuf(rel, rootbuf);
-
- /* update metadata page with new root block number */
- _bt_metaproot(rel, rootbknum, 0);
+ Buffer rootbuf;
+ Page lpage,
+ rpage,
+ rootpage;
+ BlockNumber lbkno,
+ rbkno;
+ BlockNumber rootbknum;
+ BTPageOpaque rootopaque;
+ ItemId itemid;
+ BTItem item;
+ Size itemsz;
+ BTItem new_item;
+
+ /* get a new root page */
+ rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
+ rootpage = BufferGetPage(rootbuf);
+ _bt_pageinit(rootpage, BufferGetPageSize(rootbuf));
+
+ /* set btree special data */
+ rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
+ rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
+ rootopaque->btpo_flags |= BTP_ROOT;
+
+ /*
+ * Insert the internal tuple pointers.
+ */
+
+ lbkno = BufferGetBlockNumber(lbuf);
+ rbkno = BufferGetBlockNumber(rbuf);
+ lpage = BufferGetPage(lbuf);
+ rpage = BufferGetPage(rbuf);
+
+ /*
+ * step over the high key on the left page while building the left
+ * page pointer.
+ */
+ itemid = PageGetItemId(lpage, P_FIRSTKEY);
+ itemsz = ItemIdGetLength(itemid);
+ item = (BTItem) PageGetItem(lpage, itemid);
+ new_item = _bt_formitem(&(item->bti_itup));
+ ItemPointerSet(&(new_item->bti_itup.t_tid), lbkno, P_HIKEY);
+
+ /*
+ * insert the left page pointer into the new root page. the root page
+ * is the rightmost page on its level so the "high key" item is the
+ * first data item.
+ */
+ if (PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add leftkey to new root page");
+ pfree(new_item);
+
+ /*
+ * the right page is the rightmost page on the second level, so the
+ * "high key" item is the first data item on that page as well.
+ */
+ itemid = PageGetItemId(rpage, P_HIKEY);
+ itemsz = ItemIdGetLength(itemid);
+ item = (BTItem) PageGetItem(rpage, itemid);
+ new_item = _bt_formitem(&(item->bti_itup));
+ ItemPointerSet(&(new_item->bti_itup.t_tid), rbkno, P_HIKEY);
+
+ /*
+ * insert the right page pointer into the new root page.
+ */
+ if (PageAddItem(rootpage, (Item) new_item, itemsz, P_FIRSTKEY, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add rightkey to new root page");
+ pfree(new_item);
+
+ /* write and let go of the root buffer */
+ rootbknum = BufferGetBlockNumber(rootbuf);
+ _bt_wrtbuf(rel, rootbuf);
+
+ /* update metadata page with new root block number */
+ _bt_metaproot(rel, rootbknum, 0);
}
/*
- * _bt_pgaddtup() -- add a tuple to a particular page in the index.
+ * _bt_pgaddtup() -- add a tuple to a particular page in the index.
*
- * This routine adds the tuple to the page as requested, and keeps the
- * write lock and reference associated with the page's buffer. It is
- * an error to call pgaddtup() without a write lock and reference. If
- * afteritem is non-null, it's the item that we expect our new item
- * to follow. Otherwise, we do a binary search for the correct place
- * and insert the new item there.
+ * This routine adds the tuple to the page as requested, and keeps the
+ * write lock and reference associated with the page's buffer. It is
+ * an error to call pgaddtup() without a write lock and reference. If
+ * afteritem is non-null, it's the item that we expect our new item
+ * to follow. Otherwise, we do a binary search for the correct place
+ * and insert the new item there.
*/
-static OffsetNumber
+static OffsetNumber
_bt_pgaddtup(Relation rel,
- Buffer buf,
- int keysz,
- ScanKey itup_scankey,
- Size itemsize,
- BTItem btitem,
- BTItem afteritem)
+ Buffer buf,
+ int keysz,
+ ScanKey itup_scankey,
+ Size itemsize,
+ BTItem btitem,
+ BTItem afteritem)
{
- OffsetNumber itup_off;
- OffsetNumber first;
- Page page;
- BTPageOpaque opaque;
- BTItem chkitem;
-
- page = BufferGetPage(buf);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- first = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
-
- if (afteritem == (BTItem) NULL) {
- itup_off = _bt_binsrch(rel, buf, keysz, itup_scankey, BT_INSERTION);
- } else {
- itup_off = first;
-
- do {
- chkitem =
- (BTItem) PageGetItem(page, PageGetItemId(page, itup_off));
- itup_off = OffsetNumberNext(itup_off);
- } while ( ! BTItemSame (chkitem, afteritem) );
- }
-
- if ( PageAddItem(page, (Item) btitem, itemsize, itup_off, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add item to the page");
-
- /* write the buffer, but hold our lock */
- _bt_wrtnorelbuf(rel, buf);
-
- return (itup_off);
+ OffsetNumber itup_off;
+ OffsetNumber first;
+ Page page;
+ BTPageOpaque opaque;
+ BTItem chkitem;
+
+ page = BufferGetPage(buf);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ first = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ if (afteritem == (BTItem) NULL)
+ {
+ itup_off = _bt_binsrch(rel, buf, keysz, itup_scankey, BT_INSERTION);
+ }
+ else
+ {
+ itup_off = first;
+
+ do
+ {
+ chkitem =
+ (BTItem) PageGetItem(page, PageGetItemId(page, itup_off));
+ itup_off = OffsetNumberNext(itup_off);
+ } while (!BTItemSame(chkitem, afteritem));
+ }
+
+ if (PageAddItem(page, (Item) btitem, itemsize, itup_off, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add item to the page");
+
+ /* write the buffer, but hold our lock */
+ _bt_wrtnorelbuf(rel, buf);
+
+ return (itup_off);
}
/*
- * _bt_goesonpg() -- Does a new tuple belong on this page?
+ * _bt_goesonpg() -- Does a new tuple belong on this page?
*
- * This is part of the complexity introduced by allowing duplicate
- * keys into the index. The tuple belongs on this page if:
+ * This is part of the complexity introduced by allowing duplicate
+ * keys into the index. The tuple belongs on this page if:
*
- * + there is no page to the right of this one; or
- * + it is less than the high key on the page; or
- * + the item it is to follow ("afteritem") appears on this
- * page.
+ * + there is no page to the right of this one; or
+ * + it is less than the high key on the page; or
+ * + the item it is to follow ("afteritem") appears on this
+ * page.
*/
-static bool
+static bool
_bt_goesonpg(Relation rel,
- Buffer buf,
- Size keysz,
- ScanKey scankey,
- BTItem afteritem)
+ Buffer buf,
+ Size keysz,
+ ScanKey scankey,
+ BTItem afteritem)
{
- Page page;
- ItemId hikey;
- BTPageOpaque opaque;
- BTItem chkitem;
- OffsetNumber offnum, maxoff;
- bool found;
-
- page = BufferGetPage(buf);
-
- /* no right neighbor? */
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- if (P_RIGHTMOST(opaque))
- return (true);
-
- /*
- * this is a non-rightmost page, so it must have a high key item.
- *
- * If the scan key is < the high key (the min key on the next page),
- * then it for sure belongs here.
- */
- hikey = PageGetItemId(page, P_HIKEY);
- if (_bt_skeycmp(rel, keysz, scankey, page, hikey, BTLessStrategyNumber))
- return (true);
-
- /*
- * If the scan key is > the high key, then it for sure doesn't belong
- * here.
- */
-
- if (_bt_skeycmp(rel, keysz, scankey, page, hikey, BTGreaterStrategyNumber))
- return (false);
-
- /*
- * If we have no adjacency information, and the item is equal to the
- * high key on the page (by here it is), then the item does not belong
- * on this page.
- *
- * Now it's not true in all cases. - vadim 06/10/97
- */
-
- if (afteritem == (BTItem) NULL)
- {
- if ( opaque->btpo_flags & BTP_LEAF )
- return (false);
- if ( opaque->btpo_flags & BTP_CHAIN )
- return (true);
- if ( _bt_skeycmp (rel, keysz, scankey, page,
- PageGetItemId(page, P_FIRSTKEY),
- BTEqualStrategyNumber) )
- return (true);
- return (false);
- }
-
- /* damn, have to work for it. i hate that. */
- maxoff = PageGetMaxOffsetNumber(page);
-
- /*
- * Search the entire page for the afteroid. We need to do this, rather
- * than doing a binary search and starting from there, because if the
- * key we're searching for is the leftmost key in the tree at this
- * level, then a binary search will do the wrong thing. Splits are
- * pretty infrequent, so the cost isn't as bad as it could be.
- */
-
- found = false;
- for (offnum = P_FIRSTKEY;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum)) {
- chkitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
-
- if ( BTItemSame (chkitem, afteritem) ) {
- found = true;
- break;
+ Page page;
+ ItemId hikey;
+ BTPageOpaque opaque;
+ BTItem chkitem;
+ OffsetNumber offnum,
+ maxoff;
+ bool found;
+
+ page = BufferGetPage(buf);
+
+ /* no right neighbor? */
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ if (P_RIGHTMOST(opaque))
+ return (true);
+
+ /*
+ * this is a non-rightmost page, so it must have a high key item.
+ *
+ * If the scan key is < the high key (the min key on the next page), then
+ * it for sure belongs here.
+ */
+ hikey = PageGetItemId(page, P_HIKEY);
+ if (_bt_skeycmp(rel, keysz, scankey, page, hikey, BTLessStrategyNumber))
+ return (true);
+
+ /*
+ * If the scan key is > the high key, then it for sure doesn't belong
+ * here.
+ */
+
+ if (_bt_skeycmp(rel, keysz, scankey, page, hikey, BTGreaterStrategyNumber))
+ return (false);
+
+ /*
+ * If we have no adjacency information, and the item is equal to the
+ * high key on the page (by here it is), then the item does not belong
+ * on this page.
+ *
+ * Now it's not true in all cases. - vadim 06/10/97
+ */
+
+ if (afteritem == (BTItem) NULL)
+ {
+ if (opaque->btpo_flags & BTP_LEAF)
+ return (false);
+ if (opaque->btpo_flags & BTP_CHAIN)
+ return (true);
+ if (_bt_skeycmp(rel, keysz, scankey, page,
+ PageGetItemId(page, P_FIRSTKEY),
+ BTEqualStrategyNumber))
+ return (true);
+ return (false);
+ }
+
+ /* damn, have to work for it. i hate that. */
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ /*
+ * Search the entire page for the afteroid. We need to do this,
+ * rather than doing a binary search and starting from there, because
+ * if the key we're searching for is the leftmost key in the tree at
+ * this level, then a binary search will do the wrong thing. Splits
+ * are pretty infrequent, so the cost isn't as bad as it could be.
+ */
+
+ found = false;
+ for (offnum = P_FIRSTKEY;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ chkitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+
+ if (BTItemSame(chkitem, afteritem))
+ {
+ found = true;
+ break;
+ }
}
- }
-
- return (found);
+
+ return (found);
}
/*
- * _bt_itemcmp() -- compare item1 to item2 using a requested
- * strategy (<, <=, =, >=, >)
+ * _bt_itemcmp() -- compare item1 to item2 using a requested
+ * strategy (<, <=, =, >=, >)
*
*/
bool
_bt_itemcmp(Relation rel,
- Size keysz,
- BTItem item1,
- BTItem item2,
- StrategyNumber strat)
+ Size keysz,
+ BTItem item1,
+ BTItem item2,
+ StrategyNumber strat)
{
- TupleDesc tupDes;
- IndexTuple indexTuple1, indexTuple2;
- Datum attrDatum1, attrDatum2;
- int i;
- bool isFirstNull, isSecondNull;
- bool compare;
- bool useEqual = false;
-
- if ( strat == BTLessEqualStrategyNumber )
- {
- useEqual = true;
- strat = BTLessStrategyNumber;
- }
- else if ( strat == BTGreaterEqualStrategyNumber )
- {
- useEqual = true;
- strat = BTGreaterStrategyNumber;
- }
-
- tupDes = RelationGetTupleDescriptor(rel);
- indexTuple1 = &(item1->bti_itup);
- indexTuple2 = &(item2->bti_itup);
-
- for (i = 1; i <= keysz; i++) {
- attrDatum1 = index_getattr(indexTuple1, i, tupDes, &isFirstNull);
- attrDatum2 = index_getattr(indexTuple2, i, tupDes, &isSecondNull);
-
- /* see comments about NULLs handling in btbuild */
- if ( isFirstNull ) /* attr in item1 is NULL */
+ TupleDesc tupDes;
+ IndexTuple indexTuple1,
+ indexTuple2;
+ Datum attrDatum1,
+ attrDatum2;
+ int i;
+ bool isFirstNull,
+ isSecondNull;
+ bool compare;
+ bool useEqual = false;
+
+ if (strat == BTLessEqualStrategyNumber)
{
- if ( isSecondNull ) /* attr in item2 is NULL too */
- compare = ( strat == BTEqualStrategyNumber ) ? true : false;
- else
- compare = ( strat == BTGreaterStrategyNumber ) ? true : false;
- }
- else if ( isSecondNull ) /* attr in item1 is NOT_NULL and */
- { /* and attr in item2 is NULL */
- compare = ( strat == BTLessStrategyNumber ) ? true : false;
- }
- else
- {
- compare = _bt_invokestrat(rel, i, strat, attrDatum1, attrDatum2);
+ useEqual = true;
+ strat = BTLessStrategyNumber;
}
-
- if ( compare ) /* true for one of ">, <, =" */
+ else if (strat == BTGreaterEqualStrategyNumber)
{
- if ( strat != BTEqualStrategyNumber )
- return (true);
+ useEqual = true;
+ strat = BTGreaterStrategyNumber;
}
- else /* false for one of ">, <, =" */
+
+ tupDes = RelationGetTupleDescriptor(rel);
+ indexTuple1 = &(item1->bti_itup);
+ indexTuple2 = &(item2->bti_itup);
+
+ for (i = 1; i <= keysz; i++)
{
- if ( strat == BTEqualStrategyNumber )
- return (false);
- /*
- * if original strat was "<=, >=" OR
- * "<, >" but some attribute(s) left
- * - need to test for Equality
- */
- if ( useEqual || i < keysz )
- {
- if ( isFirstNull || isSecondNull )
- compare = ( isFirstNull && isSecondNull ) ? true : false;
- else
- compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber,
- attrDatum1, attrDatum2);
- if ( compare ) /* item1' and item2' attributes are equal */
- continue; /* - try to compare next attributes */
- }
- return (false);
+ attrDatum1 = index_getattr(indexTuple1, i, tupDes, &isFirstNull);
+ attrDatum2 = index_getattr(indexTuple2, i, tupDes, &isSecondNull);
+
+ /* see comments about NULLs handling in btbuild */
+ if (isFirstNull) /* attr in item1 is NULL */
+ {
+ if (isSecondNull) /* attr in item2 is NULL too */
+ compare = (strat == BTEqualStrategyNumber) ? true : false;
+ else
+ compare = (strat == BTGreaterStrategyNumber) ? true : false;
+ }
+ else if (isSecondNull) /* attr in item1 is NOT_NULL and */
+ { /* and attr in item2 is NULL */
+ compare = (strat == BTLessStrategyNumber) ? true : false;
+ }
+ else
+ {
+ compare = _bt_invokestrat(rel, i, strat, attrDatum1, attrDatum2);
+ }
+
+ if (compare) /* true for one of ">, <, =" */
+ {
+ if (strat != BTEqualStrategyNumber)
+ return (true);
+ }
+ else
+/* false for one of ">, <, =" */
+ {
+ if (strat == BTEqualStrategyNumber)
+ return (false);
+
+ /*
+ * if original strat was "<=, >=" OR "<, >" but some
+ * attribute(s) left - need to test for Equality
+ */
+ if (useEqual || i < keysz)
+ {
+ if (isFirstNull || isSecondNull)
+ compare = (isFirstNull && isSecondNull) ? true : false;
+ else
+ compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber,
+ attrDatum1, attrDatum2);
+ if (compare) /* item1' and item2' attributes are equal */
+ continue; /* - try to compare next attributes */
+ }
+ return (false);
+ }
}
- }
- return (true);
+ return (true);
}
/*
- * _bt_updateitem() -- updates the key of the item identified by the
- * oid with the key of newItem (done in place if
- * possible)
+ * _bt_updateitem() -- updates the key of the item identified by the
+ * oid with the key of newItem (done in place if
+ * possible)
*
*/
static void
_bt_updateitem(Relation rel,
- Size keysz,
- Buffer buf,
- BTItem oldItem,
- BTItem newItem)
+ Size keysz,
+ Buffer buf,
+ BTItem oldItem,
+ BTItem newItem)
{
- Page page;
- OffsetNumber maxoff;
- OffsetNumber i;
- ItemPointerData itemPtrData;
- BTItem item;
- IndexTuple oldIndexTuple, newIndexTuple;
- int first;
-
- page = BufferGetPage(buf);
- maxoff = PageGetMaxOffsetNumber(page);
-
- /* locate item on the page */
- first = P_RIGHTMOST((BTPageOpaque) PageGetSpecialPointer(page))
- ? P_HIKEY : P_FIRSTKEY;
- i = first;
- do {
- item = (BTItem) PageGetItem(page, PageGetItemId(page, i));
- i = OffsetNumberNext(i);
- } while (i <= maxoff && ! BTItemSame (item, oldItem));
-
- /* this should never happen (in theory) */
- if ( ! BTItemSame (item, oldItem) ) {
- elog(FATAL, "_bt_getstackbuf was lying!!");
- }
-
- /*
- * It's defined by caller (_bt_insertonpg)
- */
- /*
- if(IndexTupleDSize(newItem->bti_itup) >
- IndexTupleDSize(item->bti_itup)) {
- elog(NOTICE, "trying to overwrite a smaller value with a bigger one in _bt_updateitem");
- elog(WARN, "this is not good.");
- }
- */
-
- oldIndexTuple = &(item->bti_itup);
- newIndexTuple = &(newItem->bti_itup);
+ Page page;
+ OffsetNumber maxoff;
+ OffsetNumber i;
+ ItemPointerData itemPtrData;
+ BTItem item;
+ IndexTuple oldIndexTuple,
+ newIndexTuple;
+ int first;
+
+ page = BufferGetPage(buf);
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ /* locate item on the page */
+ first = P_RIGHTMOST((BTPageOpaque) PageGetSpecialPointer(page))
+ ? P_HIKEY : P_FIRSTKEY;
+ i = first;
+ do
+ {
+ item = (BTItem) PageGetItem(page, PageGetItemId(page, i));
+ i = OffsetNumberNext(i);
+ } while (i <= maxoff && !BTItemSame(item, oldItem));
+
+ /* this should never happen (in theory) */
+ if (!BTItemSame(item, oldItem))
+ {
+ elog(FATAL, "_bt_getstackbuf was lying!!");
+ }
+
+ /*
+ * It's defined by caller (_bt_insertonpg)
+ */
+
+ /*
+ * if(IndexTupleDSize(newItem->bti_itup) >
+ * IndexTupleDSize(item->bti_itup)) { elog(NOTICE, "trying to
+ * overwrite a smaller value with a bigger one in _bt_updateitem");
+ * elog(WARN, "this is not good."); }
+ */
+
+ oldIndexTuple = &(item->bti_itup);
+ newIndexTuple = &(newItem->bti_itup);
/* keep the original item pointer */
- ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData);
- CopyIndexTuple(newIndexTuple, &oldIndexTuple);
- ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid));
-
+ ItemPointerCopy(&(oldIndexTuple->t_tid), &itemPtrData);
+ CopyIndexTuple(newIndexTuple, &oldIndexTuple);
+ ItemPointerCopy(&itemPtrData, &(oldIndexTuple->t_tid));
+
}
/*
@@ -1409,177 +1460,179 @@ _bt_updateitem(Relation rel,
*
* Rule is simple: NOT_NULL not equal NULL, NULL not_equal NULL too.
*/
-static bool
-_bt_isequal (TupleDesc itupdesc, Page page, OffsetNumber offnum,
- int keysz, ScanKey scankey)
+static bool
+_bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
+ int keysz, ScanKey scankey)
{
- Datum datum;
- BTItem btitem;
- IndexTuple itup;
- ScanKey entry;
- AttrNumber attno;
- long result;
- int i;
- bool null;
-
- btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &(btitem->bti_itup);
-
- for (i = 1; i <= keysz; i++)
- {
- entry = &scankey[i - 1];
- attno = entry->sk_attno;
- Assert (attno == i);
- datum = index_getattr(itup, attno, itupdesc, &null);
-
- /* NULLs are not equal */
- if ( entry->sk_flags & SK_ISNULL || null )
- return (false);
-
- result = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
- entry->sk_argument, datum);
- if (result != 0)
- return (false);
- }
-
- /* by here, the keys are equal */
- return (true);
+ Datum datum;
+ BTItem btitem;
+ IndexTuple itup;
+ ScanKey entry;
+ AttrNumber attno;
+ long result;
+ int i;
+ bool null;
+
+ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &(btitem->bti_itup);
+
+ for (i = 1; i <= keysz; i++)
+ {
+ entry = &scankey[i - 1];
+ attno = entry->sk_attno;
+ Assert(attno == i);
+ datum = index_getattr(itup, attno, itupdesc, &null);
+
+ /* NULLs are not equal */
+ if (entry->sk_flags & SK_ISNULL || null)
+ return (false);
+
+ result = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
+ entry->sk_argument, datum);
+ if (result != 0)
+ return (false);
+ }
+
+ /* by here, the keys are equal */
+ return (true);
}
#ifdef NOT_USED
/*
- * _bt_shift - insert btitem on the passed page after shifting page
- * to the right in the tree.
+ * _bt_shift - insert btitem on the passed page after shifting page
+ * to the right in the tree.
*
* NOTE: tested for shifting leftmost page only, having btitem < hikey.
*/
-static InsertIndexResult
-_bt_shift (Relation rel, Buffer buf, BTStack stack, int keysz,
- ScanKey scankey, BTItem btitem, BTItem hikey)
+static InsertIndexResult
+_bt_shift(Relation rel, Buffer buf, BTStack stack, int keysz,
+ ScanKey scankey, BTItem btitem, BTItem hikey)
{
- InsertIndexResult res;
- int itemsz;
- Page page;
- BlockNumber bknum;
- BTPageOpaque pageop;
- Buffer rbuf;
- Page rpage;
- BTPageOpaque rpageop;
- Buffer pbuf;
- Page ppage;
- BTPageOpaque ppageop;
- Buffer nbuf;
- Page npage;
- BTPageOpaque npageop;
- BlockNumber nbknum;
- BTItem nitem;
- OffsetNumber afteroff;
-
- btitem = _bt_formitem(&(btitem->bti_itup));
- hikey = _bt_formitem(&(hikey->bti_itup));
-
- page = BufferGetPage(buf);
-
- /* grab new page */
- nbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
- nbknum = BufferGetBlockNumber(nbuf);
- npage = BufferGetPage(nbuf);
- _bt_pageinit(npage, BufferGetPageSize(nbuf));
- npageop = (BTPageOpaque) PageGetSpecialPointer(npage);
-
- /* copy content of the passed page */
- memmove ((char *) npage, (char *) page, BufferGetPageSize(buf));
-
- /* re-init old (passed) page */
- _bt_pageinit(page, BufferGetPageSize(buf));
- pageop = (BTPageOpaque) PageGetSpecialPointer(page);
-
- /* init old page opaque */
- pageop->btpo_flags = npageop->btpo_flags; /* restore flags */
- pageop->btpo_flags &= ~BTP_CHAIN;
- if ( _bt_itemcmp (rel, keysz, hikey, btitem, BTEqualStrategyNumber) )
- pageop->btpo_flags |= BTP_CHAIN;
- pageop->btpo_prev = npageop->btpo_prev; /* restore prev */
- pageop->btpo_next = nbknum; /* next points to the new page */
-
- /* init shifted page opaque */
- npageop->btpo_prev = bknum = BufferGetBlockNumber(buf);
-
- /* shifted page is ok, populate old page */
-
- /* add passed hikey */
- itemsz = IndexTupleDSize(hikey->bti_itup)
- + (sizeof(BTItemData) - sizeof(IndexTupleData));
- itemsz = DOUBLEALIGN(itemsz);
- if ( PageAddItem(page, (Item) hikey, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add hikey in _bt_shift");
- pfree (hikey);
-
- /* add btitem */
- itemsz = IndexTupleDSize(btitem->bti_itup)
- + (sizeof(BTItemData) - sizeof(IndexTupleData));
- itemsz = DOUBLEALIGN(itemsz);
- if ( PageAddItem(page, (Item) btitem, itemsz, P_FIRSTKEY, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add firstkey in _bt_shift");
- pfree (btitem);
- nitem = (BTItem) PageGetItem(page, PageGetItemId(page, P_FIRSTKEY));
- btitem = _bt_formitem(&(nitem->bti_itup));
- ItemPointerSet(&(btitem->bti_itup.t_tid), bknum, P_HIKEY);
-
- /* ok, write them out */
- _bt_wrtnorelbuf(rel, nbuf);
- _bt_wrtnorelbuf(rel, buf);
-
- /* fix btpo_prev on right sibling of old page */
- if ( !P_RIGHTMOST (npageop) )
- {
- rbuf = _bt_getbuf(rel, npageop->btpo_next, BT_WRITE);
- rpage = BufferGetPage(rbuf);
- rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage);
- rpageop->btpo_prev = nbknum;
- _bt_wrtbuf(rel, rbuf);
- }
-
- /* get parent pointing to the old page */
- ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
- bknum, P_HIKEY);
- pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
- ppage = BufferGetPage(pbuf);
- ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
-
- _bt_relbuf(rel, nbuf, BT_WRITE);
- _bt_relbuf(rel, buf, BT_WRITE);
-
- /* re-set parent' pointer - we shifted our page to the right ! */
- nitem = (BTItem) PageGetItem (ppage,
- PageGetItemId (ppage, stack->bts_offset));
- ItemPointerSet(&(nitem->bti_itup.t_tid), nbknum, P_HIKEY);
- ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid), nbknum, P_HIKEY);
- _bt_wrtnorelbuf(rel, pbuf);
-
- /*
- * Now we want insert into the parent pointer to our old page. It has to
- * be inserted before the pointer to new page. You may get problems here
- * (in the _bt_goesonpg and/or _bt_pgaddtup), but may be not - I don't
- * know. It works if old page is leftmost (nitem is NULL) and
- * btitem < hikey and it's all what we need currently. - vadim 05/30/97
- */
- nitem = NULL;
- afteroff = P_FIRSTKEY;
- if ( !P_RIGHTMOST (ppageop) )
- afteroff = OffsetNumberNext (afteroff);
- if ( stack->bts_offset >= afteroff )
- {
- afteroff = OffsetNumberPrev (stack->bts_offset);
- nitem = (BTItem) PageGetItem (ppage, PageGetItemId (ppage, afteroff));
- nitem = _bt_formitem(&(nitem->bti_itup));
- }
- res = _bt_insertonpg(rel, pbuf, stack->bts_parent,
- keysz, scankey, btitem, nitem);
- pfree (btitem);
-
- ItemPointerSet(&(res->pointerData), nbknum, P_HIKEY);
-
- return (res);
+ InsertIndexResult res;
+ int itemsz;
+ Page page;
+ BlockNumber bknum;
+ BTPageOpaque pageop;
+ Buffer rbuf;
+ Page rpage;
+ BTPageOpaque rpageop;
+ Buffer pbuf;
+ Page ppage;
+ BTPageOpaque ppageop;
+ Buffer nbuf;
+ Page npage;
+ BTPageOpaque npageop;
+ BlockNumber nbknum;
+ BTItem nitem;
+ OffsetNumber afteroff;
+
+ btitem = _bt_formitem(&(btitem->bti_itup));
+ hikey = _bt_formitem(&(hikey->bti_itup));
+
+ page = BufferGetPage(buf);
+
+ /* grab new page */
+ nbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
+ nbknum = BufferGetBlockNumber(nbuf);
+ npage = BufferGetPage(nbuf);
+ _bt_pageinit(npage, BufferGetPageSize(nbuf));
+ npageop = (BTPageOpaque) PageGetSpecialPointer(npage);
+
+ /* copy content of the passed page */
+ memmove((char *) npage, (char *) page, BufferGetPageSize(buf));
+
+ /* re-init old (passed) page */
+ _bt_pageinit(page, BufferGetPageSize(buf));
+ pageop = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ /* init old page opaque */
+ pageop->btpo_flags = npageop->btpo_flags; /* restore flags */
+ pageop->btpo_flags &= ~BTP_CHAIN;
+ if (_bt_itemcmp(rel, keysz, hikey, btitem, BTEqualStrategyNumber))
+ pageop->btpo_flags |= BTP_CHAIN;
+ pageop->btpo_prev = npageop->btpo_prev; /* restore prev */
+ pageop->btpo_next = nbknum; /* next points to the new page */
+
+ /* init shifted page opaque */
+ npageop->btpo_prev = bknum = BufferGetBlockNumber(buf);
+
+ /* shifted page is ok, populate old page */
+
+ /* add passed hikey */
+ itemsz = IndexTupleDSize(hikey->bti_itup)
+ + (sizeof(BTItemData) - sizeof(IndexTupleData));
+ itemsz = DOUBLEALIGN(itemsz);
+ if (PageAddItem(page, (Item) hikey, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add hikey in _bt_shift");
+ pfree(hikey);
+
+ /* add btitem */
+ itemsz = IndexTupleDSize(btitem->bti_itup)
+ + (sizeof(BTItemData) - sizeof(IndexTupleData));
+ itemsz = DOUBLEALIGN(itemsz);
+ if (PageAddItem(page, (Item) btitem, itemsz, P_FIRSTKEY, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add firstkey in _bt_shift");
+ pfree(btitem);
+ nitem = (BTItem) PageGetItem(page, PageGetItemId(page, P_FIRSTKEY));
+ btitem = _bt_formitem(&(nitem->bti_itup));
+ ItemPointerSet(&(btitem->bti_itup.t_tid), bknum, P_HIKEY);
+
+ /* ok, write them out */
+ _bt_wrtnorelbuf(rel, nbuf);
+ _bt_wrtnorelbuf(rel, buf);
+
+ /* fix btpo_prev on right sibling of old page */
+ if (!P_RIGHTMOST(npageop))
+ {
+ rbuf = _bt_getbuf(rel, npageop->btpo_next, BT_WRITE);
+ rpage = BufferGetPage(rbuf);
+ rpageop = (BTPageOpaque) PageGetSpecialPointer(rpage);
+ rpageop->btpo_prev = nbknum;
+ _bt_wrtbuf(rel, rbuf);
+ }
+
+ /* get parent pointing to the old page */
+ ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid),
+ bknum, P_HIKEY);
+ pbuf = _bt_getstackbuf(rel, stack, BT_WRITE);
+ ppage = BufferGetPage(pbuf);
+ ppageop = (BTPageOpaque) PageGetSpecialPointer(ppage);
+
+ _bt_relbuf(rel, nbuf, BT_WRITE);
+ _bt_relbuf(rel, buf, BT_WRITE);
+
+ /* re-set parent' pointer - we shifted our page to the right ! */
+ nitem = (BTItem) PageGetItem(ppage,
+ PageGetItemId(ppage, stack->bts_offset));
+ ItemPointerSet(&(nitem->bti_itup.t_tid), nbknum, P_HIKEY);
+ ItemPointerSet(&(stack->bts_btitem->bti_itup.t_tid), nbknum, P_HIKEY);
+ _bt_wrtnorelbuf(rel, pbuf);
+
+ /*
+ * Now we want insert into the parent pointer to our old page. It has
+ * to be inserted before the pointer to new page. You may get problems
+ * here (in the _bt_goesonpg and/or _bt_pgaddtup), but may be not - I
+ * don't know. It works if old page is leftmost (nitem is NULL) and
+ * btitem < hikey and it's all what we need currently. - vadim
+ * 05/30/97
+ */
+ nitem = NULL;
+ afteroff = P_FIRSTKEY;
+ if (!P_RIGHTMOST(ppageop))
+ afteroff = OffsetNumberNext(afteroff);
+ if (stack->bts_offset >= afteroff)
+ {
+ afteroff = OffsetNumberPrev(stack->bts_offset);
+ nitem = (BTItem) PageGetItem(ppage, PageGetItemId(ppage, afteroff));
+ nitem = _bt_formitem(&(nitem->bti_itup));
+ }
+ res = _bt_insertonpg(rel, pbuf, stack->bts_parent,
+ keysz, scankey, btitem, nitem);
+ pfree(btitem);
+
+ ItemPointerSet(&(res->pointerData), nbknum, P_HIKEY);
+
+ return (res);
}
+
#endif
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 9142c557378..6551af4c17c 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* nbtpage.c--
- * BTree-specific page management code for the Postgres btree access
- * method.
+ * BTree-specific page management code for the Postgres btree access
+ * method.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.9 1997/08/19 21:29:36 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.10 1997/09/07 04:38:52 momjian Exp $
*
- * NOTES
- * Postgres btree pages look like ordinary relation pages. The opaque
- * data at high addresses includes pointers to left and right siblings
- * and flag data describing page state. The first page in a btree, page
- * zero, is special -- it stores meta-information describing the tree.
- * Pages one and higher store the actual tree data.
+ * NOTES
+ * Postgres btree pages look like ordinary relation pages. The opaque
+ * data at high addresses includes pointers to left and right siblings
+ * and flag data describing page state. The first page in a btree, page
+ * zero, is special -- it stores meta-information describing the tree.
+ * Pages one and higher store the actual tree data.
*
*-------------------------------------------------------------------------
*/
@@ -31,16 +31,16 @@
#include <storage/lmgr.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static void _bt_setpagelock(Relation rel, BlockNumber blkno, int access);
-static void _bt_unsetpagelock(Relation rel, BlockNumber blkno, int access);
+static void _bt_setpagelock(Relation rel, BlockNumber blkno, int access);
+static void _bt_unsetpagelock(Relation rel, BlockNumber blkno, int access);
#define BTREE_METAPAGE 0
-#define BTREE_MAGIC 0x053162
+#define BTREE_MAGIC 0x053162
#ifdef BTREE_VERSION_1
#define BTREE_VERSION 1
@@ -48,546 +48,574 @@ static void _bt_unsetpagelock(Relation rel, BlockNumber blkno, int access);
#define BTREE_VERSION 0
#endif
-typedef struct BTMetaPageData {
- uint32 btm_magic;
- uint32 btm_version;
- BlockNumber btm_root;
+typedef struct BTMetaPageData
+{
+ uint32 btm_magic;
+ uint32 btm_version;
+ BlockNumber btm_root;
#ifdef BTREE_VERSION_1
- int32 btm_level;
+ int32 btm_level;
#endif
-} BTMetaPageData;
+} BTMetaPageData;
-#define BTPageGetMeta(p) \
- ((BTMetaPageData *) &((PageHeader) p)->pd_linp[0])
+#define BTPageGetMeta(p) \
+ ((BTMetaPageData *) &((PageHeader) p)->pd_linp[0])
-extern bool BuildingBtree;
+extern bool BuildingBtree;
/*
- * We use high-concurrency locking on btrees. There are two cases in
- * which we don't do locking. One is when we're building the btree.
- * Since the creating transaction has not committed, no one can see
- * the index, and there's no reason to share locks. The second case
- * is when we're just starting up the database system. We use some
- * special-purpose initialization code in the relation cache manager
- * (see utils/cache/relcache.c) to allow us to do indexed scans on
- * the system catalogs before we'd normally be able to. This happens
- * before the lock table is fully initialized, so we can't use it.
- * Strictly speaking, this violates 2pl, but we don't do 2pl on the
- * system catalogs anyway, so I declare this to be okay.
+ * We use high-concurrency locking on btrees. There are two cases in
+ * which we don't do locking. One is when we're building the btree.
+ * Since the creating transaction has not committed, no one can see
+ * the index, and there's no reason to share locks. The second case
+ * is when we're just starting up the database system. We use some
+ * special-purpose initialization code in the relation cache manager
+ * (see utils/cache/relcache.c) to allow us to do indexed scans on
+ * the system catalogs before we'd normally be able to. This happens
+ * before the lock table is fully initialized, so we can't use it.
+ * Strictly speaking, this violates 2pl, but we don't do 2pl on the
+ * system catalogs anyway, so I declare this to be okay.
*/
-#define USELOCKING (!BuildingBtree && !IsInitProcessingMode())
+#define USELOCKING (!BuildingBtree && !IsInitProcessingMode())
/*
- * _bt_metapinit() -- Initialize the metadata page of a btree.
+ * _bt_metapinit() -- Initialize the metadata page of a btree.
*/
void
_bt_metapinit(Relation rel)
{
- Buffer buf;
- Page pg;
- int nblocks;
- BTMetaPageData metad;
- BTPageOpaque op;
-
- /* can't be sharing this with anyone, now... */
- if (USELOCKING)
- RelationSetLockForWrite(rel);
-
- if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0) {
- elog(WARN, "Cannot initialize non-empty btree %s",
- RelationGetRelationName(rel));
- }
-
- buf = ReadBuffer(rel, P_NEW);
- pg = BufferGetPage(buf);
- _bt_pageinit(pg, BufferGetPageSize(buf));
-
- metad.btm_magic = BTREE_MAGIC;
- metad.btm_version = BTREE_VERSION;
- metad.btm_root = P_NONE;
+ Buffer buf;
+ Page pg;
+ int nblocks;
+ BTMetaPageData metad;
+ BTPageOpaque op;
+
+ /* can't be sharing this with anyone, now... */
+ if (USELOCKING)
+ RelationSetLockForWrite(rel);
+
+ if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0)
+ {
+ elog(WARN, "Cannot initialize non-empty btree %s",
+ RelationGetRelationName(rel));
+ }
+
+ buf = ReadBuffer(rel, P_NEW);
+ pg = BufferGetPage(buf);
+ _bt_pageinit(pg, BufferGetPageSize(buf));
+
+ metad.btm_magic = BTREE_MAGIC;
+ metad.btm_version = BTREE_VERSION;
+ metad.btm_root = P_NONE;
#ifdef BTREE_VERSION_1
- metad.btm_level = 0;
+ metad.btm_level = 0;
#endif
- memmove((char *) BTPageGetMeta(pg), (char *) &metad, sizeof(metad));
-
- op = (BTPageOpaque) PageGetSpecialPointer(pg);
- op->btpo_flags = BTP_META;
-
- WriteBuffer(buf);
-
- /* all done */
- if (USELOCKING)
- RelationUnsetLockForWrite(rel);
+ memmove((char *) BTPageGetMeta(pg), (char *) &metad, sizeof(metad));
+
+ op = (BTPageOpaque) PageGetSpecialPointer(pg);
+ op->btpo_flags = BTP_META;
+
+ WriteBuffer(buf);
+
+ /* all done */
+ if (USELOCKING)
+ RelationUnsetLockForWrite(rel);
}
#ifdef NOT_USED
/*
- * _bt_checkmeta() -- Verify that the metadata stored in a btree are
- * reasonable.
+ * _bt_checkmeta() -- Verify that the metadata stored in a btree are
+ * reasonable.
*/
void
_bt_checkmeta(Relation rel)
{
- Buffer metabuf;
- Page metap;
- BTMetaPageData *metad;
- BTPageOpaque op;
- int nblocks;
-
- /* if the relation is empty, this is init time; don't complain */
- if ((nblocks = RelationGetNumberOfBlocks(rel)) == 0)
- return;
-
- metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
- metap = BufferGetPage(metabuf);
- op = (BTPageOpaque) PageGetSpecialPointer(metap);
- if (!(op->btpo_flags & BTP_META)) {
- elog(WARN, "Invalid metapage for index %s",
- RelationGetRelationName(rel));
- }
- metad = BTPageGetMeta(metap);
-
- if (metad->btm_magic != BTREE_MAGIC) {
- elog(WARN, "Index %s is not a btree",
- RelationGetRelationName(rel));
- }
-
- if (metad->btm_version != BTREE_VERSION) {
- elog(WARN, "Version mismatch on %s: version %d file, version %d code",
- RelationGetRelationName(rel),
- metad->btm_version, BTREE_VERSION);
- }
-
- _bt_relbuf(rel, metabuf, BT_READ);
+ Buffer metabuf;
+ Page metap;
+ BTMetaPageData *metad;
+ BTPageOpaque op;
+ int nblocks;
+
+ /* if the relation is empty, this is init time; don't complain */
+ if ((nblocks = RelationGetNumberOfBlocks(rel)) == 0)
+ return;
+
+ metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
+ metap = BufferGetPage(metabuf);
+ op = (BTPageOpaque) PageGetSpecialPointer(metap);
+ if (!(op->btpo_flags & BTP_META))
+ {
+ elog(WARN, "Invalid metapage for index %s",
+ RelationGetRelationName(rel));
+ }
+ metad = BTPageGetMeta(metap);
+
+ if (metad->btm_magic != BTREE_MAGIC)
+ {
+ elog(WARN, "Index %s is not a btree",
+ RelationGetRelationName(rel));
+ }
+
+ if (metad->btm_version != BTREE_VERSION)
+ {
+ elog(WARN, "Version mismatch on %s: version %d file, version %d code",
+ RelationGetRelationName(rel),
+ metad->btm_version, BTREE_VERSION);
+ }
+
+ _bt_relbuf(rel, metabuf, BT_READ);
}
+
#endif
/*
- * _bt_getroot() -- Get the root page of the btree.
+ * _bt_getroot() -- Get the root page of the btree.
*
- * Since the root page can move around the btree file, we have to read
- * its location from the metadata page, and then read the root page
- * itself. If no root page exists yet, we have to create one. The
- * standard class of race conditions exists here; I think I covered
- * them all in the Hopi Indian rain dance of lock requests below.
+ * Since the root page can move around the btree file, we have to read
+ * its location from the metadata page, and then read the root page
+ * itself. If no root page exists yet, we have to create one. The
+ * standard class of race conditions exists here; I think I covered
+ * them all in the Hopi Indian rain dance of lock requests below.
*
- * We pass in the access type (BT_READ or BT_WRITE), and return the
- * root page's buffer with the appropriate lock type set. Reference
- * count on the root page gets bumped by ReadBuffer. The metadata
- * page is unlocked and unreferenced by this process when this routine
- * returns.
+ * We pass in the access type (BT_READ or BT_WRITE), and return the
+ * root page's buffer with the appropriate lock type set. Reference
+ * count on the root page gets bumped by ReadBuffer. The metadata
+ * page is unlocked and unreferenced by this process when this routine
+ * returns.
*/
Buffer
_bt_getroot(Relation rel, int access)
{
- Buffer metabuf;
- Page metapg;
- BTPageOpaque metaopaque;
- Buffer rootbuf;
- Page rootpg;
- BTPageOpaque rootopaque;
- BlockNumber rootblkno;
- BTMetaPageData *metad;
-
- metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
- metapg = BufferGetPage(metabuf);
- metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
- Assert(metaopaque->btpo_flags & BTP_META);
- metad = BTPageGetMeta(metapg);
-
- if (metad->btm_magic != BTREE_MAGIC) {
- elog(WARN, "Index %s is not a btree",
- RelationGetRelationName(rel));
- }
-
- if (metad->btm_version != BTREE_VERSION) {
- elog(WARN, "Version mismatch on %s: version %d file, version %d code",
- RelationGetRelationName(rel),
- metad->btm_version, BTREE_VERSION);
- }
-
- /* if no root page initialized yet, do it */
- if (metad->btm_root == P_NONE) {
-
- /* turn our read lock in for a write lock */
- _bt_relbuf(rel, metabuf, BT_READ);
- metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
+ Buffer metabuf;
+ Page metapg;
+ BTPageOpaque metaopaque;
+ Buffer rootbuf;
+ Page rootpg;
+ BTPageOpaque rootopaque;
+ BlockNumber rootblkno;
+ BTMetaPageData *metad;
+
+ metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
metapg = BufferGetPage(metabuf);
metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
Assert(metaopaque->btpo_flags & BTP_META);
metad = BTPageGetMeta(metapg);
-
- /*
- * Race condition: if someone else initialized the metadata between
- * the time we released the read lock and acquired the write lock,
- * above, we want to avoid doing it again.
- */
-
- if (metad->btm_root == P_NONE) {
-
- /*
- * Get, initialize, write, and leave a lock of the appropriate
- * type on the new root page. Since this is the first page in
- * the tree, it's a leaf.
- */
-
- rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
- rootblkno = BufferGetBlockNumber(rootbuf);
- rootpg = BufferGetPage(rootbuf);
- metad->btm_root = rootblkno;
+
+ if (metad->btm_magic != BTREE_MAGIC)
+ {
+ elog(WARN, "Index %s is not a btree",
+ RelationGetRelationName(rel));
+ }
+
+ if (metad->btm_version != BTREE_VERSION)
+ {
+ elog(WARN, "Version mismatch on %s: version %d file, version %d code",
+ RelationGetRelationName(rel),
+ metad->btm_version, BTREE_VERSION);
+ }
+
+ /* if no root page initialized yet, do it */
+ if (metad->btm_root == P_NONE)
+ {
+
+ /* turn our read lock in for a write lock */
+ _bt_relbuf(rel, metabuf, BT_READ);
+ metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
+ metapg = BufferGetPage(metabuf);
+ metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);
+ Assert(metaopaque->btpo_flags & BTP_META);
+ metad = BTPageGetMeta(metapg);
+
+ /*
+ * Race condition: if someone else initialized the metadata
+ * between the time we released the read lock and acquired the
+ * write lock, above, we want to avoid doing it again.
+ */
+
+ if (metad->btm_root == P_NONE)
+ {
+
+ /*
+ * Get, initialize, write, and leave a lock of the appropriate
+ * type on the new root page. Since this is the first page in
+ * the tree, it's a leaf.
+ */
+
+ rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
+ rootblkno = BufferGetBlockNumber(rootbuf);
+ rootpg = BufferGetPage(rootbuf);
+ metad->btm_root = rootblkno;
#ifdef BTREE_VERSION_1
- metad->btm_level = 1;
+ metad->btm_level = 1;
#endif
- _bt_pageinit(rootpg, BufferGetPageSize(rootbuf));
- rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpg);
- rootopaque->btpo_flags |= (BTP_LEAF | BTP_ROOT);
- _bt_wrtnorelbuf(rel, rootbuf);
-
- /* swap write lock for read lock, if appropriate */
- if (access != BT_WRITE) {
- _bt_setpagelock(rel, rootblkno, BT_READ);
- _bt_unsetpagelock(rel, rootblkno, BT_WRITE);
- }
-
- /* okay, metadata is correct */
- _bt_wrtbuf(rel, metabuf);
- } else {
-
- /*
- * Metadata initialized by someone else. In order to guarantee
- * no deadlocks, we have to release the metadata page and start
- * all over again.
- */
-
- _bt_relbuf(rel, metabuf, BT_WRITE);
- return (_bt_getroot(rel, access));
+ _bt_pageinit(rootpg, BufferGetPageSize(rootbuf));
+ rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpg);
+ rootopaque->btpo_flags |= (BTP_LEAF | BTP_ROOT);
+ _bt_wrtnorelbuf(rel, rootbuf);
+
+ /* swap write lock for read lock, if appropriate */
+ if (access != BT_WRITE)
+ {
+ _bt_setpagelock(rel, rootblkno, BT_READ);
+ _bt_unsetpagelock(rel, rootblkno, BT_WRITE);
+ }
+
+ /* okay, metadata is correct */
+ _bt_wrtbuf(rel, metabuf);
+ }
+ else
+ {
+
+ /*
+ * Metadata initialized by someone else. In order to
+ * guarantee no deadlocks, we have to release the metadata
+ * page and start all over again.
+ */
+
+ _bt_relbuf(rel, metabuf, BT_WRITE);
+ return (_bt_getroot(rel, access));
+ }
}
- } else {
- rootbuf = _bt_getbuf(rel, metad->btm_root, access);
-
- /* done with the meta page */
- _bt_relbuf(rel, metabuf, BT_READ);
- }
-
- /*
- * Race condition: If the root page split between the time we looked
- * at the metadata page and got the root buffer, then we got the wrong
- * buffer.
- */
-
- rootpg = BufferGetPage(rootbuf);
- rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpg);
- if (!(rootopaque->btpo_flags & BTP_ROOT)) {
-
- /* it happened, try again */
- _bt_relbuf(rel, rootbuf, access);
- return (_bt_getroot(rel, access));
- }
-
- /*
- * By here, we have a correct lock on the root block, its reference
- * count is correct, and we have no lock set on the metadata page.
- * Return the root block.
- */
-
- return (rootbuf);
+ else
+ {
+ rootbuf = _bt_getbuf(rel, metad->btm_root, access);
+
+ /* done with the meta page */
+ _bt_relbuf(rel, metabuf, BT_READ);
+ }
+
+ /*
+ * Race condition: If the root page split between the time we looked
+ * at the metadata page and got the root buffer, then we got the wrong
+ * buffer.
+ */
+
+ rootpg = BufferGetPage(rootbuf);
+ rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpg);
+ if (!(rootopaque->btpo_flags & BTP_ROOT))
+ {
+
+ /* it happened, try again */
+ _bt_relbuf(rel, rootbuf, access);
+ return (_bt_getroot(rel, access));
+ }
+
+ /*
+ * By here, we have a correct lock on the root block, its reference
+ * count is correct, and we have no lock set on the metadata page.
+ * Return the root block.
+ */
+
+ return (rootbuf);
}
/*
- * _bt_getbuf() -- Get a buffer by block number for read or write.
+ * _bt_getbuf() -- Get a buffer by block number for read or write.
*
- * When this routine returns, the appropriate lock is set on the
- * requested buffer its reference count is correct.
+ * When this routine returns, the appropriate lock is set on the
+ * requested buffer its reference count is correct.
*/
Buffer
_bt_getbuf(Relation rel, BlockNumber blkno, int access)
{
- Buffer buf;
- Page page;
-
- /*
- * If we want a new block, we can't set a lock of the appropriate type
- * until we've instantiated the buffer.
- */
-
- if (blkno != P_NEW) {
- if (access == BT_WRITE)
- _bt_setpagelock(rel, blkno, BT_WRITE);
- else
- _bt_setpagelock(rel, blkno, BT_READ);
-
- buf = ReadBuffer(rel, blkno);
- } else {
- buf = ReadBuffer(rel, blkno);
- blkno = BufferGetBlockNumber(buf);
- page = BufferGetPage(buf);
- _bt_pageinit(page, BufferGetPageSize(buf));
-
- if (access == BT_WRITE)
- _bt_setpagelock(rel, blkno, BT_WRITE);
+ Buffer buf;
+ Page page;
+
+ /*
+ * If we want a new block, we can't set a lock of the appropriate type
+ * until we've instantiated the buffer.
+ */
+
+ if (blkno != P_NEW)
+ {
+ if (access == BT_WRITE)
+ _bt_setpagelock(rel, blkno, BT_WRITE);
+ else
+ _bt_setpagelock(rel, blkno, BT_READ);
+
+ buf = ReadBuffer(rel, blkno);
+ }
else
- _bt_setpagelock(rel, blkno, BT_READ);
- }
-
- /* ref count and lock type are correct */
- return (buf);
+ {
+ buf = ReadBuffer(rel, blkno);
+ blkno = BufferGetBlockNumber(buf);
+ page = BufferGetPage(buf);
+ _bt_pageinit(page, BufferGetPageSize(buf));
+
+ if (access == BT_WRITE)
+ _bt_setpagelock(rel, blkno, BT_WRITE);
+ else
+ _bt_setpagelock(rel, blkno, BT_READ);
+ }
+
+ /* ref count and lock type are correct */
+ return (buf);
}
/*
- * _bt_relbuf() -- release a locked buffer.
+ * _bt_relbuf() -- release a locked buffer.
*/
void
_bt_relbuf(Relation rel, Buffer buf, int access)
{
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(buf);
-
- /* access had better be one of read or write */
- if (access == BT_WRITE)
- _bt_unsetpagelock(rel, blkno, BT_WRITE);
- else
- _bt_unsetpagelock(rel, blkno, BT_READ);
-
- ReleaseBuffer(buf);
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(buf);
+
+ /* access had better be one of read or write */
+ if (access == BT_WRITE)
+ _bt_unsetpagelock(rel, blkno, BT_WRITE);
+ else
+ _bt_unsetpagelock(rel, blkno, BT_READ);
+
+ ReleaseBuffer(buf);
}
/*
- * _bt_wrtbuf() -- write a btree page to disk.
+ * _bt_wrtbuf() -- write a btree page to disk.
*
- * This routine releases the lock held on the buffer and our reference
- * to it. It is an error to call _bt_wrtbuf() without a write lock
- * or a reference to the buffer.
+ * This routine releases the lock held on the buffer and our reference
+ * to it. It is an error to call _bt_wrtbuf() without a write lock
+ * or a reference to the buffer.
*/
void
_bt_wrtbuf(Relation rel, Buffer buf)
{
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(buf);
- WriteBuffer(buf);
- _bt_unsetpagelock(rel, blkno, BT_WRITE);
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(buf);
+ WriteBuffer(buf);
+ _bt_unsetpagelock(rel, blkno, BT_WRITE);
}
/*
- * _bt_wrtnorelbuf() -- write a btree page to disk, but do not release
- * our reference or lock.
+ * _bt_wrtnorelbuf() -- write a btree page to disk, but do not release
+ * our reference or lock.
*
- * It is an error to call _bt_wrtnorelbuf() without a write lock
- * or a reference to the buffer.
+ * It is an error to call _bt_wrtnorelbuf() without a write lock
+ * or a reference to the buffer.
*/
void
_bt_wrtnorelbuf(Relation rel, Buffer buf)
{
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(buf);
- WriteNoReleaseBuffer(buf);
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(buf);
+ WriteNoReleaseBuffer(buf);
}
/*
- * _bt_pageinit() -- Initialize a new page.
+ * _bt_pageinit() -- Initialize a new page.
*/
void
_bt_pageinit(Page page, Size size)
{
- /*
- * Cargo-cult programming -- don't really need this to be zero, but
- * creating new pages is an infrequent occurrence and it makes me feel
- * good when I know they're empty.
- */
-
- memset(page, 0, size);
-
- PageInit(page, size, sizeof(BTPageOpaqueData));
+
+ /*
+ * Cargo-cult programming -- don't really need this to be zero, but
+ * creating new pages is an infrequent occurrence and it makes me feel
+ * good when I know they're empty.
+ */
+
+ memset(page, 0, size);
+
+ PageInit(page, size, sizeof(BTPageOpaqueData));
}
/*
- * _bt_metaproot() -- Change the root page of the btree.
+ * _bt_metaproot() -- Change the root page of the btree.
*
- * Lehman and Yao require that the root page move around in order to
- * guarantee deadlock-free short-term, fine-granularity locking. When
- * we split the root page, we record the new parent in the metadata page
- * for the relation. This routine does the work.
+ * Lehman and Yao require that the root page move around in order to
+ * guarantee deadlock-free short-term, fine-granularity locking. When
+ * we split the root page, we record the new parent in the metadata page
+ * for the relation. This routine does the work.
*
- * No direct preconditions, but if you don't have the a write lock on
- * at least the old root page when you call this, you're making a big
- * mistake. On exit, metapage data is correct and we no longer have
- * a reference to or lock on the metapage.
+ * No direct preconditions, but if you don't have the a write lock on
+ * at least the old root page when you call this, you're making a big
+ * mistake. On exit, metapage data is correct and we no longer have
+ * a reference to or lock on the metapage.
*/
void
_bt_metaproot(Relation rel, BlockNumber rootbknum, int level)
{
- Buffer metabuf;
- Page metap;
- BTPageOpaque metaopaque;
- BTMetaPageData *metad;
-
- metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
- metap = BufferGetPage(metabuf);
- metaopaque = (BTPageOpaque) PageGetSpecialPointer(metap);
- Assert(metaopaque->btpo_flags & BTP_META);
- metad = BTPageGetMeta(metap);
- metad->btm_root = rootbknum;
+ Buffer metabuf;
+ Page metap;
+ BTPageOpaque metaopaque;
+ BTMetaPageData *metad;
+
+ metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
+ metap = BufferGetPage(metabuf);
+ metaopaque = (BTPageOpaque) PageGetSpecialPointer(metap);
+ Assert(metaopaque->btpo_flags & BTP_META);
+ metad = BTPageGetMeta(metap);
+ metad->btm_root = rootbknum;
#ifdef BTREE_VERSION_1
- if ( level == 0 ) /* called from _do_insert */
- metad->btm_level += 1;
- else
- metad->btm_level = level; /* called from btsort */
+ if (level == 0) /* called from _do_insert */
+ metad->btm_level += 1;
+ else
+ metad->btm_level = level; /* called from btsort */
#endif
- _bt_wrtbuf(rel, metabuf);
+ _bt_wrtbuf(rel, metabuf);
}
/*
- * _bt_getstackbuf() -- Walk back up the tree one step, and find the item
- * we last looked at in the parent.
+ * _bt_getstackbuf() -- Walk back up the tree one step, and find the item
+ * we last looked at in the parent.
*
- * This is possible because we save a bit image of the last item
- * we looked at in the parent, and the update algorithm guarantees
- * that if items above us in the tree move, they only move right.
+ * This is possible because we save a bit image of the last item
+ * we looked at in the parent, and the update algorithm guarantees
+ * that if items above us in the tree move, they only move right.
*
- * Also, re-set bts_blkno & bts_offset if changed and
- * bts_btitem (it may be changed - see _bt_insertonpg).
+ * Also, re-set bts_blkno & bts_offset if changed and
+ * bts_btitem (it may be changed - see _bt_insertonpg).
*/
Buffer
_bt_getstackbuf(Relation rel, BTStack stack, int access)
{
- Buffer buf;
- BlockNumber blkno;
- OffsetNumber start, offnum, maxoff;
- OffsetNumber i;
- Page page;
- ItemId itemid;
- BTItem item;
- BTPageOpaque opaque;
- BTItem item_save;
- int item_nbytes;
-
- blkno = stack->bts_blkno;
- buf = _bt_getbuf(rel, blkno, access);
- page = BufferGetPage(buf);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- maxoff = PageGetMaxOffsetNumber(page);
-
- if (maxoff >= stack->bts_offset) {
- itemid = PageGetItemId(page, stack->bts_offset);
- item = (BTItem) PageGetItem(page, itemid);
-
- /* if the item is where we left it, we're done */
- if ( BTItemSame (item, stack->bts_btitem) )
- {
- pfree(stack->bts_btitem);
- item_nbytes = ItemIdGetLength(itemid);
- item_save = (BTItem) palloc(item_nbytes);
- memmove((char *) item_save, (char *) item, item_nbytes);
- stack->bts_btitem = item_save;
- return (buf);
- }
-
- /* if the item has just moved right on this page, we're done */
- for (i = OffsetNumberNext(stack->bts_offset);
- i <= maxoff;
- i = OffsetNumberNext(i)) {
- itemid = PageGetItemId(page, i);
- item = (BTItem) PageGetItem(page, itemid);
-
- /* if the item is where we left it, we're done */
- if ( BTItemSame (item, stack->bts_btitem) )
- {
- stack->bts_offset = i;
- pfree(stack->bts_btitem);
- item_nbytes = ItemIdGetLength(itemid);
- item_save = (BTItem) palloc(item_nbytes);
- memmove((char *) item_save, (char *) item, item_nbytes);
- stack->bts_btitem = item_save;
- return (buf);
- }
- }
- }
-
- /* by here, the item we're looking for moved right at least one page */
- for (;;) {
- blkno = opaque->btpo_next;
- if (P_RIGHTMOST(opaque))
- elog(FATAL, "my bits moved right off the end of the world!");
-
- _bt_relbuf(rel, buf, access);
+ Buffer buf;
+ BlockNumber blkno;
+ OffsetNumber start,
+ offnum,
+ maxoff;
+ OffsetNumber i;
+ Page page;
+ ItemId itemid;
+ BTItem item;
+ BTPageOpaque opaque;
+ BTItem item_save;
+ int item_nbytes;
+
+ blkno = stack->bts_blkno;
buf = _bt_getbuf(rel, blkno, access);
page = BufferGetPage(buf);
- maxoff = PageGetMaxOffsetNumber(page);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
-
- /* if we have a right sibling, step over the high key */
- start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
-
- /* see if it's on this page */
- for (offnum = start;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum)) {
- itemid = PageGetItemId(page, offnum);
- item = (BTItem) PageGetItem(page, itemid);
- if ( BTItemSame (item, stack->bts_btitem) )
- {
- stack->bts_offset = offnum;
- stack->bts_blkno = blkno;
- pfree(stack->bts_btitem);
- item_nbytes = ItemIdGetLength(itemid);
- item_save = (BTItem) palloc(item_nbytes);
- memmove((char *) item_save, (char *) item, item_nbytes);
- stack->bts_btitem = item_save;
- return (buf);
- }
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ if (maxoff >= stack->bts_offset)
+ {
+ itemid = PageGetItemId(page, stack->bts_offset);
+ item = (BTItem) PageGetItem(page, itemid);
+
+ /* if the item is where we left it, we're done */
+ if (BTItemSame(item, stack->bts_btitem))
+ {
+ pfree(stack->bts_btitem);
+ item_nbytes = ItemIdGetLength(itemid);
+ item_save = (BTItem) palloc(item_nbytes);
+ memmove((char *) item_save, (char *) item, item_nbytes);
+ stack->bts_btitem = item_save;
+ return (buf);
+ }
+
+ /* if the item has just moved right on this page, we're done */
+ for (i = OffsetNumberNext(stack->bts_offset);
+ i <= maxoff;
+ i = OffsetNumberNext(i))
+ {
+ itemid = PageGetItemId(page, i);
+ item = (BTItem) PageGetItem(page, itemid);
+
+ /* if the item is where we left it, we're done */
+ if (BTItemSame(item, stack->bts_btitem))
+ {
+ stack->bts_offset = i;
+ pfree(stack->bts_btitem);
+ item_nbytes = ItemIdGetLength(itemid);
+ item_save = (BTItem) palloc(item_nbytes);
+ memmove((char *) item_save, (char *) item, item_nbytes);
+ stack->bts_btitem = item_save;
+ return (buf);
+ }
+ }
+ }
+
+ /* by here, the item we're looking for moved right at least one page */
+ for (;;)
+ {
+ blkno = opaque->btpo_next;
+ if (P_RIGHTMOST(opaque))
+ elog(FATAL, "my bits moved right off the end of the world!");
+
+ _bt_relbuf(rel, buf, access);
+ buf = _bt_getbuf(rel, blkno, access);
+ page = BufferGetPage(buf);
+ maxoff = PageGetMaxOffsetNumber(page);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ /* if we have a right sibling, step over the high key */
+ start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ /* see if it's on this page */
+ for (offnum = start;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ itemid = PageGetItemId(page, offnum);
+ item = (BTItem) PageGetItem(page, itemid);
+ if (BTItemSame(item, stack->bts_btitem))
+ {
+ stack->bts_offset = offnum;
+ stack->bts_blkno = blkno;
+ pfree(stack->bts_btitem);
+ item_nbytes = ItemIdGetLength(itemid);
+ item_save = (BTItem) palloc(item_nbytes);
+ memmove((char *) item_save, (char *) item, item_nbytes);
+ stack->bts_btitem = item_save;
+ return (buf);
+ }
+ }
}
- }
}
static void
_bt_setpagelock(Relation rel, BlockNumber blkno, int access)
{
- ItemPointerData iptr;
-
- if (USELOCKING) {
- ItemPointerSet(&iptr, blkno, P_HIKEY);
-
- if (access == BT_WRITE)
- RelationSetSingleWLockPage(rel, &iptr);
- else
- RelationSetSingleRLockPage(rel, &iptr);
- }
+ ItemPointerData iptr;
+
+ if (USELOCKING)
+ {
+ ItemPointerSet(&iptr, blkno, P_HIKEY);
+
+ if (access == BT_WRITE)
+ RelationSetSingleWLockPage(rel, &iptr);
+ else
+ RelationSetSingleRLockPage(rel, &iptr);
+ }
}
static void
_bt_unsetpagelock(Relation rel, BlockNumber blkno, int access)
{
- ItemPointerData iptr;
-
- if (USELOCKING) {
- ItemPointerSet(&iptr, blkno, P_HIKEY);
-
- if (access == BT_WRITE)
- RelationUnsetSingleWLockPage(rel, &iptr);
- else
- RelationUnsetSingleRLockPage(rel, &iptr);
- }
+ ItemPointerData iptr;
+
+ if (USELOCKING)
+ {
+ ItemPointerSet(&iptr, blkno, P_HIKEY);
+
+ if (access == BT_WRITE)
+ RelationUnsetSingleWLockPage(rel, &iptr);
+ else
+ RelationUnsetSingleRLockPage(rel, &iptr);
+ }
}
void
_bt_pagedel(Relation rel, ItemPointer tid)
{
- Buffer buf;
- Page page;
- BlockNumber blkno;
- OffsetNumber offno;
-
- blkno = ItemPointerGetBlockNumber(tid);
- offno = ItemPointerGetOffsetNumber(tid);
-
- buf = _bt_getbuf(rel, blkno, BT_WRITE);
- page = BufferGetPage(buf);
-
- PageIndexTupleDelete(page, offno);
-
- /* write the buffer and release the lock */
- _bt_wrtbuf(rel, buf);
+ Buffer buf;
+ Page page;
+ BlockNumber blkno;
+ OffsetNumber offno;
+
+ blkno = ItemPointerGetBlockNumber(tid);
+ offno = ItemPointerGetOffsetNumber(tid);
+
+ buf = _bt_getbuf(rel, blkno, BT_WRITE);
+ page = BufferGetPage(buf);
+
+ PageIndexTupleDelete(page, offno);
+
+ /* write the buffer and release the lock */
+ _bt_wrtbuf(rel, buf);
}
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index b672901f8db..dccbd77b355 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* btree.c--
- * Implementation of Lehman and Yao's btree management algorithm for
- * Postgres.
+ * Implementation of Lehman and Yao's btree management algorithm for
+ * Postgres.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.19 1997/05/05 03:41:17 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.20 1997/09/07 04:38:54 momjian Exp $
*
* NOTES
- * This file contains only the public interface routines.
+ * This file contains only the public interface routines.
*
*-------------------------------------------------------------------------
*/
@@ -28,546 +28,579 @@
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
#ifdef BTREE_BUILD_STATS
#include <tcop/tcopprot.h>
-extern int ShowExecutorStats;
+extern int ShowExecutorStats;
+
#endif
-bool BuildingBtree = false; /* see comment in btbuild() */
-bool FastBuild = true; /* use sort/build instead of insertion build */
+bool BuildingBtree = false; /* see comment in btbuild() */
+bool FastBuild = true; /* use sort/build instead of
+ * insertion build */
/*
- * btbuild() -- build a new btree index.
+ * btbuild() -- build a new btree index.
*
- * We use a global variable to record the fact that we're creating
- * a new index. This is used to avoid high-concurrency locking,
- * since the index won't be visible until this transaction commits
- * and since building is guaranteed to be single-threaded.
+ * We use a global variable to record the fact that we're creating
+ * a new index. This is used to avoid high-concurrency locking,
+ * since the index won't be visible until this transaction commits
+ * and since building is guaranteed to be single-threaded.
*/
void
btbuild(Relation heap,
- Relation index,
- int natts,
- AttrNumber *attnum,
- IndexStrategy istrat,
- uint16 pcount,
- Datum *params,
- FuncIndexInfo *finfo,
- PredInfo *predInfo)
+ Relation index,
+ int natts,
+ AttrNumber * attnum,
+ IndexStrategy istrat,
+ uint16 pcount,
+ Datum * params,
+ FuncIndexInfo * finfo,
+ PredInfo * predInfo)
{
- HeapScanDesc hscan;
- Buffer buffer;
- HeapTuple htup;
- IndexTuple itup;
- TupleDesc htupdesc, itupdesc;
- Datum *attdata;
- bool *nulls;
- InsertIndexResult res = 0;
- int nhtups, nitups;
- int i;
- BTItem btitem;
+ HeapScanDesc hscan;
+ Buffer buffer;
+ HeapTuple htup;
+ IndexTuple itup;
+ TupleDesc htupdesc,
+ itupdesc;
+ Datum *attdata;
+ bool *nulls;
+ InsertIndexResult res = 0;
+ int nhtups,
+ nitups;
+ int i;
+ BTItem btitem;
+
#ifndef OMIT_PARTIAL_INDEX
- ExprContext *econtext = (ExprContext *) NULL;
- TupleTable tupleTable = (TupleTable) NULL;
- TupleTableSlot *slot = (TupleTableSlot *) NULL;
-#endif
- Oid hrelid, irelid;
- Node *pred, *oldPred;
- void *spool = (void *) NULL;
- bool isunique;
- bool usefast;
-
- /* note that this is a new btree */
- BuildingBtree = true;
-
- pred = predInfo->pred;
- oldPred = predInfo->oldPred;
-
- /*
- * bootstrap processing does something strange, so don't use
- * sort/build for initial catalog indices. at some point i need
- * to look harder at this. (there is some kind of incremental
- * processing going on there.) -- pma 08/29/95
- */
- usefast = (FastBuild && IsNormalProcessingMode());
+ ExprContext *econtext = (ExprContext *) NULL;
+ TupleTable tupleTable = (TupleTable) NULL;
+ TupleTableSlot *slot = (TupleTableSlot *) NULL;
-#ifdef BTREE_BUILD_STATS
- if ( ShowExecutorStats )
- ResetUsage ();
#endif
+ Oid hrelid,
+ irelid;
+ Node *pred,
+ *oldPred;
+ void *spool = (void *) NULL;
+ bool isunique;
+ bool usefast;
- /* see if index is unique */
- isunique = IndexIsUniqueNoCache(RelationGetRelationId(index));
-
- /* initialize the btree index metadata page (if this is a new index) */
- if (oldPred == NULL)
- _bt_metapinit(index);
-
- /* get tuple descriptors for heap and index relations */
- htupdesc = RelationGetTupleDescriptor(heap);
- itupdesc = RelationGetTupleDescriptor(index);
-
- /* get space for data items that'll appear in the index tuple */
- attdata = (Datum *) palloc(natts * sizeof(Datum));
- nulls = (bool *) palloc(natts * sizeof(bool));
-
- /*
- * If this is a predicate (partial) index, we will need to evaluate the
- * predicate using ExecQual, which requires the current tuple to be in a
- * slot of a TupleTable. In addition, ExecQual must have an ExprContext
- * referring to that slot. Here, we initialize dummy TupleTable and
- * ExprContext objects for this purpose. --Nels, Feb '92
- */
-#ifndef OMIT_PARTIAL_INDEX
- if (pred != NULL || oldPred != NULL) {
- tupleTable = ExecCreateTupleTable(1);
- slot = ExecAllocTableSlot(tupleTable);
- econtext = makeNode(ExprContext);
- FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer);
+ /* note that this is a new btree */
+ BuildingBtree = true;
+
+ pred = predInfo->pred;
+ oldPred = predInfo->oldPred;
/*
- * we never want to use sort/build if we are extending an
- * existing partial index -- it works by inserting the
- * newly-qualifying tuples into the existing index.
- * (sort/build would overwrite the existing index with one
- * consisting of the newly-qualifying tuples.)
+ * bootstrap processing does something strange, so don't use
+ * sort/build for initial catalog indices. at some point i need to
+ * look harder at this. (there is some kind of incremental processing
+ * going on there.) -- pma 08/29/95
*/
- usefast = false;
- }
-#endif /* OMIT_PARTIAL_INDEX */
-
- /* start a heap scan */
- hscan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
- htup = heap_getnext(hscan, 0, &buffer);
-
- /* build the index */
- nhtups = nitups = 0;
-
- if (usefast) {
- spool = _bt_spoolinit(index, 7, isunique);
- res = (InsertIndexResult) NULL;
- }
-
- for (; HeapTupleIsValid(htup); htup = heap_getnext(hscan, 0, &buffer)) {
-
- nhtups++;
-
+ usefast = (FastBuild && IsNormalProcessingMode());
+
+#ifdef BTREE_BUILD_STATS
+ if (ShowExecutorStats)
+ ResetUsage();
+#endif
+
+ /* see if index is unique */
+ isunique = IndexIsUniqueNoCache(RelationGetRelationId(index));
+
+ /* initialize the btree index metadata page (if this is a new index) */
+ if (oldPred == NULL)
+ _bt_metapinit(index);
+
+ /* get tuple descriptors for heap and index relations */
+ htupdesc = RelationGetTupleDescriptor(heap);
+ itupdesc = RelationGetTupleDescriptor(index);
+
+ /* get space for data items that'll appear in the index tuple */
+ attdata = (Datum *) palloc(natts * sizeof(Datum));
+ nulls = (bool *) palloc(natts * sizeof(bool));
+
/*
- * If oldPred != NULL, this is an EXTEND INDEX command, so skip
- * this tuple if it was already in the existing partial index
+ * If this is a predicate (partial) index, we will need to evaluate
+ * the predicate using ExecQual, which requires the current tuple to
+ * be in a slot of a TupleTable. In addition, ExecQual must have an
+ * ExprContext referring to that slot. Here, we initialize dummy
+ * TupleTable and ExprContext objects for this purpose. --Nels, Feb
+ * '92
*/
- if (oldPred != NULL) {
+#ifndef OMIT_PARTIAL_INDEX
+ if (pred != NULL || oldPred != NULL)
+ {
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ econtext = makeNode(ExprContext);
+ FillDummyExprContext(econtext, slot, htupdesc, InvalidBuffer);
+
+ /*
+ * we never want to use sort/build if we are extending an existing
+ * partial index -- it works by inserting the newly-qualifying
+ * tuples into the existing index. (sort/build would overwrite the
+ * existing index with one consisting of the newly-qualifying
+ * tuples.)
+ */
+ usefast = false;
+ }
+#endif /* OMIT_PARTIAL_INDEX */
+
+ /* start a heap scan */
+ hscan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
+ htup = heap_getnext(hscan, 0, &buffer);
+
+ /* build the index */
+ nhtups = nitups = 0;
+
+ if (usefast)
+ {
+ spool = _bt_spoolinit(index, 7, isunique);
+ res = (InsertIndexResult) NULL;
+ }
+
+ for (; HeapTupleIsValid(htup); htup = heap_getnext(hscan, 0, &buffer))
+ {
+
+ nhtups++;
+
+ /*
+ * If oldPred != NULL, this is an EXTEND INDEX command, so skip
+ * this tuple if it was already in the existing partial index
+ */
+ if (oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, htup);*/
- slot->val = htup;
- if (ExecQual((List*)oldPred, econtext) == true) {
+ /* SetSlotContents(slot, htup); */
+ slot->val = htup;
+ if (ExecQual((List *) oldPred, econtext) == true)
+ {
+ nitups++;
+ continue;
+ }
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
+ /*
+ * Skip this tuple if it doesn't satisfy the partial-index
+ * predicate
+ */
+ if (pred != NULL)
+ {
+#ifndef OMIT_PARTIAL_INDEX
+ /* SetSlotContents(slot, htup); */
+ slot->val = htup;
+ if (ExecQual((List *) pred, econtext) == false)
+ continue;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
nitups++;
- continue;
- }
-#endif /* OMIT_PARTIAL_INDEX */
+
+ /*
+ * For the current heap tuple, extract all the attributes we use
+ * in this index, and note which are null.
+ */
+
+ for (i = 1; i <= natts; i++)
+ {
+ int attoff;
+ bool attnull;
+
+ /*
+ * Offsets are from the start of the tuple, and are
+ * zero-based; indices are one-based. The next call returns i
+ * - 1. That's data hiding for you.
+ */
+
+ attoff = AttrNumberGetAttrOffset(i);
+ attdata[attoff] = GetIndexValue(htup,
+ htupdesc,
+ attoff,
+ attnum,
+ finfo,
+ &attnull,
+ buffer);
+ nulls[attoff] = (attnull ? 'n' : ' ');
+ }
+
+ /* form an index tuple and point it at the heap tuple */
+ itup = index_formtuple(itupdesc, attdata, nulls);
+
+ /*
+ * If the single index key is null, we don't insert it into the
+ * index. Btrees support scans on <, <=, =, >=, and >. Relational
+ * algebra says that A op B (where op is one of the operators
+ * above) returns null if either A or B is null. This means that
+ * no qualification used in an index scan could ever return true
+ * on a null attribute. It also means that indices can't be used
+ * by ISNULL or NOTNULL scans, but that's an artifact of the
+ * strategy map architecture chosen in 1986, not of the way nulls
+ * are handled here.
+ */
+
+ /*
+ * New comments: NULLs handling. While we can't do NULL
+ * comparison, we can follow simple rule for ordering items on
+ * btree pages - NULLs greater NOT_NULLs and NULL = NULL is TRUE.
+ * Sure, it's just rule for placing/finding items and no more -
+ * keytest'll return FALSE for a = 5 for items having 'a' isNULL.
+ * Look at _bt_skeycmp, _bt_compare and _bt_itemcmp for how it
+ * works. - vadim 03/23/97
+ *
+ * if (itup->t_info & INDEX_NULL_MASK) { pfree(itup); continue; }
+ */
+
+ itup->t_tid = htup->t_ctid;
+ btitem = _bt_formitem(itup);
+
+ /*
+ * if we are doing bottom-up btree build, we insert the index into
+ * a spool page for subsequent processing. otherwise, we insert
+ * into the btree.
+ */
+ if (usefast)
+ {
+ _bt_spool(index, btitem, spool);
+ }
+ else
+ {
+ res = _bt_doinsert(index, btitem, isunique, heap);
+ }
+
+ pfree(btitem);
+ pfree(itup);
+ if (res)
+ {
+ pfree(res);
+ }
}
-
- /* Skip this tuple if it doesn't satisfy the partial-index predicate */
- if (pred != NULL) {
+
+ /* okay, all heap tuples are indexed */
+ heap_endscan(hscan);
+
+ if (pred != NULL || oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /* SetSlotContents(slot, htup); */
- slot->val = htup;
- if (ExecQual((List*)pred, econtext) == false)
- continue;
-#endif /* OMIT_PARTIAL_INDEX */
+ ExecDestroyTupleTable(tupleTable, true);
+ pfree(econtext);
+#endif /* OMIT_PARTIAL_INDEX */
}
-
- nitups++;
-
+
/*
- * For the current heap tuple, extract all the attributes
- * we use in this index, and note which are null.
+ * if we are doing bottom-up btree build, we now have a bunch of
+ * sorted runs in the spool pages. finish the build by (1) merging
+ * the runs, (2) inserting the sorted tuples into btree pages and (3)
+ * building the upper levels.
*/
-
- for (i = 1; i <= natts; i++) {
- int attoff;
- bool attnull;
-
- /*
- * Offsets are from the start of the tuple, and are
- * zero-based; indices are one-based. The next call
- * returns i - 1. That's data hiding for you.
- */
-
- attoff = AttrNumberGetAttrOffset(i);
- attdata[attoff] = GetIndexValue(htup,
- htupdesc,
- attoff,
- attnum,
- finfo,
- &attnull,
- buffer);
- nulls[attoff] = (attnull ? 'n' : ' ');
+ if (usefast)
+ {
+ _bt_spool(index, (BTItem) NULL, spool); /* flush the spool */
+ _bt_leafbuild(index, spool);
+ _bt_spooldestroy(spool);
}
-
- /* form an index tuple and point it at the heap tuple */
- itup = index_formtuple(itupdesc, attdata, nulls);
-
- /*
- * If the single index key is null, we don't insert it into
- * the index. Btrees support scans on <, <=, =, >=, and >.
- * Relational algebra says that A op B (where op is one of the
- * operators above) returns null if either A or B is null. This
- * means that no qualification used in an index scan could ever
- * return true on a null attribute. It also means that indices
- * can't be used by ISNULL or NOTNULL scans, but that's an
- * artifact of the strategy map architecture chosen in 1986, not
- * of the way nulls are handled here.
- */
- /*
- * New comments: NULLs handling.
- * While we can't do NULL comparison, we can follow simple
- * rule for ordering items on btree pages - NULLs greater
- * NOT_NULLs and NULL = NULL is TRUE. Sure, it's just rule
- * for placing/finding items and no more - keytest'll return
- * FALSE for a = 5 for items having 'a' isNULL.
- * Look at _bt_skeycmp, _bt_compare and _bt_itemcmp for
- * how it works. - vadim 03/23/97
-
- if (itup->t_info & INDEX_NULL_MASK) {
- pfree(itup);
- continue;
+
+#ifdef BTREE_BUILD_STATS
+ if (ShowExecutorStats)
+ {
+ fprintf(stderr, "! BtreeBuild Stats:\n");
+ ShowUsage();
+ ResetUsage();
}
- */
-
- itup->t_tid = htup->t_ctid;
- btitem = _bt_formitem(itup);
+#endif
/*
- * if we are doing bottom-up btree build, we insert the index
- * into a spool page for subsequent processing. otherwise, we
- * insert into the btree.
+ * Since we just counted the tuples in the heap, we update its stats
+ * in pg_class to guarantee that the planner takes advantage of the
+ * index we just created. Finally, only update statistics during
+ * normal index definitions, not for indices on system catalogs
+ * created during bootstrap processing. We must close the relations
+ * before updatings statistics to guarantee that the relcache entries
+ * are flushed when we increment the command counter in UpdateStats().
*/
- if (usefast) {
- _bt_spool(index, btitem, spool);
- } else {
- res = _bt_doinsert(index, btitem, isunique, heap);
+ if (IsNormalProcessingMode())
+ {
+ hrelid = heap->rd_id;
+ irelid = index->rd_id;
+ heap_close(heap);
+ index_close(index);
+ UpdateStats(hrelid, nhtups, true);
+ UpdateStats(irelid, nitups, false);
+ if (oldPred != NULL)
+ {
+ if (nitups == nhtups)
+ pred = NULL;
+ UpdateIndexPredicate(irelid, oldPred, pred);
+ }
}
- pfree(btitem);
- pfree(itup);
- if (res) {
- pfree(res);
- }
- }
-
- /* okay, all heap tuples are indexed */
- heap_endscan(hscan);
-
- if (pred != NULL || oldPred != NULL) {
-#ifndef OMIT_PARTIAL_INDEX
- ExecDestroyTupleTable(tupleTable, true);
- pfree(econtext);
-#endif /* OMIT_PARTIAL_INDEX */
- }
-
- /*
- * if we are doing bottom-up btree build, we now have a bunch of
- * sorted runs in the spool pages. finish the build by (1)
- * merging the runs, (2) inserting the sorted tuples into btree
- * pages and (3) building the upper levels.
- */
- if (usefast) {
- _bt_spool(index, (BTItem) NULL, spool); /* flush the spool */
- _bt_leafbuild(index, spool);
- _bt_spooldestroy(spool);
- }
+ pfree(nulls);
+ pfree(attdata);
-#ifdef BTREE_BUILD_STATS
- if ( ShowExecutorStats )
- {
- fprintf(stderr, "! BtreeBuild Stats:\n");
- ShowUsage ();
- ResetUsage ();
- }
-#endif
-
- /*
- * Since we just counted the tuples in the heap, we update its
- * stats in pg_class to guarantee that the planner takes advantage
- * of the index we just created. Finally, only update statistics
- * during normal index definitions, not for indices on system catalogs
- * created during bootstrap processing. We must close the relations
- * before updatings statistics to guarantee that the relcache entries
- * are flushed when we increment the command counter in UpdateStats().
- */
- if (IsNormalProcessingMode())
- {
- hrelid = heap->rd_id;
- irelid = index->rd_id;
- heap_close(heap);
- index_close(index);
- UpdateStats(hrelid, nhtups, true);
- UpdateStats(irelid, nitups, false);
- if (oldPred != NULL) {
- if (nitups == nhtups) pred = NULL;
- UpdateIndexPredicate(irelid, oldPred, pred);
- }
- }
-
- pfree(nulls);
- pfree(attdata);
-
- /* all done */
- BuildingBtree = false;
+ /* all done */
+ BuildingBtree = false;
}
/*
- * btinsert() -- insert an index tuple into a btree.
+ * btinsert() -- insert an index tuple into a btree.
*
- * Descend the tree recursively, find the appropriate location for our
- * new tuple, put it there, set its unique OID as appropriate, and
- * return an InsertIndexResult to the caller.
+ * Descend the tree recursively, find the appropriate location for our
+ * new tuple, put it there, set its unique OID as appropriate, and
+ * return an InsertIndexResult to the caller.
*/
InsertIndexResult
-btinsert(Relation rel, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
+btinsert(Relation rel, Datum * datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
{
- BTItem btitem;
- IndexTuple itup;
- InsertIndexResult res;
-
- /* generate an index tuple */
- itup = index_formtuple(RelationGetTupleDescriptor(rel), datum, nulls);
- itup->t_tid = *ht_ctid;
-
- /*
- * See comments in btbuild.
-
- if (itup->t_info & INDEX_NULL_MASK)
- return ((InsertIndexResult) NULL);
- */
-
- btitem = _bt_formitem(itup);
-
- res = _bt_doinsert(rel, btitem,
- IndexIsUnique(RelationGetRelationId(rel)), heapRel);
-
- pfree(btitem);
- pfree(itup);
-
- /* adjust any active scans that will be affected by this insertion */
- _bt_adjscans(rel, &(res->pointerData), BT_INSERT);
-
- return (res);
+ BTItem btitem;
+ IndexTuple itup;
+ InsertIndexResult res;
+
+ /* generate an index tuple */
+ itup = index_formtuple(RelationGetTupleDescriptor(rel), datum, nulls);
+ itup->t_tid = *ht_ctid;
+
+ /*
+ * See comments in btbuild.
+ *
+ * if (itup->t_info & INDEX_NULL_MASK) return ((InsertIndexResult) NULL);
+ */
+
+ btitem = _bt_formitem(itup);
+
+ res = _bt_doinsert(rel, btitem,
+ IndexIsUnique(RelationGetRelationId(rel)), heapRel);
+
+ pfree(btitem);
+ pfree(itup);
+
+ /* adjust any active scans that will be affected by this insertion */
+ _bt_adjscans(rel, &(res->pointerData), BT_INSERT);
+
+ return (res);
}
/*
- * btgettuple() -- Get the next tuple in the scan.
+ * btgettuple() -- Get the next tuple in the scan.
*/
-char *
+char *
btgettuple(IndexScanDesc scan, ScanDirection dir)
{
- RetrieveIndexResult res;
-
- /*
- * If we've already initialized this scan, we can just advance it
- * in the appropriate direction. If we haven't done so yet, we
- * call a routine to get the first item in the scan.
- */
-
- if (ItemPointerIsValid(&(scan->currentItemData)))
- res = _bt_next(scan, dir);
- else
- res = _bt_first(scan, dir);
-
- return ((char *) res);
+ RetrieveIndexResult res;
+
+ /*
+ * If we've already initialized this scan, we can just advance it in
+ * the appropriate direction. If we haven't done so yet, we call a
+ * routine to get the first item in the scan.
+ */
+
+ if (ItemPointerIsValid(&(scan->currentItemData)))
+ res = _bt_next(scan, dir);
+ else
+ res = _bt_first(scan, dir);
+
+ return ((char *) res);
}
/*
- * btbeginscan() -- start a scan on a btree index
+ * btbeginscan() -- start a scan on a btree index
*/
-char *
+char *
btbeginscan(Relation rel, bool fromEnd, uint16 keysz, ScanKey scankey)
{
- IndexScanDesc scan;
-
- /* get the scan */
- scan = RelationGetIndexScan(rel, fromEnd, keysz, scankey);
-
- /* register scan in case we change pages it's using */
- _bt_regscan(scan);
-
- return ((char *) scan);
+ IndexScanDesc scan;
+
+ /* get the scan */
+ scan = RelationGetIndexScan(rel, fromEnd, keysz, scankey);
+
+ /* register scan in case we change pages it's using */
+ _bt_regscan(scan);
+
+ return ((char *) scan);
}
/*
- * btrescan() -- rescan an index relation
+ * btrescan() -- rescan an index relation
*/
void
btrescan(IndexScanDesc scan, bool fromEnd, ScanKey scankey)
{
- ItemPointer iptr;
- BTScanOpaque so;
-
- so = (BTScanOpaque) scan->opaque;
-
- /* we hold a read lock on the current page in the scan */
- if (ItemPointerIsValid(iptr = &(scan->currentItemData))) {
- _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
- so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- /* and we hold a read lock on the last marked item in the scan */
- if (ItemPointerIsValid(iptr = &(scan->currentMarkData))) {
- _bt_relbuf(scan->relation, so->btso_mrkbuf, BT_READ);
- so->btso_mrkbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- if ( so == NULL ) /* if called from btbeginscan */
- {
- so = (BTScanOpaque) palloc(sizeof(BTScanOpaqueData));
- so->btso_curbuf = so->btso_mrkbuf = InvalidBuffer;
- so->keyData = (ScanKey) NULL;
- if ( scan->numberOfKeys > 0)
- so->keyData = (ScanKey) palloc (scan->numberOfKeys * sizeof(ScanKeyData));
- scan->opaque = so;
- scan->flags = 0x0;
- }
-
- /*
- * Reset the scan keys. Note that keys ordering stuff
- * moved to _bt_first. - vadim 05/05/97
- */
- so->numberOfKeys = scan->numberOfKeys;
- if (scan->numberOfKeys > 0) {
- memmove(scan->keyData,
- scankey,
- scan->numberOfKeys * sizeof(ScanKeyData));
- memmove(so->keyData,
- scankey,
- so->numberOfKeys * sizeof(ScanKeyData));
- }
+ ItemPointer iptr;
+ BTScanOpaque so;
+
+ so = (BTScanOpaque) scan->opaque;
+
+ /* we hold a read lock on the current page in the scan */
+ if (ItemPointerIsValid(iptr = &(scan->currentItemData)))
+ {
+ _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
+ so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ /* and we hold a read lock on the last marked item in the scan */
+ if (ItemPointerIsValid(iptr = &(scan->currentMarkData)))
+ {
+ _bt_relbuf(scan->relation, so->btso_mrkbuf, BT_READ);
+ so->btso_mrkbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ if (so == NULL) /* if called from btbeginscan */
+ {
+ so = (BTScanOpaque) palloc(sizeof(BTScanOpaqueData));
+ so->btso_curbuf = so->btso_mrkbuf = InvalidBuffer;
+ so->keyData = (ScanKey) NULL;
+ if (scan->numberOfKeys > 0)
+ so->keyData = (ScanKey) palloc(scan->numberOfKeys * sizeof(ScanKeyData));
+ scan->opaque = so;
+ scan->flags = 0x0;
+ }
+
+ /*
+ * Reset the scan keys. Note that keys ordering stuff moved to
+ * _bt_first. - vadim 05/05/97
+ */
+ so->numberOfKeys = scan->numberOfKeys;
+ if (scan->numberOfKeys > 0)
+ {
+ memmove(scan->keyData,
+ scankey,
+ scan->numberOfKeys * sizeof(ScanKeyData));
+ memmove(so->keyData,
+ scankey,
+ so->numberOfKeys * sizeof(ScanKeyData));
+ }
}
void
btmovescan(IndexScanDesc scan, Datum v)
{
- ItemPointer iptr;
- BTScanOpaque so;
-
- so = (BTScanOpaque) scan->opaque;
-
- /* release any locks we still hold */
- if (ItemPointerIsValid(iptr = &(scan->currentItemData))) {
- _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
- so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
-/* scan->keyData[0].sk_argument = v; */
- so->keyData[0].sk_argument = v;
+ ItemPointer iptr;
+ BTScanOpaque so;
+
+ so = (BTScanOpaque) scan->opaque;
+
+ /* release any locks we still hold */
+ if (ItemPointerIsValid(iptr = &(scan->currentItemData)))
+ {
+ _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
+ so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+/* scan->keyData[0].sk_argument = v; */
+ so->keyData[0].sk_argument = v;
}
/*
- * btendscan() -- close down a scan
+ * btendscan() -- close down a scan
*/
void
btendscan(IndexScanDesc scan)
{
- ItemPointer iptr;
- BTScanOpaque so;
-
- so = (BTScanOpaque) scan->opaque;
-
- /* release any locks we still hold */
- if (ItemPointerIsValid(iptr = &(scan->currentItemData))) {
- if (BufferIsValid(so->btso_curbuf))
- _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
- so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- if (ItemPointerIsValid(iptr = &(scan->currentMarkData))) {
- if (BufferIsValid(so->btso_mrkbuf))
- _bt_relbuf(scan->relation, so->btso_mrkbuf, BT_READ);
- so->btso_mrkbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- if ( so->keyData != (ScanKey) NULL )
- pfree (so->keyData);
- pfree (so);
-
- _bt_dropscan(scan);
+ ItemPointer iptr;
+ BTScanOpaque so;
+
+ so = (BTScanOpaque) scan->opaque;
+
+ /* release any locks we still hold */
+ if (ItemPointerIsValid(iptr = &(scan->currentItemData)))
+ {
+ if (BufferIsValid(so->btso_curbuf))
+ _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
+ so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ if (ItemPointerIsValid(iptr = &(scan->currentMarkData)))
+ {
+ if (BufferIsValid(so->btso_mrkbuf))
+ _bt_relbuf(scan->relation, so->btso_mrkbuf, BT_READ);
+ so->btso_mrkbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ if (so->keyData != (ScanKey) NULL)
+ pfree(so->keyData);
+ pfree(so);
+
+ _bt_dropscan(scan);
}
/*
- * btmarkpos() -- save current scan position
+ * btmarkpos() -- save current scan position
*/
void
btmarkpos(IndexScanDesc scan)
{
- ItemPointer iptr;
- BTScanOpaque so;
-
- so = (BTScanOpaque) scan->opaque;
-
- /* release lock on old marked data, if any */
- if (ItemPointerIsValid(iptr = &(scan->currentMarkData))) {
- _bt_relbuf(scan->relation, so->btso_mrkbuf, BT_READ);
- so->btso_mrkbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- /* bump lock on currentItemData and copy to currentMarkData */
- if (ItemPointerIsValid(&(scan->currentItemData))) {
- so->btso_mrkbuf = _bt_getbuf(scan->relation,
- BufferGetBlockNumber(so->btso_curbuf),
- BT_READ);
- scan->currentMarkData = scan->currentItemData;
- }
+ ItemPointer iptr;
+ BTScanOpaque so;
+
+ so = (BTScanOpaque) scan->opaque;
+
+ /* release lock on old marked data, if any */
+ if (ItemPointerIsValid(iptr = &(scan->currentMarkData)))
+ {
+ _bt_relbuf(scan->relation, so->btso_mrkbuf, BT_READ);
+ so->btso_mrkbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ /* bump lock on currentItemData and copy to currentMarkData */
+ if (ItemPointerIsValid(&(scan->currentItemData)))
+ {
+ so->btso_mrkbuf = _bt_getbuf(scan->relation,
+ BufferGetBlockNumber(so->btso_curbuf),
+ BT_READ);
+ scan->currentMarkData = scan->currentItemData;
+ }
}
/*
- * btrestrpos() -- restore scan to last saved position
+ * btrestrpos() -- restore scan to last saved position
*/
void
btrestrpos(IndexScanDesc scan)
{
- ItemPointer iptr;
- BTScanOpaque so;
-
- so = (BTScanOpaque) scan->opaque;
-
- /* release lock on current data, if any */
- if (ItemPointerIsValid(iptr = &(scan->currentItemData))) {
- _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
- so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(iptr);
- }
-
- /* bump lock on currentMarkData and copy to currentItemData */
- if (ItemPointerIsValid(&(scan->currentMarkData))) {
- so->btso_curbuf = _bt_getbuf(scan->relation,
- BufferGetBlockNumber(so->btso_mrkbuf),
- BT_READ);
-
- scan->currentItemData = scan->currentMarkData;
- }
+ ItemPointer iptr;
+ BTScanOpaque so;
+
+ so = (BTScanOpaque) scan->opaque;
+
+ /* release lock on current data, if any */
+ if (ItemPointerIsValid(iptr = &(scan->currentItemData)))
+ {
+ _bt_relbuf(scan->relation, so->btso_curbuf, BT_READ);
+ so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(iptr);
+ }
+
+ /* bump lock on currentMarkData and copy to currentItemData */
+ if (ItemPointerIsValid(&(scan->currentMarkData)))
+ {
+ so->btso_curbuf = _bt_getbuf(scan->relation,
+ BufferGetBlockNumber(so->btso_mrkbuf),
+ BT_READ);
+
+ scan->currentItemData = scan->currentMarkData;
+ }
}
/* stubs */
void
btdelete(Relation rel, ItemPointer tid)
{
- /* adjust any active scans that will be affected by this deletion */
- _bt_adjscans(rel, tid, BT_DELETE);
-
- /* delete the data from the page */
- _bt_pagedel(rel, tid);
+ /* adjust any active scans that will be affected by this deletion */
+ _bt_adjscans(rel, tid, BT_DELETE);
+
+ /* delete the data from the page */
+ _bt_pagedel(rel, tid);
}
diff --git a/src/backend/access/nbtree/nbtscan.c b/src/backend/access/nbtree/nbtscan.c
index 5e23fe13d7b..8a2042403ad 100644
--- a/src/backend/access/nbtree/nbtscan.c
+++ b/src/backend/access/nbtree/nbtscan.c
@@ -1,28 +1,28 @@
/*-------------------------------------------------------------------------
*
* btscan.c--
- * manage scans on btrees.
+ * manage scans on btrees.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.7 1997/02/18 17:13:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.8 1997/09/07 04:38:57 momjian Exp $
*
*
* NOTES
- * Because we can be doing an index scan on a relation while we update
- * it, we need to avoid missing data that moves around in the index.
- * The routines and global variables in this file guarantee that all
- * scans in the local address space stay correctly positioned. This
- * is all we need to worry about, since write locking guarantees that
- * no one else will be on the same page at the same time as we are.
+ * Because we can be doing an index scan on a relation while we update
+ * it, we need to avoid missing data that moves around in the index.
+ * The routines and global variables in this file guarantee that all
+ * scans in the local address space stay correctly positioned. This
+ * is all we need to worry about, since write locking guarantees that
+ * no one else will be on the same page at the same time as we are.
*
- * The scheme is to manage a list of active scans in the current backend.
- * Whenever we add or remove records from an index, or whenever we
- * split a leaf page, we check the list of active scans to see if any
- * has been affected. A scan is affected only if it is on the same
- * relation, and the same page, as the update.
+ * The scheme is to manage a list of active scans in the current backend.
+ * Whenever we add or remove records from an index, or whenever we
+ * split a leaf page, we check the list of active scans to see if any
+ * has been affected. A scan is affected only if it is on the same
+ * relation, and the same page, as the update.
*
*-------------------------------------------------------------------------
*/
@@ -32,83 +32,87 @@
#include <storage/bufpage.h>
#include <access/nbtree.h>
-typedef struct BTScanListData {
- IndexScanDesc btsl_scan;
- struct BTScanListData *btsl_next;
-} BTScanListData;
+typedef struct BTScanListData
+{
+ IndexScanDesc btsl_scan;
+ struct BTScanListData *btsl_next;
+} BTScanListData;
-typedef BTScanListData *BTScanList;
+typedef BTScanListData *BTScanList;
-static BTScanList BTScans = (BTScanList) NULL;
+static BTScanList BTScans = (BTScanList) NULL;
-static void _bt_scandel(IndexScanDesc scan, int op, BlockNumber blkno, OffsetNumber offno);
-static bool _bt_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
+static void _bt_scandel(IndexScanDesc scan, int op, BlockNumber blkno, OffsetNumber offno);
+static bool _bt_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
/*
- * _bt_regscan() -- register a new scan.
+ * _bt_regscan() -- register a new scan.
*/
void
_bt_regscan(IndexScanDesc scan)
{
- BTScanList new_el;
-
- new_el = (BTScanList) palloc(sizeof(BTScanListData));
- new_el->btsl_scan = scan;
- new_el->btsl_next = BTScans;
- BTScans = new_el;
+ BTScanList new_el;
+
+ new_el = (BTScanList) palloc(sizeof(BTScanListData));
+ new_el->btsl_scan = scan;
+ new_el->btsl_next = BTScans;
+ BTScans = new_el;
}
/*
- * _bt_dropscan() -- drop a scan from the scan list
+ * _bt_dropscan() -- drop a scan from the scan list
*/
void
_bt_dropscan(IndexScanDesc scan)
{
- BTScanList chk, last;
-
- last = (BTScanList) NULL;
- for (chk = BTScans;
- chk != (BTScanList) NULL && chk->btsl_scan != scan;
- chk = chk->btsl_next) {
- last = chk;
- }
-
- if (chk == (BTScanList) NULL)
- elog(WARN, "btree scan list trashed; can't find 0x%lx", scan);
-
- if (last == (BTScanList) NULL)
- BTScans = chk->btsl_next;
- else
- last->btsl_next = chk->btsl_next;
-
- pfree (chk);
+ BTScanList chk,
+ last;
+
+ last = (BTScanList) NULL;
+ for (chk = BTScans;
+ chk != (BTScanList) NULL && chk->btsl_scan != scan;
+ chk = chk->btsl_next)
+ {
+ last = chk;
+ }
+
+ if (chk == (BTScanList) NULL)
+ elog(WARN, "btree scan list trashed; can't find 0x%lx", scan);
+
+ if (last == (BTScanList) NULL)
+ BTScans = chk->btsl_next;
+ else
+ last->btsl_next = chk->btsl_next;
+
+ pfree(chk);
}
/*
- * _bt_adjscans() -- adjust all scans in the scan list to compensate
- * for a given deletion or insertion
+ * _bt_adjscans() -- adjust all scans in the scan list to compensate
+ * for a given deletion or insertion
*/
void
_bt_adjscans(Relation rel, ItemPointer tid, int op)
{
- BTScanList l;
- Oid relid;
-
- relid = rel->rd_id;
- for (l = BTScans; l != (BTScanList) NULL; l = l->btsl_next) {
- if (relid == l->btsl_scan->relation->rd_id)
- _bt_scandel(l->btsl_scan, op,
- ItemPointerGetBlockNumber(tid),
- ItemPointerGetOffsetNumber(tid));
- }
+ BTScanList l;
+ Oid relid;
+
+ relid = rel->rd_id;
+ for (l = BTScans; l != (BTScanList) NULL; l = l->btsl_next)
+ {
+ if (relid == l->btsl_scan->relation->rd_id)
+ _bt_scandel(l->btsl_scan, op,
+ ItemPointerGetBlockNumber(tid),
+ ItemPointerGetOffsetNumber(tid));
+ }
}
/*
- * _bt_scandel() -- adjust a single scan
+ * _bt_scandel() -- adjust a single scan
*
* because each index page is always maintained as an ordered array of
* index tuples, the index tuples on a given page shift beneath any
- * given scan. an index modification "behind" a scan position (i.e.,
+ * given scan. an index modification "behind" a scan position (i.e.,
* same page, lower or equal offset number) will therefore force us to
* adjust the scan in the following ways:
*
@@ -126,80 +130,85 @@ _bt_adjscans(Relation rel, ItemPointer tid, int op)
static void
_bt_scandel(IndexScanDesc scan, int op, BlockNumber blkno, OffsetNumber offno)
{
- ItemPointer current;
- Buffer buf;
- BTScanOpaque so;
-
- if (!_bt_scantouched(scan, blkno, offno))
- return;
-
- so = (BTScanOpaque) scan->opaque;
- buf = so->btso_curbuf;
-
- current = &(scan->currentItemData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno) {
- switch (op) {
- case BT_INSERT:
- _bt_step(scan, &buf, ForwardScanDirection);
- break;
- case BT_DELETE:
- _bt_step(scan, &buf, BackwardScanDirection);
- break;
- default:
- elog(WARN, "_bt_scandel: bad operation '%d'", op);
- /*NOTREACHED*/
+ ItemPointer current;
+ Buffer buf;
+ BTScanOpaque so;
+
+ if (!_bt_scantouched(scan, blkno, offno))
+ return;
+
+ so = (BTScanOpaque) scan->opaque;
+ buf = so->btso_curbuf;
+
+ current = &(scan->currentItemData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ {
+ switch (op)
+ {
+ case BT_INSERT:
+ _bt_step(scan, &buf, ForwardScanDirection);
+ break;
+ case BT_DELETE:
+ _bt_step(scan, &buf, BackwardScanDirection);
+ break;
+ default:
+ elog(WARN, "_bt_scandel: bad operation '%d'", op);
+ /* NOTREACHED */
+ }
+ so->btso_curbuf = buf;
}
- so->btso_curbuf = buf;
- }
-
- current = &(scan->currentMarkData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno) {
- ItemPointerData tmp;
- tmp = *current;
- *current = scan->currentItemData;
- scan->currentItemData = tmp;
- switch (op) {
- case BT_INSERT:
- _bt_step(scan, &buf, ForwardScanDirection);
- break;
- case BT_DELETE:
- _bt_step(scan, &buf, BackwardScanDirection);
- break;
- default:
- elog(WARN, "_bt_scandel: bad operation '%d'", op);
- /*NOTREACHED*/
+
+ current = &(scan->currentMarkData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ {
+ ItemPointerData tmp;
+
+ tmp = *current;
+ *current = scan->currentItemData;
+ scan->currentItemData = tmp;
+ switch (op)
+ {
+ case BT_INSERT:
+ _bt_step(scan, &buf, ForwardScanDirection);
+ break;
+ case BT_DELETE:
+ _bt_step(scan, &buf, BackwardScanDirection);
+ break;
+ default:
+ elog(WARN, "_bt_scandel: bad operation '%d'", op);
+ /* NOTREACHED */
+ }
+ so->btso_mrkbuf = buf;
+ tmp = *current;
+ *current = scan->currentItemData;
+ scan->currentItemData = tmp;
}
- so->btso_mrkbuf = buf;
- tmp = *current;
- *current = scan->currentItemData;
- scan->currentItemData = tmp;
- }
}
/*
- * _bt_scantouched() -- check to see if a scan is affected by a given
- * change to the index
+ * _bt_scantouched() -- check to see if a scan is affected by a given
+ * change to the index
*/
-static bool
+static bool
_bt_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
{
- ItemPointer current;
-
- current = &(scan->currentItemData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno)
- return (true);
-
- current = &(scan->currentMarkData);
- if (ItemPointerIsValid(current)
- && ItemPointerGetBlockNumber(current) == blkno
- && ItemPointerGetOffsetNumber(current) >= offno)
- return (true);
-
- return (false);
+ ItemPointer current;
+
+ current = &(scan->currentItemData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ return (true);
+
+ current = &(scan->currentMarkData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ return (true);
+
+ return (false);
}
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 1d1c8072b93..8b1f75b7533 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* btsearch.c--
- * search code for postgres btrees.
+ * search code for postgres btrees.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.23 1997/08/19 21:29:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.24 1997/09/07 04:38:58 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,1435 +22,1516 @@
#include <catalog/pg_proc.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static BTStack
-_bt_searchr(Relation rel, int keysz, ScanKey scankey,
- Buffer *bufP, BTStack stack_in);
-static OffsetNumber
-_bt_firsteq(Relation rel, TupleDesc itupdesc, Page page,
- Size keysz, ScanKey scankey, OffsetNumber offnum);
-static int
-_bt_compare(Relation rel, TupleDesc itupdesc, Page page,
- int keysz, ScanKey scankey, OffsetNumber offnum);
-static bool
-_bt_twostep(IndexScanDesc scan, Buffer *bufP, ScanDirection dir);
-static RetrieveIndexResult
-_bt_endpoint(IndexScanDesc scan, ScanDirection dir);
+static BTStack
+_bt_searchr(Relation rel, int keysz, ScanKey scankey,
+ Buffer * bufP, BTStack stack_in);
+static OffsetNumber
+_bt_firsteq(Relation rel, TupleDesc itupdesc, Page page,
+ Size keysz, ScanKey scankey, OffsetNumber offnum);
+static int
+_bt_compare(Relation rel, TupleDesc itupdesc, Page page,
+ int keysz, ScanKey scankey, OffsetNumber offnum);
+static bool
+ _bt_twostep(IndexScanDesc scan, Buffer * bufP, ScanDirection dir);
+static RetrieveIndexResult
+ _bt_endpoint(IndexScanDesc scan, ScanDirection dir);
/*
- * _bt_search() -- Search for a scan key in the index.
+ * _bt_search() -- Search for a scan key in the index.
*
- * This routine is actually just a helper that sets things up and
- * calls a recursive-descent search routine on the tree.
+ * This routine is actually just a helper that sets things up and
+ * calls a recursive-descent search routine on the tree.
*/
BTStack
-_bt_search(Relation rel, int keysz, ScanKey scankey, Buffer *bufP)
+_bt_search(Relation rel, int keysz, ScanKey scankey, Buffer * bufP)
{
- *bufP = _bt_getroot(rel, BT_READ);
- return (_bt_searchr(rel, keysz, scankey, bufP, (BTStack) NULL));
+ *bufP = _bt_getroot(rel, BT_READ);
+ return (_bt_searchr(rel, keysz, scankey, bufP, (BTStack) NULL));
}
/*
- * _bt_searchr() -- Search the tree recursively for a particular scankey.
+ * _bt_searchr() -- Search the tree recursively for a particular scankey.
*/
-static BTStack
+static BTStack
_bt_searchr(Relation rel,
- int keysz,
- ScanKey scankey,
- Buffer *bufP,
- BTStack stack_in)
+ int keysz,
+ ScanKey scankey,
+ Buffer * bufP,
+ BTStack stack_in)
{
- BTStack stack;
- OffsetNumber offnum;
- Page page;
- BTPageOpaque opaque;
- BlockNumber par_blkno;
- BlockNumber blkno;
- ItemId itemid;
- BTItem btitem;
- BTItem item_save;
- int item_nbytes;
- IndexTuple itup;
-
- /* if this is a leaf page, we're done */
- page = BufferGetPage(*bufP);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- if (opaque->btpo_flags & BTP_LEAF)
- return (stack_in);
-
- /*
- * Find the appropriate item on the internal page, and get the child
- * page that it points to.
- */
-
- par_blkno = BufferGetBlockNumber(*bufP);
- offnum = _bt_binsrch(rel, *bufP, keysz, scankey, BT_DESCENT);
- itemid = PageGetItemId(page, offnum);
- btitem = (BTItem) PageGetItem(page, itemid);
- itup = &(btitem->bti_itup);
- blkno = ItemPointerGetBlockNumber(&(itup->t_tid));
-
- /*
- * We need to save the bit image of the index entry we chose in the
- * parent page on a stack. In case we split the tree, we'll use this
- * bit image to figure out what our real parent page is, in case the
- * parent splits while we're working lower in the tree. See the paper
- * by Lehman and Yao for how this is detected and handled. (We use
- * unique OIDs to disambiguate duplicate keys in the index -- Lehman
- * and Yao disallow duplicate keys).
- */
-
- item_nbytes = ItemIdGetLength(itemid);
- item_save = (BTItem) palloc(item_nbytes);
- memmove((char *) item_save, (char *) btitem, item_nbytes);
- stack = (BTStack) palloc(sizeof(BTStackData));
- stack->bts_blkno = par_blkno;
- stack->bts_offset = offnum;
- stack->bts_btitem = item_save;
- stack->bts_parent = stack_in;
-
- /* drop the read lock on the parent page and acquire one on the child */
- _bt_relbuf(rel, *bufP, BT_READ);
- *bufP = _bt_getbuf(rel, blkno, BT_READ);
-
- /*
- * Race -- the page we just grabbed may have split since we read its
- * pointer in the parent. If it has, we may need to move right to its
- * new sibling. Do that.
- */
-
- *bufP = _bt_moveright(rel, *bufP, keysz, scankey, BT_READ);
-
- /* okay, all set to move down a level */
- return (_bt_searchr(rel, keysz, scankey, bufP, stack));
+ BTStack stack;
+ OffsetNumber offnum;
+ Page page;
+ BTPageOpaque opaque;
+ BlockNumber par_blkno;
+ BlockNumber blkno;
+ ItemId itemid;
+ BTItem btitem;
+ BTItem item_save;
+ int item_nbytes;
+ IndexTuple itup;
+
+ /* if this is a leaf page, we're done */
+ page = BufferGetPage(*bufP);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ if (opaque->btpo_flags & BTP_LEAF)
+ return (stack_in);
+
+ /*
+ * Find the appropriate item on the internal page, and get the child
+ * page that it points to.
+ */
+
+ par_blkno = BufferGetBlockNumber(*bufP);
+ offnum = _bt_binsrch(rel, *bufP, keysz, scankey, BT_DESCENT);
+ itemid = PageGetItemId(page, offnum);
+ btitem = (BTItem) PageGetItem(page, itemid);
+ itup = &(btitem->bti_itup);
+ blkno = ItemPointerGetBlockNumber(&(itup->t_tid));
+
+ /*
+ * We need to save the bit image of the index entry we chose in the
+ * parent page on a stack. In case we split the tree, we'll use this
+ * bit image to figure out what our real parent page is, in case the
+ * parent splits while we're working lower in the tree. See the paper
+ * by Lehman and Yao for how this is detected and handled. (We use
+ * unique OIDs to disambiguate duplicate keys in the index -- Lehman
+ * and Yao disallow duplicate keys).
+ */
+
+ item_nbytes = ItemIdGetLength(itemid);
+ item_save = (BTItem) palloc(item_nbytes);
+ memmove((char *) item_save, (char *) btitem, item_nbytes);
+ stack = (BTStack) palloc(sizeof(BTStackData));
+ stack->bts_blkno = par_blkno;
+ stack->bts_offset = offnum;
+ stack->bts_btitem = item_save;
+ stack->bts_parent = stack_in;
+
+ /* drop the read lock on the parent page and acquire one on the child */
+ _bt_relbuf(rel, *bufP, BT_READ);
+ *bufP = _bt_getbuf(rel, blkno, BT_READ);
+
+ /*
+ * Race -- the page we just grabbed may have split since we read its
+ * pointer in the parent. If it has, we may need to move right to its
+ * new sibling. Do that.
+ */
+
+ *bufP = _bt_moveright(rel, *bufP, keysz, scankey, BT_READ);
+
+ /* okay, all set to move down a level */
+ return (_bt_searchr(rel, keysz, scankey, bufP, stack));
}
/*
- * _bt_moveright() -- move right in the btree if necessary.
+ * _bt_moveright() -- move right in the btree if necessary.
*
- * When we drop and reacquire a pointer to a page, it is possible that
- * the page has changed in the meanwhile. If this happens, we're
- * guaranteed that the page has "split right" -- that is, that any
- * data that appeared on the page originally is either on the page
- * or strictly to the right of it.
+ * When we drop and reacquire a pointer to a page, it is possible that
+ * the page has changed in the meanwhile. If this happens, we're
+ * guaranteed that the page has "split right" -- that is, that any
+ * data that appeared on the page originally is either on the page
+ * or strictly to the right of it.
*
- * This routine decides whether or not we need to move right in the
- * tree by examining the high key entry on the page. If that entry
- * is strictly less than one we expect to be on the page, then our
- * picture of the page is incorrect and we need to move right.
+ * This routine decides whether or not we need to move right in the
+ * tree by examining the high key entry on the page. If that entry
+ * is strictly less than one we expect to be on the page, then our
+ * picture of the page is incorrect and we need to move right.
*
- * On entry, we have the buffer pinned and a lock of the proper type.
- * If we move right, we release the buffer and lock and acquire the
- * same on the right sibling.
+ * On entry, we have the buffer pinned and a lock of the proper type.
+ * If we move right, we release the buffer and lock and acquire the
+ * same on the right sibling.
*/
Buffer
_bt_moveright(Relation rel,
- Buffer buf,
- int keysz,
- ScanKey scankey,
- int access)
+ Buffer buf,
+ int keysz,
+ ScanKey scankey,
+ int access)
{
- Page page;
- BTPageOpaque opaque;
- ItemId hikey;
- BlockNumber rblkno;
- int natts = rel->rd_rel->relnatts;
-
- page = BufferGetPage(buf);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
-
- /* if we're on a rightmost page, we don't need to move right */
- if (P_RIGHTMOST(opaque))
- return (buf);
-
- /* by convention, item 0 on non-rightmost pages is the high key */
- hikey = PageGetItemId(page, P_HIKEY);
-
- /*
- * If the scan key that brought us to this page is >= the high key
- * stored on the page, then the page has split and we need to move
- * right.
- */
-
- if (_bt_skeycmp(rel, keysz, scankey, page, hikey,
- BTGreaterEqualStrategyNumber))
- {
- /* move right as long as we need to */
- do
+ Page page;
+ BTPageOpaque opaque;
+ ItemId hikey;
+ BlockNumber rblkno;
+ int natts = rel->rd_rel->relnatts;
+
+ page = BufferGetPage(buf);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ /* if we're on a rightmost page, we don't need to move right */
+ if (P_RIGHTMOST(opaque))
+ return (buf);
+
+ /* by convention, item 0 on non-rightmost pages is the high key */
+ hikey = PageGetItemId(page, P_HIKEY);
+
+ /*
+ * If the scan key that brought us to this page is >= the high key
+ * stored on the page, then the page has split and we need to move
+ * right.
+ */
+
+ if (_bt_skeycmp(rel, keysz, scankey, page, hikey,
+ BTGreaterEqualStrategyNumber))
{
- OffsetNumber offmax = PageGetMaxOffsetNumber(page);
- /*
- * If this page consists of all duplicate keys (hikey and first
- * key on the page have the same value), then we don't need to
- * step right.
- *
- * NOTE for multi-column indices: we may do scan using
- * keys not for all attrs. But we handle duplicates
- * using all attrs in _bt_insert/_bt_spool code.
- * And so we've to compare scankey with _last_ item
- * on this page to do not lose "good" tuples if number
- * of attrs > keysize. Example: (2,0) - last items on
- * this page, (2,1) - first item on next page (hikey),
- * our scankey is x = 2. Scankey == (2,1) because of
- * we compare first attrs only, but we shouldn't to move
- * right of here. - vadim 04/15/97
- */
-
- if ( _bt_skeycmp (rel, keysz, scankey, page, hikey,
- BTEqualStrategyNumber) )
- {
- if ( opaque->btpo_flags & BTP_CHAIN )
- {
- Assert ( ( opaque->btpo_flags & BTP_LEAF ) || offmax > P_HIKEY );
- break;
- }
- if ( offmax > P_HIKEY )
- {
- if ( natts == keysz ) /* sanity checks */
- {
- if ( _bt_skeycmp (rel, keysz, scankey, page,
- PageGetItemId (page, P_FIRSTKEY),
- BTEqualStrategyNumber) )
- elog (FATAL, "btree: BTP_CHAIN flag was expected");
- if ( _bt_skeycmp (rel, keysz, scankey, page,
- PageGetItemId (page, offmax),
- BTEqualStrategyNumber) )
- elog (FATAL, "btree: unexpected equal last item");
- if ( _bt_skeycmp (rel, keysz, scankey, page,
- PageGetItemId (page, offmax),
- BTLessStrategyNumber) )
- elog (FATAL, "btree: unexpected greater last item");
- /* move right */
- }
- else if ( _bt_skeycmp (rel, keysz, scankey, page,
- PageGetItemId (page, offmax),
- BTLessEqualStrategyNumber) )
- break;
- }
- }
-
- /* step right one page */
- rblkno = opaque->btpo_next;
- _bt_relbuf(rel, buf, access);
- buf = _bt_getbuf(rel, rblkno, access);
- page = BufferGetPage(buf);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- hikey = PageGetItemId(page, P_HIKEY);
-
- } while (! P_RIGHTMOST(opaque)
- && _bt_skeycmp(rel, keysz, scankey, page, hikey,
- BTGreaterEqualStrategyNumber));
- }
- return (buf);
+ /* move right as long as we need to */
+ do
+ {
+ OffsetNumber offmax = PageGetMaxOffsetNumber(page);
+
+ /*
+ * If this page consists of all duplicate keys (hikey and
+ * first key on the page have the same value), then we don't
+ * need to step right.
+ *
+ * NOTE for multi-column indices: we may do scan using keys not
+ * for all attrs. But we handle duplicates using all attrs in
+ * _bt_insert/_bt_spool code. And so we've to compare scankey
+ * with _last_ item on this page to do not lose "good" tuples
+ * if number of attrs > keysize. Example: (2,0) - last items
+ * on this page, (2,1) - first item on next page (hikey), our
+ * scankey is x = 2. Scankey == (2,1) because of we compare
+ * first attrs only, but we shouldn't to move right of here.
+ * - vadim 04/15/97
+ */
+
+ if (_bt_skeycmp(rel, keysz, scankey, page, hikey,
+ BTEqualStrategyNumber))
+ {
+ if (opaque->btpo_flags & BTP_CHAIN)
+ {
+ Assert((opaque->btpo_flags & BTP_LEAF) || offmax > P_HIKEY);
+ break;
+ }
+ if (offmax > P_HIKEY)
+ {
+ if (natts == keysz) /* sanity checks */
+ {
+ if (_bt_skeycmp(rel, keysz, scankey, page,
+ PageGetItemId(page, P_FIRSTKEY),
+ BTEqualStrategyNumber))
+ elog(FATAL, "btree: BTP_CHAIN flag was expected");
+ if (_bt_skeycmp(rel, keysz, scankey, page,
+ PageGetItemId(page, offmax),
+ BTEqualStrategyNumber))
+ elog(FATAL, "btree: unexpected equal last item");
+ if (_bt_skeycmp(rel, keysz, scankey, page,
+ PageGetItemId(page, offmax),
+ BTLessStrategyNumber))
+ elog(FATAL, "btree: unexpected greater last item");
+ /* move right */
+ }
+ else if (_bt_skeycmp(rel, keysz, scankey, page,
+ PageGetItemId(page, offmax),
+ BTLessEqualStrategyNumber))
+ break;
+ }
+ }
+
+ /* step right one page */
+ rblkno = opaque->btpo_next;
+ _bt_relbuf(rel, buf, access);
+ buf = _bt_getbuf(rel, rblkno, access);
+ page = BufferGetPage(buf);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ hikey = PageGetItemId(page, P_HIKEY);
+
+ } while (!P_RIGHTMOST(opaque)
+ && _bt_skeycmp(rel, keysz, scankey, page, hikey,
+ BTGreaterEqualStrategyNumber));
+ }
+ return (buf);
}
/*
- * _bt_skeycmp() -- compare a scan key to a particular item on a page using
- * a requested strategy (<, <=, =, >=, >).
+ * _bt_skeycmp() -- compare a scan key to a particular item on a page using
+ * a requested strategy (<, <=, =, >=, >).
*
- * We ignore the unique OIDs stored in the btree item here. Those
- * numbers are intended for use internally only, in repositioning a
- * scan after a page split. They do not impose any meaningful ordering.
+ * We ignore the unique OIDs stored in the btree item here. Those
+ * numbers are intended for use internally only, in repositioning a
+ * scan after a page split. They do not impose any meaningful ordering.
*
- * The comparison is A <op> B, where A is the scan key and B is the
- * tuple pointed at by itemid on page.
+ * The comparison is A <op> B, where A is the scan key and B is the
+ * tuple pointed at by itemid on page.
*/
bool
_bt_skeycmp(Relation rel,
- Size keysz,
- ScanKey scankey,
- Page page,
- ItemId itemid,
- StrategyNumber strat)
+ Size keysz,
+ ScanKey scankey,
+ Page page,
+ ItemId itemid,
+ StrategyNumber strat)
{
- BTItem item;
- IndexTuple indexTuple;
- TupleDesc tupDes;
- ScanKey entry;
- int i;
- Datum attrDatum;
- Datum keyDatum;
- bool compare;
- bool isNull;
- bool useEqual = false;
- bool keyNull;
-
- if ( strat == BTLessEqualStrategyNumber )
- {
- useEqual = true;
- strat = BTLessStrategyNumber;
- }
- else if ( strat == BTGreaterEqualStrategyNumber )
- {
- useEqual = true;
- strat = BTGreaterStrategyNumber;
- }
-
- item = (BTItem) PageGetItem(page, itemid);
- indexTuple = &(item->bti_itup);
-
- tupDes = RelationGetTupleDescriptor(rel);
-
- /* see if the comparison is true for all of the key attributes */
- for (i=1; i <= keysz; i++) {
-
- entry = &scankey[i-1];
- Assert ( entry->sk_attno == i );
- attrDatum = index_getattr(indexTuple,
- entry->sk_attno,
- tupDes,
- &isNull);
- keyDatum = entry->sk_argument;
-
- /* see comments about NULLs handling in btbuild */
- if ( entry->sk_flags & SK_ISNULL ) /* key is NULL */
+ BTItem item;
+ IndexTuple indexTuple;
+ TupleDesc tupDes;
+ ScanKey entry;
+ int i;
+ Datum attrDatum;
+ Datum keyDatum;
+ bool compare;
+ bool isNull;
+ bool useEqual = false;
+ bool keyNull;
+
+ if (strat == BTLessEqualStrategyNumber)
{
- Assert ( entry->sk_procedure == NullValueRegProcedure );
- keyNull = true;
- if ( isNull )
- compare = ( strat == BTEqualStrategyNumber ) ? true : false;
- else
- compare = ( strat == BTGreaterStrategyNumber ) ? true : false;
- }
- else if ( isNull ) /* key is NOT_NULL and item is NULL */
- {
- keyNull = false;
- compare = ( strat == BTLessStrategyNumber ) ? true : false;
- }
- else
- {
- keyNull = false;
- compare = _bt_invokestrat(rel, i, strat, keyDatum, attrDatum);
+ useEqual = true;
+ strat = BTLessStrategyNumber;
}
-
- if ( compare ) /* true for one of ">, <, =" */
+ else if (strat == BTGreaterEqualStrategyNumber)
{
- if ( strat != BTEqualStrategyNumber )
- return (true);
+ useEqual = true;
+ strat = BTGreaterStrategyNumber;
}
- else /* false for one of ">, <, =" */
+
+ item = (BTItem) PageGetItem(page, itemid);
+ indexTuple = &(item->bti_itup);
+
+ tupDes = RelationGetTupleDescriptor(rel);
+
+ /* see if the comparison is true for all of the key attributes */
+ for (i = 1; i <= keysz; i++)
{
- if ( strat == BTEqualStrategyNumber )
- return (false);
- /*
- * if original strat was "<=, >=" OR
- * "<, >" but some attribute(s) left
- * - need to test for Equality
- */
- if ( useEqual || i < keysz )
- {
- if ( keyNull || isNull )
- compare = ( keyNull && isNull ) ? true : false;
- else
- compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber,
- keyDatum, attrDatum);
- if ( compare ) /* key' and item' attributes are equal */
- continue; /* - try to compare next attributes */
- }
- return (false);
+
+ entry = &scankey[i - 1];
+ Assert(entry->sk_attno == i);
+ attrDatum = index_getattr(indexTuple,
+ entry->sk_attno,
+ tupDes,
+ &isNull);
+ keyDatum = entry->sk_argument;
+
+ /* see comments about NULLs handling in btbuild */
+ if (entry->sk_flags & SK_ISNULL) /* key is NULL */
+ {
+ Assert(entry->sk_procedure == NullValueRegProcedure);
+ keyNull = true;
+ if (isNull)
+ compare = (strat == BTEqualStrategyNumber) ? true : false;
+ else
+ compare = (strat == BTGreaterStrategyNumber) ? true : false;
+ }
+ else if (isNull) /* key is NOT_NULL and item is NULL */
+ {
+ keyNull = false;
+ compare = (strat == BTLessStrategyNumber) ? true : false;
+ }
+ else
+ {
+ keyNull = false;
+ compare = _bt_invokestrat(rel, i, strat, keyDatum, attrDatum);
+ }
+
+ if (compare) /* true for one of ">, <, =" */
+ {
+ if (strat != BTEqualStrategyNumber)
+ return (true);
+ }
+ else
+/* false for one of ">, <, =" */
+ {
+ if (strat == BTEqualStrategyNumber)
+ return (false);
+
+ /*
+ * if original strat was "<=, >=" OR "<, >" but some
+ * attribute(s) left - need to test for Equality
+ */
+ if (useEqual || i < keysz)
+ {
+ if (keyNull || isNull)
+ compare = (keyNull && isNull) ? true : false;
+ else
+ compare = _bt_invokestrat(rel, i, BTEqualStrategyNumber,
+ keyDatum, attrDatum);
+ if (compare) /* key' and item' attributes are equal */
+ continue; /* - try to compare next attributes */
+ }
+ return (false);
+ }
}
- }
-
- return (true);
+
+ return (true);
}
/*
- * _bt_binsrch() -- Do a binary search for a key on a particular page.
+ * _bt_binsrch() -- Do a binary search for a key on a particular page.
*
- * The scankey we get has the compare function stored in the procedure
- * entry of each data struct. We invoke this regproc to do the
- * comparison for every key in the scankey. _bt_binsrch() returns
- * the OffsetNumber of the first matching key on the page, or the
- * OffsetNumber at which the matching key would appear if it were
- * on this page.
+ * The scankey we get has the compare function stored in the procedure
+ * entry of each data struct. We invoke this regproc to do the
+ * comparison for every key in the scankey. _bt_binsrch() returns
+ * the OffsetNumber of the first matching key on the page, or the
+ * OffsetNumber at which the matching key would appear if it were
+ * on this page.
*
- * By the time this procedure is called, we're sure we're looking
- * at the right page -- don't need to walk right. _bt_binsrch() has
- * no lock or refcount side effects on the buffer.
+ * By the time this procedure is called, we're sure we're looking
+ * at the right page -- don't need to walk right. _bt_binsrch() has
+ * no lock or refcount side effects on the buffer.
*/
OffsetNumber
_bt_binsrch(Relation rel,
- Buffer buf,
- int keysz,
- ScanKey scankey,
- int srchtype)
+ Buffer buf,
+ int keysz,
+ ScanKey scankey,
+ int srchtype)
{
- TupleDesc itupdesc;
- Page page;
- BTPageOpaque opaque;
- OffsetNumber low, mid, high;
- int natts = rel->rd_rel->relnatts;
- int result;
-
- itupdesc = RelationGetTupleDescriptor(rel);
- page = BufferGetPage(buf);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
-
- /* by convention, item 1 on any non-rightmost page is the high key */
- low = mid = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
-
- high = PageGetMaxOffsetNumber(page);
-
- /*
- * Since for non-rightmost pages, the first item on the page is the
- * high key, there are two notions of emptiness. One is if nothing
- * appears on the page. The other is if nothing but the high key does.
- * The reason we test high <= low, rather than high == low, is that
- * after vacuuming there may be nothing *but* the high key on a page.
- * In that case, given the scheme above, low = 2 and high = 1.
- */
-
- if ( PageIsEmpty (page) )
- return (low);
- if ( (! P_RIGHTMOST(opaque) && high <= low))
- {
- if ( high < low ||
- (srchtype == BT_DESCENT && !(opaque->btpo_flags & BTP_LEAF)) )
- return (low);
- /* It's insertion and high == low == 2 */
- result = _bt_compare(rel, itupdesc, page, keysz, scankey, low);
- if ( result > 0 )
- return ( OffsetNumberNext (low) );
- return (low);
- }
-
- while ((high - low) > 1) {
- mid = low + ((high - low) / 2);
- result = _bt_compare(rel, itupdesc, page, keysz, scankey, mid);
-
- if (result > 0)
- low = mid;
- else if (result < 0)
- high = mid - 1;
- else
+ TupleDesc itupdesc;
+ Page page;
+ BTPageOpaque opaque;
+ OffsetNumber low,
+ mid,
+ high;
+ int natts = rel->rd_rel->relnatts;
+ int result;
+
+ itupdesc = RelationGetTupleDescriptor(rel);
+ page = BufferGetPage(buf);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ /* by convention, item 1 on any non-rightmost page is the high key */
+ low = mid = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ high = PageGetMaxOffsetNumber(page);
+
+ /*
+ * Since for non-rightmost pages, the first item on the page is the
+ * high key, there are two notions of emptiness. One is if nothing
+ * appears on the page. The other is if nothing but the high key
+ * does. The reason we test high <= low, rather than high == low, is
+ * that after vacuuming there may be nothing *but* the high key on a
+ * page. In that case, given the scheme above, low = 2 and high = 1.
+ */
+
+ if (PageIsEmpty(page))
+ return (low);
+ if ((!P_RIGHTMOST(opaque) && high <= low))
{
- mid = _bt_firsteq(rel, itupdesc, page, keysz, scankey, mid);
- /*
- * NOTE for multi-column indices: we may do scan using
- * keys not for all attrs. But we handle duplicates using
- * all attrs in _bt_insert/_bt_spool code. And so while
- * searching on internal pages having number of attrs > keysize
- * we want to point at the last item < the scankey, not at the
- * first item = the scankey (!!!), and let _bt_moveright
- * decide later whether to move right or not (see comments and
- * example there). Note also that INSERTions are not affected
- * by this code (natts == keysz). - vadim 04/15/97
- */
- if ( natts == keysz || opaque->btpo_flags & BTP_LEAF )
- return (mid);
- low = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
- if ( mid == low )
- return (mid);
- return (OffsetNumberPrev(mid));
+ if (high < low ||
+ (srchtype == BT_DESCENT && !(opaque->btpo_flags & BTP_LEAF)))
+ return (low);
+ /* It's insertion and high == low == 2 */
+ result = _bt_compare(rel, itupdesc, page, keysz, scankey, low);
+ if (result > 0)
+ return (OffsetNumberNext(low));
+ return (low);
}
- }
-
- /*
- * We terminated because the endpoints got too close together. There
- * are two cases to take care of.
- *
- * For non-insertion searches on internal pages, we want to point at
- * the last key <, or first key =, the scankey on the page. This
- * guarantees that we'll descend the tree correctly.
- * (NOTE comments above for multi-column indices).
- *
- * For all other cases, we want to point at the first key >=
- * the scankey on the page. This guarantees that scans and
- * insertions will happen correctly.
- */
-
- if (!(opaque->btpo_flags & BTP_LEAF) && srchtype == BT_DESCENT)
- { /*
- * We want the last key <, or first key ==, the scan key.
- */
- result = _bt_compare(rel, itupdesc, page, keysz, scankey, high);
-
- if (result == 0)
+
+ while ((high - low) > 1)
{
- mid = _bt_firsteq(rel, itupdesc, page, keysz, scankey, high);
- /*
- * If natts > keysz we want last item < the scan key.
- * See comments above for multi-column indices.
- */
- if ( natts == keysz )
- return (mid);
- low = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
- if ( mid == low )
- return (mid);
- return (OffsetNumberPrev(mid));
+ mid = low + ((high - low) / 2);
+ result = _bt_compare(rel, itupdesc, page, keysz, scankey, mid);
+
+ if (result > 0)
+ low = mid;
+ else if (result < 0)
+ high = mid - 1;
+ else
+ {
+ mid = _bt_firsteq(rel, itupdesc, page, keysz, scankey, mid);
+
+ /*
+ * NOTE for multi-column indices: we may do scan using keys
+ * not for all attrs. But we handle duplicates using all attrs
+ * in _bt_insert/_bt_spool code. And so while searching on
+ * internal pages having number of attrs > keysize we want to
+ * point at the last item < the scankey, not at the first item
+ * = the scankey (!!!), and let _bt_moveright decide later
+ * whether to move right or not (see comments and example
+ * there). Note also that INSERTions are not affected by this
+ * code (natts == keysz). - vadim 04/15/97
+ */
+ if (natts == keysz || opaque->btpo_flags & BTP_LEAF)
+ return (mid);
+ low = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+ if (mid == low)
+ return (mid);
+ return (OffsetNumberPrev(mid));
+ }
+ }
+
+ /*
+ * We terminated because the endpoints got too close together. There
+ * are two cases to take care of.
+ *
+ * For non-insertion searches on internal pages, we want to point at the
+ * last key <, or first key =, the scankey on the page. This
+ * guarantees that we'll descend the tree correctly. (NOTE comments
+ * above for multi-column indices).
+ *
+ * For all other cases, we want to point at the first key >= the scankey
+ * on the page. This guarantees that scans and insertions will happen
+ * correctly.
+ */
+
+ if (!(opaque->btpo_flags & BTP_LEAF) && srchtype == BT_DESCENT)
+ { /* We want the last key <, or first key
+ * ==, the scan key. */
+ result = _bt_compare(rel, itupdesc, page, keysz, scankey, high);
+
+ if (result == 0)
+ {
+ mid = _bt_firsteq(rel, itupdesc, page, keysz, scankey, high);
+
+ /*
+ * If natts > keysz we want last item < the scan key. See
+ * comments above for multi-column indices.
+ */
+ if (natts == keysz)
+ return (mid);
+ low = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+ if (mid == low)
+ return (mid);
+ return (OffsetNumberPrev(mid));
+ }
+ else if (result > 0)
+ return (high);
+ else
+ return (low);
}
- else if (result > 0)
- return (high);
- else
- return (low);
- }
- else /* we want the first key >= the scan key */
- {
- result = _bt_compare(rel, itupdesc, page, keysz, scankey, low);
- if (result <= 0)
- return (low);
else
+/* we want the first key >= the scan key */
{
- if (low == high)
- return (OffsetNumberNext(low));
-
- result = _bt_compare(rel, itupdesc, page, keysz, scankey, high);
- if (result <= 0)
- return (high);
- else
- return (OffsetNumberNext(high));
+ result = _bt_compare(rel, itupdesc, page, keysz, scankey, low);
+ if (result <= 0)
+ return (low);
+ else
+ {
+ if (low == high)
+ return (OffsetNumberNext(low));
+
+ result = _bt_compare(rel, itupdesc, page, keysz, scankey, high);
+ if (result <= 0)
+ return (high);
+ else
+ return (OffsetNumberNext(high));
+ }
}
- }
}
-static OffsetNumber
+static OffsetNumber
_bt_firsteq(Relation rel,
- TupleDesc itupdesc,
- Page page,
- Size keysz,
- ScanKey scankey,
- OffsetNumber offnum)
+ TupleDesc itupdesc,
+ Page page,
+ Size keysz,
+ ScanKey scankey,
+ OffsetNumber offnum)
{
- BTPageOpaque opaque;
- OffsetNumber limit;
-
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
-
- /* skip the high key, if any */
- limit = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
-
- /* walk backwards looking for the first key in the chain of duplicates */
- while (offnum > limit
- && _bt_compare(rel, itupdesc, page,
- keysz, scankey, OffsetNumberPrev(offnum)) == 0) {
- offnum = OffsetNumberPrev(offnum);
- }
-
- return (offnum);
+ BTPageOpaque opaque;
+ OffsetNumber limit;
+
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+
+ /* skip the high key, if any */
+ limit = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ /* walk backwards looking for the first key in the chain of duplicates */
+ while (offnum > limit
+ && _bt_compare(rel, itupdesc, page,
+ keysz, scankey, OffsetNumberPrev(offnum)) == 0)
+ {
+ offnum = OffsetNumberPrev(offnum);
+ }
+
+ return (offnum);
}
/*
- * _bt_compare() -- Compare scankey to a particular tuple on the page.
+ * _bt_compare() -- Compare scankey to a particular tuple on the page.
*
- * This routine returns:
- * -1 if scankey < tuple at offnum;
- * 0 if scankey == tuple at offnum;
- * +1 if scankey > tuple at offnum.
+ * This routine returns:
+ * -1 if scankey < tuple at offnum;
+ * 0 if scankey == tuple at offnum;
+ * +1 if scankey > tuple at offnum.
*
- * -- Old comments:
- * In order to avoid having to propagate changes up the tree any time
- * a new minimal key is inserted, the leftmost entry on the leftmost
- * page is less than all possible keys, by definition.
+ * -- Old comments:
+ * In order to avoid having to propagate changes up the tree any time
+ * a new minimal key is inserted, the leftmost entry on the leftmost
+ * page is less than all possible keys, by definition.
*
- * -- New ones:
- * New insertion code (fix against updating _in_place_ if new minimal
- * key has bigger size than old one) may delete P_HIKEY entry on the
- * root page in order to insert new minimal key - and so this definition
- * does not work properly in this case and breaks key' order on root
- * page. BTW, this propagation occures only while page' splitting,
- * but not "any time a new min key is inserted" (see _bt_insertonpg).
- * - vadim 12/05/96
+ * -- New ones:
+ * New insertion code (fix against updating _in_place_ if new minimal
+ * key has bigger size than old one) may delete P_HIKEY entry on the
+ * root page in order to insert new minimal key - and so this definition
+ * does not work properly in this case and breaks key' order on root
+ * page. BTW, this propagation occures only while page' splitting,
+ * but not "any time a new min key is inserted" (see _bt_insertonpg).
+ * - vadim 12/05/96
*/
static int
_bt_compare(Relation rel,
- TupleDesc itupdesc,
- Page page,
- int keysz,
- ScanKey scankey,
- OffsetNumber offnum)
+ TupleDesc itupdesc,
+ Page page,
+ int keysz,
+ ScanKey scankey,
+ OffsetNumber offnum)
{
- Datum datum;
- BTItem btitem;
- ItemId itemid;
- IndexTuple itup;
- BTPageOpaque opaque;
- ScanKey entry;
- AttrNumber attno;
- int result;
- int i;
- bool null;
-
- /*
- * If this is a leftmost internal page, and if our comparison is
- * with the first key on the page, then the item at that position is
- * by definition less than the scan key.
- *
- * - see new comments above...
- */
-
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- if (!(opaque->btpo_flags & BTP_LEAF)
- && P_LEFTMOST(opaque)
- && offnum == P_HIKEY) {
- itemid = PageGetItemId(page, offnum);
-
+ Datum datum;
+ BTItem btitem;
+ ItemId itemid;
+ IndexTuple itup;
+ BTPageOpaque opaque;
+ ScanKey entry;
+ AttrNumber attno;
+ int result;
+ int i;
+ bool null;
+
/*
- * we just have to believe that this will only be called with
- * offnum == P_HIKEY when P_HIKEY is the OffsetNumber of the
- * first actual data key (i.e., this is also a rightmost
- * page). there doesn't seem to be any code that implies
- * that the leftmost page is normally missing a high key as
- * well as the rightmost page. but that implies that this
- * code path only applies to the root -- which seems
- * unlikely..
+ * If this is a leftmost internal page, and if our comparison is with
+ * the first key on the page, then the item at that position is by
+ * definition less than the scan key.
*
- * - see new comments above...
+ * - see new comments above...
*/
- if (! P_RIGHTMOST(opaque)) {
- elog(WARN, "_bt_compare: invalid comparison to high key");
- }
+
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ if (!(opaque->btpo_flags & BTP_LEAF)
+ && P_LEFTMOST(opaque)
+ && offnum == P_HIKEY)
+ {
+ itemid = PageGetItemId(page, offnum);
+
+ /*
+ * we just have to believe that this will only be called with
+ * offnum == P_HIKEY when P_HIKEY is the OffsetNumber of the first
+ * actual data key (i.e., this is also a rightmost page). there
+ * doesn't seem to be any code that implies that the leftmost page
+ * is normally missing a high key as well as the rightmost page.
+ * but that implies that this code path only applies to the root
+ * -- which seems unlikely..
+ *
+ * - see new comments above...
+ */
+ if (!P_RIGHTMOST(opaque))
+ {
+ elog(WARN, "_bt_compare: invalid comparison to high key");
+ }
#if 0
+
+ /*
+ * We just have to belive that right answer will not break
+ * anything. I've checked code and all seems to be ok. See new
+ * comments above...
+ *
+ * -- Old comments If the item on the page is equal to the scankey,
+ * that's okay to admit. We just can't claim that the first key
+ * on the page is greater than anything.
+ */
+
+ if (_bt_skeycmp(rel, keysz, scankey, page, itemid,
+ BTEqualStrategyNumber))
+ {
+ return (0);
+ }
+ return (1);
+#endif
+ }
+
+ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &(btitem->bti_itup);
+
/*
- * We just have to belive that right answer will not
- * break anything. I've checked code and all seems to be ok.
- * See new comments above...
+ * The scan key is set up with the attribute number associated with
+ * each term in the key. It is important that, if the index is
+ * multi-key, the scan contain the first k key attributes, and that
+ * they be in order. If you think about how multi-key ordering works,
+ * you'll understand why this is.
*
- * -- Old comments
- * If the item on the page is equal to the scankey, that's
- * okay to admit. We just can't claim that the first key on
- * the page is greater than anything.
+ * We don't test for violation of this condition here.
*/
-
- if (_bt_skeycmp(rel, keysz, scankey, page, itemid,
- BTEqualStrategyNumber)) {
- return (0);
- }
- return (1);
-#endif
- }
-
- btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &(btitem->bti_itup);
-
- /*
- * The scan key is set up with the attribute number associated with each
- * term in the key. It is important that, if the index is multi-key,
- * the scan contain the first k key attributes, and that they be in
- * order. If you think about how multi-key ordering works, you'll
- * understand why this is.
- *
- * We don't test for violation of this condition here.
- */
-
- for (i = 1; i <= keysz; i++) {
- long tmpres;
-
- entry = &scankey[i - 1];
- attno = entry->sk_attno;
- datum = index_getattr(itup, attno, itupdesc, &null);
-
- /* see comments about NULLs handling in btbuild */
- if ( entry->sk_flags & SK_ISNULL ) /* key is NULL */
+
+ for (i = 1; i <= keysz; i++)
{
- Assert ( entry->sk_procedure == NullValueRegProcedure );
- if ( null )
- tmpres = (long) 0; /* NULL "=" NULL */
- else
- tmpres = (long) 1; /* NULL ">" NOT_NULL */
- }
- else if ( null ) /* key is NOT_NULL and item is NULL */
- {
- tmpres = (long) -1; /* NOT_NULL "<" NULL */
- }
- else
- {
- tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
- entry->sk_argument, datum);
+ long tmpres;
+
+ entry = &scankey[i - 1];
+ attno = entry->sk_attno;
+ datum = index_getattr(itup, attno, itupdesc, &null);
+
+ /* see comments about NULLs handling in btbuild */
+ if (entry->sk_flags & SK_ISNULL) /* key is NULL */
+ {
+ Assert(entry->sk_procedure == NullValueRegProcedure);
+ if (null)
+ tmpres = (long) 0; /* NULL "=" NULL */
+ else
+ tmpres = (long) 1; /* NULL ">" NOT_NULL */
+ }
+ else if (null) /* key is NOT_NULL and item is NULL */
+ {
+ tmpres = (long) -1; /* NOT_NULL "<" NULL */
+ }
+ else
+ {
+ tmpres = (long) FMGR_PTR2(entry->sk_func, entry->sk_procedure,
+ entry->sk_argument, datum);
+ }
+ result = tmpres;
+
+ /* if the keys are unequal, return the difference */
+ if (result != 0)
+ return (result);
}
- result = tmpres;
-
- /* if the keys are unequal, return the difference */
- if (result != 0)
- return (result);
- }
-
- /* by here, the keys are equal */
- return (0);
+
+ /* by here, the keys are equal */
+ return (0);
}
/*
- * _bt_next() -- Get the next item in a scan.
+ * _bt_next() -- Get the next item in a scan.
*
- * On entry, we have a valid currentItemData in the scan, and a
- * read lock on the page that contains that item. We do not have
- * the page pinned. We return the next item in the scan. On
- * exit, we have the page containing the next item locked but not
- * pinned.
+ * On entry, we have a valid currentItemData in the scan, and a
+ * read lock on the page that contains that item. We do not have
+ * the page pinned. We return the next item in the scan. On
+ * exit, we have the page containing the next item locked but not
+ * pinned.
*/
RetrieveIndexResult
_bt_next(IndexScanDesc scan, ScanDirection dir)
{
- Relation rel;
- Buffer buf;
- Page page;
- OffsetNumber offnum;
- RetrieveIndexResult res;
- ItemPointer current;
- BTItem btitem;
- IndexTuple itup;
- BTScanOpaque so;
- Size keysok;
-
- rel = scan->relation;
- so = (BTScanOpaque) scan->opaque;
- current = &(scan->currentItemData);
-
- /*
- * XXX 10 may 91: somewhere there's a bug in our management of the
- * cached buffer for this scan. wei discovered it. the following
- * is a workaround so he can work until i figure out what's going on.
- */
-
- if (!BufferIsValid(so->btso_curbuf))
- so->btso_curbuf = _bt_getbuf(rel, ItemPointerGetBlockNumber(current),
- BT_READ);
-
- /* we still have the buffer pinned and locked */
- buf = so->btso_curbuf;
-
- do
- {
- /* step one tuple in the appropriate direction */
- if (!_bt_step(scan, &buf, dir))
- return ((RetrieveIndexResult) NULL);
-
- /* by here, current is the tuple we want to return */
- offnum = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &btitem->bti_itup;
-
- if ( _bt_checkkeys (scan, itup, &keysok) )
- {
- Assert (keysok == so->numberOfKeys);
- res = FormRetrieveIndexResult(current, &(itup->t_tid));
-
- /* remember which buffer we have pinned and locked */
- so->btso_curbuf = buf;
- return (res);
- }
+ Relation rel;
+ Buffer buf;
+ Page page;
+ OffsetNumber offnum;
+ RetrieveIndexResult res;
+ ItemPointer current;
+ BTItem btitem;
+ IndexTuple itup;
+ BTScanOpaque so;
+ Size keysok;
+
+ rel = scan->relation;
+ so = (BTScanOpaque) scan->opaque;
+ current = &(scan->currentItemData);
+
+ /*
+ * XXX 10 may 91: somewhere there's a bug in our management of the
+ * cached buffer for this scan. wei discovered it. the following is
+ * a workaround so he can work until i figure out what's going on.
+ */
+
+ if (!BufferIsValid(so->btso_curbuf))
+ so->btso_curbuf = _bt_getbuf(rel, ItemPointerGetBlockNumber(current),
+ BT_READ);
+
+ /* we still have the buffer pinned and locked */
+ buf = so->btso_curbuf;
+
+ do
+ {
+ /* step one tuple in the appropriate direction */
+ if (!_bt_step(scan, &buf, dir))
+ return ((RetrieveIndexResult) NULL);
- } while ( keysok >= so->numberOfFirstKeys );
+ /* by here, current is the tuple we want to return */
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &btitem->bti_itup;
+
+ if (_bt_checkkeys(scan, itup, &keysok))
+ {
+ Assert(keysok == so->numberOfKeys);
+ res = FormRetrieveIndexResult(current, &(itup->t_tid));
+
+ /* remember which buffer we have pinned and locked */
+ so->btso_curbuf = buf;
+ return (res);
+ }
+
+ } while (keysok >= so->numberOfFirstKeys);
- ItemPointerSetInvalid(current);
- so->btso_curbuf = InvalidBuffer;
- _bt_relbuf(rel, buf, BT_READ);
-
- return ((RetrieveIndexResult) NULL);
+ ItemPointerSetInvalid(current);
+ so->btso_curbuf = InvalidBuffer;
+ _bt_relbuf(rel, buf, BT_READ);
+
+ return ((RetrieveIndexResult) NULL);
}
/*
- * _bt_first() -- Find the first item in a scan.
+ * _bt_first() -- Find the first item in a scan.
*
- * We need to be clever about the type of scan, the operation it's
- * performing, and the tree ordering. We return the RetrieveIndexResult
- * of the first item in the tree that satisfies the qualification
- * associated with the scan descriptor. On exit, the page containing
- * the current index tuple is read locked and pinned, and the scan's
- * opaque data entry is updated to include the buffer.
+ * We need to be clever about the type of scan, the operation it's
+ * performing, and the tree ordering. We return the RetrieveIndexResult
+ * of the first item in the tree that satisfies the qualification
+ * associated with the scan descriptor. On exit, the page containing
+ * the current index tuple is read locked and pinned, and the scan's
+ * opaque data entry is updated to include the buffer.
*/
RetrieveIndexResult
_bt_first(IndexScanDesc scan, ScanDirection dir)
{
- Relation rel;
- TupleDesc itupdesc;
- Buffer buf;
- Page page;
- BTPageOpaque pop;
- BTStack stack;
- OffsetNumber offnum, maxoff;
- bool offGmax = false;
- BTItem btitem;
- IndexTuple itup;
- ItemPointer current;
- BlockNumber blkno;
- StrategyNumber strat;
- RetrieveIndexResult res;
- RegProcedure proc;
- int result;
- BTScanOpaque so;
- ScanKeyData skdata;
- Size keysok;
-
- rel = scan->relation;
- so = (BTScanOpaque) scan->opaque;
-
- /*
- * Order the keys in the qualification and be sure
- * that the scan exploits the tree order.
- */
- so->numberOfFirstKeys = 0; /* may be changed by _bt_orderkeys */
- so->qual_ok = 1; /* may be changed by _bt_orderkeys */
- scan->scanFromEnd = false;
- if ( so->numberOfKeys > 0 )
- {
- _bt_orderkeys(rel, so);
-
- strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure);
+ Relation rel;
+ TupleDesc itupdesc;
+ Buffer buf;
+ Page page;
+ BTPageOpaque pop;
+ BTStack stack;
+ OffsetNumber offnum,
+ maxoff;
+ bool offGmax = false;
+ BTItem btitem;
+ IndexTuple itup;
+ ItemPointer current;
+ BlockNumber blkno;
+ StrategyNumber strat;
+ RetrieveIndexResult res;
+ RegProcedure proc;
+ int result;
+ BTScanOpaque so;
+ ScanKeyData skdata;
+ Size keysok;
- /* NOTE: it assumes ForwardScanDirection */
- if ( strat == BTLessStrategyNumber ||
- strat == BTLessEqualStrategyNumber )
- scan->scanFromEnd = true;
- }
- else
- scan->scanFromEnd = true;
-
- if ( so->qual_ok == 0 )
- return ((RetrieveIndexResult) NULL);
-
- /* if we just need to walk down one edge of the tree, do that */
- if (scan->scanFromEnd)
- return (_bt_endpoint(scan, dir));
-
- itupdesc = RelationGetTupleDescriptor(rel);
- current = &(scan->currentItemData);
-
- /*
- * Okay, we want something more complicated. What we'll do is use
- * the first item in the scan key passed in (which has been correctly
- * ordered to take advantage of index ordering) to position ourselves
- * at the right place in the scan.
- */
- /* _bt_orderkeys disallows it, but it's place to add some code latter */
- if ( so->keyData[0].sk_flags & SK_ISNULL )
- {
- elog (WARN, "_bt_first: btree doesn't support is(not)null, yet");
- return ((RetrieveIndexResult) NULL);
- }
- proc = index_getprocid(rel, 1, BTORDER_PROC);
- ScanKeyEntryInitialize(&skdata, so->keyData[0].sk_flags, 1, proc,
- so->keyData[0].sk_argument);
-
- stack = _bt_search(rel, 1, &skdata, &buf);
- _bt_freestack(stack);
-
- blkno = BufferGetBlockNumber(buf);
- page = BufferGetPage(buf);
-
- /*
- * This will happen if the tree we're searching is entirely empty,
- * or if we're doing a search for a key that would appear on an
- * entirely empty internal page. In either case, there are no
- * matching tuples in the index.
- */
-
- if (PageIsEmpty(page)) {
- ItemPointerSetInvalid(current);
- so->btso_curbuf = InvalidBuffer;
- _bt_relbuf(rel, buf, BT_READ);
- return ((RetrieveIndexResult) NULL);
- }
- maxoff = PageGetMaxOffsetNumber(page);
- pop = (BTPageOpaque) PageGetSpecialPointer(page);
-
- /*
- * Now _bt_moveright doesn't move from non-rightmost leaf page
- * if scankey == hikey and there is only hikey there. It's
- * good for insertion, but we need to do work for scan here.
- * - vadim 05/27/97
- */
-
- while ( maxoff == P_HIKEY && !P_RIGHTMOST(pop) &&
- _bt_skeycmp(rel, 1, &skdata, page,
- PageGetItemId(page, P_HIKEY),
- BTGreaterEqualStrategyNumber) )
- {
- /* step right one page */
- blkno = pop->btpo_next;
- _bt_relbuf(rel, buf, BT_READ);
- buf = _bt_getbuf(rel, blkno, BT_READ);
+ rel = scan->relation;
+ so = (BTScanOpaque) scan->opaque;
+
+ /*
+ * Order the keys in the qualification and be sure that the scan
+ * exploits the tree order.
+ */
+ so->numberOfFirstKeys = 0; /* may be changed by _bt_orderkeys */
+ so->qual_ok = 1; /* may be changed by _bt_orderkeys */
+ scan->scanFromEnd = false;
+ if (so->numberOfKeys > 0)
+ {
+ _bt_orderkeys(rel, so);
+
+ strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure);
+
+ /* NOTE: it assumes ForwardScanDirection */
+ if (strat == BTLessStrategyNumber ||
+ strat == BTLessEqualStrategyNumber)
+ scan->scanFromEnd = true;
+ }
+ else
+ scan->scanFromEnd = true;
+
+ if (so->qual_ok == 0)
+ return ((RetrieveIndexResult) NULL);
+
+ /* if we just need to walk down one edge of the tree, do that */
+ if (scan->scanFromEnd)
+ return (_bt_endpoint(scan, dir));
+
+ itupdesc = RelationGetTupleDescriptor(rel);
+ current = &(scan->currentItemData);
+
+ /*
+ * Okay, we want something more complicated. What we'll do is use the
+ * first item in the scan key passed in (which has been correctly
+ * ordered to take advantage of index ordering) to position ourselves
+ * at the right place in the scan.
+ */
+ /* _bt_orderkeys disallows it, but it's place to add some code latter */
+ if (so->keyData[0].sk_flags & SK_ISNULL)
+ {
+ elog(WARN, "_bt_first: btree doesn't support is(not)null, yet");
+ return ((RetrieveIndexResult) NULL);
+ }
+ proc = index_getprocid(rel, 1, BTORDER_PROC);
+ ScanKeyEntryInitialize(&skdata, so->keyData[0].sk_flags, 1, proc,
+ so->keyData[0].sk_argument);
+
+ stack = _bt_search(rel, 1, &skdata, &buf);
+ _bt_freestack(stack);
+
+ blkno = BufferGetBlockNumber(buf);
page = BufferGetPage(buf);
- if (PageIsEmpty(page)) {
- ItemPointerSetInvalid(current);
- so->btso_curbuf = InvalidBuffer;
- _bt_relbuf(rel, buf, BT_READ);
- return ((RetrieveIndexResult) NULL);
+
+ /*
+ * This will happen if the tree we're searching is entirely empty, or
+ * if we're doing a search for a key that would appear on an entirely
+ * empty internal page. In either case, there are no matching tuples
+ * in the index.
+ */
+
+ if (PageIsEmpty(page))
+ {
+ ItemPointerSetInvalid(current);
+ so->btso_curbuf = InvalidBuffer;
+ _bt_relbuf(rel, buf, BT_READ);
+ return ((RetrieveIndexResult) NULL);
}
- maxoff = PageGetMaxOffsetNumber(page);
+ maxoff = PageGetMaxOffsetNumber(page);
pop = (BTPageOpaque) PageGetSpecialPointer(page);
- }
-
-
- /* find the nearest match to the manufactured scan key on the page */
- offnum = _bt_binsrch(rel, buf, 1, &skdata, BT_DESCENT);
-
- if (offnum > maxoff)
- {
- offnum = maxoff;
- offGmax = true;
- }
-
- ItemPointerSet(current, blkno, offnum);
-
- /*
- * Now find the right place to start the scan. Result is the
- * value we're looking for minus the value we're looking at
- * in the index.
- */
-
- result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
-
- /* it's yet other place to add some code latter for is(not)null */
-
- strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure);
-
- switch (strat) {
- case BTLessStrategyNumber:
- if (result <= 0) {
- do {
- if (!_bt_twostep(scan, &buf, BackwardScanDirection))
- break;
-
- offnum = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
- } while (result <= 0);
-
- /* if this is true, the key we just looked at is gone */
- if (result > 0)
- _bt_twostep(scan, &buf, ForwardScanDirection);
- }
- break;
-
- case BTLessEqualStrategyNumber:
- if (result >= 0) {
- do {
- if (!_bt_twostep(scan, &buf, ForwardScanDirection))
- break;
-
- offnum = ItemPointerGetOffsetNumber(current);
+
+ /*
+ * Now _bt_moveright doesn't move from non-rightmost leaf page if
+ * scankey == hikey and there is only hikey there. It's good for
+ * insertion, but we need to do work for scan here. - vadim 05/27/97
+ */
+
+ while (maxoff == P_HIKEY && !P_RIGHTMOST(pop) &&
+ _bt_skeycmp(rel, 1, &skdata, page,
+ PageGetItemId(page, P_HIKEY),
+ BTGreaterEqualStrategyNumber))
+ {
+ /* step right one page */
+ blkno = pop->btpo_next;
+ _bt_relbuf(rel, buf, BT_READ);
+ buf = _bt_getbuf(rel, blkno, BT_READ);
page = BufferGetPage(buf);
- result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
- } while (result >= 0);
-
- if (result < 0)
- _bt_twostep(scan, &buf, BackwardScanDirection);
+ if (PageIsEmpty(page))
+ {
+ ItemPointerSetInvalid(current);
+ so->btso_curbuf = InvalidBuffer;
+ _bt_relbuf(rel, buf, BT_READ);
+ return ((RetrieveIndexResult) NULL);
+ }
+ maxoff = PageGetMaxOffsetNumber(page);
+ pop = (BTPageOpaque) PageGetSpecialPointer(page);
}
- break;
-
- case BTEqualStrategyNumber:
- if (result != 0) {
- _bt_relbuf(scan->relation, buf, BT_READ);
- so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(&(scan->currentItemData));
- return ((RetrieveIndexResult) NULL);
+
+
+ /* find the nearest match to the manufactured scan key on the page */
+ offnum = _bt_binsrch(rel, buf, 1, &skdata, BT_DESCENT);
+
+ if (offnum > maxoff)
+ {
+ offnum = maxoff;
+ offGmax = true;
}
- break;
-
- case BTGreaterEqualStrategyNumber:
- if ( offGmax )
+
+ ItemPointerSet(current, blkno, offnum);
+
+ /*
+ * Now find the right place to start the scan. Result is the value
+ * we're looking for minus the value we're looking at in the index.
+ */
+
+ result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
+
+ /* it's yet other place to add some code latter for is(not)null */
+
+ strat = _bt_getstrat(rel, 1, so->keyData[0].sk_procedure);
+
+ switch (strat)
{
- if (result < 0)
- {
- Assert ( !P_RIGHTMOST(pop) && maxoff == P_HIKEY );
- if ( !_bt_step(scan, &buf, ForwardScanDirection) )
- {
- _bt_relbuf(scan->relation, buf, BT_READ);
- so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(&(scan->currentItemData));
- return ((RetrieveIndexResult) NULL);
+ case BTLessStrategyNumber:
+ if (result <= 0)
+ {
+ do
+ {
+ if (!_bt_twostep(scan, &buf, BackwardScanDirection))
+ break;
+
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
+ } while (result <= 0);
+
+ /* if this is true, the key we just looked at is gone */
+ if (result > 0)
+ _bt_twostep(scan, &buf, ForwardScanDirection);
}
- }
- else if (result > 0)
- { /*
- * Just remember: _bt_binsrch() returns the OffsetNumber of
- * the first matching key on the page, or the OffsetNumber at
- * which the matching key WOULD APPEAR IF IT WERE on this page.
- * No key on this page, but offnum from _bt_binsrch() greater
- * maxoff - have to move right. - vadim 12/06/96
- */
- _bt_twostep(scan, &buf, ForwardScanDirection);
- }
+ break;
+
+ case BTLessEqualStrategyNumber:
+ if (result >= 0)
+ {
+ do
+ {
+ if (!_bt_twostep(scan, &buf, ForwardScanDirection))
+ break;
+
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
+ } while (result >= 0);
+
+ if (result < 0)
+ _bt_twostep(scan, &buf, BackwardScanDirection);
+ }
+ break;
+
+ case BTEqualStrategyNumber:
+ if (result != 0)
+ {
+ _bt_relbuf(scan->relation, buf, BT_READ);
+ so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(&(scan->currentItemData));
+ return ((RetrieveIndexResult) NULL);
+ }
+ break;
+
+ case BTGreaterEqualStrategyNumber:
+ if (offGmax)
+ {
+ if (result < 0)
+ {
+ Assert(!P_RIGHTMOST(pop) && maxoff == P_HIKEY);
+ if (!_bt_step(scan, &buf, ForwardScanDirection))
+ {
+ _bt_relbuf(scan->relation, buf, BT_READ);
+ so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(&(scan->currentItemData));
+ return ((RetrieveIndexResult) NULL);
+ }
+ }
+ else if (result > 0)
+ { /* Just remember: _bt_binsrch() returns
+ * the OffsetNumber of the first matching
+ * key on the page, or the OffsetNumber at
+ * which the matching key WOULD APPEAR IF
+ * IT WERE on this page. No key on this
+ * page, but offnum from _bt_binsrch()
+ * greater maxoff - have to move right. -
+ * vadim 12/06/96 */
+ _bt_twostep(scan, &buf, ForwardScanDirection);
+ }
+ }
+ else if (result < 0)
+ {
+ do
+ {
+ if (!_bt_twostep(scan, &buf, BackwardScanDirection))
+ break;
+
+ page = BufferGetPage(buf);
+ offnum = ItemPointerGetOffsetNumber(current);
+ result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
+ } while (result < 0);
+
+ if (result > 0)
+ _bt_twostep(scan, &buf, ForwardScanDirection);
+ }
+ break;
+
+ case BTGreaterStrategyNumber:
+ /* offGmax helps as above */
+ if (result >= 0 || offGmax)
+ {
+ do
+ {
+ if (!_bt_twostep(scan, &buf, ForwardScanDirection))
+ break;
+
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
+ } while (result >= 0);
+ }
+ break;
}
- else if (result < 0)
+
+ /* okay, current item pointer for the scan is right */
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &btitem->bti_itup;
+
+ if (_bt_checkkeys(scan, itup, &keysok))
{
- do {
- if (!_bt_twostep(scan, &buf, BackwardScanDirection))
- break;
-
- page = BufferGetPage(buf);
- offnum = ItemPointerGetOffsetNumber(current);
- result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
- } while (result < 0);
-
- if (result > 0)
- _bt_twostep(scan, &buf, ForwardScanDirection);
+ res = FormRetrieveIndexResult(current, &(itup->t_tid));
+
+ /* remember which buffer we have pinned */
+ so->btso_curbuf = buf;
}
- break;
-
- case BTGreaterStrategyNumber:
- /* offGmax helps as above */
- if (result >= 0 || offGmax) {
- do {
- if (!_bt_twostep(scan, &buf, ForwardScanDirection))
- break;
-
- offnum = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- result = _bt_compare(rel, itupdesc, page, 1, &skdata, offnum);
- } while (result >= 0);
+ else if (keysok >= so->numberOfFirstKeys)
+ {
+ so->btso_curbuf = buf;
+ return (_bt_next(scan, dir));
}
- break;
- }
-
- /* okay, current item pointer for the scan is right */
- offnum = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &btitem->bti_itup;
-
- if ( _bt_checkkeys (scan, itup, &keysok) )
- {
- res = FormRetrieveIndexResult(current, &(itup->t_tid));
-
- /* remember which buffer we have pinned */
- so->btso_curbuf = buf;
- }
- else if ( keysok >= so->numberOfFirstKeys )
- {
- so->btso_curbuf = buf;
- return (_bt_next (scan, dir));
- }
- else
- {
- ItemPointerSetInvalid(current);
- so->btso_curbuf = InvalidBuffer;
- _bt_relbuf(rel, buf, BT_READ);
- res = (RetrieveIndexResult) NULL;
- }
-
- return (res);
+ else
+ {
+ ItemPointerSetInvalid(current);
+ so->btso_curbuf = InvalidBuffer;
+ _bt_relbuf(rel, buf, BT_READ);
+ res = (RetrieveIndexResult) NULL;
+ }
+
+ return (res);
}
/*
- * _bt_step() -- Step one item in the requested direction in a scan on
- * the tree.
+ * _bt_step() -- Step one item in the requested direction in a scan on
+ * the tree.
*
- * If no adjacent record exists in the requested direction, return
- * false. Else, return true and set the currentItemData for the
- * scan to the right thing.
+ * If no adjacent record exists in the requested direction, return
+ * false. Else, return true and set the currentItemData for the
+ * scan to the right thing.
*/
bool
-_bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
+_bt_step(IndexScanDesc scan, Buffer * bufP, ScanDirection dir)
{
- Page page;
- BTPageOpaque opaque;
- OffsetNumber offnum, maxoff;
- OffsetNumber start;
- BlockNumber blkno;
- BlockNumber obknum;
- BTScanOpaque so;
- ItemPointer current;
- Relation rel;
-
- rel = scan->relation;
- current = &(scan->currentItemData);
- offnum = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(*bufP);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- so = (BTScanOpaque) scan->opaque;
- maxoff = PageGetMaxOffsetNumber(page);
-
- /* get the next tuple */
- if (ScanDirectionIsForward(dir)) {
- if (!PageIsEmpty(page) && offnum < maxoff) {
- offnum = OffsetNumberNext(offnum);
- } else {
-
- /* if we're at end of scan, release the buffer and return */
- blkno = opaque->btpo_next;
- if (P_RIGHTMOST(opaque)) {
- _bt_relbuf(rel, *bufP, BT_READ);
- ItemPointerSetInvalid(current);
- *bufP = so->btso_curbuf = InvalidBuffer;
- return (false);
- } else {
-
- /* walk right to the next page with data */
- _bt_relbuf(rel, *bufP, BT_READ);
- for (;;) {
- *bufP = _bt_getbuf(rel, blkno, BT_READ);
- page = BufferGetPage(*bufP);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- maxoff = PageGetMaxOffsetNumber(page);
- start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
-
- if (!PageIsEmpty(page) && start <= maxoff) {
- break;
- } else {
+ Page page;
+ BTPageOpaque opaque;
+ OffsetNumber offnum,
+ maxoff;
+ OffsetNumber start;
+ BlockNumber blkno;
+ BlockNumber obknum;
+ BTScanOpaque so;
+ ItemPointer current;
+ Relation rel;
+
+ rel = scan->relation;
+ current = &(scan->currentItemData);
+ offnum = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(*bufP);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ so = (BTScanOpaque) scan->opaque;
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ /* get the next tuple */
+ if (ScanDirectionIsForward(dir))
+ {
+ if (!PageIsEmpty(page) && offnum < maxoff)
+ {
+ offnum = OffsetNumberNext(offnum);
+ }
+ else
+ {
+
+ /* if we're at end of scan, release the buffer and return */
blkno = opaque->btpo_next;
- _bt_relbuf(rel, *bufP, BT_READ);
- if (blkno == P_NONE) {
- *bufP = so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(current);
- return (false);
+ if (P_RIGHTMOST(opaque))
+ {
+ _bt_relbuf(rel, *bufP, BT_READ);
+ ItemPointerSetInvalid(current);
+ *bufP = so->btso_curbuf = InvalidBuffer;
+ return (false);
+ }
+ else
+ {
+
+ /* walk right to the next page with data */
+ _bt_relbuf(rel, *bufP, BT_READ);
+ for (;;)
+ {
+ *bufP = _bt_getbuf(rel, blkno, BT_READ);
+ page = BufferGetPage(*bufP);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ maxoff = PageGetMaxOffsetNumber(page);
+ start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ if (!PageIsEmpty(page) && start <= maxoff)
+ {
+ break;
+ }
+ else
+ {
+ blkno = opaque->btpo_next;
+ _bt_relbuf(rel, *bufP, BT_READ);
+ if (blkno == P_NONE)
+ {
+ *bufP = so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(current);
+ return (false);
+ }
+ }
+ }
+ offnum = start;
}
- }
}
- offnum = start;
- }
}
- } else if (ScanDirectionIsBackward(dir)) {
-
- /* remember that high key is item zero on non-rightmost pages */
- start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+ else if (ScanDirectionIsBackward(dir))
+ {
- if (offnum > start) {
- offnum = OffsetNumberPrev(offnum);
- } else {
-
- /* if we're at end of scan, release the buffer and return */
- blkno = opaque->btpo_prev;
- if (P_LEFTMOST(opaque)) {
- _bt_relbuf(rel, *bufP, BT_READ);
- *bufP = so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(current);
- return (false);
- } else {
-
- obknum = BufferGetBlockNumber(*bufP);
-
- /* walk right to the next page with data */
- _bt_relbuf(rel, *bufP, BT_READ);
- for (;;) {
- *bufP = _bt_getbuf(rel, blkno, BT_READ);
- page = BufferGetPage(*bufP);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- maxoff = PageGetMaxOffsetNumber(page);
-
- /*
- * If the adjacent page just split, then we may have the
- * wrong block. Handle this case. Because pages only
- * split right, we don't have to worry about this failing
- * to terminate.
- */
-
- while (opaque->btpo_next != obknum) {
- blkno = opaque->btpo_next;
- _bt_relbuf(rel, *bufP, BT_READ);
- *bufP = _bt_getbuf(rel, blkno, BT_READ);
- page = BufferGetPage(*bufP);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- maxoff = PageGetMaxOffsetNumber(page);
- }
-
- /* don't consider the high key */
- start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
-
- /* anything to look at here? */
- if (!PageIsEmpty(page) && maxoff >= start) {
- break;
- } else {
+ /* remember that high key is item zero on non-rightmost pages */
+ start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ if (offnum > start)
+ {
+ offnum = OffsetNumberPrev(offnum);
+ }
+ else
+ {
+
+ /* if we're at end of scan, release the buffer and return */
blkno = opaque->btpo_prev;
- obknum = BufferGetBlockNumber(*bufP);
- _bt_relbuf(rel, *bufP, BT_READ);
- if (blkno == P_NONE) {
- *bufP = so->btso_curbuf = InvalidBuffer;
- ItemPointerSetInvalid(current);
- return (false);
+ if (P_LEFTMOST(opaque))
+ {
+ _bt_relbuf(rel, *bufP, BT_READ);
+ *bufP = so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(current);
+ return (false);
+ }
+ else
+ {
+
+ obknum = BufferGetBlockNumber(*bufP);
+
+ /* walk right to the next page with data */
+ _bt_relbuf(rel, *bufP, BT_READ);
+ for (;;)
+ {
+ *bufP = _bt_getbuf(rel, blkno, BT_READ);
+ page = BufferGetPage(*bufP);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ /*
+ * If the adjacent page just split, then we may have
+ * the wrong block. Handle this case. Because pages
+ * only split right, we don't have to worry about this
+ * failing to terminate.
+ */
+
+ while (opaque->btpo_next != obknum)
+ {
+ blkno = opaque->btpo_next;
+ _bt_relbuf(rel, *bufP, BT_READ);
+ *bufP = _bt_getbuf(rel, blkno, BT_READ);
+ page = BufferGetPage(*bufP);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ maxoff = PageGetMaxOffsetNumber(page);
+ }
+
+ /* don't consider the high key */
+ start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ /* anything to look at here? */
+ if (!PageIsEmpty(page) && maxoff >= start)
+ {
+ break;
+ }
+ else
+ {
+ blkno = opaque->btpo_prev;
+ obknum = BufferGetBlockNumber(*bufP);
+ _bt_relbuf(rel, *bufP, BT_READ);
+ if (blkno == P_NONE)
+ {
+ *bufP = so->btso_curbuf = InvalidBuffer;
+ ItemPointerSetInvalid(current);
+ return (false);
+ }
+ }
+ }
+ offnum = maxoff;/* XXX PageIsEmpty? */
}
- }
}
- offnum = maxoff; /* XXX PageIsEmpty? */
- }
}
- }
- blkno = BufferGetBlockNumber(*bufP);
- so->btso_curbuf = *bufP;
- ItemPointerSet(current, blkno, offnum);
-
- return (true);
+ blkno = BufferGetBlockNumber(*bufP);
+ so->btso_curbuf = *bufP;
+ ItemPointerSet(current, blkno, offnum);
+
+ return (true);
}
/*
- * _bt_twostep() -- Move to an adjacent record in a scan on the tree,
- * if an adjacent record exists.
+ * _bt_twostep() -- Move to an adjacent record in a scan on the tree,
+ * if an adjacent record exists.
*
- * This is like _bt_step, except that if no adjacent record exists
- * it restores us to where we were before trying the step. This is
- * only hairy when you cross page boundaries, since the page you cross
- * from could have records inserted or deleted, or could even split.
- * This is unlikely, but we try to handle it correctly here anyway.
+ * This is like _bt_step, except that if no adjacent record exists
+ * it restores us to where we were before trying the step. This is
+ * only hairy when you cross page boundaries, since the page you cross
+ * from could have records inserted or deleted, or could even split.
+ * This is unlikely, but we try to handle it correctly here anyway.
*
- * This routine contains the only case in which our changes to Lehman
- * and Yao's algorithm.
+ * This routine contains the only case in which our changes to Lehman
+ * and Yao's algorithm.
*
- * Like step, this routine leaves the scan's currentItemData in the
- * proper state and acquires a lock and pin on *bufP. If the twostep
- * succeeded, we return true; otherwise, we return false.
+ * Like step, this routine leaves the scan's currentItemData in the
+ * proper state and acquires a lock and pin on *bufP. If the twostep
+ * succeeded, we return true; otherwise, we return false.
*/
-static bool
-_bt_twostep(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
+static bool
+_bt_twostep(IndexScanDesc scan, Buffer * bufP, ScanDirection dir)
{
- Page page;
- BTPageOpaque opaque;
- OffsetNumber offnum, maxoff;
- OffsetNumber start;
- ItemPointer current;
- ItemId itemid;
- int itemsz;
- BTItem btitem;
- BTItem svitem;
- BlockNumber blkno;
-
- blkno = BufferGetBlockNumber(*bufP);
- page = BufferGetPage(*bufP);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- maxoff = PageGetMaxOffsetNumber(page);
- current = &(scan->currentItemData);
- offnum = ItemPointerGetOffsetNumber(current);
-
- start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
-
- /* if we're safe, just do it */
- if (ScanDirectionIsForward(dir) && offnum < maxoff) { /* XXX PageIsEmpty? */
- ItemPointerSet(current, blkno, OffsetNumberNext(offnum));
- return (true);
- } else if (ScanDirectionIsBackward(dir) && offnum > start) {
- ItemPointerSet(current, blkno, OffsetNumberPrev(offnum));
- return (true);
- }
-
- /* if we've hit end of scan we don't have to do any work */
- if (ScanDirectionIsForward(dir) && P_RIGHTMOST(opaque)) {
- return (false);
- } else if (ScanDirectionIsBackward(dir) && P_LEFTMOST(opaque)) {
- return (false);
- }
-
- /*
- * Okay, it's off the page; let _bt_step() do the hard work, and we'll
- * try to remember where we were. This is not guaranteed to work; this
- * is the only place in the code where concurrency can screw us up,
- * and it's because we want to be able to move in two directions in
- * the scan.
- */
-
- itemid = PageGetItemId(page, offnum);
- itemsz = ItemIdGetLength(itemid);
- btitem = (BTItem) PageGetItem(page, itemid);
- svitem = (BTItem) palloc(itemsz);
- memmove((char *) svitem, (char *) btitem, itemsz);
-
- if (_bt_step(scan, bufP, dir)) {
- pfree(svitem);
- return (true);
- }
-
- /* try to find our place again */
- *bufP = _bt_getbuf(scan->relation, blkno, BT_READ);
- page = BufferGetPage(*bufP);
- maxoff = PageGetMaxOffsetNumber(page);
-
- while (offnum <= maxoff) {
+ Page page;
+ BTPageOpaque opaque;
+ OffsetNumber offnum,
+ maxoff;
+ OffsetNumber start;
+ ItemPointer current;
+ ItemId itemid;
+ int itemsz;
+ BTItem btitem;
+ BTItem svitem;
+ BlockNumber blkno;
+
+ blkno = BufferGetBlockNumber(*bufP);
+ page = BufferGetPage(*bufP);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ maxoff = PageGetMaxOffsetNumber(page);
+ current = &(scan->currentItemData);
+ offnum = ItemPointerGetOffsetNumber(current);
+
+ start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ /* if we're safe, just do it */
+ if (ScanDirectionIsForward(dir) && offnum < maxoff)
+ { /* XXX PageIsEmpty? */
+ ItemPointerSet(current, blkno, OffsetNumberNext(offnum));
+ return (true);
+ }
+ else if (ScanDirectionIsBackward(dir) && offnum > start)
+ {
+ ItemPointerSet(current, blkno, OffsetNumberPrev(offnum));
+ return (true);
+ }
+
+ /* if we've hit end of scan we don't have to do any work */
+ if (ScanDirectionIsForward(dir) && P_RIGHTMOST(opaque))
+ {
+ return (false);
+ }
+ else if (ScanDirectionIsBackward(dir) && P_LEFTMOST(opaque))
+ {
+ return (false);
+ }
+
+ /*
+ * Okay, it's off the page; let _bt_step() do the hard work, and we'll
+ * try to remember where we were. This is not guaranteed to work;
+ * this is the only place in the code where concurrency can screw us
+ * up, and it's because we want to be able to move in two directions
+ * in the scan.
+ */
+
itemid = PageGetItemId(page, offnum);
+ itemsz = ItemIdGetLength(itemid);
btitem = (BTItem) PageGetItem(page, itemid);
- if ( BTItemSame (btitem, svitem) ) {
- pfree(svitem);
- ItemPointerSet(current, blkno, offnum);
- return (false);
+ svitem = (BTItem) palloc(itemsz);
+ memmove((char *) svitem, (char *) btitem, itemsz);
+
+ if (_bt_step(scan, bufP, dir))
+ {
+ pfree(svitem);
+ return (true);
+ }
+
+ /* try to find our place again */
+ *bufP = _bt_getbuf(scan->relation, blkno, BT_READ);
+ page = BufferGetPage(*bufP);
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ while (offnum <= maxoff)
+ {
+ itemid = PageGetItemId(page, offnum);
+ btitem = (BTItem) PageGetItem(page, itemid);
+ if (BTItemSame(btitem, svitem))
+ {
+ pfree(svitem);
+ ItemPointerSet(current, blkno, offnum);
+ return (false);
+ }
}
- }
-
- /*
- * XXX crash and burn -- can't find our place. We can be a little
- * smarter -- walk to the next page to the right, for example, since
- * that's the only direction that splits happen in. Deletions screw
- * us up less often since they're only done by the vacuum daemon.
- */
-
- elog(WARN, "btree synchronization error: concurrent update botched scan");
-
- return (false);
+
+ /*
+ * XXX crash and burn -- can't find our place. We can be a little
+ * smarter -- walk to the next page to the right, for example, since
+ * that's the only direction that splits happen in. Deletions screw
+ * us up less often since they're only done by the vacuum daemon.
+ */
+
+ elog(WARN, "btree synchronization error: concurrent update botched scan");
+
+ return (false);
}
/*
- * _bt_endpoint() -- Find the first or last key in the index.
+ * _bt_endpoint() -- Find the first or last key in the index.
*/
-static RetrieveIndexResult
+static RetrieveIndexResult
_bt_endpoint(IndexScanDesc scan, ScanDirection dir)
{
- Relation rel;
- Buffer buf;
- Page page;
- BTPageOpaque opaque;
- ItemPointer current;
- OffsetNumber offnum, maxoff;
- OffsetNumber start = 0;
- BlockNumber blkno;
- BTItem btitem;
- IndexTuple itup;
- BTScanOpaque so;
- RetrieveIndexResult res;
- Size keysok;
-
- rel = scan->relation;
- current = &(scan->currentItemData);
- so = (BTScanOpaque) scan->opaque;
-
- buf = _bt_getroot(rel, BT_READ);
- blkno = BufferGetBlockNumber(buf);
- page = BufferGetPage(buf);
- opaque = (BTPageOpaque) PageGetSpecialPointer(page);
-
- for (;;) {
- if (opaque->btpo_flags & BTP_LEAF)
- break;
-
- if (ScanDirectionIsForward(dir)) {
- offnum = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
- } else {
- offnum = PageGetMaxOffsetNumber(page);
- }
-
- btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
- itup = &(btitem->bti_itup);
-
- blkno = ItemPointerGetBlockNumber(&(itup->t_tid));
-
- _bt_relbuf(rel, buf, BT_READ);
- buf = _bt_getbuf(rel, blkno, BT_READ);
+ Relation rel;
+ Buffer buf;
+ Page page;
+ BTPageOpaque opaque;
+ ItemPointer current;
+ OffsetNumber offnum,
+ maxoff;
+ OffsetNumber start = 0;
+ BlockNumber blkno;
+ BTItem btitem;
+ IndexTuple itup;
+ BTScanOpaque so;
+ RetrieveIndexResult res;
+ Size keysok;
+
+ rel = scan->relation;
+ current = &(scan->currentItemData);
+ so = (BTScanOpaque) scan->opaque;
+
+ buf = _bt_getroot(rel, BT_READ);
+ blkno = BufferGetBlockNumber(buf);
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
-
- /*
- * Race condition: If the child page we just stepped onto is
- * in the process of being split, we need to make sure we're
- * all the way at the right edge of the tree. See the paper
- * by Lehman and Yao.
- */
-
- if (ScanDirectionIsBackward(dir) && ! P_RIGHTMOST(opaque)) {
- do {
- blkno = opaque->btpo_next;
+
+ for (;;)
+ {
+ if (opaque->btpo_flags & BTP_LEAF)
+ break;
+
+ if (ScanDirectionIsForward(dir))
+ {
+ offnum = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+ }
+ else
+ {
+ offnum = PageGetMaxOffsetNumber(page);
+ }
+
+ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
+ itup = &(btitem->bti_itup);
+
+ blkno = ItemPointerGetBlockNumber(&(itup->t_tid));
+
_bt_relbuf(rel, buf, BT_READ);
buf = _bt_getbuf(rel, blkno, BT_READ);
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
- } while (! P_RIGHTMOST(opaque));
+
+ /*
+ * Race condition: If the child page we just stepped onto is in
+ * the process of being split, we need to make sure we're all the
+ * way at the right edge of the tree. See the paper by Lehman and
+ * Yao.
+ */
+
+ if (ScanDirectionIsBackward(dir) && !P_RIGHTMOST(opaque))
+ {
+ do
+ {
+ blkno = opaque->btpo_next;
+ _bt_relbuf(rel, buf, BT_READ);
+ buf = _bt_getbuf(rel, blkno, BT_READ);
+ page = BufferGetPage(buf);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(page);
+ } while (!P_RIGHTMOST(opaque));
+ }
}
- }
-
- /* okay, we've got the {left,right}-most page in the tree */
- maxoff = PageGetMaxOffsetNumber(page);
-
- if (ScanDirectionIsForward(dir)) {
- if ( !P_LEFTMOST(opaque) ) /* non-leftmost page ? */
- elog (WARN, "_bt_endpoint: leftmost page (%u) has not leftmost flag", blkno);
- start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
- /*
- * I don't understand this stuff! It doesn't work for non-rightmost
- * pages with only one element (P_HIKEY) which we have after
- * deletion itups by vacuum (it's case of start > maxoff).
- * Scanning in BackwardScanDirection is not understandable at all.
- * Well - new stuff. - vadim 12/06/96
- */
+
+ /* okay, we've got the {left,right}-most page in the tree */
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ if (ScanDirectionIsForward(dir))
+ {
+ if (!P_LEFTMOST(opaque))/* non-leftmost page ? */
+ elog(WARN, "_bt_endpoint: leftmost page (%u) has not leftmost flag", blkno);
+ start = P_RIGHTMOST(opaque) ? P_HIKEY : P_FIRSTKEY;
+
+ /*
+ * I don't understand this stuff! It doesn't work for
+ * non-rightmost pages with only one element (P_HIKEY) which we
+ * have after deletion itups by vacuum (it's case of start >
+ * maxoff). Scanning in BackwardScanDirection is not
+ * understandable at all. Well - new stuff. - vadim 12/06/96
+ */
#if 0
- if (PageIsEmpty(page) || start > maxoff) {
- ItemPointerSet(current, blkno, maxoff);
- if (!_bt_step(scan, &buf, BackwardScanDirection))
- return ((RetrieveIndexResult) NULL);
-
- start = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- }
+ if (PageIsEmpty(page) || start > maxoff)
+ {
+ ItemPointerSet(current, blkno, maxoff);
+ if (!_bt_step(scan, &buf, BackwardScanDirection))
+ return ((RetrieveIndexResult) NULL);
+
+ start = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ }
#endif
- if ( PageIsEmpty (page) )
+ if (PageIsEmpty(page))
+ {
+ if (start != P_HIKEY) /* non-rightmost page */
+ elog(WARN, "_bt_endpoint: non-rightmost page (%u) is empty", blkno);
+
+ /*
+ * It's left- & right- most page - root page, - and it's
+ * empty...
+ */
+ _bt_relbuf(rel, buf, BT_READ);
+ ItemPointerSetInvalid(current);
+ so->btso_curbuf = InvalidBuffer;
+ return ((RetrieveIndexResult) NULL);
+ }
+ if (start > maxoff) /* start == 2 && maxoff == 1 */
+ {
+ ItemPointerSet(current, blkno, maxoff);
+ if (!_bt_step(scan, &buf, ForwardScanDirection))
+ return ((RetrieveIndexResult) NULL);
+
+ start = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ }
+ /* new stuff ends here */
+ else
+ {
+ ItemPointerSet(current, blkno, start);
+ }
+ }
+ else if (ScanDirectionIsBackward(dir))
{
- if ( start != P_HIKEY ) /* non-rightmost page */
- elog (WARN, "_bt_endpoint: non-rightmost page (%u) is empty", blkno);
- /* It's left- & right- most page - root page, - and it's empty... */
- _bt_relbuf(rel, buf, BT_READ);
- ItemPointerSetInvalid(current);
- so->btso_curbuf = InvalidBuffer;
- return ((RetrieveIndexResult) NULL);
+
+ /*
+ * I don't understand this stuff too! If RIGHT-most leaf page is
+ * empty why do scanning in ForwardScanDirection ??? Well - new
+ * stuff. - vadim 12/06/96
+ */
+#if 0
+ if (PageIsEmpty(page))
+ {
+ ItemPointerSet(current, blkno, FirstOffsetNumber);
+ if (!_bt_step(scan, &buf, ForwardScanDirection))
+ return ((RetrieveIndexResult) NULL);
+
+ start = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ }
+#endif
+ if (PageIsEmpty(page))
+ {
+ /* If it's leftmost page too - it's empty root page... */
+ if (P_LEFTMOST(opaque))
+ {
+ _bt_relbuf(rel, buf, BT_READ);
+ ItemPointerSetInvalid(current);
+ so->btso_curbuf = InvalidBuffer;
+ return ((RetrieveIndexResult) NULL);
+ }
+ /* Go back ! */
+ ItemPointerSet(current, blkno, FirstOffsetNumber);
+ if (!_bt_step(scan, &buf, BackwardScanDirection))
+ return ((RetrieveIndexResult) NULL);
+
+ start = ItemPointerGetOffsetNumber(current);
+ page = BufferGetPage(buf);
+ }
+ /* new stuff ends here */
+ else
+ {
+ start = PageGetMaxOffsetNumber(page);
+ ItemPointerSet(current, blkno, start);
+ }
}
- if ( start > maxoff ) /* start == 2 && maxoff == 1 */
+ else
{
- ItemPointerSet(current, blkno, maxoff);
- if (!_bt_step(scan, &buf, ForwardScanDirection))
- return ((RetrieveIndexResult) NULL);
-
- start = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
+ elog(WARN, "Illegal scan direction %d", dir);
}
- /* new stuff ends here */
- else {
- ItemPointerSet(current, blkno, start);
+
+ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, start));
+ itup = &(btitem->bti_itup);
+
+ /* see if we picked a winner */
+ if (_bt_checkkeys(scan, itup, &keysok))
+ {
+ res = FormRetrieveIndexResult(current, &(itup->t_tid));
+
+ /* remember which buffer we have pinned */
+ so->btso_curbuf = buf;
}
- } else if (ScanDirectionIsBackward(dir)) {
- /*
- * I don't understand this stuff too! If RIGHT-most leaf page is
- * empty why do scanning in ForwardScanDirection ???
- * Well - new stuff. - vadim 12/06/96
- */
-#if 0
- if (PageIsEmpty(page)) {
- ItemPointerSet(current, blkno, FirstOffsetNumber);
- if (!_bt_step(scan, &buf, ForwardScanDirection))
- return ((RetrieveIndexResult) NULL);
-
- start = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
+ else if (keysok >= so->numberOfFirstKeys)
+ {
+ so->btso_curbuf = buf;
+ return (_bt_next(scan, dir));
}
-#endif
- if (PageIsEmpty(page))
+ else
{
- /* If it's leftmost page too - it's empty root page... */
- if ( P_LEFTMOST(opaque) )
- {
- _bt_relbuf(rel, buf, BT_READ);
ItemPointerSetInvalid(current);
so->btso_curbuf = InvalidBuffer;
- return ((RetrieveIndexResult) NULL);
- }
- /* Go back ! */
- ItemPointerSet(current, blkno, FirstOffsetNumber);
- if (!_bt_step(scan, &buf, BackwardScanDirection))
- return ((RetrieveIndexResult) NULL);
-
- start = ItemPointerGetOffsetNumber(current);
- page = BufferGetPage(buf);
- }
- /* new stuff ends here */
- else {
- start = PageGetMaxOffsetNumber(page);
- ItemPointerSet(current, blkno, start);
+ _bt_relbuf(rel, buf, BT_READ);
+ res = (RetrieveIndexResult) NULL;
}
- } else {
- elog(WARN, "Illegal scan direction %d", dir);
- }
-
- btitem = (BTItem) PageGetItem(page, PageGetItemId(page, start));
- itup = &(btitem->bti_itup);
-
- /* see if we picked a winner */
- if ( _bt_checkkeys (scan, itup, &keysok) )
- {
- res = FormRetrieveIndexResult(current, &(itup->t_tid));
-
- /* remember which buffer we have pinned */
- so->btso_curbuf = buf;
- }
- else if ( keysok >= so->numberOfFirstKeys )
- {
- so->btso_curbuf = buf;
- return (_bt_next (scan, dir));
- }
- else
- {
- ItemPointerSetInvalid(current);
- so->btso_curbuf = InvalidBuffer;
- _bt_relbuf(rel, buf, BT_READ);
- res = (RetrieveIndexResult) NULL;
- }
-
- return (res);
+
+ return (res);
}
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index 8e054d24abf..09cb43769f2 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -5,30 +5,30 @@
*
*
* IDENTIFICATION
- * $Id: nbtsort.c,v 1.19 1997/08/19 21:29:46 momjian Exp $
+ * $Id: nbtsort.c,v 1.20 1997/09/07 04:39:02 momjian Exp $
*
* NOTES
*
* what we do is:
* - generate a set of initial one-block runs, distributed round-robin
- * between the output tapes.
+ * between the output tapes.
* - for each pass,
- * - swap input and output tape sets, rewinding both and truncating
- * the output tapes.
- * - merge the current run in each input tape to the current output
- * tape.
- * - when each input run has been exhausted, switch to another output
- * tape and start processing another run.
+ * - swap input and output tape sets, rewinding both and truncating
+ * the output tapes.
+ * - merge the current run in each input tape to the current output
+ * tape.
+ * - when each input run has been exhausted, switch to another output
+ * tape and start processing another run.
* - when we have fewer runs than tapes, we know we are ready to start
- * merging into the btree leaf pages. (i.e., we do not have to wait
- * until we have exactly one tape.)
+ * merging into the btree leaf pages. (i.e., we do not have to wait
+ * until we have exactly one tape.)
* - as we extract tuples from the final runs, we build the pages for
- * each level. when we have only one page on a level, it must be the
- * root -- it can be attached to the btree metapage and we are done.
+ * each level. when we have only one page on a level, it must be the
+ * root -- it can be attached to the btree metapage and we are done.
*
* conventions:
* - external interface routines take in and return "void *" for their
- * opaque handles. this is for modularity reasons.
+ * opaque handles. this is for modularity reasons.
*
* this code is moderately slow (~10% slower) compared to the regular
* btree (insertion) build code on sorted or well-clustered data. on
@@ -58,20 +58,21 @@
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
#ifdef BTREE_BUILD_STATS
#include <tcop/tcopprot.h>
-extern int ShowExecutorStats;
+extern int ShowExecutorStats;
+
#endif
-static BTItem _bt_buildadd(Relation index, void *pstate, BTItem bti, int flags);
-static BTItem _bt_minitem(Page opage, BlockNumber oblkno, int atend);
-static void *_bt_pagestate(Relation index, int flags, int level, bool doupper);
-static void _bt_uppershutdown(Relation index, BTPageState *state);
+static BTItem _bt_buildadd(Relation index, void *pstate, BTItem bti, int flags);
+static BTItem _bt_minitem(Page opage, BlockNumber oblkno, int atend);
+static void *_bt_pagestate(Relation index, int flags, int level, bool doupper);
+static void _bt_uppershutdown(Relation index, BTPageState * state);
/*
* turn on debugging output.
@@ -83,18 +84,18 @@ static void _bt_uppershutdown(Relation index, BTPageState *state);
#define FASTBUILD_SPOOL
#define FASTBUILD_MERGE
-#define MAXTAPES (7)
-#define TAPEBLCKSZ (MAXBLCKSZ << 2)
-#define TAPETEMP "pg_btsortXXXXXX"
+#define MAXTAPES (7)
+#define TAPEBLCKSZ (MAXBLCKSZ << 2)
+#define TAPETEMP "pg_btsortXXXXXX"
-extern int NDirectFileRead;
-extern int NDirectFileWrite;
-extern char *mktemp(char *template);
+extern int NDirectFileRead;
+extern int NDirectFileWrite;
+extern char *mktemp(char *template);
/*
- * this is what we use to shovel BTItems in and out of memory. it's
+ * this is what we use to shovel BTItems in and out of memory. it's
* bigger than a standard block because we are doing a lot of strictly
- * sequential i/o. this is obviously something of a tradeoff since we
+ * sequential i/o. this is obviously something of a tradeoff since we
* are potentially reading a bunch of zeroes off of disk in many
* cases.
*
@@ -104,14 +105,15 @@ extern char *mktemp(char *template);
* the only thing like that so i'm not going to worry about wasting a
* few bytes.
*/
-typedef struct {
- int bttb_magic; /* magic number */
- int bttb_fd; /* file descriptor */
- int bttb_top; /* top of free space within bttb_data */
- short bttb_ntup; /* number of tuples in this block */
- short bttb_eor; /* End-Of-Run marker */
- char bttb_data[TAPEBLCKSZ - 2 * sizeof(double)];
-} BTTapeBlock;
+typedef struct
+{
+ int bttb_magic; /* magic number */
+ int bttb_fd; /* file descriptor */
+ int bttb_top; /* top of free space within bttb_data */
+ short bttb_ntup; /* number of tuples in this block */
+ short bttb_eor; /* End-Of-Run marker */
+ char bttb_data[TAPEBLCKSZ - 2 * sizeof(double)];
+} BTTapeBlock;
/*
* this structure holds the bookkeeping for a simple balanced multiway
@@ -120,13 +122,14 @@ typedef struct {
* right now. though if psort was in a condition that i could hack it
* to do this, you bet i would.)
*/
-typedef struct {
- int bts_ntapes;
- int bts_tape;
- BTTapeBlock **bts_itape; /* input tape blocks */
- BTTapeBlock **bts_otape; /* output tape blocks */
- bool isunique;
-} BTSpool;
+typedef struct
+{
+ int bts_ntapes;
+ int bts_tape;
+ BTTapeBlock **bts_itape; /* input tape blocks */
+ BTTapeBlock **bts_otape; /* output tape blocks */
+ bool isunique;
+} BTSpool;
/*-------------------------------------------------------------------------
* sorting comparison routine - returns {-1,0,1} depending on whether
@@ -146,101 +149,102 @@ typedef struct {
* what the heck.
* *-------------------------------------------------------------------------
*/
-typedef struct {
- Datum *btsk_datum;
- char *btsk_nulls;
- BTItem btsk_item;
-} BTSortKey;
+typedef struct
+{
+ Datum *btsk_datum;
+ char *btsk_nulls;
+ BTItem btsk_item;
+} BTSortKey;
static Relation _bt_sortrel;
-static int _bt_nattr;
-static BTSpool * _bt_inspool;
+static int _bt_nattr;
+static BTSpool *_bt_inspool;
static void
-_bt_isortcmpinit(Relation index, BTSpool *spool)
+_bt_isortcmpinit(Relation index, BTSpool * spool)
{
- _bt_sortrel = index;
- _bt_inspool = spool;
- _bt_nattr = index->rd_att->natts;
+ _bt_sortrel = index;
+ _bt_inspool = spool;
+ _bt_nattr = index->rd_att->natts;
}
static int
-_bt_isortcmp(BTSortKey *k1, BTSortKey *k2)
+_bt_isortcmp(BTSortKey * k1, BTSortKey * k2)
{
- Datum *k1_datum = k1->btsk_datum;
- Datum *k2_datum = k2->btsk_datum;
- char *k1_nulls = k1->btsk_nulls;
- char *k2_nulls = k2->btsk_nulls;
- bool equal_isnull = false;
- int i;
-
- if (k1->btsk_item == (BTItem) NULL)
- {
- if (k2->btsk_item == (BTItem) NULL)
- return(0); /* 1 = 2 */
- return(1); /* 1 > 2 */
- }
- else if (k2->btsk_item == (BTItem) NULL)
- return(-1); /* 1 < 2 */
-
- for (i = 0; i < _bt_nattr; i++)
- {
- if ( k1_nulls[i] != ' ' ) /* k1 attr is NULL */
+ Datum *k1_datum = k1->btsk_datum;
+ Datum *k2_datum = k2->btsk_datum;
+ char *k1_nulls = k1->btsk_nulls;
+ char *k2_nulls = k2->btsk_nulls;
+ bool equal_isnull = false;
+ int i;
+
+ if (k1->btsk_item == (BTItem) NULL)
{
- if ( k2_nulls[i] != ' ' ) /* the same for k2 */
- {
- equal_isnull = true;
- continue;
- }
- return (1); /* NULL ">" NOT_NULL */
+ if (k2->btsk_item == (BTItem) NULL)
+ return (0); /* 1 = 2 */
+ return (1); /* 1 > 2 */
}
- else if ( k2_nulls[i] != ' ' ) /* k2 attr is NULL */
- return (-1); /* NOT_NULL "<" NULL */
-
- if (_bt_invokestrat(_bt_sortrel, i+1, BTGreaterStrategyNumber,
- k1_datum[i], k2_datum[i]))
- return(1); /* 1 > 2 */
- else if (_bt_invokestrat(_bt_sortrel, i+1, BTGreaterStrategyNumber,
- k2_datum[i], k1_datum[i]))
- return(-1); /* 1 < 2 */
- }
-
- if ( _bt_inspool->isunique && !equal_isnull )
- {
- _bt_spooldestroy ((void*)_bt_inspool);
- elog (WARN, "Cannot create unique index. Table contains non-unique values");
- }
- return(0); /* 1 = 2 */
+ else if (k2->btsk_item == (BTItem) NULL)
+ return (-1); /* 1 < 2 */
+
+ for (i = 0; i < _bt_nattr; i++)
+ {
+ if (k1_nulls[i] != ' ') /* k1 attr is NULL */
+ {
+ if (k2_nulls[i] != ' ') /* the same for k2 */
+ {
+ equal_isnull = true;
+ continue;
+ }
+ return (1); /* NULL ">" NOT_NULL */
+ }
+ else if (k2_nulls[i] != ' ') /* k2 attr is NULL */
+ return (-1); /* NOT_NULL "<" NULL */
+
+ if (_bt_invokestrat(_bt_sortrel, i + 1, BTGreaterStrategyNumber,
+ k1_datum[i], k2_datum[i]))
+ return (1); /* 1 > 2 */
+ else if (_bt_invokestrat(_bt_sortrel, i + 1, BTGreaterStrategyNumber,
+ k2_datum[i], k1_datum[i]))
+ return (-1); /* 1 < 2 */
+ }
+
+ if (_bt_inspool->isunique && !equal_isnull)
+ {
+ _bt_spooldestroy((void *) _bt_inspool);
+ elog(WARN, "Cannot create unique index. Table contains non-unique values");
+ }
+ return (0); /* 1 = 2 */
}
static void
-_bt_setsortkey(Relation index, BTItem bti, BTSortKey *sk)
+_bt_setsortkey(Relation index, BTItem bti, BTSortKey * sk)
{
- sk->btsk_item = (BTItem) NULL;
- sk->btsk_datum = (Datum*) NULL;
- sk->btsk_nulls = (char*) NULL;
-
- if (bti != (BTItem) NULL)
- {
- IndexTuple it = &(bti->bti_itup);
- TupleDesc itdesc = index->rd_att;
- Datum *dp = (Datum*) palloc (_bt_nattr * sizeof (Datum));
- char *np = (char*) palloc (_bt_nattr * sizeof (char));
- bool isnull;
- int i;
-
- for (i = 0; i < _bt_nattr; i++)
- {
- dp[i] = index_getattr(it, i+1, itdesc, &isnull);
- if ( isnull )
- np[i] = 'n';
- else
- np[i] = ' ';
+ sk->btsk_item = (BTItem) NULL;
+ sk->btsk_datum = (Datum *) NULL;
+ sk->btsk_nulls = (char *) NULL;
+
+ if (bti != (BTItem) NULL)
+ {
+ IndexTuple it = &(bti->bti_itup);
+ TupleDesc itdesc = index->rd_att;
+ Datum *dp = (Datum *) palloc(_bt_nattr * sizeof(Datum));
+ char *np = (char *) palloc(_bt_nattr * sizeof(char));
+ bool isnull;
+ int i;
+
+ for (i = 0; i < _bt_nattr; i++)
+ {
+ dp[i] = index_getattr(it, i + 1, itdesc, &isnull);
+ if (isnull)
+ np[i] = 'n';
+ else
+ np[i] = ' ';
+ }
+ sk->btsk_item = bti;
+ sk->btsk_datum = dp;
+ sk->btsk_nulls = np;
}
- sk->btsk_item = bti;
- sk->btsk_datum = dp;
- sk->btsk_nulls = np;
- }
}
/*-------------------------------------------------------------------------
@@ -254,84 +258,100 @@ _bt_setsortkey(Relation index, BTItem bti, BTSortKey *sk)
* XXX these probably ought to be generic library functions.
*-------------------------------------------------------------------------
*/
-typedef struct {
- int btpqe_tape; /* tape identifier */
- BTSortKey btpqe_item; /* pointer to BTItem in tape buffer */
-} BTPriQueueElem;
-
-#define MAXELEM MAXTAPES
-typedef struct {
- int btpq_nelem;
- BTPriQueueElem btpq_queue[MAXELEM];
- Relation btpq_rel;
-} BTPriQueue;
+typedef struct
+{
+ int btpqe_tape; /* tape identifier */
+ BTSortKey btpqe_item; /* pointer to BTItem in tape buffer */
+} BTPriQueueElem;
+
+#define MAXELEM MAXTAPES
+typedef struct
+{
+ int btpq_nelem;
+ BTPriQueueElem btpq_queue[MAXELEM];
+ Relation btpq_rel;
+} BTPriQueue;
/* be sure to call _bt_isortcmpinit first */
#define GREATER(a, b) \
- (_bt_isortcmp(&((a)->btpqe_item), &((b)->btpqe_item)) > 0)
+ (_bt_isortcmp(&((a)->btpqe_item), &((b)->btpqe_item)) > 0)
static void
-_bt_pqsift(BTPriQueue *q, int parent)
+_bt_pqsift(BTPriQueue * q, int parent)
{
- int child;
- BTPriQueueElem e;
-
- for (child = parent * 2 + 1;
- child < q->btpq_nelem;
- child = parent * 2 + 1) {
- if (child < q->btpq_nelem - 1) {
- if (GREATER(&(q->btpq_queue[child]), &(q->btpq_queue[child+1]))) {
- ++child;
- }
- }
- if (GREATER(&(q->btpq_queue[parent]), &(q->btpq_queue[child]))) {
- e = q->btpq_queue[child]; /* struct = */
- q->btpq_queue[child] = q->btpq_queue[parent]; /* struct = */
- q->btpq_queue[parent] = e; /* struct = */
- parent = child;
- } else {
- parent = child + 1;
+ int child;
+ BTPriQueueElem e;
+
+ for (child = parent * 2 + 1;
+ child < q->btpq_nelem;
+ child = parent * 2 + 1)
+ {
+ if (child < q->btpq_nelem - 1)
+ {
+ if (GREATER(&(q->btpq_queue[child]), &(q->btpq_queue[child + 1])))
+ {
+ ++child;
+ }
+ }
+ if (GREATER(&(q->btpq_queue[parent]), &(q->btpq_queue[child])))
+ {
+ e = q->btpq_queue[child]; /* struct = */
+ q->btpq_queue[child] = q->btpq_queue[parent]; /* struct = */
+ q->btpq_queue[parent] = e; /* struct = */
+ parent = child;
+ }
+ else
+ {
+ parent = child + 1;
+ }
}
- }
}
static int
-_bt_pqnext(BTPriQueue *q, BTPriQueueElem *e)
+_bt_pqnext(BTPriQueue * q, BTPriQueueElem * e)
{
- if (q->btpq_nelem < 1) { /* already empty */
- return(-1);
- }
- *e = q->btpq_queue[0]; /* struct = */
-
- if (--q->btpq_nelem < 1) { /* now empty, don't sift */
- return(0);
- }
- q->btpq_queue[0] = q->btpq_queue[q->btpq_nelem]; /* struct = */
- _bt_pqsift(q, 0);
- return(0);
+ if (q->btpq_nelem < 1)
+ { /* already empty */
+ return (-1);
+ }
+ *e = q->btpq_queue[0]; /* struct = */
+
+ if (--q->btpq_nelem < 1)
+ { /* now empty, don't sift */
+ return (0);
+ }
+ q->btpq_queue[0] = q->btpq_queue[q->btpq_nelem]; /* struct = */
+ _bt_pqsift(q, 0);
+ return (0);
}
static void
-_bt_pqadd(BTPriQueue *q, BTPriQueueElem *e)
+_bt_pqadd(BTPriQueue * q, BTPriQueueElem * e)
{
- int child, parent;
-
- if (q->btpq_nelem >= MAXELEM) {
- elog(WARN, "_bt_pqadd: queue overflow");
- }
-
- child = q->btpq_nelem++;
- while (child > 0) {
- parent = child / 2;
- if (GREATER(e, &(q->btpq_queue[parent]))) {
- break;
- } else {
- q->btpq_queue[child] = q->btpq_queue[parent]; /* struct = */
- child = parent;
+ int child,
+ parent;
+
+ if (q->btpq_nelem >= MAXELEM)
+ {
+ elog(WARN, "_bt_pqadd: queue overflow");
+ }
+
+ child = q->btpq_nelem++;
+ while (child > 0)
+ {
+ parent = child / 2;
+ if (GREATER(e, &(q->btpq_queue[parent])))
+ {
+ break;
+ }
+ else
+ {
+ q->btpq_queue[child] = q->btpq_queue[parent]; /* struct = */
+ child = parent;
+ }
}
- }
- q->btpq_queue[child] = *e; /* struct = */
+ q->btpq_queue[child] = *e; /* struct = */
}
/*-------------------------------------------------------------------------
@@ -339,37 +359,37 @@ _bt_pqadd(BTPriQueue *q, BTPriQueueElem *e)
*-------------------------------------------------------------------------
*/
-#define BTITEMSZ(btitem) \
- ((btitem) ? \
- (IndexTupleDSize((btitem)->bti_itup) + \
- (sizeof(BTItemData) - sizeof(IndexTupleData))) : \
- 0)
-#define SPCLEFT(tape) \
- (sizeof((tape)->bttb_data) - (tape)->bttb_top)
-#define EMPTYTAPE(tape) \
- ((tape)->bttb_ntup <= 0)
-#define BTTAPEMAGIC 0x19660226
+#define BTITEMSZ(btitem) \
+ ((btitem) ? \
+ (IndexTupleDSize((btitem)->bti_itup) + \
+ (sizeof(BTItemData) - sizeof(IndexTupleData))) : \
+ 0)
+#define SPCLEFT(tape) \
+ (sizeof((tape)->bttb_data) - (tape)->bttb_top)
+#define EMPTYTAPE(tape) \
+ ((tape)->bttb_ntup <= 0)
+#define BTTAPEMAGIC 0x19660226
/*
* reset the tape header for its next use without doing anything to
- * the physical tape file. (setting bttb_top to 0 makes the block
+ * the physical tape file. (setting bttb_top to 0 makes the block
* empty.)
*/
static void
-_bt_tapereset(BTTapeBlock *tape)
+_bt_tapereset(BTTapeBlock * tape)
{
- tape->bttb_eor = 0;
- tape->bttb_top = 0;
- tape->bttb_ntup = 0;
+ tape->bttb_eor = 0;
+ tape->bttb_top = 0;
+ tape->bttb_ntup = 0;
}
/*
* rewind the physical tape file.
*/
static void
-_bt_taperewind(BTTapeBlock *tape)
+_bt_taperewind(BTTapeBlock * tape)
{
- FileSeek(tape->bttb_fd, 0, SEEK_SET);
+ FileSeek(tape->bttb_fd, 0, SEEK_SET);
}
/*
@@ -382,17 +402,17 @@ _bt_taperewind(BTTapeBlock *tape)
* least you don't have to delete and reinsert the directory entries.
*/
static void
-_bt_tapeclear(BTTapeBlock *tape)
+_bt_tapeclear(BTTapeBlock * tape)
{
- /* blow away the contents of the old file */
- _bt_taperewind(tape);
+ /* blow away the contents of the old file */
+ _bt_taperewind(tape);
#if 0
- FileSync(tape->bttb_fd);
+ FileSync(tape->bttb_fd);
#endif
- FileTruncate(tape->bttb_fd, 0);
+ FileTruncate(tape->bttb_fd, 0);
- /* reset the buffer */
- _bt_tapereset(tape);
+ /* reset the buffer */
+ _bt_tapereset(tape);
}
/*
@@ -402,43 +422,44 @@ _bt_tapeclear(BTTapeBlock *tape)
static BTTapeBlock *
_bt_tapecreate(char *fname)
{
- BTTapeBlock *tape = (BTTapeBlock *) palloc(sizeof(BTTapeBlock));
+ BTTapeBlock *tape = (BTTapeBlock *) palloc(sizeof(BTTapeBlock));
- if (tape == (BTTapeBlock *) NULL) {
- elog(WARN, "_bt_tapecreate: out of memory");
- }
+ if (tape == (BTTapeBlock *) NULL)
+ {
+ elog(WARN, "_bt_tapecreate: out of memory");
+ }
- tape->bttb_magic = BTTAPEMAGIC;
+ tape->bttb_magic = BTTAPEMAGIC;
- tape->bttb_fd = FileNameOpenFile(fname, O_RDWR|O_CREAT|O_TRUNC, 0600);
- Assert(tape->bttb_fd >= 0);
+ tape->bttb_fd = FileNameOpenFile(fname, O_RDWR | O_CREAT | O_TRUNC, 0600);
+ Assert(tape->bttb_fd >= 0);
- /* initialize the buffer */
- _bt_tapereset(tape);
+ /* initialize the buffer */
+ _bt_tapereset(tape);
- return(tape);
+ return (tape);
}
/*
* destroy the BTTapeBlock structure and its physical tape file.
*/
static void
-_bt_tapedestroy(BTTapeBlock *tape)
+_bt_tapedestroy(BTTapeBlock * tape)
{
- FileUnlink(tape->bttb_fd);
- pfree((void *) tape);
+ FileUnlink(tape->bttb_fd);
+ pfree((void *) tape);
}
/*
* flush the tape block to the file, marking End-Of-Run if requested.
*/
static void
-_bt_tapewrite(BTTapeBlock *tape, int eor)
+_bt_tapewrite(BTTapeBlock * tape, int eor)
{
- tape->bttb_eor = eor;
- FileWrite(tape->bttb_fd, (char *) tape, TAPEBLCKSZ);
- NDirectFileWrite += TAPEBLCKSZ/MAXBLCKSZ;
- _bt_tapereset(tape);
+ tape->bttb_eor = eor;
+ FileWrite(tape->bttb_fd, (char *) tape, TAPEBLCKSZ);
+ NDirectFileWrite += TAPEBLCKSZ / MAXBLCKSZ;
+ _bt_tapereset(tape);
}
/*
@@ -447,34 +468,36 @@ _bt_tapewrite(BTTapeBlock *tape, int eor)
*
* returns:
* - 0 if there are no more blocks in the tape or in this run (call
- * _bt_tapereset to clear the End-Of-Run marker)
+ * _bt_tapereset to clear the End-Of-Run marker)
* - 1 if a valid block was read
*/
static int
-_bt_taperead(BTTapeBlock *tape)
+_bt_taperead(BTTapeBlock * tape)
{
- int fd;
- int nread;
-
- if (tape->bttb_eor) {
- return(0); /* we are already at End-Of-Run */
- }
-
- /*
- * we're clobbering the old tape block, but we do need to save the
- * VFD (the one in the block we're reading is bogus).
- */
- fd = tape->bttb_fd;
- nread = FileRead(fd, (char *) tape, TAPEBLCKSZ);
- tape->bttb_fd = fd;
-
- if (nread != TAPEBLCKSZ) {
- Assert(nread == 0); /* we are at EOF */
- return(0);
- }
- Assert(tape->bttb_magic == BTTAPEMAGIC);
- NDirectFileRead += TAPEBLCKSZ/MAXBLCKSZ;
- return(1);
+ int fd;
+ int nread;
+
+ if (tape->bttb_eor)
+ {
+ return (0); /* we are already at End-Of-Run */
+ }
+
+ /*
+ * we're clobbering the old tape block, but we do need to save the VFD
+ * (the one in the block we're reading is bogus).
+ */
+ fd = tape->bttb_fd;
+ nread = FileRead(fd, (char *) tape, TAPEBLCKSZ);
+ tape->bttb_fd = fd;
+
+ if (nread != TAPEBLCKSZ)
+ {
+ Assert(nread == 0); /* we are at EOF */
+ return (0);
+ }
+ Assert(tape->bttb_magic == BTTAPEMAGIC);
+ NDirectFileRead += TAPEBLCKSZ / MAXBLCKSZ;
+ return (1);
}
/*
@@ -487,19 +510,20 @@ _bt_taperead(BTTapeBlock *tape)
* side effects:
* - sets 'pos' to the current position within the block.
*/
-static BTItem
-_bt_tapenext(BTTapeBlock *tape, char **pos)
+static BTItem
+_bt_tapenext(BTTapeBlock * tape, char **pos)
{
- Size itemsz;
- BTItem bti;
-
- if (*pos >= tape->bttb_data + tape->bttb_top) {
- return((BTItem) NULL);
- }
- bti = (BTItem) *pos;
- itemsz = BTITEMSZ(bti);
- *pos += DOUBLEALIGN(itemsz);
- return(bti);
+ Size itemsz;
+ BTItem bti;
+
+ if (*pos >= tape->bttb_data + tape->bttb_top)
+ {
+ return ((BTItem) NULL);
+ }
+ bti = (BTItem) * pos;
+ itemsz = BTITEMSZ(bti);
+ *pos += DOUBLEALIGN(itemsz);
+ return (bti);
}
/*
@@ -514,11 +538,11 @@ _bt_tapenext(BTTapeBlock *tape, char **pos)
* the beginning of free space.
*/
static void
-_bt_tapeadd(BTTapeBlock *tape, BTItem item, int itemsz)
+_bt_tapeadd(BTTapeBlock * tape, BTItem item, int itemsz)
{
- memcpy(tape->bttb_data + tape->bttb_top, item, itemsz);
- ++tape->bttb_ntup;
- tape->bttb_top += DOUBLEALIGN(itemsz);
+ memcpy(tape->bttb_data + tape->bttb_top, item, itemsz);
+ ++tape->bttb_ntup;
+ tape->bttb_top += DOUBLEALIGN(itemsz);
}
/*-------------------------------------------------------------------------
@@ -530,41 +554,44 @@ _bt_tapeadd(BTTapeBlock *tape, BTItem item, int itemsz)
* create and initialize a spool structure, including the underlying
* files.
*/
-void *
+void *
_bt_spoolinit(Relation index, int ntapes, bool isunique)
{
- BTSpool *btspool = (BTSpool *) palloc(sizeof(BTSpool));
- int i;
- char *fname = (char *) palloc(sizeof(TAPETEMP) + 1);
-
- if (btspool == (BTSpool *) NULL || fname == (char *) NULL) {
- elog(WARN, "_bt_spoolinit: out of memory");
- }
- memset((char *) btspool, 0, sizeof(BTSpool));
- btspool->bts_ntapes = ntapes;
- btspool->bts_tape = 0;
- btspool->isunique = isunique;
-
- btspool->bts_itape =
- (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
- btspool->bts_otape =
- (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
- if (btspool->bts_itape == (BTTapeBlock **) NULL ||
- btspool->bts_otape == (BTTapeBlock **) NULL) {
- elog(WARN, "_bt_spoolinit: out of memory");
- }
-
- for (i = 0; i < ntapes; ++i) {
- btspool->bts_itape[i] =
- _bt_tapecreate(mktemp(strcpy(fname, TAPETEMP)));
- btspool->bts_otape[i] =
- _bt_tapecreate(mktemp(strcpy(fname, TAPETEMP)));
- }
- pfree((void *) fname);
-
- _bt_isortcmpinit(index, btspool);
-
- return((void *) btspool);
+ BTSpool *btspool = (BTSpool *) palloc(sizeof(BTSpool));
+ int i;
+ char *fname = (char *) palloc(sizeof(TAPETEMP) + 1);
+
+ if (btspool == (BTSpool *) NULL || fname == (char *) NULL)
+ {
+ elog(WARN, "_bt_spoolinit: out of memory");
+ }
+ memset((char *) btspool, 0, sizeof(BTSpool));
+ btspool->bts_ntapes = ntapes;
+ btspool->bts_tape = 0;
+ btspool->isunique = isunique;
+
+ btspool->bts_itape =
+ (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
+ btspool->bts_otape =
+ (BTTapeBlock **) palloc(sizeof(BTTapeBlock *) * ntapes);
+ if (btspool->bts_itape == (BTTapeBlock **) NULL ||
+ btspool->bts_otape == (BTTapeBlock **) NULL)
+ {
+ elog(WARN, "_bt_spoolinit: out of memory");
+ }
+
+ for (i = 0; i < ntapes; ++i)
+ {
+ btspool->bts_itape[i] =
+ _bt_tapecreate(mktemp(strcpy(fname, TAPETEMP)));
+ btspool->bts_otape[i] =
+ _bt_tapecreate(mktemp(strcpy(fname, TAPETEMP)));
+ }
+ pfree((void *) fname);
+
+ _bt_isortcmpinit(index, btspool);
+
+ return ((void *) btspool);
}
/*
@@ -573,29 +600,32 @@ _bt_spoolinit(Relation index, int ntapes, bool isunique)
void
_bt_spooldestroy(void *spool)
{
- BTSpool *btspool = (BTSpool *) spool;
- int i;
-
- for (i = 0; i < btspool->bts_ntapes; ++i) {
- _bt_tapedestroy(btspool->bts_otape[i]);
- _bt_tapedestroy(btspool->bts_itape[i]);
- }
- pfree((void *) btspool);
+ BTSpool *btspool = (BTSpool *) spool;
+ int i;
+
+ for (i = 0; i < btspool->bts_ntapes; ++i)
+ {
+ _bt_tapedestroy(btspool->bts_otape[i]);
+ _bt_tapedestroy(btspool->bts_itape[i]);
+ }
+ pfree((void *) btspool);
}
/*
* flush out any dirty output tape blocks
*/
static void
-_bt_spoolflush(BTSpool *btspool)
+_bt_spoolflush(BTSpool * btspool)
{
- int i;
+ int i;
- for (i = 0; i < btspool->bts_ntapes; ++i) {
- if (!EMPTYTAPE(btspool->bts_otape[i])) {
- _bt_tapewrite(btspool->bts_otape[i], 1);
+ for (i = 0; i < btspool->bts_ntapes; ++i)
+ {
+ if (!EMPTYTAPE(btspool->bts_otape[i]))
+ {
+ _bt_tapewrite(btspool->bts_otape[i], 1);
+ }
}
- }
}
/*
@@ -605,36 +635,37 @@ _bt_spoolflush(BTSpool *btspool)
* output tapes.
*/
static void
-_bt_spoolswap(BTSpool *btspool)
+_bt_spoolswap(BTSpool * btspool)
{
- File tmpfd;
- BTTapeBlock *itape;
- BTTapeBlock *otape;
- int i;
+ File tmpfd;
+ BTTapeBlock *itape;
+ BTTapeBlock *otape;
+ int i;
- for (i = 0; i < btspool->bts_ntapes; ++i) {
- itape = btspool->bts_itape[i];
- otape = btspool->bts_otape[i];
+ for (i = 0; i < btspool->bts_ntapes; ++i)
+ {
+ itape = btspool->bts_itape[i];
+ otape = btspool->bts_otape[i];
- /*
- * swap the input and output VFDs.
- */
- tmpfd = itape->bttb_fd;
- itape->bttb_fd = otape->bttb_fd;
- otape->bttb_fd = tmpfd;
+ /*
+ * swap the input and output VFDs.
+ */
+ tmpfd = itape->bttb_fd;
+ itape->bttb_fd = otape->bttb_fd;
+ otape->bttb_fd = tmpfd;
- /*
- * rewind the new input tape.
- */
- _bt_taperewind(itape);
- _bt_tapereset(itape);
+ /*
+ * rewind the new input tape.
+ */
+ _bt_taperewind(itape);
+ _bt_tapereset(itape);
- /*
- * clear the new output tape -- it's ok to throw away the old
- * inputs.
- */
- _bt_tapeclear(otape);
- }
+ /*
+ * clear the new output tape -- it's ok to throw away the old
+ * inputs.
+ */
+ _bt_tapeclear(otape);
+ }
}
/*-------------------------------------------------------------------------
@@ -643,7 +674,7 @@ _bt_spoolswap(BTSpool *btspool)
*/
/*
- * spool 'btitem' into an initial run. as tape blocks are filled, the
+ * spool 'btitem' into an initial run. as tape blocks are filled, the
* block BTItems are qsorted and written into some output tape (it
* doesn't matter which; we go round-robin for simplicity). the
* initial runs are therefore always just one block.
@@ -651,134 +682,137 @@ _bt_spoolswap(BTSpool *btspool)
void
_bt_spool(Relation index, BTItem btitem, void *spool)
{
- BTSpool *btspool = (BTSpool *) spool;
- BTTapeBlock *itape;
- Size itemsz;
-
- _bt_isortcmpinit (index, btspool);
-
- itape = btspool->bts_itape[btspool->bts_tape];
- itemsz = BTITEMSZ(btitem);
- itemsz = DOUBLEALIGN(itemsz);
-
- /*
- * if this buffer is too full for this BTItemData, or if we have
- * run out of BTItems, we need to sort the buffer and write it
- * out. in this case, the BTItemData will go into the next tape's
- * buffer.
- */
- if (btitem == (BTItem) NULL || SPCLEFT(itape) < itemsz) {
- BTSortKey *parray = (BTSortKey *) NULL;
- BTTapeBlock *otape;
- BTItem bti;
- char *pos;
- int btisz;
- int it_ntup = itape->bttb_ntup;
- int i;
+ BTSpool *btspool = (BTSpool *) spool;
+ BTTapeBlock *itape;
+ Size itemsz;
- /*
- * build an array of pointers to the BTItemDatas on the input
- * block.
- */
- if (it_ntup > 0) {
- parray =
- (BTSortKey *) palloc(it_ntup * sizeof(BTSortKey));
- pos = itape->bttb_data;
- for (i = 0; i < it_ntup; ++i) {
- _bt_setsortkey(index, _bt_tapenext(itape, &pos), &(parray[i]));
- }
-
- /*
- * qsort the pointer array.
- */
- qsort((void *) parray, it_ntup, sizeof(BTSortKey),
- (int (*)(const void *,const void *))_bt_isortcmp);
- }
+ _bt_isortcmpinit(index, btspool);
+
+ itape = btspool->bts_itape[btspool->bts_tape];
+ itemsz = BTITEMSZ(btitem);
+ itemsz = DOUBLEALIGN(itemsz);
/*
- * write the spooled run into the output tape. we copy the
- * BTItemDatas in the order dictated by the sorted array of
- * BTItems, not the original order.
- *
- * (since everything was DOUBLEALIGN'd and is all on a single
- * tape block, everything had *better* still fit on one tape
- * block..)
+ * if this buffer is too full for this BTItemData, or if we have run
+ * out of BTItems, we need to sort the buffer and write it out. in
+ * this case, the BTItemData will go into the next tape's buffer.
*/
- otape = btspool->bts_otape[btspool->bts_tape];
- for (i = 0; i < it_ntup; ++i) {
- bti = parray[i].btsk_item;
- btisz = BTITEMSZ(bti);
- btisz = DOUBLEALIGN(btisz);
- _bt_tapeadd(otape, bti, btisz);
+ if (btitem == (BTItem) NULL || SPCLEFT(itape) < itemsz)
+ {
+ BTSortKey *parray = (BTSortKey *) NULL;
+ BTTapeBlock *otape;
+ BTItem bti;
+ char *pos;
+ int btisz;
+ int it_ntup = itape->bttb_ntup;
+ int i;
+
+ /*
+ * build an array of pointers to the BTItemDatas on the input
+ * block.
+ */
+ if (it_ntup > 0)
+ {
+ parray =
+ (BTSortKey *) palloc(it_ntup * sizeof(BTSortKey));
+ pos = itape->bttb_data;
+ for (i = 0; i < it_ntup; ++i)
+ {
+ _bt_setsortkey(index, _bt_tapenext(itape, &pos), &(parray[i]));
+ }
+
+ /*
+ * qsort the pointer array.
+ */
+ qsort((void *) parray, it_ntup, sizeof(BTSortKey),
+ (int (*) (const void *, const void *)) _bt_isortcmp);
+ }
+
+ /*
+ * write the spooled run into the output tape. we copy the
+ * BTItemDatas in the order dictated by the sorted array of
+ * BTItems, not the original order.
+ *
+ * (since everything was DOUBLEALIGN'd and is all on a single tape
+ * block, everything had *better* still fit on one tape block..)
+ */
+ otape = btspool->bts_otape[btspool->bts_tape];
+ for (i = 0; i < it_ntup; ++i)
+ {
+ bti = parray[i].btsk_item;
+ btisz = BTITEMSZ(bti);
+ btisz = DOUBLEALIGN(btisz);
+ _bt_tapeadd(otape, bti, btisz);
#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_SPOOL)
- {
- bool isnull;
- Datum d = index_getattr(&(bti->bti_itup), 1, index->rd_att,
- &isnull);
- printf("_bt_spool: inserted <%x> into output tape %d\n",
- d, btspool->bts_tape);
- }
-#endif /* FASTBUILD_DEBUG && FASTBUILD_SPOOL */
- }
+ {
+ bool isnull;
+ Datum d = index_getattr(&(bti->bti_itup), 1, index->rd_att,
+ &isnull);
- /*
- * the initial runs are always single tape blocks. flush the
- * output block, marking End-Of-Run.
- */
- _bt_tapewrite(otape, 1);
+ printf("_bt_spool: inserted <%x> into output tape %d\n",
+ d, btspool->bts_tape);
+ }
+#endif /* FASTBUILD_DEBUG && FASTBUILD_SPOOL */
+ }
- /*
- * reset the input buffer for the next run. we don't have to
- * write it out or anything -- we only use it to hold the
- * unsorted BTItemDatas, the output tape contains all the
- * sorted stuff.
- *
- * changing bts_tape changes the output tape and input tape;
- * we change itape for the code below.
- */
- _bt_tapereset(itape);
- btspool->bts_tape = (btspool->bts_tape + 1) % btspool->bts_ntapes;
- itape = btspool->bts_itape[btspool->bts_tape];
+ /*
+ * the initial runs are always single tape blocks. flush the
+ * output block, marking End-Of-Run.
+ */
+ _bt_tapewrite(otape, 1);
- /*
- * destroy the pointer array.
- */
- if (parray != (BTSortKey *) NULL)
- {
- for (i = 0; i < it_ntup; i++)
- {
- if ( parray[i].btsk_datum != (Datum*) NULL )
- pfree ((void*)(parray[i].btsk_datum));
- if ( parray[i].btsk_nulls != (char*) NULL )
- pfree ((void*)(parray[i].btsk_nulls));
- }
- pfree((void *) parray);
+ /*
+ * reset the input buffer for the next run. we don't have to
+ * write it out or anything -- we only use it to hold the unsorted
+ * BTItemDatas, the output tape contains all the sorted stuff.
+ *
+ * changing bts_tape changes the output tape and input tape; we
+ * change itape for the code below.
+ */
+ _bt_tapereset(itape);
+ btspool->bts_tape = (btspool->bts_tape + 1) % btspool->bts_ntapes;
+ itape = btspool->bts_itape[btspool->bts_tape];
+
+ /*
+ * destroy the pointer array.
+ */
+ if (parray != (BTSortKey *) NULL)
+ {
+ for (i = 0; i < it_ntup; i++)
+ {
+ if (parray[i].btsk_datum != (Datum *) NULL)
+ pfree((void *) (parray[i].btsk_datum));
+ if (parray[i].btsk_nulls != (char *) NULL)
+ pfree((void *) (parray[i].btsk_nulls));
+ }
+ pfree((void *) parray);
+ }
}
- }
- /* insert this item into the current buffer */
- if (btitem != (BTItem) NULL) {
- _bt_tapeadd(itape, btitem, itemsz);
- }
+ /* insert this item into the current buffer */
+ if (btitem != (BTItem) NULL)
+ {
+ _bt_tapeadd(itape, btitem, itemsz);
+ }
}
/*
* allocate a new, clean btree page, not linked to any siblings.
*/
static void
-_bt_blnewpage(Relation index, Buffer *buf, Page *page, int flags)
+_bt_blnewpage(Relation index, Buffer * buf, Page * page, int flags)
{
- BTPageOpaque opaque;
+ BTPageOpaque opaque;
- *buf = _bt_getbuf(index, P_NEW, BT_WRITE);
+ *buf = _bt_getbuf(index, P_NEW, BT_WRITE);
#if 0
- printf("\tblk=%d\n", BufferGetBlockNumber(*buf));
+ printf("\tblk=%d\n", BufferGetBlockNumber(*buf));
#endif
- *page = BufferGetPage(*buf);
- _bt_pageinit(*page, BufferGetPageSize(*buf));
- opaque = (BTPageOpaque) PageGetSpecialPointer(*page);
- opaque->btpo_prev = opaque->btpo_next = P_NONE;
- opaque->btpo_flags = flags;
+ *page = BufferGetPage(*buf);
+ _bt_pageinit(*page, BufferGetPageSize(*buf));
+ opaque = (BTPageOpaque) PageGetSpecialPointer(*page);
+ opaque->btpo_prev = opaque->btpo_next = P_NONE;
+ opaque->btpo_flags = flags;
}
/*
@@ -790,42 +824,44 @@ _bt_blnewpage(Relation index, Buffer *buf, Page *page, int flags)
static void
_bt_slideleft(Relation index, Buffer buf, Page page)
{
- OffsetNumber off;
- OffsetNumber maxoff;
- ItemId previi;
- ItemId thisii;
-
- if (!PageIsEmpty(page)) {
- maxoff = PageGetMaxOffsetNumber(page);
- previi = PageGetItemId(page, P_HIKEY);
- for (off = P_FIRSTKEY; off <= maxoff; off = OffsetNumberNext(off)) {
- thisii = PageGetItemId(page, off);
- *previi = *thisii;
- previi = thisii;
+ OffsetNumber off;
+ OffsetNumber maxoff;
+ ItemId previi;
+ ItemId thisii;
+
+ if (!PageIsEmpty(page))
+ {
+ maxoff = PageGetMaxOffsetNumber(page);
+ previi = PageGetItemId(page, P_HIKEY);
+ for (off = P_FIRSTKEY; off <= maxoff; off = OffsetNumberNext(off))
+ {
+ thisii = PageGetItemId(page, off);
+ *previi = *thisii;
+ previi = thisii;
+ }
+ ((PageHeader) page)->pd_lower -= sizeof(ItemIdData);
}
- ((PageHeader) page)->pd_lower -= sizeof(ItemIdData);
- }
}
/*
* allocate and initialize a new BTPageState. the returned structure
* is suitable for immediate use by _bt_buildadd.
*/
-static void *
+static void *
_bt_pagestate(Relation index, int flags, int level, bool doupper)
{
- BTPageState *state = (BTPageState *) palloc(sizeof(BTPageState));
-
- memset((char *) state, 0, sizeof(BTPageState));
- _bt_blnewpage(index, &(state->btps_buf), &(state->btps_page), flags);
- state->btps_firstoff = InvalidOffsetNumber;
- state->btps_lastoff = P_HIKEY;
- state->btps_lastbti = (BTItem) NULL;
- state->btps_next = (BTPageState *) NULL;
- state->btps_level = level;
- state->btps_doupper = doupper;
-
- return((void *) state);
+ BTPageState *state = (BTPageState *) palloc(sizeof(BTPageState));
+
+ memset((char *) state, 0, sizeof(BTPageState));
+ _bt_blnewpage(index, &(state->btps_buf), &(state->btps_page), flags);
+ state->btps_firstoff = InvalidOffsetNumber;
+ state->btps_lastoff = P_HIKEY;
+ state->btps_lastbti = (BTItem) NULL;
+ state->btps_next = (BTPageState *) NULL;
+ state->btps_level = level;
+ state->btps_doupper = doupper;
+
+ return ((void *) state);
}
/*
@@ -834,19 +870,19 @@ _bt_pagestate(Relation index, int flags, int level, bool doupper)
* the page to which the item used to point, e.g., a heap page if
* 'opage' is a leaf page).
*/
-static BTItem
+static BTItem
_bt_minitem(Page opage, BlockNumber oblkno, int atend)
{
- OffsetNumber off;
- BTItem obti;
- BTItem nbti;
+ OffsetNumber off;
+ BTItem obti;
+ BTItem nbti;
- off = atend ? P_HIKEY : P_FIRSTKEY;
- obti = (BTItem) PageGetItem(opage, PageGetItemId(opage, off));
- nbti = _bt_formitem(&(obti->bti_itup));
- ItemPointerSet(&(nbti->bti_itup.t_tid), oblkno, P_HIKEY);
+ off = atend ? P_HIKEY : P_FIRSTKEY;
+ obti = (BTItem) PageGetItem(opage, PageGetItemId(opage, off));
+ nbti = _bt_formitem(&(obti->bti_itup));
+ ItemPointerSet(&(nbti->bti_itup.t_tid), oblkno, P_HIKEY);
- return(nbti);
+ return (nbti);
}
/*
@@ -855,26 +891,26 @@ _bt_minitem(Page opage, BlockNumber oblkno, int atend)
* we must be careful to observe the following restrictions, placed
* upon us by the conventions in nbtsearch.c:
* - rightmost pages start data items at P_HIKEY instead of at
- * P_FIRSTKEY.
+ * P_FIRSTKEY.
* - duplicates cannot be split among pages unless the chain of
- * duplicates starts at the first data item.
+ * duplicates starts at the first data item.
*
* a leaf page being built looks like:
*
* +----------------+---------------------------------+
- * | PageHeaderData | linp0 linp1 linp2 ... |
+ * | PageHeaderData | linp0 linp1 linp2 ... |
* +-----------+----+---------------------------------+
- * | ... linpN | ^ first |
+ * | ... linpN | ^ first |
* +-----------+--------------------------------------+
- * | ^ last |
- * | |
- * | v last |
+ * | ^ last |
+ * | |
+ * | v last |
* +-------------+------------------------------------+
- * | | itemN ... |
+ * | | itemN ... |
* +-------------+------------------+-----------------+
- * | ... item3 item2 item1 | "special space" |
+ * | ... item3 item2 item1 | "special space" |
* +--------------------------------+-----------------+
- * ^ first
+ * ^ first
*
* contrast this with the diagram in bufpage.h; note the mismatch
* between linps and items. this is because we reserve linp0 as a
@@ -888,216 +924,230 @@ _bt_minitem(Page opage, BlockNumber oblkno, int atend)
*
* if all keys are unique, 'first' will always be the same as 'last'.
*/
-static BTItem
+static BTItem
_bt_buildadd(Relation index, void *pstate, BTItem bti, int flags)
{
- BTPageState *state = (BTPageState *) pstate;
- Buffer nbuf;
- Page npage;
- BTItem last_bti;
- OffsetNumber first_off;
- OffsetNumber last_off;
- OffsetNumber off;
- Size pgspc;
- Size btisz;
-
- nbuf = state->btps_buf;
- npage = state->btps_page;
- first_off = state->btps_firstoff;
- last_off = state->btps_lastoff;
- last_bti = state->btps_lastbti;
-
- pgspc = PageGetFreeSpace(npage);
- btisz = BTITEMSZ(bti);
- btisz = DOUBLEALIGN(btisz);
- if (pgspc < btisz) {
- Buffer obuf = nbuf;
- Page opage = npage;
- OffsetNumber o, n;
- ItemId ii;
- ItemId hii;
-
- _bt_blnewpage(index, &nbuf, &npage, flags);
+ BTPageState *state = (BTPageState *) pstate;
+ Buffer nbuf;
+ Page npage;
+ BTItem last_bti;
+ OffsetNumber first_off;
+ OffsetNumber last_off;
+ OffsetNumber off;
+ Size pgspc;
+ Size btisz;
+
+ nbuf = state->btps_buf;
+ npage = state->btps_page;
+ first_off = state->btps_firstoff;
+ last_off = state->btps_lastoff;
+ last_bti = state->btps_lastbti;
+
+ pgspc = PageGetFreeSpace(npage);
+ btisz = BTITEMSZ(bti);
+ btisz = DOUBLEALIGN(btisz);
+ if (pgspc < btisz)
+ {
+ Buffer obuf = nbuf;
+ Page opage = npage;
+ OffsetNumber o,
+ n;
+ ItemId ii;
+ ItemId hii;
- /*
- * if 'last' is part of a chain of duplicates that does not
- * start at the beginning of the old page, the entire chain is
- * copied to the new page; we delete all of the duplicates
- * from the old page except the first, which becomes the high
- * key item of the old page.
- *
- * if the chain starts at the beginning of the page or there
- * is no chain ('first' == 'last'), we need only copy 'last'
- * to the new page. again, 'first' (== 'last') becomes the
- * high key of the old page.
- *
- * note that in either case, we copy at least one item to the
- * new page, so 'last_bti' will always be valid. 'bti' will
- * never be the first data item on the new page.
- */
- if (first_off == P_FIRSTKEY) {
- Assert(last_off != P_FIRSTKEY);
- first_off = last_off;
- }
- for (o = first_off, n = P_FIRSTKEY;
- o <= last_off;
- o = OffsetNumberNext(o), n = OffsetNumberNext(n)) {
- ii = PageGetItemId(opage, o);
- if ( PageAddItem(npage, PageGetItem(opage, ii),
- ii->lp_len, n, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add item to the page in _bt_sort (1)");
+ _bt_blnewpage(index, &nbuf, &npage, flags);
+
+ /*
+ * if 'last' is part of a chain of duplicates that does not start
+ * at the beginning of the old page, the entire chain is copied to
+ * the new page; we delete all of the duplicates from the old page
+ * except the first, which becomes the high key item of the old
+ * page.
+ *
+ * if the chain starts at the beginning of the page or there is no
+ * chain ('first' == 'last'), we need only copy 'last' to the new
+ * page. again, 'first' (== 'last') becomes the high key of the
+ * old page.
+ *
+ * note that in either case, we copy at least one item to the new
+ * page, so 'last_bti' will always be valid. 'bti' will never be
+ * the first data item on the new page.
+ */
+ if (first_off == P_FIRSTKEY)
+ {
+ Assert(last_off != P_FIRSTKEY);
+ first_off = last_off;
+ }
+ for (o = first_off, n = P_FIRSTKEY;
+ o <= last_off;
+ o = OffsetNumberNext(o), n = OffsetNumberNext(n))
+ {
+ ii = PageGetItemId(opage, o);
+ if (PageAddItem(npage, PageGetItem(opage, ii),
+ ii->lp_len, n, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add item to the page in _bt_sort (1)");
#if 0
#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
- {
- bool isnull;
- BTItem tmpbti =
- (BTItem) PageGetItem(npage, PageGetItemId(npage, n));
- Datum d = index_getattr(&(tmpbti->bti_itup), 1,
- index->rd_att, &isnull);
- printf("_bt_buildadd: moved <%x> to offset %d at level %d\n",
- d, n, state->btps_level);
- }
-#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
+ {
+ bool isnull;
+ BTItem tmpbti =
+ (BTItem) PageGetItem(npage, PageGetItemId(npage, n));
+ Datum d = index_getattr(&(tmpbti->bti_itup), 1,
+ index->rd_att, &isnull);
+
+ printf("_bt_buildadd: moved <%x> to offset %d at level %d\n",
+ d, n, state->btps_level);
+ }
+#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
#endif
- }
- /*
- * this loop is backward because PageIndexTupleDelete shuffles
- * the tuples to fill holes in the page -- by starting at the
- * end and working back, we won't create holes (and thereby
- * avoid shuffling).
- */
- for (o = last_off; o > first_off; o = OffsetNumberPrev(o)) {
- PageIndexTupleDelete(opage, o);
- }
- hii = PageGetItemId(opage, P_HIKEY);
- ii = PageGetItemId(opage, first_off);
- *hii = *ii;
- ii->lp_flags &= ~LP_USED;
- ((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
+ }
- first_off = P_FIRSTKEY;
- last_off = PageGetMaxOffsetNumber(npage);
- last_bti = (BTItem) PageGetItem(npage, PageGetItemId(npage, last_off));
+ /*
+ * this loop is backward because PageIndexTupleDelete shuffles the
+ * tuples to fill holes in the page -- by starting at the end and
+ * working back, we won't create holes (and thereby avoid
+ * shuffling).
+ */
+ for (o = last_off; o > first_off; o = OffsetNumberPrev(o))
+ {
+ PageIndexTupleDelete(opage, o);
+ }
+ hii = PageGetItemId(opage, P_HIKEY);
+ ii = PageGetItemId(opage, first_off);
+ *hii = *ii;
+ ii->lp_flags &= ~LP_USED;
+ ((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
- /*
- * set the page (side link) pointers.
- */
- {
- BTPageOpaque oopaque = (BTPageOpaque) PageGetSpecialPointer(opage);
- BTPageOpaque nopaque = (BTPageOpaque) PageGetSpecialPointer(npage);
-
- oopaque->btpo_next = BufferGetBlockNumber(nbuf);
- nopaque->btpo_prev = BufferGetBlockNumber(obuf);
- nopaque->btpo_next = P_NONE;
-
- if ( _bt_itemcmp(index, _bt_nattr,
- (BTItem) PageGetItem(opage, PageGetItemId(opage, P_HIKEY)),
- (BTItem) PageGetItem(opage, PageGetItemId(opage, P_FIRSTKEY)),
- BTEqualStrategyNumber) )
- oopaque->btpo_flags |= BTP_CHAIN;
- }
+ first_off = P_FIRSTKEY;
+ last_off = PageGetMaxOffsetNumber(npage);
+ last_bti = (BTItem) PageGetItem(npage, PageGetItemId(npage, last_off));
- /*
- * copy the old buffer's minimum key to its parent. if we
- * don't have a parent, we have to create one; this adds a new
- * btree level.
- */
- if (state->btps_doupper) {
- BTItem nbti;
-
- if (state->btps_next == (BTPageState *) NULL) {
- state->btps_next =
- _bt_pagestate(index, 0, state->btps_level + 1, true);
- }
- nbti = _bt_minitem(opage, BufferGetBlockNumber(obuf), 0);
- _bt_buildadd(index, state->btps_next, nbti, 0);
- pfree((void *) nbti);
+ /*
+ * set the page (side link) pointers.
+ */
+ {
+ BTPageOpaque oopaque = (BTPageOpaque) PageGetSpecialPointer(opage);
+ BTPageOpaque nopaque = (BTPageOpaque) PageGetSpecialPointer(npage);
+
+ oopaque->btpo_next = BufferGetBlockNumber(nbuf);
+ nopaque->btpo_prev = BufferGetBlockNumber(obuf);
+ nopaque->btpo_next = P_NONE;
+
+ if (_bt_itemcmp(index, _bt_nattr,
+ (BTItem) PageGetItem(opage, PageGetItemId(opage, P_HIKEY)),
+ (BTItem) PageGetItem(opage, PageGetItemId(opage, P_FIRSTKEY)),
+ BTEqualStrategyNumber))
+ oopaque->btpo_flags |= BTP_CHAIN;
+ }
+
+ /*
+ * copy the old buffer's minimum key to its parent. if we don't
+ * have a parent, we have to create one; this adds a new btree
+ * level.
+ */
+ if (state->btps_doupper)
+ {
+ BTItem nbti;
+
+ if (state->btps_next == (BTPageState *) NULL)
+ {
+ state->btps_next =
+ _bt_pagestate(index, 0, state->btps_level + 1, true);
+ }
+ nbti = _bt_minitem(opage, BufferGetBlockNumber(obuf), 0);
+ _bt_buildadd(index, state->btps_next, nbti, 0);
+ pfree((void *) nbti);
+ }
+
+ /*
+ * write out the old stuff. we never want to see it again, so we
+ * can give up our lock (if we had one; BuildingBtree is set, so
+ * we aren't locking).
+ */
+ _bt_wrtbuf(index, obuf);
}
/*
- * write out the old stuff. we never want to see it again, so
- * we can give up our lock (if we had one; BuildingBtree is
- * set, so we aren't locking).
+ * if this item is different from the last item added, we start a new
+ * chain of duplicates.
*/
- _bt_wrtbuf(index, obuf);
- }
-
- /*
- * if this item is different from the last item added, we start a
- * new chain of duplicates.
- */
- off = OffsetNumberNext(last_off);
- if ( PageAddItem(npage, (Item) bti, btisz, off, LP_USED) == InvalidOffsetNumber )
- elog (FATAL, "btree: failed to add item to the page in _bt_sort (2)");
+ off = OffsetNumberNext(last_off);
+ if (PageAddItem(npage, (Item) bti, btisz, off, LP_USED) == InvalidOffsetNumber)
+ elog(FATAL, "btree: failed to add item to the page in _bt_sort (2)");
#if 0
#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
- {
- bool isnull;
- Datum d = index_getattr(&(bti->bti_itup), 1, index->rd_att, &isnull);
- printf("_bt_buildadd: inserted <%x> at offset %d at level %d\n",
- d, off, state->btps_level);
- }
-#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
+ {
+ bool isnull;
+ Datum d = index_getattr(&(bti->bti_itup), 1, index->rd_att, &isnull);
+
+ printf("_bt_buildadd: inserted <%x> at offset %d at level %d\n",
+ d, off, state->btps_level);
+ }
+#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
#endif
- if (last_bti == (BTItem) NULL)
- {
- first_off = P_FIRSTKEY;
- }
- else if ( !_bt_itemcmp(index, _bt_nattr,
- bti, last_bti, BTEqualStrategyNumber) )
- {
- first_off = off;
- }
- last_off = off;
- last_bti = (BTItem) PageGetItem(npage, PageGetItemId(npage, off));
-
- state->btps_buf = nbuf;
- state->btps_page = npage;
- state->btps_lastbti = last_bti;
- state->btps_lastoff = last_off;
- state->btps_firstoff = first_off;
-
- return(last_bti);
+ if (last_bti == (BTItem) NULL)
+ {
+ first_off = P_FIRSTKEY;
+ }
+ else if (!_bt_itemcmp(index, _bt_nattr,
+ bti, last_bti, BTEqualStrategyNumber))
+ {
+ first_off = off;
+ }
+ last_off = off;
+ last_bti = (BTItem) PageGetItem(npage, PageGetItemId(npage, off));
+
+ state->btps_buf = nbuf;
+ state->btps_page = npage;
+ state->btps_lastbti = last_bti;
+ state->btps_lastoff = last_off;
+ state->btps_firstoff = first_off;
+
+ return (last_bti);
}
static void
-_bt_uppershutdown(Relation index, BTPageState *state)
+_bt_uppershutdown(Relation index, BTPageState * state)
{
- BTPageState *s;
- BlockNumber blkno;
- BTPageOpaque opaque;
- BTItem bti;
+ BTPageState *s;
+ BlockNumber blkno;
+ BTPageOpaque opaque;
+ BTItem bti;
- for (s = state; s != (BTPageState *) NULL; s = s->btps_next) {
- blkno = BufferGetBlockNumber(s->btps_buf);
- opaque = (BTPageOpaque) PageGetSpecialPointer(s->btps_page);
+ for (s = state; s != (BTPageState *) NULL; s = s->btps_next)
+ {
+ blkno = BufferGetBlockNumber(s->btps_buf);
+ opaque = (BTPageOpaque) PageGetSpecialPointer(s->btps_page);
- /*
- * if this is the root, attach it to the metapage. otherwise,
- * stick the minimum key of the last page on this level (which
- * has not been split, or else it wouldn't be the last page)
- * into its parent. this may cause the last page of upper
- * levels to split, but that's not a problem -- we haven't
- * gotten to them yet.
- */
- if (s->btps_doupper) {
- if (s->btps_next == (BTPageState *) NULL) {
- opaque->btpo_flags |= BTP_ROOT;
- _bt_metaproot(index, blkno, s->btps_level + 1);
- } else {
- bti = _bt_minitem(s->btps_page, blkno, 0);
- _bt_buildadd(index, s->btps_next, bti, 0);
- pfree((void *) bti);
- }
- }
+ /*
+ * if this is the root, attach it to the metapage. otherwise,
+ * stick the minimum key of the last page on this level (which has
+ * not been split, or else it wouldn't be the last page) into its
+ * parent. this may cause the last page of upper levels to split,
+ * but that's not a problem -- we haven't gotten to them yet.
+ */
+ if (s->btps_doupper)
+ {
+ if (s->btps_next == (BTPageState *) NULL)
+ {
+ opaque->btpo_flags |= BTP_ROOT;
+ _bt_metaproot(index, blkno, s->btps_level + 1);
+ }
+ else
+ {
+ bti = _bt_minitem(s->btps_page, blkno, 0);
+ _bt_buildadd(index, s->btps_next, bti, 0);
+ pfree((void *) bti);
+ }
+ }
- /*
- * this is the rightmost page, so the ItemId array needs to be
- * slid back one slot.
- */
- _bt_slideleft(index, s->btps_buf, s->btps_page);
- _bt_wrtbuf(index, s->btps_buf);
- }
+ /*
+ * this is the rightmost page, so the ItemId array needs to be
+ * slid back one slot.
+ */
+ _bt_slideleft(index, s->btps_buf, s->btps_page);
+ _bt_wrtbuf(index, s->btps_buf);
+ }
}
/*
@@ -1105,203 +1155,230 @@ _bt_uppershutdown(Relation index, BTPageState *state)
* merging passes until at most one run is left in each tape. at that
* point, merge the final tape runs into a set of btree leaves.
*
- * XXX three nested loops? gross. cut me up into smaller routines.
+ * XXX three nested loops? gross. cut me up into smaller routines.
*/
static void
-_bt_merge(Relation index, BTSpool *btspool)
+_bt_merge(Relation index, BTSpool * btspool)
{
- BTPageState *state;
- BTPriQueue q;
- BTPriQueueElem e;
- BTSortKey btsk;
- BTItem bti;
- BTTapeBlock *itape;
- BTTapeBlock *otape;
- char *tapepos[MAXTAPES];
- int tapedone[MAXTAPES];
- int t;
- int goodtapes;
- int npass;
- int nruns;
- Size btisz;
- bool doleaf = false;
-
- /*
- * initialize state needed for the merge into the btree leaf pages.
- */
- state = (BTPageState *) _bt_pagestate(index, BTP_LEAF, 0, true);
-
- npass = 0;
- do { /* pass */
+ BTPageState *state;
+ BTPriQueue q;
+ BTPriQueueElem e;
+ BTSortKey btsk;
+ BTItem bti;
+ BTTapeBlock *itape;
+ BTTapeBlock *otape;
+ char *tapepos[MAXTAPES];
+ int tapedone[MAXTAPES];
+ int t;
+ int goodtapes;
+ int npass;
+ int nruns;
+ Size btisz;
+ bool doleaf = false;
+
/*
- * each pass starts by flushing the previous outputs and
- * swapping inputs and outputs. flushing sets End-of-Run for
- * any dirty output tapes. swapping clears the new output
- * tapes and rewinds the new input tapes.
+ * initialize state needed for the merge into the btree leaf pages.
*/
- btspool->bts_tape = btspool->bts_ntapes - 1;
- _bt_spoolflush(btspool);
- _bt_spoolswap(btspool);
-
- ++npass;
- nruns = 0;
-
- for (;;) { /* run */
- /*
- * each run starts by selecting a new output tape. the
- * merged results of a given run are always sent to this
- * one tape.
- */
- btspool->bts_tape = (btspool->bts_tape + 1) % btspool->bts_ntapes;
- otape = btspool->bts_otape[btspool->bts_tape];
-
- /*
- * initialize the priority queue by loading it with the
- * first element of the given run in each tape. since we
- * are starting a new run, we reset the tape (clearing the
- * End-Of-Run marker) before reading it. this means that
- * _bt_taperead will return 0 only if the tape is actually
- * at EOF.
- */
- memset((char *) &q, 0, sizeof(BTPriQueue));
- goodtapes = 0;
- for (t = 0; t < btspool->bts_ntapes; ++t) {
- itape = btspool->bts_itape[t];
- tapepos[t] = itape->bttb_data;
- tapedone[t] = 0;
- _bt_tapereset(itape);
- do {
- if (_bt_taperead(itape) == 0) {
- tapedone[t] = 1;
- }
- } while (!tapedone[t] && EMPTYTAPE(itape));
- if (!tapedone[t]) {
- ++goodtapes;
- e.btpqe_tape = t;
- _bt_setsortkey(index, _bt_tapenext(itape, &tapepos[t]),
- &(e.btpqe_item));
- if (e.btpqe_item.btsk_item != (BTItem) NULL) {
- _bt_pqadd(&q, &e);
- }
- }
- }
- /*
- * if we don't have any tapes with any input (i.e., they
- * are all at EOF), there is no work to do in this run --
- * we must be done with this pass.
- */
- if (goodtapes == 0) {
- break; /* for */
- }
- ++nruns;
-
- /*
- * output the smallest element from the queue until there
- * are no more.
- */
- while (_bt_pqnext(&q, &e) >= 0) { /* item */
+ state = (BTPageState *) _bt_pagestate(index, BTP_LEAF, 0, true);
+
+ npass = 0;
+ do
+ { /* pass */
+
/*
- * replace the element taken from priority queue,
- * fetching a new block if needed. a tape can run out
- * if it hits either End-Of-Run or EOF.
+ * each pass starts by flushing the previous outputs and swapping
+ * inputs and outputs. flushing sets End-of-Run for any dirty
+ * output tapes. swapping clears the new output tapes and rewinds
+ * the new input tapes.
*/
- t = e.btpqe_tape;
- btsk = e.btpqe_item;
- bti = btsk.btsk_item;
- if (bti != (BTItem) NULL) {
- btisz = BTITEMSZ(bti);
- btisz = DOUBLEALIGN(btisz);
- if (doleaf) {
- _bt_buildadd(index, state, bti, BTP_LEAF);
-#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
+ btspool->bts_tape = btspool->bts_ntapes - 1;
+ _bt_spoolflush(btspool);
+ _bt_spoolswap(btspool);
+
+ ++npass;
+ nruns = 0;
+
+ for (;;)
+ { /* run */
+
+ /*
+ * each run starts by selecting a new output tape. the merged
+ * results of a given run are always sent to this one tape.
+ */
+ btspool->bts_tape = (btspool->bts_tape + 1) % btspool->bts_ntapes;
+ otape = btspool->bts_otape[btspool->bts_tape];
+
+ /*
+ * initialize the priority queue by loading it with the first
+ * element of the given run in each tape. since we are
+ * starting a new run, we reset the tape (clearing the
+ * End-Of-Run marker) before reading it. this means that
+ * _bt_taperead will return 0 only if the tape is actually at
+ * EOF.
+ */
+ memset((char *) &q, 0, sizeof(BTPriQueue));
+ goodtapes = 0;
+ for (t = 0; t < btspool->bts_ntapes; ++t)
{
- bool isnull;
- Datum d = index_getattr(&(bti->bti_itup), 1,
- index->rd_att, &isnull);
- printf("_bt_merge: [pass %d run %d] inserted <%x> from tape %d into block %d\n",
- npass, nruns, d, t,
- BufferGetBlockNumber(state->btps_buf));
+ itape = btspool->bts_itape[t];
+ tapepos[t] = itape->bttb_data;
+ tapedone[t] = 0;
+ _bt_tapereset(itape);
+ do
+ {
+ if (_bt_taperead(itape) == 0)
+ {
+ tapedone[t] = 1;
+ }
+ } while (!tapedone[t] && EMPTYTAPE(itape));
+ if (!tapedone[t])
+ {
+ ++goodtapes;
+ e.btpqe_tape = t;
+ _bt_setsortkey(index, _bt_tapenext(itape, &tapepos[t]),
+ &(e.btpqe_item));
+ if (e.btpqe_item.btsk_item != (BTItem) NULL)
+ {
+ _bt_pqadd(&q, &e);
+ }
+ }
}
-#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
- } else {
- if (SPCLEFT(otape) < btisz) {
- /*
- * if it's full, write it out and add the
- * item to the next block. (since we will
- * be adding another tuple immediately
- * after this, we can be sure that there
- * will be at least one more block in this
- * run and so we know we do *not* want to
- * set End-Of-Run here.)
- */
- _bt_tapewrite(otape, 0);
- }
- _bt_tapeadd(otape, bti, btisz);
-#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
+
+ /*
+ * if we don't have any tapes with any input (i.e., they are
+ * all at EOF), there is no work to do in this run -- we must
+ * be done with this pass.
+ */
+ if (goodtapes == 0)
{
- bool isnull;
- Datum d = index_getattr(&(bti->bti_itup), 1,
- index->rd_att, &isnull);
- printf("_bt_merge: [pass %d run %d] inserted <%x> from tape %d into output tape %d\n",
- npass, nruns, d, t,
- btspool->bts_tape);
- }
-#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
- }
-
- if ( btsk.btsk_datum != (Datum*) NULL )
- pfree ((void*)(btsk.btsk_datum));
- if ( btsk.btsk_nulls != (char*) NULL )
- pfree ((void*)(btsk.btsk_nulls));
-
- }
- itape = btspool->bts_itape[t];
- if (!tapedone[t]) {
- BTItem newbti = _bt_tapenext(itape, &tapepos[t]);
-
- if (newbti == (BTItem) NULL) {
- do {
- if (_bt_taperead(itape) == 0) {
- tapedone[t] = 1;
- }
- } while (!tapedone[t] && EMPTYTAPE(itape));
- if (!tapedone[t]) {
- tapepos[t] = itape->bttb_data;
- newbti = _bt_tapenext(itape, &tapepos[t]);
+ break; /* for */
}
- }
- if (newbti != (BTItem) NULL) {
- BTPriQueueElem nexte;
-
- nexte.btpqe_tape = t;
- _bt_setsortkey(index, newbti, &(nexte.btpqe_item));
- _bt_pqadd(&q, &nexte);
- }
+ ++nruns;
+
+ /*
+ * output the smallest element from the queue until there are
+ * no more.
+ */
+ while (_bt_pqnext(&q, &e) >= 0)
+ { /* item */
+
+ /*
+ * replace the element taken from priority queue, fetching
+ * a new block if needed. a tape can run out if it hits
+ * either End-Of-Run or EOF.
+ */
+ t = e.btpqe_tape;
+ btsk = e.btpqe_item;
+ bti = btsk.btsk_item;
+ if (bti != (BTItem) NULL)
+ {
+ btisz = BTITEMSZ(bti);
+ btisz = DOUBLEALIGN(btisz);
+ if (doleaf)
+ {
+ _bt_buildadd(index, state, bti, BTP_LEAF);
+#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
+ {
+ bool isnull;
+ Datum d = index_getattr(&(bti->bti_itup), 1,
+ index->rd_att, &isnull);
+
+ printf("_bt_merge: [pass %d run %d] inserted <%x> from tape %d into block %d\n",
+ npass, nruns, d, t,
+ BufferGetBlockNumber(state->btps_buf));
+ }
+#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
+ }
+ else
+ {
+ if (SPCLEFT(otape) < btisz)
+ {
+
+ /*
+ * if it's full, write it out and add the item
+ * to the next block. (since we will be
+ * adding another tuple immediately after
+ * this, we can be sure that there will be at
+ * least one more block in this run and so we
+ * know we do *not* want to set End-Of-Run
+ * here.)
+ */
+ _bt_tapewrite(otape, 0);
+ }
+ _bt_tapeadd(otape, bti, btisz);
+#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
+ {
+ bool isnull;
+ Datum d = index_getattr(&(bti->bti_itup), 1,
+ index->rd_att, &isnull);
+
+ printf("_bt_merge: [pass %d run %d] inserted <%x> from tape %d into output tape %d\n",
+ npass, nruns, d, t,
+ btspool->bts_tape);
+ }
+#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
+ }
+
+ if (btsk.btsk_datum != (Datum *) NULL)
+ pfree((void *) (btsk.btsk_datum));
+ if (btsk.btsk_nulls != (char *) NULL)
+ pfree((void *) (btsk.btsk_nulls));
+
+ }
+ itape = btspool->bts_itape[t];
+ if (!tapedone[t])
+ {
+ BTItem newbti = _bt_tapenext(itape, &tapepos[t]);
+
+ if (newbti == (BTItem) NULL)
+ {
+ do
+ {
+ if (_bt_taperead(itape) == 0)
+ {
+ tapedone[t] = 1;
+ }
+ } while (!tapedone[t] && EMPTYTAPE(itape));
+ if (!tapedone[t])
+ {
+ tapepos[t] = itape->bttb_data;
+ newbti = _bt_tapenext(itape, &tapepos[t]);
+ }
+ }
+ if (newbti != (BTItem) NULL)
+ {
+ BTPriQueueElem nexte;
+
+ nexte.btpqe_tape = t;
+ _bt_setsortkey(index, newbti, &(nexte.btpqe_item));
+ _bt_pqadd(&q, &nexte);
+ }
+ }
+ } /* item */
+
+ /*
+ * that's it for this run. flush the output tape, marking
+ * End-of-Run.
+ */
+ _bt_tapewrite(otape, 1);
+ } /* run */
+
+ /*
+ * we are here because we ran out of input on all of the input
+ * tapes.
+ *
+ * if this pass did not generate more actual output runs than we have
+ * tapes, we know we have at most one run in each tape. this
+ * means that we are ready to merge into the final btree leaf
+ * pages instead of merging into a tape file.
+ */
+ if (nruns <= btspool->bts_ntapes)
+ {
+ doleaf = true;
}
- } /* item */
-
- /*
- * that's it for this run. flush the output tape, marking
- * End-of-Run.
- */
- _bt_tapewrite(otape, 1);
- } /* run */
-
- /*
- * we are here because we ran out of input on all of the input
- * tapes.
- *
- * if this pass did not generate more actual output runs than
- * we have tapes, we know we have at most one run in each
- * tape. this means that we are ready to merge into the final
- * btree leaf pages instead of merging into a tape file.
- */
- if (nruns <= btspool->bts_ntapes) {
- doleaf = true;
- }
- } while (nruns > 0); /* pass */
+ } while (nruns > 0); /* pass */
- _bt_uppershutdown(index, state);
+ _bt_uppershutdown(index, state);
}
@@ -1320,62 +1397,65 @@ _bt_merge(Relation index, BTSpool *btspool)
void
_bt_upperbuild(Relation index)
{
- Buffer rbuf;
- BlockNumber blk;
- Page rpage;
- BTPageOpaque ropaque;
- BTPageState *state;
- BTItem nbti;
-
- /*
- * find the first leaf block. while we're at it, clear the
- * BTP_ROOT flag that we set while building it (so we could find
- * it later).
- */
- rbuf = _bt_getroot(index, BT_WRITE);
- blk = BufferGetBlockNumber(rbuf);
- rpage = BufferGetPage(rbuf);
- ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
- ropaque->btpo_flags &= ~BTP_ROOT;
- _bt_wrtbuf(index, rbuf);
-
- state = (BTPageState *) _bt_pagestate(index, 0, 0, true);
-
- /* for each page... */
- do {
-#if 0
- printf("\t\tblk=%d\n", blk);
-#endif
- rbuf = _bt_getbuf(index, blk, BT_READ);
+ Buffer rbuf;
+ BlockNumber blk;
+ Page rpage;
+ BTPageOpaque ropaque;
+ BTPageState *state;
+ BTItem nbti;
+
+ /*
+ * find the first leaf block. while we're at it, clear the BTP_ROOT
+ * flag that we set while building it (so we could find it later).
+ */
+ rbuf = _bt_getroot(index, BT_WRITE);
+ blk = BufferGetBlockNumber(rbuf);
rpage = BufferGetPage(rbuf);
ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
-
- /* for each item... */
- if (!PageIsEmpty(rpage)) {
- /*
- * form a new index tuple corresponding to the minimum key
- * of the lower page and insert it into a page at this
- * level.
- */
- nbti = _bt_minitem(rpage, blk, P_RIGHTMOST(ropaque));
+ ropaque->btpo_flags &= ~BTP_ROOT;
+ _bt_wrtbuf(index, rbuf);
+
+ state = (BTPageState *) _bt_pagestate(index, 0, 0, true);
+
+ /* for each page... */
+ do
+ {
+#if 0
+ printf("\t\tblk=%d\n", blk);
+#endif
+ rbuf = _bt_getbuf(index, blk, BT_READ);
+ rpage = BufferGetPage(rbuf);
+ ropaque = (BTPageOpaque) PageGetSpecialPointer(rpage);
+
+ /* for each item... */
+ if (!PageIsEmpty(rpage))
+ {
+
+ /*
+ * form a new index tuple corresponding to the minimum key of
+ * the lower page and insert it into a page at this level.
+ */
+ nbti = _bt_minitem(rpage, blk, P_RIGHTMOST(ropaque));
#if defined(FASTBUILD_DEBUG) && defined(FASTBUILD_MERGE)
- {
- bool isnull;
- Datum d = index_getattr(&(nbti->bti_itup), 1, index->rd_att,
- &isnull);
- printf("_bt_upperbuild: inserting <%x> at %d\n",
- d, state->btps_level);
- }
-#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
- _bt_buildadd(index, state, nbti, 0);
- pfree((void *) nbti);
- }
- blk = ropaque->btpo_next;
- _bt_relbuf(index, rbuf, BT_READ);
- } while (blk != P_NONE);
-
- _bt_uppershutdown(index, state);
+ {
+ bool isnull;
+ Datum d = index_getattr(&(nbti->bti_itup), 1, index->rd_att,
+ &isnull);
+
+ printf("_bt_upperbuild: inserting <%x> at %d\n",
+ d, state->btps_level);
+ }
+#endif /* FASTBUILD_DEBUG && FASTBUILD_MERGE */
+ _bt_buildadd(index, state, nbti, 0);
+ pfree((void *) nbti);
+ }
+ blk = ropaque->btpo_next;
+ _bt_relbuf(index, rbuf, BT_READ);
+ } while (blk != P_NONE);
+
+ _bt_uppershutdown(index, state);
}
+
#endif
/*
@@ -1385,17 +1465,17 @@ _bt_upperbuild(Relation index)
void
_bt_leafbuild(Relation index, void *spool)
{
- _bt_isortcmpinit (index, (BTSpool *) spool);
+ _bt_isortcmpinit(index, (BTSpool *) spool);
#ifdef BTREE_BUILD_STATS
- if ( ShowExecutorStats )
- {
- fprintf(stderr, "! BtreeBuild (Spool) Stats:\n");
- ShowUsage ();
- ResetUsage ();
- }
+ if (ShowExecutorStats)
+ {
+ fprintf(stderr, "! BtreeBuild (Spool) Stats:\n");
+ ShowUsage();
+ ResetUsage();
+ }
#endif
- _bt_merge(index, (BTSpool *) spool);
+ _bt_merge(index, (BTSpool *) spool);
}
diff --git a/src/backend/access/nbtree/nbtstrat.c b/src/backend/access/nbtree/nbtstrat.c
index 6de003c06a9..5215d2000d8 100644
--- a/src/backend/access/nbtree/nbtstrat.c
+++ b/src/backend/access/nbtree/nbtstrat.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* btstrat.c--
- * Srategy map entries for the btree indexed access method
+ * Srategy map entries for the btree indexed access method
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtstrat.c,v 1.4 1996/11/05 10:35:37 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtstrat.c,v 1.5 1997/09/07 04:39:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,111 +20,111 @@
/*
* Note:
- * StrategyNegate, StrategyCommute, and StrategyNegateCommute
- * assume <, <=, ==, >=, > ordering.
+ * StrategyNegate, StrategyCommute, and StrategyNegateCommute
+ * assume <, <=, ==, >=, > ordering.
*/
-static StrategyNumber BTNegate[5] = {
- BTGreaterEqualStrategyNumber,
- BTGreaterStrategyNumber,
- InvalidStrategy,
- BTLessStrategyNumber,
- BTLessEqualStrategyNumber
+static StrategyNumber BTNegate[5] = {
+ BTGreaterEqualStrategyNumber,
+ BTGreaterStrategyNumber,
+ InvalidStrategy,
+ BTLessStrategyNumber,
+ BTLessEqualStrategyNumber
};
-static StrategyNumber BTCommute[5] = {
- BTGreaterStrategyNumber,
- BTGreaterEqualStrategyNumber,
- InvalidStrategy,
- BTLessEqualStrategyNumber,
- BTLessStrategyNumber
+static StrategyNumber BTCommute[5] = {
+ BTGreaterStrategyNumber,
+ BTGreaterEqualStrategyNumber,
+ InvalidStrategy,
+ BTLessEqualStrategyNumber,
+ BTLessStrategyNumber
};
-static StrategyNumber BTNegateCommute[5] = {
- BTLessEqualStrategyNumber,
- BTLessStrategyNumber,
- InvalidStrategy,
- BTGreaterStrategyNumber,
- BTGreaterEqualStrategyNumber
+static StrategyNumber BTNegateCommute[5] = {
+ BTLessEqualStrategyNumber,
+ BTLessStrategyNumber,
+ InvalidStrategy,
+ BTGreaterStrategyNumber,
+ BTGreaterEqualStrategyNumber
};
-static uint16 BTLessTermData[] = { /* XXX type clash */
- 2,
- BTLessStrategyNumber,
- SK_NEGATE,
- BTLessStrategyNumber,
- SK_NEGATE | SK_COMMUTE
+static uint16 BTLessTermData[] = { /* XXX type clash */
+ 2,
+ BTLessStrategyNumber,
+ SK_NEGATE,
+ BTLessStrategyNumber,
+ SK_NEGATE | SK_COMMUTE
};
-static uint16 BTLessEqualTermData[] = { /* XXX type clash */
- 2,
- BTLessEqualStrategyNumber,
- 0x0,
- BTLessEqualStrategyNumber,
- SK_COMMUTE
+static uint16 BTLessEqualTermData[] = { /* XXX type clash */
+ 2,
+ BTLessEqualStrategyNumber,
+ 0x0,
+ BTLessEqualStrategyNumber,
+ SK_COMMUTE
};
static uint16 BTGreaterEqualTermData[] = { /* XXX type clash */
- 2,
- BTGreaterEqualStrategyNumber,
- 0x0,
- BTGreaterEqualStrategyNumber,
- SK_COMMUTE
- };
-
-static uint16 BTGreaterTermData[] = { /* XXX type clash */
- 2,
- BTGreaterStrategyNumber,
- SK_NEGATE,
- BTGreaterStrategyNumber,
- SK_NEGATE | SK_COMMUTE
+ 2,
+ BTGreaterEqualStrategyNumber,
+ 0x0,
+ BTGreaterEqualStrategyNumber,
+ SK_COMMUTE
};
-static StrategyTerm BTEqualExpressionData[] = {
- (StrategyTerm)BTLessTermData, /* XXX */
- (StrategyTerm)BTLessEqualTermData, /* XXX */
- (StrategyTerm)BTGreaterEqualTermData, /* XXX */
- (StrategyTerm)BTGreaterTermData, /* XXX */
- NULL
+static uint16 BTGreaterTermData[] = { /* XXX type clash */
+ 2,
+ BTGreaterStrategyNumber,
+ SK_NEGATE,
+ BTGreaterStrategyNumber,
+ SK_NEGATE | SK_COMMUTE
};
-static StrategyEvaluationData BTEvaluationData = {
- /* XXX static for simplicity */
-
- BTMaxStrategyNumber,
- (StrategyTransformMap)BTNegate, /* XXX */
- (StrategyTransformMap)BTCommute, /* XXX */
- (StrategyTransformMap)BTNegateCommute, /* XXX */
+static StrategyTerm BTEqualExpressionData[] = {
+ (StrategyTerm) BTLessTermData, /* XXX */
+ (StrategyTerm) BTLessEqualTermData, /* XXX */
+ (StrategyTerm) BTGreaterEqualTermData, /* XXX */
+ (StrategyTerm) BTGreaterTermData, /* XXX */
+ NULL
+};
+
+static StrategyEvaluationData BTEvaluationData = {
+ /* XXX static for simplicity */
+
+ BTMaxStrategyNumber,
+ (StrategyTransformMap) BTNegate, /* XXX */
+ (StrategyTransformMap) BTCommute, /* XXX */
+ (StrategyTransformMap) BTNegateCommute, /* XXX */
- { NULL, NULL, (StrategyExpression)BTEqualExpressionData, NULL, NULL,
- NULL,NULL,NULL,NULL,NULL,NULL,NULL}
+ {NULL, NULL, (StrategyExpression) BTEqualExpressionData, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL}
};
/* ----------------------------------------------------------------
- * RelationGetBTStrategy
+ * RelationGetBTStrategy
* ----------------------------------------------------------------
*/
StrategyNumber
_bt_getstrat(Relation rel,
- AttrNumber attno,
- RegProcedure proc)
+ AttrNumber attno,
+ RegProcedure proc)
{
- StrategyNumber strat;
-
- strat = RelationGetStrategy(rel, attno, &BTEvaluationData, proc);
-
- Assert(StrategyNumberIsValid(strat));
-
- return (strat);
+ StrategyNumber strat;
+
+ strat = RelationGetStrategy(rel, attno, &BTEvaluationData, proc);
+
+ Assert(StrategyNumberIsValid(strat));
+
+ return (strat);
}
bool
_bt_invokestrat(Relation rel,
- AttrNumber attno,
- StrategyNumber strat,
- Datum left,
- Datum right)
+ AttrNumber attno,
+ StrategyNumber strat,
+ Datum left,
+ Datum right)
{
- return (RelationInvokeStrategy(rel, &BTEvaluationData, attno, strat,
- left, right));
+ return (RelationInvokeStrategy(rel, &BTEvaluationData, attno, strat,
+ left, right));
}
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 738e55dbccd..096f1d2691e 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* btutils.c--
- * Utility code for Postgres btree implementation.
+ * Utility code for Postgres btree implementation.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.11 1997/08/19 21:29:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.12 1997/09/07 04:39:05 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,367 +23,384 @@
#include <catalog/pg_proc.h>
#include <executor/execdebug.h>
-extern int NIndexTupleProcessed;
+extern int NIndexTupleProcessed;
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-ScanKey
+ScanKey
_bt_mkscankey(Relation rel, IndexTuple itup)
-{
- ScanKey skey;
- TupleDesc itupdesc;
- int natts;
- int i;
- Datum arg;
- RegProcedure proc;
- bool null;
- bits16 flag;
-
- natts = rel->rd_rel->relnatts;
- itupdesc = RelationGetTupleDescriptor(rel);
-
- skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
-
- for (i = 0; i < natts; i++) {
- arg = index_getattr(itup, i + 1, itupdesc, &null);
- if ( null )
- {
- proc = NullValueRegProcedure;
- flag = SK_ISNULL;
- }
- else
+{
+ ScanKey skey;
+ TupleDesc itupdesc;
+ int natts;
+ int i;
+ Datum arg;
+ RegProcedure proc;
+ bool null;
+ bits16 flag;
+
+ natts = rel->rd_rel->relnatts;
+ itupdesc = RelationGetTupleDescriptor(rel);
+
+ skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));
+
+ for (i = 0; i < natts; i++)
{
- proc = index_getprocid(rel, i + 1, BTORDER_PROC);
- flag = 0x0;
+ arg = index_getattr(itup, i + 1, itupdesc, &null);
+ if (null)
+ {
+ proc = NullValueRegProcedure;
+ flag = SK_ISNULL;
+ }
+ else
+ {
+ proc = index_getprocid(rel, i + 1, BTORDER_PROC);
+ flag = 0x0;
+ }
+ ScanKeyEntryInitialize(&skey[i],
+ flag, (AttrNumber) (i + 1), proc, arg);
}
- ScanKeyEntryInitialize(&skey[i],
- flag, (AttrNumber) (i + 1), proc, arg);
- }
-
- return (skey);
+
+ return (skey);
}
void
_bt_freeskey(ScanKey skey)
{
- pfree(skey);
+ pfree(skey);
}
void
_bt_freestack(BTStack stack)
{
- BTStack ostack;
-
- while (stack != (BTStack) NULL) {
- ostack = stack;
- stack = stack->bts_parent;
- pfree(ostack->bts_btitem);
- pfree(ostack);
- }
+ BTStack ostack;
+
+ while (stack != (BTStack) NULL)
+ {
+ ostack = stack;
+ stack = stack->bts_parent;
+ pfree(ostack->bts_btitem);
+ pfree(ostack);
+ }
}
/*
- * _bt_orderkeys() -- Put keys in a sensible order for conjunctive quals.
+ * _bt_orderkeys() -- Put keys in a sensible order for conjunctive quals.
*
- * The order of the keys in the qual match the ordering imposed by
- * the index. This routine only needs to be called if there are
- * more than one qual clauses using this index.
+ * The order of the keys in the qual match the ordering imposed by
+ * the index. This routine only needs to be called if there are
+ * more than one qual clauses using this index.
*/
void
_bt_orderkeys(Relation relation, BTScanOpaque so)
{
- ScanKey xform;
- ScanKeyData *cur;
- StrategyMap map;
- int nbytes;
- long test;
- int i, j;
- int init[BTMaxStrategyNumber+1];
- ScanKey key;
- uint16 numberOfKeys = so->numberOfKeys;
- uint16 new_numberOfKeys = 0;
- AttrNumber attno = 1;
-
- if ( numberOfKeys < 1 )
- return;
-
- key = so->keyData;
-
- cur = &key[0];
- if ( cur->sk_attno != 1 )
- elog (WARN, "_bt_orderkeys: key(s) for attribute 1 missed");
-
- if ( numberOfKeys == 1 )
- {
- /*
- * We don't use indices for 'A is null' and 'A is not null'
- * currently and 'A < = > <> NULL' is non-sense' - so
- * qual is not Ok. - vadim 03/21/97
- */
- if ( cur->sk_flags & SK_ISNULL )
- so->qual_ok = 0;
- so->numberOfFirstKeys = 1;
- return;
- }
-
- /* get space for the modified array of keys */
- nbytes = BTMaxStrategyNumber * sizeof(ScanKeyData);
- xform = (ScanKey) palloc(nbytes);
-
- memset(xform, 0, nbytes);
- map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
- BTMaxStrategyNumber,
- attno);
- for (j = 0; j <= BTMaxStrategyNumber; j++)
- init[j] = 0;
-
- /* check each key passed in */
- for (i = 0; ; )
- {
- if ( i < numberOfKeys )
- cur = &key[i];
-
- if ( cur->sk_flags & SK_ISNULL ) /* see comments above */
- so->qual_ok = 0;
-
- if ( i == numberOfKeys || cur->sk_attno != attno )
+ ScanKey xform;
+ ScanKeyData *cur;
+ StrategyMap map;
+ int nbytes;
+ long test;
+ int i,
+ j;
+ int init[BTMaxStrategyNumber + 1];
+ ScanKey key;
+ uint16 numberOfKeys = so->numberOfKeys;
+ uint16 new_numberOfKeys = 0;
+ AttrNumber attno = 1;
+
+ if (numberOfKeys < 1)
+ return;
+
+ key = so->keyData;
+
+ cur = &key[0];
+ if (cur->sk_attno != 1)
+ elog(WARN, "_bt_orderkeys: key(s) for attribute 1 missed");
+
+ if (numberOfKeys == 1)
{
- if ( cur->sk_attno != attno + 1 && i < numberOfKeys )
- {
- elog (WARN, "_bt_orderkeys: key(s) for attribute %d missed", attno + 1);
- }
- /*
- * If = has been specified, no other key will be used.
- * In case of key < 2 && key == 1 and so on
- * we have to set qual_ok to 0
- */
- if (init[BTEqualStrategyNumber - 1])
- {
- ScanKeyData *eq, *chk;
-
- eq = &xform[BTEqualStrategyNumber - 1];
- for (j = BTMaxStrategyNumber; --j >= 0; )
- {
- if ( j == (BTEqualStrategyNumber - 1) || init[j] == 0 )
- continue;
- chk = &xform[j];
- test = (long) fmgr(chk->sk_procedure, eq->sk_argument, chk->sk_argument);
- if (!test)
- so->qual_ok = 0;
- }
- init[BTLessStrategyNumber - 1] = 0;
- init[BTLessEqualStrategyNumber - 1] = 0;
- init[BTGreaterEqualStrategyNumber - 1] = 0;
- init[BTGreaterStrategyNumber - 1] = 0;
- }
-
- /* only one of <, <= */
- if (init[BTLessStrategyNumber - 1]
- && init[BTLessEqualStrategyNumber - 1])
- {
- ScanKeyData *lt, *le;
-
- lt = &xform[BTLessStrategyNumber - 1];
- le = &xform[BTLessEqualStrategyNumber - 1];
+
/*
- * DO NOT use the cached function stuff here -- this is key
- * ordering, happens only when the user expresses a hokey
- * qualification, and gets executed only once, anyway. The
- * transform maps are hard-coded, and can't be initialized
- * in the correct way.
+ * We don't use indices for 'A is null' and 'A is not null'
+ * currently and 'A < = > <> NULL' is non-sense' - so qual is not
+ * Ok. - vadim 03/21/97
*/
- test = (long) fmgr(le->sk_procedure, lt->sk_argument, le->sk_argument);
- if (test)
- init[BTLessEqualStrategyNumber - 1] = 0;
- else
- init[BTLessStrategyNumber - 1] = 0;
- }
-
- /* only one of >, >= */
- if (init[BTGreaterStrategyNumber - 1]
- && init[BTGreaterEqualStrategyNumber - 1])
- {
- ScanKeyData *gt, *ge;
-
- gt = &xform[BTGreaterStrategyNumber - 1];
- ge = &xform[BTGreaterEqualStrategyNumber - 1];
-
- /* see note above on function cache */
- test = (long) fmgr(ge->sk_procedure, gt->sk_argument, ge->sk_argument);
- if (test)
- init[BTGreaterEqualStrategyNumber - 1] = 0;
- else
- init[BTGreaterStrategyNumber - 1] = 0;
- }
-
- /* okay, reorder and count */
- for (j = BTMaxStrategyNumber; --j >= 0; )
- if (init[j])
- key[new_numberOfKeys++] = xform[j];
-
- if ( attno == 1 )
- so->numberOfFirstKeys = new_numberOfKeys;
-
- if ( i == numberOfKeys )
- break;
-
- /* initialization for new attno */
- attno = cur->sk_attno;
- memset(xform, 0, nbytes);
- map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
- BTMaxStrategyNumber,
- attno);
- /* haven't looked at any strategies yet */
- for (j = 0; j <= BTMaxStrategyNumber; j++)
- init[j] = 0;
+ if (cur->sk_flags & SK_ISNULL)
+ so->qual_ok = 0;
+ so->numberOfFirstKeys = 1;
+ return;
}
- for (j = BTMaxStrategyNumber; --j >= 0; )
- {
- if (cur->sk_procedure == map->entry[j].sk_procedure)
- break;
- }
-
- /* have we seen one of these before? */
- if (init[j])
- {
- /* yup, use the appropriate value */
- test =
- (long) FMGR_PTR2(cur->sk_func, cur->sk_procedure,
- cur->sk_argument, xform[j].sk_argument);
- if (test)
- xform[j].sk_argument = cur->sk_argument;
- else if ( j == (BTEqualStrategyNumber - 1) )
- so->qual_ok = 0; /* key == a && key == b, but a != b */
- } else
+ /* get space for the modified array of keys */
+ nbytes = BTMaxStrategyNumber * sizeof(ScanKeyData);
+ xform = (ScanKey) palloc(nbytes);
+
+ memset(xform, 0, nbytes);
+ map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
+ BTMaxStrategyNumber,
+ attno);
+ for (j = 0; j <= BTMaxStrategyNumber; j++)
+ init[j] = 0;
+
+ /* check each key passed in */
+ for (i = 0;;)
{
- /* nope, use this value */
- memmove(&xform[j], cur, sizeof(*cur));
- init[j] = 1;
+ if (i < numberOfKeys)
+ cur = &key[i];
+
+ if (cur->sk_flags & SK_ISNULL) /* see comments above */
+ so->qual_ok = 0;
+
+ if (i == numberOfKeys || cur->sk_attno != attno)
+ {
+ if (cur->sk_attno != attno + 1 && i < numberOfKeys)
+ {
+ elog(WARN, "_bt_orderkeys: key(s) for attribute %d missed", attno + 1);
+ }
+
+ /*
+ * If = has been specified, no other key will be used. In case
+ * of key < 2 && key == 1 and so on we have to set qual_ok to
+ * 0
+ */
+ if (init[BTEqualStrategyNumber - 1])
+ {
+ ScanKeyData *eq,
+ *chk;
+
+ eq = &xform[BTEqualStrategyNumber - 1];
+ for (j = BTMaxStrategyNumber; --j >= 0;)
+ {
+ if (j == (BTEqualStrategyNumber - 1) || init[j] == 0)
+ continue;
+ chk = &xform[j];
+ test = (long) fmgr(chk->sk_procedure, eq->sk_argument, chk->sk_argument);
+ if (!test)
+ so->qual_ok = 0;
+ }
+ init[BTLessStrategyNumber - 1] = 0;
+ init[BTLessEqualStrategyNumber - 1] = 0;
+ init[BTGreaterEqualStrategyNumber - 1] = 0;
+ init[BTGreaterStrategyNumber - 1] = 0;
+ }
+
+ /* only one of <, <= */
+ if (init[BTLessStrategyNumber - 1]
+ && init[BTLessEqualStrategyNumber - 1])
+ {
+ ScanKeyData *lt,
+ *le;
+
+ lt = &xform[BTLessStrategyNumber - 1];
+ le = &xform[BTLessEqualStrategyNumber - 1];
+
+ /*
+ * DO NOT use the cached function stuff here -- this is
+ * key ordering, happens only when the user expresses a
+ * hokey qualification, and gets executed only once,
+ * anyway. The transform maps are hard-coded, and can't
+ * be initialized in the correct way.
+ */
+ test = (long) fmgr(le->sk_procedure, lt->sk_argument, le->sk_argument);
+ if (test)
+ init[BTLessEqualStrategyNumber - 1] = 0;
+ else
+ init[BTLessStrategyNumber - 1] = 0;
+ }
+
+ /* only one of >, >= */
+ if (init[BTGreaterStrategyNumber - 1]
+ && init[BTGreaterEqualStrategyNumber - 1])
+ {
+ ScanKeyData *gt,
+ *ge;
+
+ gt = &xform[BTGreaterStrategyNumber - 1];
+ ge = &xform[BTGreaterEqualStrategyNumber - 1];
+
+ /* see note above on function cache */
+ test = (long) fmgr(ge->sk_procedure, gt->sk_argument, ge->sk_argument);
+ if (test)
+ init[BTGreaterEqualStrategyNumber - 1] = 0;
+ else
+ init[BTGreaterStrategyNumber - 1] = 0;
+ }
+
+ /* okay, reorder and count */
+ for (j = BTMaxStrategyNumber; --j >= 0;)
+ if (init[j])
+ key[new_numberOfKeys++] = xform[j];
+
+ if (attno == 1)
+ so->numberOfFirstKeys = new_numberOfKeys;
+
+ if (i == numberOfKeys)
+ break;
+
+ /* initialization for new attno */
+ attno = cur->sk_attno;
+ memset(xform, 0, nbytes);
+ map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
+ BTMaxStrategyNumber,
+ attno);
+ /* haven't looked at any strategies yet */
+ for (j = 0; j <= BTMaxStrategyNumber; j++)
+ init[j] = 0;
+ }
+
+ for (j = BTMaxStrategyNumber; --j >= 0;)
+ {
+ if (cur->sk_procedure == map->entry[j].sk_procedure)
+ break;
+ }
+
+ /* have we seen one of these before? */
+ if (init[j])
+ {
+ /* yup, use the appropriate value */
+ test =
+ (long) FMGR_PTR2(cur->sk_func, cur->sk_procedure,
+ cur->sk_argument, xform[j].sk_argument);
+ if (test)
+ xform[j].sk_argument = cur->sk_argument;
+ else if (j == (BTEqualStrategyNumber - 1))
+ so->qual_ok = 0;/* key == a && key == b, but a != b */
+ }
+ else
+ {
+ /* nope, use this value */
+ memmove(&xform[j], cur, sizeof(*cur));
+ init[j] = 1;
+ }
+
+ i++;
}
-
- i++;
- }
-
- so->numberOfKeys = new_numberOfKeys;
-
- pfree(xform);
+
+ so->numberOfKeys = new_numberOfKeys;
+
+ pfree(xform);
}
BTItem
_bt_formitem(IndexTuple itup)
{
- int nbytes_btitem;
- BTItem btitem;
- Size tuplen;
- extern Oid newoid();
-
- /* see comments in btbuild
-
- if (itup->t_info & INDEX_NULL_MASK)
- elog(WARN, "btree indices cannot include null keys");
- */
-
- /* make a copy of the index tuple with room for the sequence number */
- tuplen = IndexTupleSize(itup);
- nbytes_btitem = tuplen +
- (sizeof(BTItemData) - sizeof(IndexTupleData));
-
- btitem = (BTItem) palloc(nbytes_btitem);
- memmove((char *) &(btitem->bti_itup), (char *) itup, tuplen);
-
+ int nbytes_btitem;
+ BTItem btitem;
+ Size tuplen;
+ extern Oid newoid();
+
+ /*
+ * see comments in btbuild
+ *
+ * if (itup->t_info & INDEX_NULL_MASK) elog(WARN, "btree indices cannot
+ * include null keys");
+ */
+
+ /* make a copy of the index tuple with room for the sequence number */
+ tuplen = IndexTupleSize(itup);
+ nbytes_btitem = tuplen +
+ (sizeof(BTItemData) - sizeof(IndexTupleData));
+
+ btitem = (BTItem) palloc(nbytes_btitem);
+ memmove((char *) &(btitem->bti_itup), (char *) itup, tuplen);
+
#ifndef BTREE_VERSION_1
- btitem->bti_oid = newoid();
+ btitem->bti_oid = newoid();
#endif
- return (btitem);
+ return (btitem);
}
#ifdef NOT_USED
bool
_bt_checkqual(IndexScanDesc scan, IndexTuple itup)
{
- BTScanOpaque so;
-
- so = (BTScanOpaque) scan->opaque;
- if (so->numberOfKeys > 0)
- return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation),
- so->numberOfKeys, so->keyData));
- else
- return (true);
+ BTScanOpaque so;
+
+ so = (BTScanOpaque) scan->opaque;
+ if (so->numberOfKeys > 0)
+ return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation),
+ so->numberOfKeys, so->keyData));
+ else
+ return (true);
}
+
#endif
#ifdef NOT_USED
bool
_bt_checkforkeys(IndexScanDesc scan, IndexTuple itup, Size keysz)
{
- BTScanOpaque so;
-
- so = (BTScanOpaque) scan->opaque;
- if ( keysz > 0 && so->numberOfKeys >= keysz )
- return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation),
- keysz, so->keyData));
- else
- return (true);
+ BTScanOpaque so;
+
+ so = (BTScanOpaque) scan->opaque;
+ if (keysz > 0 && so->numberOfKeys >= keysz)
+ return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation),
+ keysz, so->keyData));
+ else
+ return (true);
}
+
#endif
bool
-_bt_checkkeys (IndexScanDesc scan, IndexTuple tuple, Size *keysok)
+_bt_checkkeys(IndexScanDesc scan, IndexTuple tuple, Size * keysok)
{
- BTScanOpaque so = (BTScanOpaque) scan->opaque;
- Size keysz = so->numberOfKeys;
- TupleDesc tupdesc;
- ScanKey key;
- Datum datum;
- bool isNull;
- int test;
-
- *keysok = 0;
- if ( keysz == 0 )
- return (true);
-
- key = so->keyData;
- tupdesc = RelationGetTupleDescriptor(scan->relation);
-
- IncrIndexProcessed();
-
- while (keysz > 0)
- {
- datum = index_getattr(tuple,
- key[0].sk_attno,
- tupdesc,
- &isNull);
-
- /* btree doesn't support 'A is null' clauses, yet */
- if ( isNull || key[0].sk_flags & SK_ISNULL )
+ BTScanOpaque so = (BTScanOpaque) scan->opaque;
+ Size keysz = so->numberOfKeys;
+ TupleDesc tupdesc;
+ ScanKey key;
+ Datum datum;
+ bool isNull;
+ int test;
+
+ *keysok = 0;
+ if (keysz == 0)
+ return (true);
+
+ key = so->keyData;
+ tupdesc = RelationGetTupleDescriptor(scan->relation);
+
+ IncrIndexProcessed();
+
+ while (keysz > 0)
{
- return (false);
- }
+ datum = index_getattr(tuple,
+ key[0].sk_attno,
+ tupdesc,
+ &isNull);
- if (key[0].sk_flags & SK_COMMUTE) {
- test = (int) (*(key[0].sk_func))
- (DatumGetPointer(key[0].sk_argument),
- datum);
- } else {
- test = (int) (*(key[0].sk_func))
- (datum,
- DatumGetPointer(key[0].sk_argument));
- }
-
- if (!test == !(key[0].sk_flags & SK_NEGATE)) {
- return (false);
+ /* btree doesn't support 'A is null' clauses, yet */
+ if (isNull || key[0].sk_flags & SK_ISNULL)
+ {
+ return (false);
+ }
+
+ if (key[0].sk_flags & SK_COMMUTE)
+ {
+ test = (int) (*(key[0].sk_func))
+ (DatumGetPointer(key[0].sk_argument),
+ datum);
+ }
+ else
+ {
+ test = (int) (*(key[0].sk_func))
+ (datum,
+ DatumGetPointer(key[0].sk_argument));
+ }
+
+ if (!test == !(key[0].sk_flags & SK_NEGATE))
+ {
+ return (false);
+ }
+
+ keysz -= 1;
+ key++;
+ (*keysok)++;
}
-
- keysz -= 1;
- key++;
- (*keysok)++;
- }
-
- return (true);
+
+ return (true);
}
diff --git a/src/backend/access/rtree/rtget.c b/src/backend/access/rtree/rtget.c
index 09f10f1aa98..eaf16c1ae9d 100644
--- a/src/backend/access/rtree/rtget.c
+++ b/src/backend/access/rtree/rtget.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* rtget.c--
- * fetch tuples from an rtree scan.
+ * fetch tuples from an rtree scan.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtget.c,v 1.7 1996/11/21 06:13:43 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtget.c,v 1.8 1997/09/07 04:39:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <storage/bufmgr.h>
#include <access/sdir.h>
#include <access/relscan.h>
@@ -21,14 +21,15 @@
#include <access/rtree.h>
#include <storage/bufpage.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static OffsetNumber findnext(IndexScanDesc s, Page p, OffsetNumber n,
- ScanDirection dir);
+static OffsetNumber
+findnext(IndexScanDesc s, Page p, OffsetNumber n,
+ ScanDirection dir);
static RetrieveIndexResult rtscancache(IndexScanDesc s, ScanDirection dir);
static RetrieveIndexResult rtfirst(IndexScanDesc s, ScanDirection dir);
static RetrieveIndexResult rtnext(IndexScanDesc s, ScanDirection dir);
@@ -38,278 +39,315 @@ static ItemPointer rtheapptr(Relation r, ItemPointer itemp);
RetrieveIndexResult
rtgettuple(IndexScanDesc s, ScanDirection dir)
{
- RetrieveIndexResult res;
-
- /* if we have it cached in the scan desc, just return the value */
- if ((res = rtscancache(s, dir)) != (RetrieveIndexResult) NULL)
+ RetrieveIndexResult res;
+
+ /* if we have it cached in the scan desc, just return the value */
+ if ((res = rtscancache(s, dir)) != (RetrieveIndexResult) NULL)
+ return (res);
+
+ /* not cached, so we'll have to do some work */
+ if (ItemPointerIsValid(&(s->currentItemData)))
+ {
+ res = rtnext(s, dir);
+ }
+ else
+ {
+ res = rtfirst(s, dir);
+ }
return (res);
-
- /* not cached, so we'll have to do some work */
- if (ItemPointerIsValid(&(s->currentItemData))) {
- res = rtnext(s, dir);
- } else {
- res = rtfirst(s, dir);
- }
- return (res);
}
-static RetrieveIndexResult
+static RetrieveIndexResult
rtfirst(IndexScanDesc s, ScanDirection dir)
{
- Buffer b;
- Page p;
- OffsetNumber n;
- OffsetNumber maxoff;
- RetrieveIndexResult res;
- RTreePageOpaque po;
- RTreeScanOpaque so;
- RTSTACK *stk;
- BlockNumber blk;
- IndexTuple it;
-
- b = ReadBuffer(s->relation, P_ROOT);
- p = BufferGetPage(b);
- po = (RTreePageOpaque) PageGetSpecialPointer(p);
- so = (RTreeScanOpaque) s->opaque;
-
- for (;;) {
- maxoff = PageGetMaxOffsetNumber(p);
- if (ScanDirectionIsBackward(dir))
- n = findnext(s, p, maxoff, dir);
- else
- n = findnext(s, p, FirstOffsetNumber, dir);
-
- while (n < FirstOffsetNumber || n > maxoff) {
-
- ReleaseBuffer(b);
- if (so->s_stack == (RTSTACK *) NULL)
- return ((RetrieveIndexResult) NULL);
-
- stk = so->s_stack;
- b = ReadBuffer(s->relation, stk->rts_blk);
- p = BufferGetPage(b);
- po = (RTreePageOpaque) PageGetSpecialPointer(p);
- maxoff = PageGetMaxOffsetNumber(p);
-
- if (ScanDirectionIsBackward(dir)) {
- n = OffsetNumberPrev(stk->rts_child);
- } else {
- n = OffsetNumberNext(stk->rts_child);
- }
- so->s_stack = stk->rts_parent;
- pfree(stk);
-
- n = findnext(s, p, n, dir);
- }
- if (po->flags & F_LEAF) {
- ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
-
- res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
-
- ReleaseBuffer(b);
- return (res);
- } else {
- stk = (RTSTACK *) palloc(sizeof(RTSTACK));
- stk->rts_child = n;
- stk->rts_blk = BufferGetBlockNumber(b);
- stk->rts_parent = so->s_stack;
- so->s_stack = stk;
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- blk = ItemPointerGetBlockNumber(&(it->t_tid));
-
- ReleaseBuffer(b);
- b = ReadBuffer(s->relation, blk);
- p = BufferGetPage(b);
- po = (RTreePageOpaque) PageGetSpecialPointer(p);
+ Buffer b;
+ Page p;
+ OffsetNumber n;
+ OffsetNumber maxoff;
+ RetrieveIndexResult res;
+ RTreePageOpaque po;
+ RTreeScanOpaque so;
+ RTSTACK *stk;
+ BlockNumber blk;
+ IndexTuple it;
+
+ b = ReadBuffer(s->relation, P_ROOT);
+ p = BufferGetPage(b);
+ po = (RTreePageOpaque) PageGetSpecialPointer(p);
+ so = (RTreeScanOpaque) s->opaque;
+
+ for (;;)
+ {
+ maxoff = PageGetMaxOffsetNumber(p);
+ if (ScanDirectionIsBackward(dir))
+ n = findnext(s, p, maxoff, dir);
+ else
+ n = findnext(s, p, FirstOffsetNumber, dir);
+
+ while (n < FirstOffsetNumber || n > maxoff)
+ {
+
+ ReleaseBuffer(b);
+ if (so->s_stack == (RTSTACK *) NULL)
+ return ((RetrieveIndexResult) NULL);
+
+ stk = so->s_stack;
+ b = ReadBuffer(s->relation, stk->rts_blk);
+ p = BufferGetPage(b);
+ po = (RTreePageOpaque) PageGetSpecialPointer(p);
+ maxoff = PageGetMaxOffsetNumber(p);
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = OffsetNumberPrev(stk->rts_child);
+ }
+ else
+ {
+ n = OffsetNumberNext(stk->rts_child);
+ }
+ so->s_stack = stk->rts_parent;
+ pfree(stk);
+
+ n = findnext(s, p, n, dir);
+ }
+ if (po->flags & F_LEAF)
+ {
+ ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+
+ res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
+
+ ReleaseBuffer(b);
+ return (res);
+ }
+ else
+ {
+ stk = (RTSTACK *) palloc(sizeof(RTSTACK));
+ stk->rts_child = n;
+ stk->rts_blk = BufferGetBlockNumber(b);
+ stk->rts_parent = so->s_stack;
+ so->s_stack = stk;
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+ blk = ItemPointerGetBlockNumber(&(it->t_tid));
+
+ ReleaseBuffer(b);
+ b = ReadBuffer(s->relation, blk);
+ p = BufferGetPage(b);
+ po = (RTreePageOpaque) PageGetSpecialPointer(p);
+ }
}
- }
}
-static RetrieveIndexResult
+static RetrieveIndexResult
rtnext(IndexScanDesc s, ScanDirection dir)
{
- Buffer b;
- Page p;
- OffsetNumber n;
- OffsetNumber maxoff;
- RetrieveIndexResult res;
- RTreePageOpaque po;
- RTreeScanOpaque so;
- RTSTACK *stk;
- BlockNumber blk;
- IndexTuple it;
-
- blk = ItemPointerGetBlockNumber(&(s->currentItemData));
- n = ItemPointerGetOffsetNumber(&(s->currentItemData));
-
- if (ScanDirectionIsForward(dir)) {
- n = OffsetNumberNext(n);
- } else {
- n = OffsetNumberPrev(n);
- }
-
- b = ReadBuffer(s->relation, blk);
- p = BufferGetPage(b);
- po = (RTreePageOpaque) PageGetSpecialPointer(p);
- so = (RTreeScanOpaque) s->opaque;
-
- for (;;) {
- maxoff = PageGetMaxOffsetNumber(p);
- n = findnext(s, p, n, dir);
-
- while (n < FirstOffsetNumber || n > maxoff) {
-
- ReleaseBuffer(b);
- if (so->s_stack == (RTSTACK *) NULL)
- return ((RetrieveIndexResult) NULL);
-
- stk = so->s_stack;
- b = ReadBuffer(s->relation, stk->rts_blk);
- p = BufferGetPage(b);
- maxoff = PageGetMaxOffsetNumber(p);
- po = (RTreePageOpaque) PageGetSpecialPointer(p);
-
- if (ScanDirectionIsBackward(dir)) {
- n = OffsetNumberPrev(stk->rts_child);
- } else {
- n = OffsetNumberNext(stk->rts_child);
- }
- so->s_stack = stk->rts_parent;
- pfree(stk);
-
- n = findnext(s, p, n, dir);
+ Buffer b;
+ Page p;
+ OffsetNumber n;
+ OffsetNumber maxoff;
+ RetrieveIndexResult res;
+ RTreePageOpaque po;
+ RTreeScanOpaque so;
+ RTSTACK *stk;
+ BlockNumber blk;
+ IndexTuple it;
+
+ blk = ItemPointerGetBlockNumber(&(s->currentItemData));
+ n = ItemPointerGetOffsetNumber(&(s->currentItemData));
+
+ if (ScanDirectionIsForward(dir))
+ {
+ n = OffsetNumberNext(n);
+ }
+ else
+ {
+ n = OffsetNumberPrev(n);
}
- if (po->flags & F_LEAF) {
- ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
-
- res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
-
- ReleaseBuffer(b);
- return (res);
- } else {
- stk = (RTSTACK *) palloc(sizeof(RTSTACK));
- stk->rts_child = n;
- stk->rts_blk = BufferGetBlockNumber(b);
- stk->rts_parent = so->s_stack;
- so->s_stack = stk;
-
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- blk = ItemPointerGetBlockNumber(&(it->t_tid));
-
- ReleaseBuffer(b);
- b = ReadBuffer(s->relation, blk);
- p = BufferGetPage(b);
- po = (RTreePageOpaque) PageGetSpecialPointer(p);
-
- if (ScanDirectionIsBackward(dir)) {
- n = PageGetMaxOffsetNumber(p);
- } else {
- n = FirstOffsetNumber;
- }
+
+ b = ReadBuffer(s->relation, blk);
+ p = BufferGetPage(b);
+ po = (RTreePageOpaque) PageGetSpecialPointer(p);
+ so = (RTreeScanOpaque) s->opaque;
+
+ for (;;)
+ {
+ maxoff = PageGetMaxOffsetNumber(p);
+ n = findnext(s, p, n, dir);
+
+ while (n < FirstOffsetNumber || n > maxoff)
+ {
+
+ ReleaseBuffer(b);
+ if (so->s_stack == (RTSTACK *) NULL)
+ return ((RetrieveIndexResult) NULL);
+
+ stk = so->s_stack;
+ b = ReadBuffer(s->relation, stk->rts_blk);
+ p = BufferGetPage(b);
+ maxoff = PageGetMaxOffsetNumber(p);
+ po = (RTreePageOpaque) PageGetSpecialPointer(p);
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = OffsetNumberPrev(stk->rts_child);
+ }
+ else
+ {
+ n = OffsetNumberNext(stk->rts_child);
+ }
+ so->s_stack = stk->rts_parent;
+ pfree(stk);
+
+ n = findnext(s, p, n, dir);
+ }
+ if (po->flags & F_LEAF)
+ {
+ ItemPointerSet(&(s->currentItemData), BufferGetBlockNumber(b), n);
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+
+ res = FormRetrieveIndexResult(&(s->currentItemData), &(it->t_tid));
+
+ ReleaseBuffer(b);
+ return (res);
+ }
+ else
+ {
+ stk = (RTSTACK *) palloc(sizeof(RTSTACK));
+ stk->rts_child = n;
+ stk->rts_blk = BufferGetBlockNumber(b);
+ stk->rts_parent = so->s_stack;
+ so->s_stack = stk;
+
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+ blk = ItemPointerGetBlockNumber(&(it->t_tid));
+
+ ReleaseBuffer(b);
+ b = ReadBuffer(s->relation, blk);
+ p = BufferGetPage(b);
+ po = (RTreePageOpaque) PageGetSpecialPointer(p);
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = PageGetMaxOffsetNumber(p);
+ }
+ else
+ {
+ n = FirstOffsetNumber;
+ }
+ }
}
- }
}
-static OffsetNumber
+static OffsetNumber
findnext(IndexScanDesc s, Page p, OffsetNumber n, ScanDirection dir)
{
- OffsetNumber maxoff;
- IndexTuple it;
- RTreePageOpaque po;
- RTreeScanOpaque so;
-
- maxoff = PageGetMaxOffsetNumber(p);
- po = (RTreePageOpaque) PageGetSpecialPointer(p);
- so = (RTreeScanOpaque) s->opaque;
-
- /*
- * If we modified the index during the scan, we may have a pointer to
- * a ghost tuple, before the scan. If this is the case, back up one.
- */
-
- if (so->s_flags & RTS_CURBEFORE) {
- so->s_flags &= ~RTS_CURBEFORE;
- n = OffsetNumberPrev(n);
- }
-
- while (n >= FirstOffsetNumber && n <= maxoff) {
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- if (po->flags & F_LEAF) {
- if (index_keytest(it,
- RelationGetTupleDescriptor(s->relation),
- s->numberOfKeys, s->keyData))
- break;
- } else {
- if (index_keytest(it,
- RelationGetTupleDescriptor(s->relation),
- so->s_internalNKey, so->s_internalKey))
- break;
+ OffsetNumber maxoff;
+ IndexTuple it;
+ RTreePageOpaque po;
+ RTreeScanOpaque so;
+
+ maxoff = PageGetMaxOffsetNumber(p);
+ po = (RTreePageOpaque) PageGetSpecialPointer(p);
+ so = (RTreeScanOpaque) s->opaque;
+
+ /*
+ * If we modified the index during the scan, we may have a pointer to
+ * a ghost tuple, before the scan. If this is the case, back up one.
+ */
+
+ if (so->s_flags & RTS_CURBEFORE)
+ {
+ so->s_flags &= ~RTS_CURBEFORE;
+ n = OffsetNumberPrev(n);
}
-
- if (ScanDirectionIsBackward(dir)) {
- n = OffsetNumberPrev(n);
- } else {
- n = OffsetNumberNext(n);
+
+ while (n >= FirstOffsetNumber && n <= maxoff)
+ {
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+ if (po->flags & F_LEAF)
+ {
+ if (index_keytest(it,
+ RelationGetTupleDescriptor(s->relation),
+ s->numberOfKeys, s->keyData))
+ break;
+ }
+ else
+ {
+ if (index_keytest(it,
+ RelationGetTupleDescriptor(s->relation),
+ so->s_internalNKey, so->s_internalKey))
+ break;
+ }
+
+ if (ScanDirectionIsBackward(dir))
+ {
+ n = OffsetNumberPrev(n);
+ }
+ else
+ {
+ n = OffsetNumberNext(n);
+ }
}
- }
-
- return (n);
+
+ return (n);
}
-static RetrieveIndexResult
+static RetrieveIndexResult
rtscancache(IndexScanDesc s, ScanDirection dir)
{
- RetrieveIndexResult res;
- ItemPointer ip;
-
- if (!(ScanDirectionIsNoMovement(dir)
- && ItemPointerIsValid(&(s->currentItemData)))) {
-
- return ((RetrieveIndexResult) NULL);
- }
-
- ip = rtheapptr(s->relation, &(s->currentItemData));
-
- if (ItemPointerIsValid(ip))
- res = FormRetrieveIndexResult(&(s->currentItemData), ip);
- else
- res = (RetrieveIndexResult) NULL;
-
- pfree (ip);
-
- return (res);
+ RetrieveIndexResult res;
+ ItemPointer ip;
+
+ if (!(ScanDirectionIsNoMovement(dir)
+ && ItemPointerIsValid(&(s->currentItemData))))
+ {
+
+ return ((RetrieveIndexResult) NULL);
+ }
+
+ ip = rtheapptr(s->relation, &(s->currentItemData));
+
+ if (ItemPointerIsValid(ip))
+ res = FormRetrieveIndexResult(&(s->currentItemData), ip);
+ else
+ res = (RetrieveIndexResult) NULL;
+
+ pfree(ip);
+
+ return (res);
}
/*
- * rtheapptr returns the item pointer to the tuple in the heap relation
- * for which itemp is the index relation item pointer.
+ * rtheapptr returns the item pointer to the tuple in the heap relation
+ * for which itemp is the index relation item pointer.
*/
-static ItemPointer
+static ItemPointer
rtheapptr(Relation r, ItemPointer itemp)
{
- Buffer b;
- Page p;
- IndexTuple it;
- ItemPointer ip;
- OffsetNumber n;
-
- ip = (ItemPointer) palloc(sizeof(ItemPointerData));
- if (ItemPointerIsValid(itemp)) {
- b = ReadBuffer(r, ItemPointerGetBlockNumber(itemp));
- p = BufferGetPage(b);
- n = ItemPointerGetOffsetNumber(itemp);
- it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
- memmove((char *) ip, (char *) &(it->t_tid),
- sizeof(ItemPointerData));
- ReleaseBuffer(b);
- } else {
- ItemPointerSetInvalid(ip);
- }
-
- return (ip);
+ Buffer b;
+ Page p;
+ IndexTuple it;
+ ItemPointer ip;
+ OffsetNumber n;
+
+ ip = (ItemPointer) palloc(sizeof(ItemPointerData));
+ if (ItemPointerIsValid(itemp))
+ {
+ b = ReadBuffer(r, ItemPointerGetBlockNumber(itemp));
+ p = BufferGetPage(b);
+ n = ItemPointerGetOffsetNumber(itemp);
+ it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
+ memmove((char *) ip, (char *) &(it->t_tid),
+ sizeof(ItemPointerData));
+ ReleaseBuffer(b);
+ }
+ else
+ {
+ ItemPointerSetInvalid(ip);
+ }
+
+ return (ip);
}
diff --git a/src/backend/access/rtree/rtproc.c b/src/backend/access/rtree/rtproc.c
index ac7a3abfecf..4b7a9f2a266 100644
--- a/src/backend/access/rtree/rtproc.c
+++ b/src/backend/access/rtree/rtproc.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rtproc.c--
- * pg_amproc entries for rtrees.
+ * pg_amproc entries for rtrees.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtproc.c,v 1.7 1997/04/22 17:31:23 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtproc.c,v 1.8 1997/09/07 04:39:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,136 +17,139 @@
#include <utils/builtins.h>
#include <utils/geo_decls.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
BOX
-*rt_box_union(BOX *a, BOX *b)
+* rt_box_union(BOX * a, BOX * b)
{
- BOX *n;
-
- if ((n = (BOX *) palloc(sizeof (*n))) == (BOX *) NULL)
- elog(WARN, "Cannot allocate box for union");
-
- n->high.x = Max(a->high.x, b->high.x);
- n->high.y = Max(a->high.y, b->high.y);
- n->low.x = Min(a->low.x, b->low.x);
- n->low.y = Min(a->low.y, b->low.y);
-
- return (n);
+ BOX *n;
+
+ if ((n = (BOX *) palloc(sizeof(*n))) == (BOX *) NULL)
+ elog(WARN, "Cannot allocate box for union");
+
+ n->high.x = Max(a->high.x, b->high.x);
+ n->high.y = Max(a->high.y, b->high.y);
+ n->low.x = Min(a->low.x, b->low.x);
+ n->low.y = Min(a->low.y, b->low.y);
+
+ return (n);
}
-BOX *
-rt_box_inter(BOX *a, BOX *b)
+BOX *
+rt_box_inter(BOX * a, BOX * b)
{
- BOX *n;
-
- if ((n = (BOX *) palloc(sizeof (*n))) == (BOX *) NULL)
- elog(WARN, "Cannot allocate box for union");
-
- n->high.x = Min(a->high.x, b->high.x);
- n->high.y = Min(a->high.y, b->high.y);
- n->low.x = Max(a->low.x, b->low.x);
- n->low.y = Max(a->low.y, b->low.y);
-
- if (n->high.x < n->low.x || n->high.y < n->low.y) {
- pfree(n);
- return ((BOX *) NULL);
- }
-
- return (n);
+ BOX *n;
+
+ if ((n = (BOX *) palloc(sizeof(*n))) == (BOX *) NULL)
+ elog(WARN, "Cannot allocate box for union");
+
+ n->high.x = Min(a->high.x, b->high.x);
+ n->high.y = Min(a->high.y, b->high.y);
+ n->low.x = Max(a->low.x, b->low.x);
+ n->low.y = Max(a->low.y, b->low.y);
+
+ if (n->high.x < n->low.x || n->high.y < n->low.y)
+ {
+ pfree(n);
+ return ((BOX *) NULL);
+ }
+
+ return (n);
}
void
-rt_box_size(BOX *a, float *size)
+rt_box_size(BOX * a, float *size)
{
- if (a == (BOX *) NULL || a->high.x <= a->low.x || a->high.y <= a->low.y)
- *size = 0.0;
- else
- *size = (float) ((a->high.x - a->low.x) * (a->high.y - a->low.y));
-
- return;
+ if (a == (BOX *) NULL || a->high.x <= a->low.x || a->high.y <= a->low.y)
+ *size = 0.0;
+ else
+ *size = (float) ((a->high.x - a->low.x) * (a->high.y - a->low.y));
+
+ return;
}
/*
- * rt_bigbox_size() -- Compute a size for big boxes.
+ * rt_bigbox_size() -- Compute a size for big boxes.
*
- * In an earlier release of the system, this routine did something
- * different from rt_box_size. We now use floats, rather than ints,
- * as the return type for the size routine, so we no longer need to
- * have a special return type for big boxes.
+ * In an earlier release of the system, this routine did something
+ * different from rt_box_size. We now use floats, rather than ints,
+ * as the return type for the size routine, so we no longer need to
+ * have a special return type for big boxes.
*/
void
-rt_bigbox_size(BOX *a, float *size)
+rt_bigbox_size(BOX * a, float *size)
{
- rt_box_size(a, size);
+ rt_box_size(a, size);
}
-POLYGON *
-rt_poly_union(POLYGON *a, POLYGON *b)
+POLYGON *
+rt_poly_union(POLYGON * a, POLYGON * b)
{
- POLYGON *p;
-
- p = (POLYGON *)PALLOCTYPE(POLYGON);
-
- if (!PointerIsValid(p))
- elog(WARN, "Cannot allocate polygon for union");
-
- memset((char *) p, 0, sizeof(POLYGON)); /* zero any holes */
- p->size = sizeof(POLYGON);
- p->npts = 0;
- p->boundbox.high.x = Max(a->boundbox.high.x, b->boundbox.high.x);
- p->boundbox.high.y = Max(a->boundbox.high.y, b->boundbox.high.y);
- p->boundbox.low.x = Min(a->boundbox.low.x, b->boundbox.low.x);
- p->boundbox.low.y = Min(a->boundbox.low.y, b->boundbox.low.y);
- return p;
+ POLYGON *p;
+
+ p = (POLYGON *) PALLOCTYPE(POLYGON);
+
+ if (!PointerIsValid(p))
+ elog(WARN, "Cannot allocate polygon for union");
+
+ memset((char *) p, 0, sizeof(POLYGON)); /* zero any holes */
+ p->size = sizeof(POLYGON);
+ p->npts = 0;
+ p->boundbox.high.x = Max(a->boundbox.high.x, b->boundbox.high.x);
+ p->boundbox.high.y = Max(a->boundbox.high.y, b->boundbox.high.y);
+ p->boundbox.low.x = Min(a->boundbox.low.x, b->boundbox.low.x);
+ p->boundbox.low.y = Min(a->boundbox.low.y, b->boundbox.low.y);
+ return p;
}
void
-rt_poly_size(POLYGON *a, float *size)
+rt_poly_size(POLYGON * a, float *size)
{
- double xdim, ydim;
-
- size = (float *) palloc(sizeof(float));
- if (a == (POLYGON *) NULL ||
- a->boundbox.high.x <= a->boundbox.low.x ||
- a->boundbox.high.y <= a->boundbox.low.y)
- *size = 0.0;
- else {
- xdim = (a->boundbox.high.x - a->boundbox.low.x);
- ydim = (a->boundbox.high.y - a->boundbox.low.y);
-
- *size = (float) (xdim * ydim);
- }
-
- return;
+ double xdim,
+ ydim;
+
+ size = (float *) palloc(sizeof(float));
+ if (a == (POLYGON *) NULL ||
+ a->boundbox.high.x <= a->boundbox.low.x ||
+ a->boundbox.high.y <= a->boundbox.low.y)
+ *size = 0.0;
+ else
+ {
+ xdim = (a->boundbox.high.x - a->boundbox.low.x);
+ ydim = (a->boundbox.high.y - a->boundbox.low.y);
+
+ *size = (float) (xdim * ydim);
+ }
+
+ return;
}
-POLYGON *
-rt_poly_inter(POLYGON *a, POLYGON *b)
+POLYGON *
+rt_poly_inter(POLYGON * a, POLYGON * b)
{
- POLYGON *p;
-
- p = (POLYGON *) PALLOCTYPE(POLYGON);
-
- if (!PointerIsValid(p))
- elog(WARN, "Cannot allocate polygon for intersection");
-
- memset((char *) p, 0, sizeof(POLYGON)); /* zero any holes */
- p->size = sizeof(POLYGON);
- p->npts = 0;
- p->boundbox.high.x = Min(a->boundbox.high.x, b->boundbox.high.x);
- p->boundbox.high.y = Min(a->boundbox.high.y, b->boundbox.high.y);
- p->boundbox.low.x = Max(a->boundbox.low.x, b->boundbox.low.x);
- p->boundbox.low.y = Max(a->boundbox.low.y, b->boundbox.low.y);
-
- if (p->boundbox.high.x < p->boundbox.low.x || p->boundbox.high.y < p->boundbox.low.y)
+ POLYGON *p;
+
+ p = (POLYGON *) PALLOCTYPE(POLYGON);
+
+ if (!PointerIsValid(p))
+ elog(WARN, "Cannot allocate polygon for intersection");
+
+ memset((char *) p, 0, sizeof(POLYGON)); /* zero any holes */
+ p->size = sizeof(POLYGON);
+ p->npts = 0;
+ p->boundbox.high.x = Min(a->boundbox.high.x, b->boundbox.high.x);
+ p->boundbox.high.y = Min(a->boundbox.high.y, b->boundbox.high.y);
+ p->boundbox.low.x = Max(a->boundbox.low.x, b->boundbox.low.x);
+ p->boundbox.low.y = Max(a->boundbox.low.y, b->boundbox.low.y);
+
+ if (p->boundbox.high.x < p->boundbox.low.x || p->boundbox.high.y < p->boundbox.low.y)
{
- pfree(p);
- return ((POLYGON *) NULL);
+ pfree(p);
+ return ((POLYGON *) NULL);
}
-
- return (p);
+
+ return (p);
}
diff --git a/src/backend/access/rtree/rtree.c b/src/backend/access/rtree/rtree.c
index 4cd0580c973..ae92ea20136 100644
--- a/src/backend/access/rtree/rtree.c
+++ b/src/backend/access/rtree/rtree.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rtree.c--
- * interface routines for the postgres rtree indexed access method.
+ * interface routines for the postgres rtree indexed access method.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.13 1997/08/12 22:51:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.14 1997/09/07 04:39:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,886 +27,983 @@
#include <storage/bufpage.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-typedef struct SPLITVEC {
- OffsetNumber *spl_left;
- int spl_nleft;
- char *spl_ldatum;
- OffsetNumber *spl_right;
- int spl_nright;
- char *spl_rdatum;
-} SPLITVEC;
-
-typedef struct RTSTATE {
- func_ptr unionFn; /* union function */
- func_ptr sizeFn; /* size function */
- func_ptr interFn; /* intersection function */
-} RTSTATE;
+typedef struct SPLITVEC
+{
+ OffsetNumber *spl_left;
+ int spl_nleft;
+ char *spl_ldatum;
+ OffsetNumber *spl_right;
+ int spl_nright;
+ char *spl_rdatum;
+} SPLITVEC;
+
+typedef struct RTSTATE
+{
+ func_ptr unionFn; /* union function */
+ func_ptr sizeFn; /* size function */
+ func_ptr interFn; /* intersection function */
+} RTSTATE;
/* non-export function prototypes */
-static InsertIndexResult rtdoinsert(Relation r, IndexTuple itup,
- RTSTATE *rtstate);
-static void rttighten(Relation r, RTSTACK *stk, char *datum, int att_size,
- RTSTATE *rtstate);
-static InsertIndexResult dosplit(Relation r, Buffer buffer, RTSTACK *stack,
- IndexTuple itup, RTSTATE *rtstate);
-static void rtintinsert(Relation r, RTSTACK *stk, IndexTuple ltup,
- IndexTuple rtup, RTSTATE *rtstate);
-static void rtnewroot(Relation r, IndexTuple lt, IndexTuple rt);
-static void picksplit(Relation r, Page page, SPLITVEC *v, IndexTuple itup,
- RTSTATE *rtstate);
-static void RTInitBuffer(Buffer b, uint32 f);
-static OffsetNumber choose(Relation r, Page p, IndexTuple it,
- RTSTATE *rtstate);
-static int nospace(Page p, IndexTuple it);
-static void initRtstate(RTSTATE *rtstate, Relation index);
+static InsertIndexResult
+rtdoinsert(Relation r, IndexTuple itup,
+ RTSTATE * rtstate);
+static void
+rttighten(Relation r, RTSTACK * stk, char *datum, int att_size,
+ RTSTATE * rtstate);
+static InsertIndexResult
+dosplit(Relation r, Buffer buffer, RTSTACK * stack,
+ IndexTuple itup, RTSTATE * rtstate);
+static void
+rtintinsert(Relation r, RTSTACK * stk, IndexTuple ltup,
+ IndexTuple rtup, RTSTATE * rtstate);
+static void rtnewroot(Relation r, IndexTuple lt, IndexTuple rt);
+static void
+picksplit(Relation r, Page page, SPLITVEC * v, IndexTuple itup,
+ RTSTATE * rtstate);
+static void RTInitBuffer(Buffer b, uint32 f);
+static OffsetNumber
+choose(Relation r, Page p, IndexTuple it,
+ RTSTATE * rtstate);
+static int nospace(Page p, IndexTuple it);
+static void initRtstate(RTSTATE * rtstate, Relation index);
void
rtbuild(Relation heap,
- Relation index,
- int natts,
- AttrNumber *attnum,
- IndexStrategy istrat,
- uint16 pcount,
- Datum *params,
- FuncIndexInfo *finfo,
- PredInfo *predInfo)
+ Relation index,
+ int natts,
+ AttrNumber * attnum,
+ IndexStrategy istrat,
+ uint16 pcount,
+ Datum * params,
+ FuncIndexInfo * finfo,
+ PredInfo * predInfo)
{
- HeapScanDesc scan;
- Buffer buffer;
- AttrNumber i;
- HeapTuple htup;
- IndexTuple itup;
- TupleDesc hd, id;
- InsertIndexResult res;
- Datum *d;
- bool *nulls;
- int nb, nh, ni;
+ HeapScanDesc scan;
+ Buffer buffer;
+ AttrNumber i;
+ HeapTuple htup;
+ IndexTuple itup;
+ TupleDesc hd,
+ id;
+ InsertIndexResult res;
+ Datum *d;
+ bool *nulls;
+ int nb,
+ nh,
+ ni;
+
#ifndef OMIT_PARTIAL_INDEX
- ExprContext *econtext;
- TupleTable tupleTable;
- TupleTableSlot *slot;
+ ExprContext *econtext;
+ TupleTable tupleTable;
+ TupleTableSlot *slot;
+
#endif
- Oid hrelid, irelid;
- Node *pred, *oldPred;
- RTSTATE rtState;
-
- initRtstate(&rtState, index);
-
- /* rtrees only know how to do stupid locking now */
- RelationSetLockForWrite(index);
-
- pred = predInfo->pred;
- oldPred = predInfo->oldPred;
-
- /*
- * We expect to be called exactly once for any index relation.
- * If that's not the case, big trouble's what we have.
- */
-
- if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
- elog(WARN, "%s already contains data", index->rd_rel->relname.data);
-
- /* initialize the root page (if this is a new index) */
- if (oldPred == NULL) {
- buffer = ReadBuffer(index, P_NEW);
- RTInitBuffer(buffer, F_LEAF);
- WriteBuffer(buffer);
- }
-
- /* init the tuple descriptors and get set for a heap scan */
- hd = RelationGetTupleDescriptor(heap);
- id = RelationGetTupleDescriptor(index);
- d = (Datum *)palloc(natts * sizeof (*d));
- nulls = (bool *)palloc(natts * sizeof (*nulls));
-
- /*
- * If this is a predicate (partial) index, we will need to evaluate the
- * predicate using ExecQual, which requires the current tuple to be in a
- * slot of a TupleTable. In addition, ExecQual must have an ExprContext
- * referring to that slot. Here, we initialize dummy TupleTable and
- * ExprContext objects for this purpose. --Nels, Feb '92
- */
+ Oid hrelid,
+ irelid;
+ Node *pred,
+ *oldPred;
+ RTSTATE rtState;
+
+ initRtstate(&rtState, index);
+
+ /* rtrees only know how to do stupid locking now */
+ RelationSetLockForWrite(index);
+
+ pred = predInfo->pred;
+ oldPred = predInfo->oldPred;
+
+ /*
+ * We expect to be called exactly once for any index relation. If
+ * that's not the case, big trouble's what we have.
+ */
+
+ if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
+ elog(WARN, "%s already contains data", index->rd_rel->relname.data);
+
+ /* initialize the root page (if this is a new index) */
+ if (oldPred == NULL)
+ {
+ buffer = ReadBuffer(index, P_NEW);
+ RTInitBuffer(buffer, F_LEAF);
+ WriteBuffer(buffer);
+ }
+
+ /* init the tuple descriptors and get set for a heap scan */
+ hd = RelationGetTupleDescriptor(heap);
+ id = RelationGetTupleDescriptor(index);
+ d = (Datum *) palloc(natts * sizeof(*d));
+ nulls = (bool *) palloc(natts * sizeof(*nulls));
+
+ /*
+ * If this is a predicate (partial) index, we will need to evaluate
+ * the predicate using ExecQual, which requires the current tuple to
+ * be in a slot of a TupleTable. In addition, ExecQual must have an
+ * ExprContext referring to that slot. Here, we initialize dummy
+ * TupleTable and ExprContext objects for this purpose. --Nels, Feb
+ * '92
+ */
#ifndef OMIT_PARTIAL_INDEX
- if (pred != NULL || oldPred != NULL) {
- tupleTable = ExecCreateTupleTable(1);
- slot = ExecAllocTableSlot(tupleTable);
- econtext = makeNode(ExprContext);
- FillDummyExprContext(econtext, slot, hd, buffer);
- }
+ if (pred != NULL || oldPred != NULL)
+ {
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ econtext = makeNode(ExprContext);
+ FillDummyExprContext(econtext, slot, hd, buffer);
+ }
else
{
econtext = NULL;
tupleTable = NULL;
slot = NULL;
}
-#endif /* OMIT_PARTIAL_INDEX */
- scan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
- htup = heap_getnext(scan, 0, &buffer);
-
- /* count the tuples as we insert them */
- nh = ni = 0;
-
- for (; HeapTupleIsValid(htup); htup = heap_getnext(scan, 0, &buffer)) {
-
- nh++;
-
- /*
- * If oldPred != NULL, this is an EXTEND INDEX command, so skip
- * this tuple if it was already in the existing partial index
- */
- if (oldPred != NULL) {
+#endif /* OMIT_PARTIAL_INDEX */
+ scan = heap_beginscan(heap, 0, NowTimeQual, 0, (ScanKey) NULL);
+ htup = heap_getnext(scan, 0, &buffer);
+
+ /* count the tuples as we insert them */
+ nh = ni = 0;
+
+ for (; HeapTupleIsValid(htup); htup = heap_getnext(scan, 0, &buffer))
+ {
+
+ nh++;
+
+ /*
+ * If oldPred != NULL, this is an EXTEND INDEX command, so skip
+ * this tuple if it was already in the existing partial index
+ */
+ if (oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, htup); */
- slot->val = htup;
- if (ExecQual((List*)oldPred, econtext) == true) {
+ /* SetSlotContents(slot, htup); */
+ slot->val = htup;
+ if (ExecQual((List *) oldPred, econtext) == true)
+ {
+ ni++;
+ continue;
+ }
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
+ /*
+ * Skip this tuple if it doesn't satisfy the partial-index
+ * predicate
+ */
+ if (pred != NULL)
+ {
+#ifndef OMIT_PARTIAL_INDEX
+ /* SetSlotContents(slot, htup); */
+ slot->val = htup;
+ if (ExecQual((List *) pred, econtext) == false)
+ continue;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
ni++;
- continue;
- }
-#endif /* OMIT_PARTIAL_INDEX */
+
+ /*
+ * For the current heap tuple, extract all the attributes we use
+ * in this index, and note which are null.
+ */
+
+ for (i = 1; i <= natts; i++)
+ {
+ int attoff;
+ bool attnull;
+
+ /*
+ * Offsets are from the start of the tuple, and are
+ * zero-based; indices are one-based. The next call returns i
+ * - 1. That's data hiding for you.
+ */
+
+ attoff = AttrNumberGetAttrOffset(i);
+
+ /*
+ * d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
+ */
+ d[attoff] = GetIndexValue(htup,
+ hd,
+ attoff,
+ attnum,
+ finfo,
+ &attnull,
+ buffer);
+ nulls[attoff] = (attnull ? 'n' : ' ');
+ }
+
+ /* form an index tuple and point it at the heap tuple */
+ itup = index_formtuple(id, &d[0], nulls);
+ itup->t_tid = htup->t_ctid;
+
+ /*
+ * Since we already have the index relation locked, we call
+ * rtdoinsert directly. Normal access method calls dispatch
+ * through rtinsert, which locks the relation for write. This is
+ * the right thing to do if you're inserting single tups, but not
+ * when you're initializing the whole index at once.
+ */
+
+ res = rtdoinsert(index, itup, &rtState);
+ pfree(itup);
+ pfree(res);
}
-
- /* Skip this tuple if it doesn't satisfy the partial-index predicate */
- if (pred != NULL) {
+
+ /* okay, all heap tuples are indexed */
+ heap_endscan(scan);
+ RelationUnsetLockForWrite(index);
+
+ if (pred != NULL || oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, htup); */
- slot->val = htup;
- if (ExecQual((List*)pred, econtext) == false)
- continue;
-#endif /* OMIT_PARTIAL_INDEX */
+ ExecDestroyTupleTable(tupleTable, true);
+ pfree(econtext);
+#endif /* OMIT_PARTIAL_INDEX */
}
-
- ni++;
-
+
/*
- * For the current heap tuple, extract all the attributes
- * we use in this index, and note which are null.
+ * Since we just counted the tuples in the heap, we update its stats
+ * in pg_relation to guarantee that the planner takes advantage of the
+ * index we just created. UpdateStats() does a
+ * CommandCounterIncrement(), which flushes changed entries from the
+ * system relcache. The act of constructing an index changes these
+ * heap and index tuples in the system catalogs, so they need to be
+ * flushed. We close them to guarantee that they will be.
*/
-
- for (i = 1; i <= natts; i++) {
- int attoff;
- bool attnull;
-
- /*
- * Offsets are from the start of the tuple, and are
- * zero-based; indices are one-based. The next call
- * returns i - 1. That's data hiding for you.
- */
-
- attoff = AttrNumberGetAttrOffset(i);
- /*
- d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
- */
- d[attoff] = GetIndexValue(htup,
- hd,
- attoff,
- attnum,
- finfo,
- &attnull,
- buffer);
- nulls[attoff] = (attnull ? 'n' : ' ');
+
+ hrelid = heap->rd_id;
+ irelid = index->rd_id;
+ heap_close(heap);
+ index_close(index);
+
+ UpdateStats(hrelid, nh, true);
+ UpdateStats(irelid, ni, false);
+
+ if (oldPred != NULL)
+ {
+ if (ni == nh)
+ pred = NULL;
+ UpdateIndexPredicate(irelid, oldPred, pred);
}
-
- /* form an index tuple and point it at the heap tuple */
- itup = index_formtuple(id, &d[0], nulls);
- itup->t_tid = htup->t_ctid;
-
- /*
- * Since we already have the index relation locked, we
- * call rtdoinsert directly. Normal access method calls
- * dispatch through rtinsert, which locks the relation
- * for write. This is the right thing to do if you're
- * inserting single tups, but not when you're initializing
- * the whole index at once.
- */
-
- res = rtdoinsert(index, itup, &rtState);
- pfree(itup);
- pfree(res);
- }
-
- /* okay, all heap tuples are indexed */
- heap_endscan(scan);
- RelationUnsetLockForWrite(index);
-
- if (pred != NULL || oldPred != NULL) {
-#ifndef OMIT_PARTIAL_INDEX
- ExecDestroyTupleTable(tupleTable, true);
- pfree(econtext);
-#endif /* OMIT_PARTIAL_INDEX */
- }
-
- /*
- * Since we just counted the tuples in the heap, we update its
- * stats in pg_relation to guarantee that the planner takes
- * advantage of the index we just created. UpdateStats() does a
- * CommandCounterIncrement(), which flushes changed entries from
- * the system relcache. The act of constructing an index changes
- * these heap and index tuples in the system catalogs, so they
- * need to be flushed. We close them to guarantee that they
- * will be.
- */
-
- hrelid = heap->rd_id;
- irelid = index->rd_id;
- heap_close(heap);
- index_close(index);
-
- UpdateStats(hrelid, nh, true);
- UpdateStats(irelid, ni, false);
-
- if (oldPred != NULL) {
- if (ni == nh) pred = NULL;
- UpdateIndexPredicate(irelid, oldPred, pred);
- }
-
- /* be tidy */
- pfree(nulls);
- pfree(d);
+
+ /* be tidy */
+ pfree(nulls);
+ pfree(d);
}
/*
- * rtinsert -- wrapper for rtree tuple insertion.
+ * rtinsert -- wrapper for rtree tuple insertion.
*
- * This is the public interface routine for tuple insertion in rtrees.
- * It doesn't do any work; just locks the relation and passes the buck.
+ * This is the public interface routine for tuple insertion in rtrees.
+ * It doesn't do any work; just locks the relation and passes the buck.
*/
InsertIndexResult
-rtinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
+rtinsert(Relation r, Datum * datum, char *nulls, ItemPointer ht_ctid, Relation heapRel)
{
- InsertIndexResult res;
- IndexTuple itup;
- RTSTATE rtState;
-
- /* generate an index tuple */
- itup = index_formtuple(RelationGetTupleDescriptor(r), datum, nulls);
- itup->t_tid = *ht_ctid;
- initRtstate(&rtState, r);
-
- RelationSetLockForWrite(r);
- res = rtdoinsert(r, itup, &rtState);
-
- /* XXX two-phase locking -- don't unlock the relation until EOT */
- return (res);
+ InsertIndexResult res;
+ IndexTuple itup;
+ RTSTATE rtState;
+
+ /* generate an index tuple */
+ itup = index_formtuple(RelationGetTupleDescriptor(r), datum, nulls);
+ itup->t_tid = *ht_ctid;
+ initRtstate(&rtState, r);
+
+ RelationSetLockForWrite(r);
+ res = rtdoinsert(r, itup, &rtState);
+
+ /* XXX two-phase locking -- don't unlock the relation until EOT */
+ return (res);
}
-static InsertIndexResult
-rtdoinsert(Relation r, IndexTuple itup, RTSTATE *rtstate)
+static InsertIndexResult
+rtdoinsert(Relation r, IndexTuple itup, RTSTATE * rtstate)
{
- Page page;
- Buffer buffer;
- BlockNumber blk;
- IndexTuple which;
- OffsetNumber l;
- RTSTACK *stack;
- InsertIndexResult res;
- RTreePageOpaque opaque;
- char *datum;
-
- blk = P_ROOT;
- buffer = InvalidBuffer;
- stack = (RTSTACK *) NULL;
-
- do {
- /* let go of current buffer before getting next */
- if (buffer != InvalidBuffer)
- ReleaseBuffer(buffer);
-
- /* get next buffer */
- buffer = ReadBuffer(r, blk);
- page = (Page) BufferGetPage(buffer);
-
- opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
- if (!(opaque->flags & F_LEAF)) {
- RTSTACK *n;
- ItemId iid;
-
- n = (RTSTACK *) palloc(sizeof(RTSTACK));
- n->rts_parent = stack;
- n->rts_blk = blk;
- n->rts_child = choose(r, page, itup, rtstate);
- stack = n;
-
- iid = PageGetItemId(page, n->rts_child);
- which = (IndexTuple) PageGetItem(page, iid);
- blk = ItemPointerGetBlockNumber(&(which->t_tid));
+ Page page;
+ Buffer buffer;
+ BlockNumber blk;
+ IndexTuple which;
+ OffsetNumber l;
+ RTSTACK *stack;
+ InsertIndexResult res;
+ RTreePageOpaque opaque;
+ char *datum;
+
+ blk = P_ROOT;
+ buffer = InvalidBuffer;
+ stack = (RTSTACK *) NULL;
+
+ do
+ {
+ /* let go of current buffer before getting next */
+ if (buffer != InvalidBuffer)
+ ReleaseBuffer(buffer);
+
+ /* get next buffer */
+ buffer = ReadBuffer(r, blk);
+ page = (Page) BufferGetPage(buffer);
+
+ opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
+ if (!(opaque->flags & F_LEAF))
+ {
+ RTSTACK *n;
+ ItemId iid;
+
+ n = (RTSTACK *) palloc(sizeof(RTSTACK));
+ n->rts_parent = stack;
+ n->rts_blk = blk;
+ n->rts_child = choose(r, page, itup, rtstate);
+ stack = n;
+
+ iid = PageGetItemId(page, n->rts_child);
+ which = (IndexTuple) PageGetItem(page, iid);
+ blk = ItemPointerGetBlockNumber(&(which->t_tid));
+ }
+ } while (!(opaque->flags & F_LEAF));
+
+ if (nospace(page, itup))
+ {
+ /* need to do a split */
+ res = dosplit(r, buffer, stack, itup, rtstate);
+ freestack(stack);
+ WriteBuffer(buffer); /* don't forget to release buffer! */
+ return (res);
+ }
+
+ /* add the item and write the buffer */
+ if (PageIsEmpty(page))
+ {
+ l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
+ FirstOffsetNumber,
+ LP_USED);
}
- } while (!(opaque->flags & F_LEAF));
-
- if (nospace(page, itup)) {
- /* need to do a split */
- res = dosplit(r, buffer, stack, itup, rtstate);
+ else
+ {
+ l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
+ OffsetNumberNext(PageGetMaxOffsetNumber(page)),
+ LP_USED);
+ }
+
+ WriteBuffer(buffer);
+
+ datum = (((char *) itup) + sizeof(IndexTupleData));
+
+ /* now expand the page boundary in the parent to include the new child */
+ rttighten(r, stack, datum,
+ (IndexTupleSize(itup) - sizeof(IndexTupleData)), rtstate);
freestack(stack);
- WriteBuffer(buffer); /* don't forget to release buffer! */
+
+ /* build and return an InsertIndexResult for this insertion */
+ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
+ ItemPointerSet(&(res->pointerData), blk, l);
+
return (res);
- }
-
- /* add the item and write the buffer */
- if (PageIsEmpty(page)) {
- l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
- FirstOffsetNumber,
- LP_USED);
- } else {
- l = PageAddItem(page, (Item) itup, IndexTupleSize(itup),
- OffsetNumberNext(PageGetMaxOffsetNumber(page)),
- LP_USED);
- }
-
- WriteBuffer(buffer);
-
- datum = (((char *) itup) + sizeof(IndexTupleData));
-
- /* now expand the page boundary in the parent to include the new child */
- rttighten(r, stack, datum,
- (IndexTupleSize(itup) - sizeof(IndexTupleData)), rtstate);
- freestack(stack);
-
- /* build and return an InsertIndexResult for this insertion */
- res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
- ItemPointerSet(&(res->pointerData), blk, l);
-
- return (res);
}
static void
rttighten(Relation r,
- RTSTACK *stk,
- char *datum,
- int att_size,
- RTSTATE *rtstate)
+ RTSTACK * stk,
+ char *datum,
+ int att_size,
+ RTSTATE * rtstate)
{
- char *oldud;
- char *tdatum;
- Page p;
- float old_size, newd_size;
- Buffer b;
-
- if (stk == (RTSTACK *) NULL)
- return;
-
- b = ReadBuffer(r, stk->rts_blk);
- p = BufferGetPage(b);
-
- oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->rts_child));
- oldud += sizeof(IndexTupleData);
-
- (*rtstate->sizeFn)(oldud, &old_size);
- datum = (char *) (*rtstate->unionFn)(oldud, datum);
-
- (*rtstate->sizeFn)(datum, &newd_size);
-
- if (newd_size != old_size) {
- TupleDesc td = RelationGetTupleDescriptor(r);
-
- if (td->attrs[0]->attlen < 0) {
- /*
- * This is an internal page, so 'oldud' had better be a
- * union (constant-length) key, too. (See comment below.)
- */
- Assert(VARSIZE(datum) == VARSIZE(oldud));
- memmove(oldud, datum, VARSIZE(datum));
- } else {
- memmove(oldud, datum, att_size);
+ char *oldud;
+ char *tdatum;
+ Page p;
+ float old_size,
+ newd_size;
+ Buffer b;
+
+ if (stk == (RTSTACK *) NULL)
+ return;
+
+ b = ReadBuffer(r, stk->rts_blk);
+ p = BufferGetPage(b);
+
+ oldud = (char *) PageGetItem(p, PageGetItemId(p, stk->rts_child));
+ oldud += sizeof(IndexTupleData);
+
+ (*rtstate->sizeFn) (oldud, &old_size);
+ datum = (char *) (*rtstate->unionFn) (oldud, datum);
+
+ (*rtstate->sizeFn) (datum, &newd_size);
+
+ if (newd_size != old_size)
+ {
+ TupleDesc td = RelationGetTupleDescriptor(r);
+
+ if (td->attrs[0]->attlen < 0)
+ {
+
+ /*
+ * This is an internal page, so 'oldud' had better be a union
+ * (constant-length) key, too. (See comment below.)
+ */
+ Assert(VARSIZE(datum) == VARSIZE(oldud));
+ memmove(oldud, datum, VARSIZE(datum));
+ }
+ else
+ {
+ memmove(oldud, datum, att_size);
+ }
+ WriteBuffer(b);
+
+ /*
+ * The user may be defining an index on variable-sized data (like
+ * polygons). If so, we need to get a constant-sized datum for
+ * insertion on the internal page. We do this by calling the
+ * union proc, which is guaranteed to return a rectangle.
+ */
+
+ tdatum = (char *) (*rtstate->unionFn) (datum, datum);
+ rttighten(r, stk->rts_parent, tdatum, att_size, rtstate);
+ pfree(tdatum);
}
- WriteBuffer(b);
-
- /*
- * The user may be defining an index on variable-sized data (like
- * polygons). If so, we need to get a constant-sized datum for
- * insertion on the internal page. We do this by calling the union
- * proc, which is guaranteed to return a rectangle.
- */
-
- tdatum = (char *) (*rtstate->unionFn)(datum, datum);
- rttighten(r, stk->rts_parent, tdatum, att_size, rtstate);
- pfree(tdatum);
- } else {
- ReleaseBuffer(b);
- }
- pfree(datum);
+ else
+ {
+ ReleaseBuffer(b);
+ }
+ pfree(datum);
}
/*
- * dosplit -- split a page in the tree.
+ * dosplit -- split a page in the tree.
*
- * This is the quadratic-cost split algorithm Guttman describes in
- * his paper. The reason we chose it is that you can implement this
- * with less information about the data types on which you're operating.
+ * This is the quadratic-cost split algorithm Guttman describes in
+ * his paper. The reason we chose it is that you can implement this
+ * with less information about the data types on which you're operating.
*/
-static InsertIndexResult
+static InsertIndexResult
dosplit(Relation r,
- Buffer buffer,
- RTSTACK *stack,
- IndexTuple itup,
- RTSTATE *rtstate)
+ Buffer buffer,
+ RTSTACK * stack,
+ IndexTuple itup,
+ RTSTATE * rtstate)
{
- Page p;
- Buffer leftbuf, rightbuf;
- Page left, right;
- ItemId itemid;
- IndexTuple item;
- IndexTuple ltup, rtup;
- OffsetNumber maxoff;
- OffsetNumber i;
- OffsetNumber leftoff, rightoff;
- BlockNumber lbknum, rbknum;
- BlockNumber bufblock;
- RTreePageOpaque opaque;
- int blank;
- InsertIndexResult res;
- char *isnull;
- SPLITVEC v;
- TupleDesc tupDesc;
-
- isnull = (char *) palloc(r->rd_rel->relnatts);
- for (blank = 0; blank < r->rd_rel->relnatts; blank++)
- isnull[blank] = ' ';
- p = (Page) BufferGetPage(buffer);
- opaque = (RTreePageOpaque) PageGetSpecialPointer(p);
-
- /*
- * The root of the tree is the first block in the relation. If
- * we're about to split the root, we need to do some hocus-pocus
- * to enforce this guarantee.
- */
-
- if (BufferGetBlockNumber(buffer) == P_ROOT) {
- leftbuf = ReadBuffer(r, P_NEW);
- RTInitBuffer(leftbuf, opaque->flags);
- lbknum = BufferGetBlockNumber(leftbuf);
- left = (Page) BufferGetPage(leftbuf);
- } else {
- leftbuf = buffer;
- IncrBufferRefCount(buffer);
- lbknum = BufferGetBlockNumber(buffer);
- left = (Page) PageGetTempPage(p, sizeof(RTreePageOpaqueData));
- }
-
- rightbuf = ReadBuffer(r, P_NEW);
- RTInitBuffer(rightbuf, opaque->flags);
- rbknum = BufferGetBlockNumber(rightbuf);
- right = (Page) BufferGetPage(rightbuf);
-
- picksplit(r, p, &v, itup, rtstate);
-
- leftoff = rightoff = FirstOffsetNumber;
- maxoff = PageGetMaxOffsetNumber(p);
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
- itemid = PageGetItemId(p, i);
- item = (IndexTuple) PageGetItem(p, itemid);
-
- if (i == *(v.spl_left)) {
- PageAddItem(left, (Item) item, IndexTupleSize(item),
- leftoff, LP_USED);
- leftoff = OffsetNumberNext(leftoff);
- v.spl_left++; /* advance in left split vector */
- } else {
- PageAddItem(right, (Item) item, IndexTupleSize(item),
- rightoff, LP_USED);
- rightoff = OffsetNumberNext(rightoff);
- v.spl_right++; /* advance in right split vector */
+ Page p;
+ Buffer leftbuf,
+ rightbuf;
+ Page left,
+ right;
+ ItemId itemid;
+ IndexTuple item;
+ IndexTuple ltup,
+ rtup;
+ OffsetNumber maxoff;
+ OffsetNumber i;
+ OffsetNumber leftoff,
+ rightoff;
+ BlockNumber lbknum,
+ rbknum;
+ BlockNumber bufblock;
+ RTreePageOpaque opaque;
+ int blank;
+ InsertIndexResult res;
+ char *isnull;
+ SPLITVEC v;
+ TupleDesc tupDesc;
+
+ isnull = (char *) palloc(r->rd_rel->relnatts);
+ for (blank = 0; blank < r->rd_rel->relnatts; blank++)
+ isnull[blank] = ' ';
+ p = (Page) BufferGetPage(buffer);
+ opaque = (RTreePageOpaque) PageGetSpecialPointer(p);
+
+ /*
+ * The root of the tree is the first block in the relation. If we're
+ * about to split the root, we need to do some hocus-pocus to enforce
+ * this guarantee.
+ */
+
+ if (BufferGetBlockNumber(buffer) == P_ROOT)
+ {
+ leftbuf = ReadBuffer(r, P_NEW);
+ RTInitBuffer(leftbuf, opaque->flags);
+ lbknum = BufferGetBlockNumber(leftbuf);
+ left = (Page) BufferGetPage(leftbuf);
}
- }
-
- /* build an InsertIndexResult for this insertion */
- res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
-
- /* now insert the new index tuple */
- if (*(v.spl_left) != FirstOffsetNumber) {
- PageAddItem(left, (Item) itup, IndexTupleSize(itup),
- leftoff, LP_USED);
- leftoff = OffsetNumberNext(leftoff);
- ItemPointerSet(&(res->pointerData), lbknum, leftoff);
- } else {
- PageAddItem(right, (Item) itup, IndexTupleSize(itup),
- rightoff, LP_USED);
- rightoff = OffsetNumberNext(rightoff);
- ItemPointerSet(&(res->pointerData), rbknum, rightoff);
- }
-
- if ((bufblock = BufferGetBlockNumber(buffer)) != P_ROOT) {
- PageRestoreTempPage(left, p);
- }
- WriteBuffer(leftbuf);
- WriteBuffer(rightbuf);
-
- /*
- * Okay, the page is split. We have three things left to do:
- *
- * 1) Adjust any active scans on this index to cope with changes
- * we introduced in its structure by splitting this page.
- *
- * 2) "Tighten" the bounding box of the pointer to the left
- * page in the parent node in the tree, if any. Since we
- * moved a bunch of stuff off the left page, we expect it
- * to get smaller. This happens in the internal insertion
- * routine.
- *
- * 3) Insert a pointer to the right page in the parent. This
- * may cause the parent to split. If it does, we need to
- * repeat steps one and two for each split node in the tree.
- */
-
- /* adjust active scans */
- rtadjscans(r, RTOP_SPLIT, bufblock, FirstOffsetNumber);
-
- tupDesc = r->rd_att;
- ltup = (IndexTuple) index_formtuple(tupDesc,
- (Datum *) &(v.spl_ldatum), isnull);
- rtup = (IndexTuple) index_formtuple(tupDesc,
- (Datum *) &(v.spl_rdatum), isnull);
- pfree(isnull);
-
- /* set pointers to new child pages in the internal index tuples */
- ItemPointerSet(&(ltup->t_tid), lbknum, 1);
- ItemPointerSet(&(rtup->t_tid), rbknum, 1);
-
- rtintinsert(r, stack, ltup, rtup, rtstate);
-
- pfree(ltup);
- pfree(rtup);
-
- return (res);
+ else
+ {
+ leftbuf = buffer;
+ IncrBufferRefCount(buffer);
+ lbknum = BufferGetBlockNumber(buffer);
+ left = (Page) PageGetTempPage(p, sizeof(RTreePageOpaqueData));
+ }
+
+ rightbuf = ReadBuffer(r, P_NEW);
+ RTInitBuffer(rightbuf, opaque->flags);
+ rbknum = BufferGetBlockNumber(rightbuf);
+ right = (Page) BufferGetPage(rightbuf);
+
+ picksplit(r, p, &v, itup, rtstate);
+
+ leftoff = rightoff = FirstOffsetNumber;
+ maxoff = PageGetMaxOffsetNumber(p);
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ itemid = PageGetItemId(p, i);
+ item = (IndexTuple) PageGetItem(p, itemid);
+
+ if (i == *(v.spl_left))
+ {
+ PageAddItem(left, (Item) item, IndexTupleSize(item),
+ leftoff, LP_USED);
+ leftoff = OffsetNumberNext(leftoff);
+ v.spl_left++; /* advance in left split vector */
+ }
+ else
+ {
+ PageAddItem(right, (Item) item, IndexTupleSize(item),
+ rightoff, LP_USED);
+ rightoff = OffsetNumberNext(rightoff);
+ v.spl_right++; /* advance in right split vector */
+ }
+ }
+
+ /* build an InsertIndexResult for this insertion */
+ res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
+
+ /* now insert the new index tuple */
+ if (*(v.spl_left) != FirstOffsetNumber)
+ {
+ PageAddItem(left, (Item) itup, IndexTupleSize(itup),
+ leftoff, LP_USED);
+ leftoff = OffsetNumberNext(leftoff);
+ ItemPointerSet(&(res->pointerData), lbknum, leftoff);
+ }
+ else
+ {
+ PageAddItem(right, (Item) itup, IndexTupleSize(itup),
+ rightoff, LP_USED);
+ rightoff = OffsetNumberNext(rightoff);
+ ItemPointerSet(&(res->pointerData), rbknum, rightoff);
+ }
+
+ if ((bufblock = BufferGetBlockNumber(buffer)) != P_ROOT)
+ {
+ PageRestoreTempPage(left, p);
+ }
+ WriteBuffer(leftbuf);
+ WriteBuffer(rightbuf);
+
+ /*
+ * Okay, the page is split. We have three things left to do:
+ *
+ * 1) Adjust any active scans on this index to cope with changes we
+ * introduced in its structure by splitting this page.
+ *
+ * 2) "Tighten" the bounding box of the pointer to the left page in the
+ * parent node in the tree, if any. Since we moved a bunch of stuff
+ * off the left page, we expect it to get smaller. This happens in
+ * the internal insertion routine.
+ *
+ * 3) Insert a pointer to the right page in the parent. This may cause
+ * the parent to split. If it does, we need to repeat steps one and
+ * two for each split node in the tree.
+ */
+
+ /* adjust active scans */
+ rtadjscans(r, RTOP_SPLIT, bufblock, FirstOffsetNumber);
+
+ tupDesc = r->rd_att;
+ ltup = (IndexTuple) index_formtuple(tupDesc,
+ (Datum *) & (v.spl_ldatum), isnull);
+ rtup = (IndexTuple) index_formtuple(tupDesc,
+ (Datum *) & (v.spl_rdatum), isnull);
+ pfree(isnull);
+
+ /* set pointers to new child pages in the internal index tuples */
+ ItemPointerSet(&(ltup->t_tid), lbknum, 1);
+ ItemPointerSet(&(rtup->t_tid), rbknum, 1);
+
+ rtintinsert(r, stack, ltup, rtup, rtstate);
+
+ pfree(ltup);
+ pfree(rtup);
+
+ return (res);
}
static void
rtintinsert(Relation r,
- RTSTACK *stk,
- IndexTuple ltup,
- IndexTuple rtup,
- RTSTATE *rtstate)
+ RTSTACK * stk,
+ IndexTuple ltup,
+ IndexTuple rtup,
+ RTSTATE * rtstate)
{
- IndexTuple old;
- Buffer b;
- Page p;
- char *ldatum, *rdatum, *newdatum;
- InsertIndexResult res;
-
- if (stk == (RTSTACK *) NULL) {
- rtnewroot(r, ltup, rtup);
- return;
- }
-
- b = ReadBuffer(r, stk->rts_blk);
- p = BufferGetPage(b);
- old = (IndexTuple) PageGetItem(p, PageGetItemId(p, stk->rts_child));
-
- /*
- * This is a hack. Right now, we force rtree keys to be constant size.
- * To fix this, need delete the old key and add both left and right
- * for the two new pages. The insertion of left may force a split if
- * the new left key is bigger than the old key.
- */
-
- if (IndexTupleSize(old) != IndexTupleSize(ltup))
- elog(WARN, "Variable-length rtree keys are not supported.");
-
- /* install pointer to left child */
- memmove(old, ltup,IndexTupleSize(ltup));
-
- if (nospace(p, rtup)) {
- newdatum = (((char *) ltup) + sizeof(IndexTupleData));
- rttighten(r, stk->rts_parent, newdatum,
- (IndexTupleSize(ltup) - sizeof(IndexTupleData)), rtstate);
- res = dosplit(r, b, stk->rts_parent, rtup, rtstate);
- WriteBuffer(b); /* don't forget to release buffer! - 01/31/94 */
- pfree(res);
- } else {
- PageAddItem(p, (Item) rtup, IndexTupleSize(rtup),
- PageGetMaxOffsetNumber(p), LP_USED);
- WriteBuffer(b);
- ldatum = (((char *) ltup) + sizeof(IndexTupleData));
- rdatum = (((char *) rtup) + sizeof(IndexTupleData));
- newdatum = (char *) (*rtstate->unionFn)(ldatum, rdatum);
-
- rttighten(r, stk->rts_parent, newdatum,
- (IndexTupleSize(rtup) - sizeof(IndexTupleData)), rtstate);
-
- pfree(newdatum);
- }
+ IndexTuple old;
+ Buffer b;
+ Page p;
+ char *ldatum,
+ *rdatum,
+ *newdatum;
+ InsertIndexResult res;
+
+ if (stk == (RTSTACK *) NULL)
+ {
+ rtnewroot(r, ltup, rtup);
+ return;
+ }
+
+ b = ReadBuffer(r, stk->rts_blk);
+ p = BufferGetPage(b);
+ old = (IndexTuple) PageGetItem(p, PageGetItemId(p, stk->rts_child));
+
+ /*
+ * This is a hack. Right now, we force rtree keys to be constant
+ * size. To fix this, need delete the old key and add both left and
+ * right for the two new pages. The insertion of left may force a
+ * split if the new left key is bigger than the old key.
+ */
+
+ if (IndexTupleSize(old) != IndexTupleSize(ltup))
+ elog(WARN, "Variable-length rtree keys are not supported.");
+
+ /* install pointer to left child */
+ memmove(old, ltup, IndexTupleSize(ltup));
+
+ if (nospace(p, rtup))
+ {
+ newdatum = (((char *) ltup) + sizeof(IndexTupleData));
+ rttighten(r, stk->rts_parent, newdatum,
+ (IndexTupleSize(ltup) - sizeof(IndexTupleData)), rtstate);
+ res = dosplit(r, b, stk->rts_parent, rtup, rtstate);
+ WriteBuffer(b); /* don't forget to release buffer! -
+ * 01/31/94 */
+ pfree(res);
+ }
+ else
+ {
+ PageAddItem(p, (Item) rtup, IndexTupleSize(rtup),
+ PageGetMaxOffsetNumber(p), LP_USED);
+ WriteBuffer(b);
+ ldatum = (((char *) ltup) + sizeof(IndexTupleData));
+ rdatum = (((char *) rtup) + sizeof(IndexTupleData));
+ newdatum = (char *) (*rtstate->unionFn) (ldatum, rdatum);
+
+ rttighten(r, stk->rts_parent, newdatum,
+ (IndexTupleSize(rtup) - sizeof(IndexTupleData)), rtstate);
+
+ pfree(newdatum);
+ }
}
static void
rtnewroot(Relation r, IndexTuple lt, IndexTuple rt)
{
- Buffer b;
- Page p;
-
- b = ReadBuffer(r, P_ROOT);
- RTInitBuffer(b, 0);
- p = BufferGetPage(b);
- PageAddItem(p, (Item) lt, IndexTupleSize(lt),
- FirstOffsetNumber, LP_USED);
- PageAddItem(p, (Item) rt, IndexTupleSize(rt),
- OffsetNumberNext(FirstOffsetNumber), LP_USED);
- WriteBuffer(b);
+ Buffer b;
+ Page p;
+
+ b = ReadBuffer(r, P_ROOT);
+ RTInitBuffer(b, 0);
+ p = BufferGetPage(b);
+ PageAddItem(p, (Item) lt, IndexTupleSize(lt),
+ FirstOffsetNumber, LP_USED);
+ PageAddItem(p, (Item) rt, IndexTupleSize(rt),
+ OffsetNumberNext(FirstOffsetNumber), LP_USED);
+ WriteBuffer(b);
}
static void
picksplit(Relation r,
- Page page,
- SPLITVEC *v,
- IndexTuple itup,
- RTSTATE *rtstate)
+ Page page,
+ SPLITVEC * v,
+ IndexTuple itup,
+ RTSTATE * rtstate)
{
- OffsetNumber maxoff;
- OffsetNumber i, j;
- IndexTuple item_1, item_2;
- char *datum_alpha, *datum_beta;
- char *datum_l, *datum_r;
- char *union_d, *union_dl, *union_dr;
- char *inter_d;
- bool firsttime;
- float size_alpha, size_beta, size_union, size_inter;
- float size_waste, waste;
- float size_l, size_r;
- int nbytes;
- OffsetNumber seed_1 = 0, seed_2 = 0;
- OffsetNumber *left, *right;
-
- maxoff = PageGetMaxOffsetNumber(page);
-
- nbytes = (maxoff + 2) * sizeof(OffsetNumber);
- v->spl_left = (OffsetNumber *) palloc(nbytes);
- v->spl_right = (OffsetNumber *) palloc(nbytes);
-
- firsttime = true;
- waste = 0.0;
-
- for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i)) {
- item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
- datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
- for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j)) {
- item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, j));
- datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
-
- /* compute the wasted space by unioning these guys */
- union_d = (char *)(rtstate->unionFn)(datum_alpha, datum_beta);
- (rtstate->sizeFn)(union_d, &size_union);
- inter_d = (char *)(rtstate->interFn)(datum_alpha, datum_beta);
- (rtstate->sizeFn)(inter_d, &size_inter);
- size_waste = size_union - size_inter;
-
- pfree(union_d);
-
- if (inter_d != (char *) NULL)
- pfree(inter_d);
-
- /*
- * are these a more promising split that what we've
- * already seen?
- */
-
- if (size_waste > waste || firsttime) {
- waste = size_waste;
- seed_1 = i;
- seed_2 = j;
- firsttime = false;
- }
+ OffsetNumber maxoff;
+ OffsetNumber i,
+ j;
+ IndexTuple item_1,
+ item_2;
+ char *datum_alpha,
+ *datum_beta;
+ char *datum_l,
+ *datum_r;
+ char *union_d,
+ *union_dl,
+ *union_dr;
+ char *inter_d;
+ bool firsttime;
+ float size_alpha,
+ size_beta,
+ size_union,
+ size_inter;
+ float size_waste,
+ waste;
+ float size_l,
+ size_r;
+ int nbytes;
+ OffsetNumber seed_1 = 0,
+ seed_2 = 0;
+ OffsetNumber *left,
+ *right;
+
+ maxoff = PageGetMaxOffsetNumber(page);
+
+ nbytes = (maxoff + 2) * sizeof(OffsetNumber);
+ v->spl_left = (OffsetNumber *) palloc(nbytes);
+ v->spl_right = (OffsetNumber *) palloc(nbytes);
+
+ firsttime = true;
+ waste = 0.0;
+
+ for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
+ {
+ item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
+ datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
+ for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
+ {
+ item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, j));
+ datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
+
+ /* compute the wasted space by unioning these guys */
+ union_d = (char *) (rtstate->unionFn) (datum_alpha, datum_beta);
+ (rtstate->sizeFn) (union_d, &size_union);
+ inter_d = (char *) (rtstate->interFn) (datum_alpha, datum_beta);
+ (rtstate->sizeFn) (inter_d, &size_inter);
+ size_waste = size_union - size_inter;
+
+ pfree(union_d);
+
+ if (inter_d != (char *) NULL)
+ pfree(inter_d);
+
+ /*
+ * are these a more promising split that what we've already
+ * seen?
+ */
+
+ if (size_waste > waste || firsttime)
+ {
+ waste = size_waste;
+ seed_1 = i;
+ seed_2 = j;
+ firsttime = false;
+ }
+ }
}
- }
-
- left = v->spl_left;
- v->spl_nleft = 0;
- right = v->spl_right;
- v->spl_nright = 0;
-
- item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_1));
- datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
- datum_l = (char *)(*rtstate->unionFn)(datum_alpha, datum_alpha);
- (*rtstate->sizeFn)(datum_l, &size_l);
- item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_2));
- datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
- datum_r = (char *)(*rtstate->unionFn)(datum_beta, datum_beta);
- (*rtstate->sizeFn)(datum_r, &size_r);
-
- /*
- * Now split up the regions between the two seeds. An important
- * property of this split algorithm is that the split vector v
- * has the indices of items to be split in order in its left and
- * right vectors. We exploit this property by doing a merge in
- * the code that actually splits the page.
- *
- * For efficiency, we also place the new index tuple in this loop.
- * This is handled at the very end, when we have placed all the
- * existing tuples and i == maxoff + 1.
- */
-
- maxoff = OffsetNumberNext(maxoff);
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
-
+
+ left = v->spl_left;
+ v->spl_nleft = 0;
+ right = v->spl_right;
+ v->spl_nright = 0;
+
+ item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_1));
+ datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
+ datum_l = (char *) (*rtstate->unionFn) (datum_alpha, datum_alpha);
+ (*rtstate->sizeFn) (datum_l, &size_l);
+ item_2 = (IndexTuple) PageGetItem(page, PageGetItemId(page, seed_2));
+ datum_beta = ((char *) item_2) + sizeof(IndexTupleData);
+ datum_r = (char *) (*rtstate->unionFn) (datum_beta, datum_beta);
+ (*rtstate->sizeFn) (datum_r, &size_r);
+
/*
- * If we've already decided where to place this item, just
- * put it on the right list. Otherwise, we need to figure
- * out which page needs the least enlargement in order to
- * store the item.
+ * Now split up the regions between the two seeds. An important
+ * property of this split algorithm is that the split vector v has the
+ * indices of items to be split in order in its left and right
+ * vectors. We exploit this property by doing a merge in the code
+ * that actually splits the page.
+ *
+ * For efficiency, we also place the new index tuple in this loop. This
+ * is handled at the very end, when we have placed all the existing
+ * tuples and i == maxoff + 1.
*/
-
- if (i == seed_1) {
- *left++ = i;
- v->spl_nleft++;
- continue;
- } else if (i == seed_2) {
- *right++ = i;
- v->spl_nright++;
- continue;
- }
-
- /* okay, which page needs least enlargement? */
- if (i == maxoff) {
- item_1 = itup;
- } else {
- item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
- }
-
- datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
- union_dl = (char *)(*rtstate->unionFn)(datum_l, datum_alpha);
- union_dr = (char *)(*rtstate->unionFn)(datum_r, datum_alpha);
- (*rtstate->sizeFn)(union_dl, &size_alpha);
- (*rtstate->sizeFn)(union_dr, &size_beta);
-
- /* pick which page to add it to */
- if (size_alpha - size_l < size_beta - size_r) {
- pfree(datum_l);
- pfree(union_dr);
- datum_l = union_dl;
- size_l = size_alpha;
- *left++ = i;
- v->spl_nleft++;
- } else {
- pfree(datum_r);
- pfree(union_dl);
- datum_r = union_dr;
- size_r = size_alpha;
- *right++ = i;
- v->spl_nright++;
+
+ maxoff = OffsetNumberNext(maxoff);
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+
+ /*
+ * If we've already decided where to place this item, just put it
+ * on the right list. Otherwise, we need to figure out which page
+ * needs the least enlargement in order to store the item.
+ */
+
+ if (i == seed_1)
+ {
+ *left++ = i;
+ v->spl_nleft++;
+ continue;
+ }
+ else if (i == seed_2)
+ {
+ *right++ = i;
+ v->spl_nright++;
+ continue;
+ }
+
+ /* okay, which page needs least enlargement? */
+ if (i == maxoff)
+ {
+ item_1 = itup;
+ }
+ else
+ {
+ item_1 = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
+ }
+
+ datum_alpha = ((char *) item_1) + sizeof(IndexTupleData);
+ union_dl = (char *) (*rtstate->unionFn) (datum_l, datum_alpha);
+ union_dr = (char *) (*rtstate->unionFn) (datum_r, datum_alpha);
+ (*rtstate->sizeFn) (union_dl, &size_alpha);
+ (*rtstate->sizeFn) (union_dr, &size_beta);
+
+ /* pick which page to add it to */
+ if (size_alpha - size_l < size_beta - size_r)
+ {
+ pfree(datum_l);
+ pfree(union_dr);
+ datum_l = union_dl;
+ size_l = size_alpha;
+ *left++ = i;
+ v->spl_nleft++;
+ }
+ else
+ {
+ pfree(datum_r);
+ pfree(union_dl);
+ datum_r = union_dr;
+ size_r = size_alpha;
+ *right++ = i;
+ v->spl_nright++;
+ }
}
- }
- *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
-
- v->spl_ldatum = datum_l;
- v->spl_rdatum = datum_r;
+ *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
+
+ v->spl_ldatum = datum_l;
+ v->spl_rdatum = datum_r;
}
static void
RTInitBuffer(Buffer b, uint32 f)
{
- RTreePageOpaque opaque;
- Page page;
- Size pageSize;
-
- pageSize = BufferGetPageSize(b);
-
- page = BufferGetPage(b);
- memset(page, 0, (int) pageSize);
- PageInit(page, pageSize, sizeof(RTreePageOpaqueData));
-
- opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
- opaque->flags = f;
+ RTreePageOpaque opaque;
+ Page page;
+ Size pageSize;
+
+ pageSize = BufferGetPageSize(b);
+
+ page = BufferGetPage(b);
+ memset(page, 0, (int) pageSize);
+ PageInit(page, pageSize, sizeof(RTreePageOpaqueData));
+
+ opaque = (RTreePageOpaque) PageGetSpecialPointer(page);
+ opaque->flags = f;
}
-static OffsetNumber
-choose(Relation r, Page p, IndexTuple it, RTSTATE *rtstate)
+static OffsetNumber
+choose(Relation r, Page p, IndexTuple it, RTSTATE * rtstate)
{
- OffsetNumber maxoff;
- OffsetNumber i;
- char *ud, *id;
- char *datum;
- float usize, dsize;
- OffsetNumber which;
- float which_grow;
-
- id = ((char *) it) + sizeof(IndexTupleData);
- maxoff = PageGetMaxOffsetNumber(p);
- which_grow = -1.0;
- which = -1;
-
- for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
- datum = (char *) PageGetItem(p, PageGetItemId(p, i));
- datum += sizeof(IndexTupleData);
- (*rtstate->sizeFn)(datum, &dsize);
- ud = (char *) (*rtstate->unionFn)(datum, id);
- (*rtstate->sizeFn)(ud, &usize);
- pfree(ud);
- if (which_grow < 0 || usize - dsize < which_grow) {
- which = i;
- which_grow = usize - dsize;
- if (which_grow == 0)
- break;
+ OffsetNumber maxoff;
+ OffsetNumber i;
+ char *ud,
+ *id;
+ char *datum;
+ float usize,
+ dsize;
+ OffsetNumber which;
+ float which_grow;
+
+ id = ((char *) it) + sizeof(IndexTupleData);
+ maxoff = PageGetMaxOffsetNumber(p);
+ which_grow = -1.0;
+ which = -1;
+
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ datum = (char *) PageGetItem(p, PageGetItemId(p, i));
+ datum += sizeof(IndexTupleData);
+ (*rtstate->sizeFn) (datum, &dsize);
+ ud = (char *) (*rtstate->unionFn) (datum, id);
+ (*rtstate->sizeFn) (ud, &usize);
+ pfree(ud);
+ if (which_grow < 0 || usize - dsize < which_grow)
+ {
+ which = i;
+ which_grow = usize - dsize;
+ if (which_grow == 0)
+ break;
+ }
}
- }
-
- return (which);
+
+ return (which);
}
static int
nospace(Page p, IndexTuple it)
{
- return (PageGetFreeSpace(p) < IndexTupleSize(it));
+ return (PageGetFreeSpace(p) < IndexTupleSize(it));
}
void
-freestack(RTSTACK *s)
+freestack(RTSTACK * s)
{
- RTSTACK *p;
-
- while (s != (RTSTACK *) NULL) {
- p = s->rts_parent;
- pfree(s);
- s = p;
- }
+ RTSTACK *p;
+
+ while (s != (RTSTACK *) NULL)
+ {
+ p = s->rts_parent;
+ pfree(s);
+ s = p;
+ }
}
-char *
+char *
rtdelete(Relation r, ItemPointer tid)
{
- BlockNumber blkno;
- OffsetNumber offnum;
- Buffer buf;
- Page page;
-
- /* must write-lock on delete */
- RelationSetLockForWrite(r);
-
- blkno = ItemPointerGetBlockNumber(tid);
- offnum = ItemPointerGetOffsetNumber(tid);
-
- /* adjust any scans that will be affected by this deletion */
- rtadjscans(r, RTOP_DEL, blkno, offnum);
-
- /* delete the index tuple */
- buf = ReadBuffer(r, blkno);
- page = BufferGetPage(buf);
-
- PageIndexTupleDelete(page, offnum);
-
- WriteBuffer(buf);
-
- /* XXX -- two-phase locking, don't release the write lock */
- return ((char *) NULL);
+ BlockNumber blkno;
+ OffsetNumber offnum;
+ Buffer buf;
+ Page page;
+
+ /* must write-lock on delete */
+ RelationSetLockForWrite(r);
+
+ blkno = ItemPointerGetBlockNumber(tid);
+ offnum = ItemPointerGetOffsetNumber(tid);
+
+ /* adjust any scans that will be affected by this deletion */
+ rtadjscans(r, RTOP_DEL, blkno, offnum);
+
+ /* delete the index tuple */
+ buf = ReadBuffer(r, blkno);
+ page = BufferGetPage(buf);
+
+ PageIndexTupleDelete(page, offnum);
+
+ WriteBuffer(buf);
+
+ /* XXX -- two-phase locking, don't release the write lock */
+ return ((char *) NULL);
}
-static void initRtstate(RTSTATE *rtstate, Relation index)
+static void
+initRtstate(RTSTATE * rtstate, Relation index)
{
- RegProcedure union_proc, size_proc, inter_proc;
- func_ptr user_fn;
- int pronargs;
-
- union_proc = index_getprocid(index, 1, RT_UNION_PROC);
- size_proc = index_getprocid(index, 1, RT_SIZE_PROC);
- inter_proc = index_getprocid(index, 1, RT_INTER_PROC);
- fmgr_info(union_proc, &user_fn, &pronargs);
- rtstate->unionFn = user_fn;
- fmgr_info(size_proc, &user_fn, &pronargs);
- rtstate->sizeFn = user_fn;
- fmgr_info(inter_proc, &user_fn, &pronargs);
- rtstate->interFn = user_fn;
- return;
+ RegProcedure union_proc,
+ size_proc,
+ inter_proc;
+ func_ptr user_fn;
+ int pronargs;
+
+ union_proc = index_getprocid(index, 1, RT_UNION_PROC);
+ size_proc = index_getprocid(index, 1, RT_SIZE_PROC);
+ inter_proc = index_getprocid(index, 1, RT_INTER_PROC);
+ fmgr_info(union_proc, &user_fn, &pronargs);
+ rtstate->unionFn = user_fn;
+ fmgr_info(size_proc, &user_fn, &pronargs);
+ rtstate->sizeFn = user_fn;
+ fmgr_info(inter_proc, &user_fn, &pronargs);
+ rtstate->interFn = user_fn;
+ return;
}
#ifdef RTDEBUG
@@ -914,48 +1011,52 @@ static void initRtstate(RTSTATE *rtstate, Relation index)
void
_rtdump(Relation r)
{
- Buffer buf;
- Page page;
- OffsetNumber offnum, maxoff;
- BlockNumber blkno;
- BlockNumber nblocks;
- RTreePageOpaque po;
- IndexTuple itup;
- BlockNumber itblkno;
- OffsetNumber itoffno;
- char *datum;
- char *itkey;
-
- nblocks = RelationGetNumberOfBlocks(r);
- for (blkno = 0; blkno < nblocks; blkno++) {
- buf = ReadBuffer(r, blkno);
- page = BufferGetPage(buf);
- po = (RTreePageOpaque) PageGetSpecialPointer(page);
- maxoff = PageGetMaxOffsetNumber(page);
- printf("Page %d maxoff %d <%s>\n", blkno, maxoff,
- (po->flags & F_LEAF ? "LEAF" : "INTERNAL"));
-
- if (PageIsEmpty(page)) {
- ReleaseBuffer(buf);
- continue;
- }
-
- for (offnum = FirstOffsetNumber;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum)) {
- itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
- itblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
- itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid));
- datum = ((char *) itup);
- datum += sizeof(IndexTupleData);
- itkey = (char *) box_out((BOX *) datum);
- printf("\t[%d] size %d heap <%d,%d> key:%s\n",
- offnum, IndexTupleSize(itup), itblkno, itoffno, itkey);
- pfree(itkey);
+ Buffer buf;
+ Page page;
+ OffsetNumber offnum,
+ maxoff;
+ BlockNumber blkno;
+ BlockNumber nblocks;
+ RTreePageOpaque po;
+ IndexTuple itup;
+ BlockNumber itblkno;
+ OffsetNumber itoffno;
+ char *datum;
+ char *itkey;
+
+ nblocks = RelationGetNumberOfBlocks(r);
+ for (blkno = 0; blkno < nblocks; blkno++)
+ {
+ buf = ReadBuffer(r, blkno);
+ page = BufferGetPage(buf);
+ po = (RTreePageOpaque) PageGetSpecialPointer(page);
+ maxoff = PageGetMaxOffsetNumber(page);
+ printf("Page %d maxoff %d <%s>\n", blkno, maxoff,
+ (po->flags & F_LEAF ? "LEAF" : "INTERNAL"));
+
+ if (PageIsEmpty(page))
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
+
+ for (offnum = FirstOffsetNumber;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
+ itblkno = ItemPointerGetBlockNumber(&(itup->t_tid));
+ itoffno = ItemPointerGetOffsetNumber(&(itup->t_tid));
+ datum = ((char *) itup);
+ datum += sizeof(IndexTupleData);
+ itkey = (char *) box_out((BOX *) datum);
+ printf("\t[%d] size %d heap <%d,%d> key:%s\n",
+ offnum, IndexTupleSize(itup), itblkno, itoffno, itkey);
+ pfree(itkey);
+ }
+
+ ReleaseBuffer(buf);
}
-
- ReleaseBuffer(buf);
- }
}
-#endif /* defined RTDEBUG */
+#endif /* defined RTDEBUG */
diff --git a/src/backend/access/rtree/rtscan.c b/src/backend/access/rtree/rtscan.c
index bb8e1dcc719..26590059d6c 100644
--- a/src/backend/access/rtree/rtscan.c
+++ b/src/backend/access/rtree/rtscan.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* rtscan.c--
- * routines to manage scans on index relations
+ * routines to manage scans on index relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.10 1997/05/20 10:29:30 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.11 1997/09/07 04:39:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <storage/bufmgr.h>
#include <access/genam.h>
#include <storage/lmgr.h>
@@ -21,377 +21,411 @@
#include <access/rtree.h>
#include <access/rtstrat.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-
+
/* routines defined and used here */
-static void rtregscan(IndexScanDesc s);
-static void rtdropscan(IndexScanDesc s);
-static void rtadjone(IndexScanDesc s, int op, BlockNumber blkno,
- OffsetNumber offnum);
-static void adjuststack(RTSTACK *stk, BlockNumber blkno,
+static void rtregscan(IndexScanDesc s);
+static void rtdropscan(IndexScanDesc s);
+static void
+rtadjone(IndexScanDesc s, int op, BlockNumber blkno,
+ OffsetNumber offnum);
+static void
+adjuststack(RTSTACK * stk, BlockNumber blkno,
OffsetNumber offnum);
-static void adjustiptr(IndexScanDesc s, ItemPointer iptr,
- int op, BlockNumber blkno, OffsetNumber offnum);
+static void
+adjustiptr(IndexScanDesc s, ItemPointer iptr,
+ int op, BlockNumber blkno, OffsetNumber offnum);
/*
- * Whenever we start an rtree scan in a backend, we register it in private
- * space. Then if the rtree index gets updated, we check all registered
- * scans and adjust them if the tuple they point at got moved by the
- * update. We only need to do this in private space, because when we update
- * an rtree we have a write lock on the tree, so no other process can have
- * any locks at all on it. A single transaction can have write and read
- * locks on the same object, so that's why we need to handle this case.
+ * Whenever we start an rtree scan in a backend, we register it in private
+ * space. Then if the rtree index gets updated, we check all registered
+ * scans and adjust them if the tuple they point at got moved by the
+ * update. We only need to do this in private space, because when we update
+ * an rtree we have a write lock on the tree, so no other process can have
+ * any locks at all on it. A single transaction can have write and read
+ * locks on the same object, so that's why we need to handle this case.
*/
-typedef struct RTScanListData {
- IndexScanDesc rtsl_scan;
- struct RTScanListData *rtsl_next;
-} RTScanListData;
+typedef struct RTScanListData
+{
+ IndexScanDesc rtsl_scan;
+ struct RTScanListData *rtsl_next;
+} RTScanListData;
-typedef RTScanListData *RTScanList;
+typedef RTScanListData *RTScanList;
/* pointer to list of local scans on rtrees */
static RTScanList RTScans = (RTScanList) NULL;
-
+
IndexScanDesc
rtbeginscan(Relation r,
- bool fromEnd,
- uint16 nkeys,
- ScanKey key)
+ bool fromEnd,
+ uint16 nkeys,
+ ScanKey key)
{
- IndexScanDesc s;
-
- RelationSetLockForRead(r);
- s = RelationGetIndexScan(r, fromEnd, nkeys, key);
- rtregscan(s);
-
- return (s);
+ IndexScanDesc s;
+
+ RelationSetLockForRead(r);
+ s = RelationGetIndexScan(r, fromEnd, nkeys, key);
+ rtregscan(s);
+
+ return (s);
}
void
rtrescan(IndexScanDesc s, bool fromEnd, ScanKey key)
{
- RTreeScanOpaque p;
- RegProcedure internal_proc;
- int i;
-
- if (!IndexScanIsValid(s)) {
- elog(WARN, "rtrescan: invalid scan.");
- return;
- }
-
- /*
- * Clear all the pointers.
- */
-
- ItemPointerSetInvalid(&s->previousItemData);
- ItemPointerSetInvalid(&s->currentItemData);
- ItemPointerSetInvalid(&s->nextItemData);
- ItemPointerSetInvalid(&s->previousMarkData);
- ItemPointerSetInvalid(&s->currentMarkData);
- ItemPointerSetInvalid(&s->nextMarkData);
-
- /*
- * Set flags.
- */
- if (RelationGetNumberOfBlocks(s->relation) == 0) {
- s->flags = ScanUnmarked;
- } else if (fromEnd) {
- s->flags = ScanUnmarked | ScanUncheckedPrevious;
- } else {
- s->flags = ScanUnmarked | ScanUncheckedNext;
- }
-
- s->scanFromEnd = fromEnd;
-
- if (s->numberOfKeys > 0) {
- memmove(s->keyData,
- key,
- s->numberOfKeys * sizeof(ScanKeyData));
- }
-
- p = (RTreeScanOpaque) s->opaque;
- if (p != (RTreeScanOpaque) NULL) {
- freestack(p->s_stack);
- freestack(p->s_markstk);
- p->s_stack = p->s_markstk = (RTSTACK *) NULL;
- p->s_flags = 0x0;
- for (i = 0; i < s->numberOfKeys; i++)
+ RTreeScanOpaque p;
+ RegProcedure internal_proc;
+ int i;
+
+ if (!IndexScanIsValid(s))
+ {
+ elog(WARN, "rtrescan: invalid scan.");
+ return;
+ }
+
+ /*
+ * Clear all the pointers.
+ */
+
+ ItemPointerSetInvalid(&s->previousItemData);
+ ItemPointerSetInvalid(&s->currentItemData);
+ ItemPointerSetInvalid(&s->nextItemData);
+ ItemPointerSetInvalid(&s->previousMarkData);
+ ItemPointerSetInvalid(&s->currentMarkData);
+ ItemPointerSetInvalid(&s->nextMarkData);
+
+ /*
+ * Set flags.
+ */
+ if (RelationGetNumberOfBlocks(s->relation) == 0)
+ {
+ s->flags = ScanUnmarked;
+ }
+ else if (fromEnd)
+ {
+ s->flags = ScanUnmarked | ScanUncheckedPrevious;
+ }
+ else
+ {
+ s->flags = ScanUnmarked | ScanUncheckedNext;
+ }
+
+ s->scanFromEnd = fromEnd;
+
+ if (s->numberOfKeys > 0)
{
- p->s_internalKey[i].sk_argument = s->keyData[i].sk_argument;
+ memmove(s->keyData,
+ key,
+ s->numberOfKeys * sizeof(ScanKeyData));
}
- } else {
- /* initialize opaque data */
- p = (RTreeScanOpaque) palloc(sizeof(RTreeScanOpaqueData));
- p->s_stack = p->s_markstk = (RTSTACK *) NULL;
- p->s_internalNKey = s->numberOfKeys;
- p->s_flags = 0x0;
- s->opaque = p;
- if (s->numberOfKeys > 0) {
- p->s_internalKey =
- (ScanKey) palloc(sizeof(ScanKeyData) * s->numberOfKeys);
-
- /*
- * Scans on internal pages use different operators than they
- * do on leaf pages. For example, if the user wants all boxes
- * that exactly match (x1,y1,x2,y2), then on internal pages
- * we need to find all boxes that contain (x1,y1,x2,y2).
- */
-
- for (i = 0; i < s->numberOfKeys; i++) {
- p->s_internalKey[i].sk_argument = s->keyData[i].sk_argument;
- internal_proc = RTMapOperator(s->relation,
- s->keyData[i].sk_attno,
- s->keyData[i].sk_procedure);
- ScanKeyEntryInitialize(&(p->s_internalKey[i]),
- s->keyData[i].sk_flags,
- s->keyData[i].sk_attno,
- internal_proc,
- s->keyData[i].sk_argument);
- }
+
+ p = (RTreeScanOpaque) s->opaque;
+ if (p != (RTreeScanOpaque) NULL)
+ {
+ freestack(p->s_stack);
+ freestack(p->s_markstk);
+ p->s_stack = p->s_markstk = (RTSTACK *) NULL;
+ p->s_flags = 0x0;
+ for (i = 0; i < s->numberOfKeys; i++)
+ {
+ p->s_internalKey[i].sk_argument = s->keyData[i].sk_argument;
+ }
+ }
+ else
+ {
+ /* initialize opaque data */
+ p = (RTreeScanOpaque) palloc(sizeof(RTreeScanOpaqueData));
+ p->s_stack = p->s_markstk = (RTSTACK *) NULL;
+ p->s_internalNKey = s->numberOfKeys;
+ p->s_flags = 0x0;
+ s->opaque = p;
+ if (s->numberOfKeys > 0)
+ {
+ p->s_internalKey =
+ (ScanKey) palloc(sizeof(ScanKeyData) * s->numberOfKeys);
+
+ /*
+ * Scans on internal pages use different operators than they
+ * do on leaf pages. For example, if the user wants all boxes
+ * that exactly match (x1,y1,x2,y2), then on internal pages we
+ * need to find all boxes that contain (x1,y1,x2,y2).
+ */
+
+ for (i = 0; i < s->numberOfKeys; i++)
+ {
+ p->s_internalKey[i].sk_argument = s->keyData[i].sk_argument;
+ internal_proc = RTMapOperator(s->relation,
+ s->keyData[i].sk_attno,
+ s->keyData[i].sk_procedure);
+ ScanKeyEntryInitialize(&(p->s_internalKey[i]),
+ s->keyData[i].sk_flags,
+ s->keyData[i].sk_attno,
+ internal_proc,
+ s->keyData[i].sk_argument);
+ }
+ }
}
- }
}
void
rtmarkpos(IndexScanDesc s)
{
- RTreeScanOpaque p;
- RTSTACK *o, *n, *tmp;
-
- s->currentMarkData = s->currentItemData;
- p = (RTreeScanOpaque) s->opaque;
- if (p->s_flags & RTS_CURBEFORE)
- p->s_flags |= RTS_MRKBEFORE;
- else
- p->s_flags &= ~RTS_MRKBEFORE;
-
- o = (RTSTACK *) NULL;
- n = p->s_stack;
-
- /* copy the parent stack from the current item data */
- while (n != (RTSTACK *) NULL) {
- tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
- tmp->rts_child = n->rts_child;
- tmp->rts_blk = n->rts_blk;
- tmp->rts_parent = o;
- o = tmp;
- n = n->rts_parent;
- }
-
- freestack(p->s_markstk);
- p->s_markstk = o;
+ RTreeScanOpaque p;
+ RTSTACK *o,
+ *n,
+ *tmp;
+
+ s->currentMarkData = s->currentItemData;
+ p = (RTreeScanOpaque) s->opaque;
+ if (p->s_flags & RTS_CURBEFORE)
+ p->s_flags |= RTS_MRKBEFORE;
+ else
+ p->s_flags &= ~RTS_MRKBEFORE;
+
+ o = (RTSTACK *) NULL;
+ n = p->s_stack;
+
+ /* copy the parent stack from the current item data */
+ while (n != (RTSTACK *) NULL)
+ {
+ tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
+ tmp->rts_child = n->rts_child;
+ tmp->rts_blk = n->rts_blk;
+ tmp->rts_parent = o;
+ o = tmp;
+ n = n->rts_parent;
+ }
+
+ freestack(p->s_markstk);
+ p->s_markstk = o;
}
void
rtrestrpos(IndexScanDesc s)
{
- RTreeScanOpaque p;
- RTSTACK *o, *n, *tmp;
-
- s->currentItemData = s->currentMarkData;
- p = (RTreeScanOpaque) s->opaque;
- if (p->s_flags & RTS_MRKBEFORE)
- p->s_flags |= RTS_CURBEFORE;
- else
- p->s_flags &= ~RTS_CURBEFORE;
-
- o = (RTSTACK *) NULL;
- n = p->s_markstk;
-
- /* copy the parent stack from the current item data */
- while (n != (RTSTACK *) NULL) {
- tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
- tmp->rts_child = n->rts_child;
- tmp->rts_blk = n->rts_blk;
- tmp->rts_parent = o;
- o = tmp;
- n = n->rts_parent;
- }
-
- freestack(p->s_stack);
- p->s_stack = o;
+ RTreeScanOpaque p;
+ RTSTACK *o,
+ *n,
+ *tmp;
+
+ s->currentItemData = s->currentMarkData;
+ p = (RTreeScanOpaque) s->opaque;
+ if (p->s_flags & RTS_MRKBEFORE)
+ p->s_flags |= RTS_CURBEFORE;
+ else
+ p->s_flags &= ~RTS_CURBEFORE;
+
+ o = (RTSTACK *) NULL;
+ n = p->s_markstk;
+
+ /* copy the parent stack from the current item data */
+ while (n != (RTSTACK *) NULL)
+ {
+ tmp = (RTSTACK *) palloc(sizeof(RTSTACK));
+ tmp->rts_child = n->rts_child;
+ tmp->rts_blk = n->rts_blk;
+ tmp->rts_parent = o;
+ o = tmp;
+ n = n->rts_parent;
+ }
+
+ freestack(p->s_stack);
+ p->s_stack = o;
}
void
rtendscan(IndexScanDesc s)
{
- RTreeScanOpaque p;
-
- p = (RTreeScanOpaque) s->opaque;
-
- if (p != (RTreeScanOpaque) NULL) {
- freestack(p->s_stack);
- freestack(p->s_markstk);
- pfree (s->opaque);
- }
-
- rtdropscan(s);
- /* XXX don't unset read lock -- two-phase locking */
+ RTreeScanOpaque p;
+
+ p = (RTreeScanOpaque) s->opaque;
+
+ if (p != (RTreeScanOpaque) NULL)
+ {
+ freestack(p->s_stack);
+ freestack(p->s_markstk);
+ pfree(s->opaque);
+ }
+
+ rtdropscan(s);
+ /* XXX don't unset read lock -- two-phase locking */
}
static void
rtregscan(IndexScanDesc s)
{
- RTScanList l;
-
- l = (RTScanList) palloc(sizeof(RTScanListData));
- l->rtsl_scan = s;
- l->rtsl_next = RTScans;
- RTScans = l;
+ RTScanList l;
+
+ l = (RTScanList) palloc(sizeof(RTScanListData));
+ l->rtsl_scan = s;
+ l->rtsl_next = RTScans;
+ RTScans = l;
}
static void
rtdropscan(IndexScanDesc s)
{
- RTScanList l;
- RTScanList prev;
-
- prev = (RTScanList) NULL;
-
- for (l = RTScans;
- l != (RTScanList) NULL && l->rtsl_scan != s;
- l = l->rtsl_next) {
- prev = l;
- }
-
- if (l == (RTScanList) NULL)
- elog(WARN, "rtree scan list corrupted -- cannot find 0x%lx", s);
-
- if (prev == (RTScanList) NULL)
- RTScans = l->rtsl_next;
- else
- prev->rtsl_next = l->rtsl_next;
-
- pfree(l);
+ RTScanList l;
+ RTScanList prev;
+
+ prev = (RTScanList) NULL;
+
+ for (l = RTScans;
+ l != (RTScanList) NULL && l->rtsl_scan != s;
+ l = l->rtsl_next)
+ {
+ prev = l;
+ }
+
+ if (l == (RTScanList) NULL)
+ elog(WARN, "rtree scan list corrupted -- cannot find 0x%lx", s);
+
+ if (prev == (RTScanList) NULL)
+ RTScans = l->rtsl_next;
+ else
+ prev->rtsl_next = l->rtsl_next;
+
+ pfree(l);
}
void
rtadjscans(Relation r, int op, BlockNumber blkno, OffsetNumber offnum)
{
- RTScanList l;
- Oid relid;
-
- relid = r->rd_id;
- for (l = RTScans; l != (RTScanList) NULL; l = l->rtsl_next) {
- if (l->rtsl_scan->relation->rd_id == relid)
- rtadjone(l->rtsl_scan, op, blkno, offnum);
- }
+ RTScanList l;
+ Oid relid;
+
+ relid = r->rd_id;
+ for (l = RTScans; l != (RTScanList) NULL; l = l->rtsl_next)
+ {
+ if (l->rtsl_scan->relation->rd_id == relid)
+ rtadjone(l->rtsl_scan, op, blkno, offnum);
+ }
}
/*
- * rtadjone() -- adjust one scan for update.
+ * rtadjone() -- adjust one scan for update.
*
- * By here, the scan passed in is on a modified relation. Op tells
- * us what the modification is, and blkno and offind tell us what
- * block and offset index were affected. This routine checks the
- * current and marked positions, and the current and marked stacks,
- * to see if any stored location needs to be changed because of the
- * update. If so, we make the change here.
+ * By here, the scan passed in is on a modified relation. Op tells
+ * us what the modification is, and blkno and offind tell us what
+ * block and offset index were affected. This routine checks the
+ * current and marked positions, and the current and marked stacks,
+ * to see if any stored location needs to be changed because of the
+ * update. If so, we make the change here.
*/
static void
rtadjone(IndexScanDesc s,
- int op,
- BlockNumber blkno,
- OffsetNumber offnum)
+ int op,
+ BlockNumber blkno,
+ OffsetNumber offnum)
{
- RTreeScanOpaque so;
-
- adjustiptr(s, &(s->currentItemData), op, blkno, offnum);
- adjustiptr(s, &(s->currentMarkData), op, blkno, offnum);
-
- so = (RTreeScanOpaque) s->opaque;
-
- if (op == RTOP_SPLIT) {
- adjuststack(so->s_stack, blkno, offnum);
- adjuststack(so->s_markstk, blkno, offnum);
- }
+ RTreeScanOpaque so;
+
+ adjustiptr(s, &(s->currentItemData), op, blkno, offnum);
+ adjustiptr(s, &(s->currentMarkData), op, blkno, offnum);
+
+ so = (RTreeScanOpaque) s->opaque;
+
+ if (op == RTOP_SPLIT)
+ {
+ adjuststack(so->s_stack, blkno, offnum);
+ adjuststack(so->s_markstk, blkno, offnum);
+ }
}
/*
- * adjustiptr() -- adjust current and marked item pointers in the scan
+ * adjustiptr() -- adjust current and marked item pointers in the scan
*
- * Depending on the type of update and the place it happened, we
- * need to do nothing, to back up one record, or to start over on
- * the same page.
+ * Depending on the type of update and the place it happened, we
+ * need to do nothing, to back up one record, or to start over on
+ * the same page.
*/
static void
adjustiptr(IndexScanDesc s,
- ItemPointer iptr,
- int op,
- BlockNumber blkno,
- OffsetNumber offnum)
+ ItemPointer iptr,
+ int op,
+ BlockNumber blkno,
+ OffsetNumber offnum)
{
- OffsetNumber curoff;
- RTreeScanOpaque so;
-
- if (ItemPointerIsValid(iptr)) {
- if (ItemPointerGetBlockNumber(iptr) == blkno) {
- curoff = ItemPointerGetOffsetNumber(iptr);
- so = (RTreeScanOpaque) s->opaque;
-
- switch (op) {
- case RTOP_DEL:
- /* back up one if we need to */
- if (curoff >= offnum) {
-
- if (curoff > FirstOffsetNumber) {
- /* just adjust the item pointer */
- ItemPointerSet(iptr, blkno, OffsetNumberPrev(curoff));
- } else {
- /* remember that we're before the current tuple */
- ItemPointerSet(iptr, blkno, FirstOffsetNumber);
- if (iptr == &(s->currentItemData))
- so->s_flags |= RTS_CURBEFORE;
- else
- so->s_flags |= RTS_MRKBEFORE;
- }
+ OffsetNumber curoff;
+ RTreeScanOpaque so;
+
+ if (ItemPointerIsValid(iptr))
+ {
+ if (ItemPointerGetBlockNumber(iptr) == blkno)
+ {
+ curoff = ItemPointerGetOffsetNumber(iptr);
+ so = (RTreeScanOpaque) s->opaque;
+
+ switch (op)
+ {
+ case RTOP_DEL:
+ /* back up one if we need to */
+ if (curoff >= offnum)
+ {
+
+ if (curoff > FirstOffsetNumber)
+ {
+ /* just adjust the item pointer */
+ ItemPointerSet(iptr, blkno, OffsetNumberPrev(curoff));
+ }
+ else
+ {
+ /* remember that we're before the current tuple */
+ ItemPointerSet(iptr, blkno, FirstOffsetNumber);
+ if (iptr == &(s->currentItemData))
+ so->s_flags |= RTS_CURBEFORE;
+ else
+ so->s_flags |= RTS_MRKBEFORE;
+ }
+ }
+ break;
+
+ case RTOP_SPLIT:
+ /* back to start of page on split */
+ ItemPointerSet(iptr, blkno, FirstOffsetNumber);
+ if (iptr == &(s->currentItemData))
+ so->s_flags &= ~RTS_CURBEFORE;
+ else
+ so->s_flags &= ~RTS_MRKBEFORE;
+ break;
+
+ default:
+ elog(WARN, "Bad operation in rtree scan adjust: %d", op);
+ }
}
- break;
-
- case RTOP_SPLIT:
- /* back to start of page on split */
- ItemPointerSet(iptr, blkno, FirstOffsetNumber);
- if (iptr == &(s->currentItemData))
- so->s_flags &= ~RTS_CURBEFORE;
- else
- so->s_flags &= ~RTS_MRKBEFORE;
- break;
-
- default:
- elog(WARN, "Bad operation in rtree scan adjust: %d", op);
- }
}
- }
}
/*
- * adjuststack() -- adjust the supplied stack for a split on a page in
- * the index we're scanning.
+ * adjuststack() -- adjust the supplied stack for a split on a page in
+ * the index we're scanning.
*
- * If a page on our parent stack has split, we need to back up to the
- * beginning of the page and rescan it. The reason for this is that
- * the split algorithm for rtrees doesn't order tuples in any useful
- * way on a single page. This means on that a split, we may wind up
- * looking at some heap tuples more than once. This is handled in the
- * access method update code for heaps; if we've modified the tuple we
- * are looking at already in this transaction, we ignore the update
- * request.
+ * If a page on our parent stack has split, we need to back up to the
+ * beginning of the page and rescan it. The reason for this is that
+ * the split algorithm for rtrees doesn't order tuples in any useful
+ * way on a single page. This means on that a split, we may wind up
+ * looking at some heap tuples more than once. This is handled in the
+ * access method update code for heaps; if we've modified the tuple we
+ * are looking at already in this transaction, we ignore the update
+ * request.
*/
/*ARGSUSED*/
static void
-adjuststack(RTSTACK *stk,
- BlockNumber blkno,
- OffsetNumber offnum)
+adjuststack(RTSTACK * stk,
+ BlockNumber blkno,
+ OffsetNumber offnum)
{
- while (stk != (RTSTACK *) NULL) {
- if (stk->rts_blk == blkno)
- stk->rts_child = FirstOffsetNumber;
-
- stk = stk->rts_parent;
- }
+ while (stk != (RTSTACK *) NULL)
+ {
+ if (stk->rts_blk == blkno)
+ stk->rts_child = FirstOffsetNumber;
+
+ stk = stk->rts_parent;
+ }
}
diff --git a/src/backend/access/rtree/rtstrat.c b/src/backend/access/rtree/rtstrat.c
index 7025a30999d..c71059d3f09 100644
--- a/src/backend/access/rtree/rtstrat.c
+++ b/src/backend/access/rtree/rtstrat.c
@@ -1,241 +1,243 @@
/*-------------------------------------------------------------------------
*
* rtstrat.c--
- * strategy map data for rtrees.
+ * strategy map data for rtrees.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtstrat.c,v 1.6 1997/08/19 21:29:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtstrat.c,v 1.7 1997/09/07 04:39:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
-
+
#include <utils/rel.h>
#include <access/rtree.h>
#include <access/istrat.h>
-static StrategyNumber RelationGetRTStrategy(Relation r,
- AttrNumber attnum, RegProcedure proc);
+static StrategyNumber
+RelationGetRTStrategy(Relation r,
+ AttrNumber attnum, RegProcedure proc);
/*
- * Note: negate, commute, and negatecommute all assume that operators are
- * ordered as follows in the strategy map:
+ * Note: negate, commute, and negatecommute all assume that operators are
+ * ordered as follows in the strategy map:
*
- * left, left-or-overlap, overlap, right-or-overlap, right, same,
- * contains, contained-by
+ * left, left-or-overlap, overlap, right-or-overlap, right, same,
+ * contains, contained-by
*
- * The negate, commute, and negatecommute arrays are used by the planner
- * to plan indexed scans over data that appears in the qualificiation in
- * a boolean negation, or whose operands appear in the wrong order. For
- * example, if the operator "<%" means "contains", and the user says
+ * The negate, commute, and negatecommute arrays are used by the planner
+ * to plan indexed scans over data that appears in the qualificiation in
+ * a boolean negation, or whose operands appear in the wrong order. For
+ * example, if the operator "<%" means "contains", and the user says
*
- * where not rel.box <% "(10,10,20,20)"::box
+ * where not rel.box <% "(10,10,20,20)"::box
*
- * the planner can plan an index scan by noting that rtree indices have
- * an operator in their operator class for negating <%.
+ * the planner can plan an index scan by noting that rtree indices have
+ * an operator in their operator class for negating <%.
*
- * Similarly, if the user says something like
+ * Similarly, if the user says something like
*
- * where "(10,10,20,20)"::box <% rel.box
+ * where "(10,10,20,20)"::box <% rel.box
*
- * the planner can see that the rtree index on rel.box has an operator in
- * its opclass for commuting <%, and plan the scan using that operator.
- * This added complexity in the access methods makes the planner a lot easier
- * to write.
+ * the planner can see that the rtree index on rel.box has an operator in
+ * its opclass for commuting <%, and plan the scan using that operator.
+ * This added complexity in the access methods makes the planner a lot easier
+ * to write.
*/
/* if a op b, what operator tells us if (not a op b)? */
-static StrategyNumber RTNegate[RTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
+static StrategyNumber RTNegate[RTNStrategies] = {
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy
+};
/* if a op_1 b, what is the operator op_2 such that b op_2 a? */
-static StrategyNumber RTCommute[RTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
+static StrategyNumber RTCommute[RTNStrategies] = {
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy
+};
/* if a op_1 b, what is the operator op_2 such that (b !op_2 a)? */
-static StrategyNumber RTNegateCommute[RTNStrategies] = {
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy,
- InvalidStrategy
- };
+static StrategyNumber RTNegateCommute[RTNStrategies] = {
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy,
+ InvalidStrategy
+};
/*
- * Now do the TermData arrays. These exist in case the user doesn't give
- * us a full set of operators for a particular operator class. The idea
- * is that by making multiple comparisons using any one of the supplied
- * operators, we can decide whether two n-dimensional polygons are equal.
- * For example, if a contains b and b contains a, we may conclude that
- * a and b are equal.
- *
- * The presence of the TermData arrays in all this is a historical accident.
- * Early in the development of the POSTGRES access methods, it was believed
- * that writing functions was harder than writing arrays. This is wrong;
- * TermData is hard to understand and hard to get right. In general, when
- * someone populates a new operator class, the populate it completely. If
- * Mike Hirohama had forced Cimarron Taylor to populate the strategy map
- * for btree int2_ops completely in 1988, you wouldn't have to deal with
- * all this now. Too bad for you.
- *
- * Since you can't necessarily do this in all cases (for example, you can't
- * do it given only "intersects" or "disjoint"), TermData arrays for some
- * operators don't appear below.
- *
- * Note that if you DO supply all the operators required in a given opclass
- * by inserting them into the pg_opclass system catalog, you can get away
- * without doing all this TermData stuff. Since the rtree code is intended
- * to be a reference for access method implementors, I'm doing TermData
- * correctly here.
- *
- * Note on style: these are all actually of type StrategyTermData, but
- * since those have variable-length data at the end of the struct we can't
- * properly initialize them if we declare them to be what they are.
+ * Now do the TermData arrays. These exist in case the user doesn't give
+ * us a full set of operators for a particular operator class. The idea
+ * is that by making multiple comparisons using any one of the supplied
+ * operators, we can decide whether two n-dimensional polygons are equal.
+ * For example, if a contains b and b contains a, we may conclude that
+ * a and b are equal.
+ *
+ * The presence of the TermData arrays in all this is a historical accident.
+ * Early in the development of the POSTGRES access methods, it was believed
+ * that writing functions was harder than writing arrays. This is wrong;
+ * TermData is hard to understand and hard to get right. In general, when
+ * someone populates a new operator class, the populate it completely. If
+ * Mike Hirohama had forced Cimarron Taylor to populate the strategy map
+ * for btree int2_ops completely in 1988, you wouldn't have to deal with
+ * all this now. Too bad for you.
+ *
+ * Since you can't necessarily do this in all cases (for example, you can't
+ * do it given only "intersects" or "disjoint"), TermData arrays for some
+ * operators don't appear below.
+ *
+ * Note that if you DO supply all the operators required in a given opclass
+ * by inserting them into the pg_opclass system catalog, you can get away
+ * without doing all this TermData stuff. Since the rtree code is intended
+ * to be a reference for access method implementors, I'm doing TermData
+ * correctly here.
+ *
+ * Note on style: these are all actually of type StrategyTermData, but
+ * since those have variable-length data at the end of the struct we can't
+ * properly initialize them if we declare them to be what they are.
*/
/* if you only have "contained-by", how do you determine equality? */
-static uint16 RTContainedByTermData[] = {
- 2, /* make two comparisons */
- RTContainedByStrategyNumber, /* use "a contained-by b" */
- 0x0, /* without any magic */
- RTContainedByStrategyNumber, /* then use contained-by, */
- SK_COMMUTE /* swapping a and b */
- };
+static uint16 RTContainedByTermData[] = {
+ 2, /* make two comparisons */
+ RTContainedByStrategyNumber,/* use "a contained-by b" */
+ 0x0, /* without any magic */
+ RTContainedByStrategyNumber,/* then use contained-by, */
+ SK_COMMUTE /* swapping a and b */
+};
/* if you only have "contains", how do you determine equality? */
-static uint16 RTContainsTermData[] = {
- 2, /* make two comparisons */
- RTContainsStrategyNumber, /* use "a contains b" */
- 0x0, /* without any magic */
- RTContainsStrategyNumber, /* then use contains again, */
- SK_COMMUTE /* swapping a and b */
- };
+static uint16 RTContainsTermData[] = {
+ 2, /* make two comparisons */
+ RTContainsStrategyNumber, /* use "a contains b" */
+ 0x0, /* without any magic */
+ RTContainsStrategyNumber, /* then use contains again, */
+ SK_COMMUTE /* swapping a and b */
+};
/* now put all that together in one place for the planner */
static StrategyTerm RTEqualExpressionData[] = {
- (StrategyTerm) RTContainedByTermData,
- (StrategyTerm) RTContainsTermData,
- NULL
- };
+ (StrategyTerm) RTContainedByTermData,
+ (StrategyTerm) RTContainsTermData,
+ NULL
+};
/*
- * If you were sufficiently attentive to detail, you would go through
- * the ExpressionData pain above for every one of the seven strategies
- * we defined. I am not. Now we declare the StrategyEvaluationData
- * structure that gets shipped around to help the planner and the access
- * method decide what sort of scan it should do, based on (a) what the
- * user asked for, (b) what operators are defined for a particular opclass,
- * and (c) the reams of information we supplied above.
- *
- * The idea of all of this initialized data is to make life easier on the
- * user when he defines a new operator class to use this access method.
- * By filling in all the data, we let him get away with leaving holes in his
- * operator class, and still let him use the index. The added complexity
- * in the access methods just isn't worth the trouble, though.
+ * If you were sufficiently attentive to detail, you would go through
+ * the ExpressionData pain above for every one of the seven strategies
+ * we defined. I am not. Now we declare the StrategyEvaluationData
+ * structure that gets shipped around to help the planner and the access
+ * method decide what sort of scan it should do, based on (a) what the
+ * user asked for, (b) what operators are defined for a particular opclass,
+ * and (c) the reams of information we supplied above.
+ *
+ * The idea of all of this initialized data is to make life easier on the
+ * user when he defines a new operator class to use this access method.
+ * By filling in all the data, we let him get away with leaving holes in his
+ * operator class, and still let him use the index. The added complexity
+ * in the access methods just isn't worth the trouble, though.
*/
static StrategyEvaluationData RTEvaluationData = {
- RTNStrategies, /* # of strategies */
- (StrategyTransformMap) RTNegate, /* how to do (not qual) */
- (StrategyTransformMap) RTCommute, /* how to swap operands */
- (StrategyTransformMap) RTNegateCommute, /* how to do both */
- {
- NULL, /* express left */
- NULL, /* express overleft */
- NULL, /* express over */
- NULL, /* express overright */
- NULL, /* express right */
- (StrategyExpression) RTEqualExpressionData, /* express same */
- NULL, /* express contains */
- NULL, /* express contained-by */
- NULL,
- NULL,
- NULL
- }
+ RTNStrategies, /* # of strategies */
+ (StrategyTransformMap) RTNegate, /* how to do (not qual) */
+ (StrategyTransformMap) RTCommute, /* how to swap operands */
+ (StrategyTransformMap) RTNegateCommute, /* how to do both */
+ {
+ NULL, /* express left */
+ NULL, /* express overleft */
+ NULL, /* express over */
+ NULL, /* express overright */
+ NULL, /* express right */
+ (StrategyExpression) RTEqualExpressionData, /* express same */
+ NULL, /* express contains */
+ NULL, /* express contained-by */
+ NULL,
+ NULL,
+ NULL
+ }
};
/*
- * Okay, now something peculiar to rtrees that doesn't apply to most other
- * indexing structures: When we're searching a tree for a given value, we
- * can't do the same sorts of comparisons on internal node entries as we
- * do at leaves. The reason is that if we're looking for (say) all boxes
- * that are the same as (0,0,10,10), then we need to find all leaf pages
- * that overlap that region. So internally we search for overlap, and at
- * the leaf we search for equality.
- *
- * This array maps leaf search operators to the internal search operators.
- * We assume the normal ordering on operators:
- *
- * left, left-or-overlap, overlap, right-or-overlap, right, same,
- * contains, contained-by
+ * Okay, now something peculiar to rtrees that doesn't apply to most other
+ * indexing structures: When we're searching a tree for a given value, we
+ * can't do the same sorts of comparisons on internal node entries as we
+ * do at leaves. The reason is that if we're looking for (say) all boxes
+ * that are the same as (0,0,10,10), then we need to find all leaf pages
+ * that overlap that region. So internally we search for overlap, and at
+ * the leaf we search for equality.
+ *
+ * This array maps leaf search operators to the internal search operators.
+ * We assume the normal ordering on operators:
+ *
+ * left, left-or-overlap, overlap, right-or-overlap, right, same,
+ * contains, contained-by
*/
static StrategyNumber RTOperMap[RTNStrategies] = {
- RTOverLeftStrategyNumber,
- RTOverLeftStrategyNumber,
- RTOverlapStrategyNumber,
- RTOverRightStrategyNumber,
- RTOverRightStrategyNumber,
- RTContainsStrategyNumber,
- RTContainsStrategyNumber,
- RTOverlapStrategyNumber
- };
+ RTOverLeftStrategyNumber,
+ RTOverLeftStrategyNumber,
+ RTOverlapStrategyNumber,
+ RTOverRightStrategyNumber,
+ RTOverRightStrategyNumber,
+ RTContainsStrategyNumber,
+ RTContainsStrategyNumber,
+ RTOverlapStrategyNumber
+};
-static StrategyNumber
+static StrategyNumber
RelationGetRTStrategy(Relation r,
- AttrNumber attnum,
- RegProcedure proc)
+ AttrNumber attnum,
+ RegProcedure proc)
{
- return (RelationGetStrategy(r, attnum, &RTEvaluationData, proc));
+ return (RelationGetStrategy(r, attnum, &RTEvaluationData, proc));
}
#ifdef NOT_USED
bool
RelationInvokeRTStrategy(Relation r,
- AttrNumber attnum,
- StrategyNumber s,
- Datum left,
- Datum right)
+ AttrNumber attnum,
+ StrategyNumber s,
+ Datum left,
+ Datum right)
{
- return (RelationInvokeStrategy(r, &RTEvaluationData, attnum, s,
- left, right));
+ return (RelationInvokeStrategy(r, &RTEvaluationData, attnum, s,
+ left, right));
}
+
#endif
RegProcedure
RTMapOperator(Relation r,
- AttrNumber attnum,
- RegProcedure proc)
+ AttrNumber attnum,
+ RegProcedure proc)
{
- StrategyNumber procstrat;
- StrategyMap strategyMap;
-
- procstrat = RelationGetRTStrategy(r, attnum, proc);
- strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(r),
- RTNStrategies,
- attnum);
-
- return (strategyMap->entry[RTOperMap[procstrat - 1] - 1].sk_procedure);
+ StrategyNumber procstrat;
+ StrategyMap strategyMap;
+
+ procstrat = RelationGetRTStrategy(r, attnum, proc);
+ strategyMap = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(r),
+ RTNStrategies,
+ attnum);
+
+ return (strategyMap->entry[RTOperMap[procstrat - 1] - 1].sk_procedure);
}
diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c
index 9087e50bc40..6d721fe96af 100644
--- a/src/backend/access/transam/transam.c
+++ b/src/backend/access/transam/transam.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* transam.c--
- * postgres transaction log/time interface routines
+ * postgres transaction log/time interface routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.9 1997/08/19 21:29:59 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.10 1997/09/07 04:39:29 momjian Exp $
*
* NOTES
- * This file contains the high level access-method interface to the
- * transaction system.
- *
+ * This file contains the high level access-method interface to the
+ * transaction system.
+ *
*-------------------------------------------------------------------------
*/
@@ -26,659 +26,671 @@
#include <storage/spin.h>
#include <commands/vacuum.h>
-static int RecoveryCheckingEnabled(void);
-static void TransRecover(Relation logRelation);
-static bool TransactionLogTest(TransactionId transactionId, XidStatus status);
-static void TransactionLogUpdate(TransactionId transactionId,
- XidStatus status);
+static int RecoveryCheckingEnabled(void);
+static void TransRecover(Relation logRelation);
+static bool TransactionLogTest(TransactionId transactionId, XidStatus status);
+static void
+TransactionLogUpdate(TransactionId transactionId,
+ XidStatus status);
/* ----------------
- * global variables holding pointers to relations used
- * by the transaction system. These are initialized by
- * InitializeTransactionLog().
+ * global variables holding pointers to relations used
+ * by the transaction system. These are initialized by
+ * InitializeTransactionLog().
* ----------------
*/
-Relation LogRelation = (Relation) NULL;
-Relation TimeRelation = (Relation) NULL;
-Relation VariableRelation = (Relation) NULL;
+Relation LogRelation = (Relation) NULL;
+Relation TimeRelation = (Relation) NULL;
+Relation VariableRelation = (Relation) NULL;
/* ----------------
- * global variables holding cached transaction id's and statuses.
+ * global variables holding cached transaction id's and statuses.
* ----------------
*/
TransactionId cachedGetCommitTimeXid;
AbsoluteTime cachedGetCommitTime;
TransactionId cachedTestXid;
-XidStatus cachedTestXidStatus;
+XidStatus cachedTestXidStatus;
/* ----------------
- * transaction system constants
+ * transaction system constants
* ----------------
*/
/* ----------------------------------------------------------------
- * transaction system constants
+ * transaction system constants
*
- * read the comments for GetNewTransactionId in order to
- * understand the initial values for AmiTransactionId and
- * FirstTransactionId. -cim 3/23/90
+ * read the comments for GetNewTransactionId in order to
+ * understand the initial values for AmiTransactionId and
+ * FirstTransactionId. -cim 3/23/90
* ----------------------------------------------------------------
*/
-TransactionId NullTransactionId = (TransactionId) 0;
+TransactionId NullTransactionId = (TransactionId) 0;
-TransactionId AmiTransactionId = (TransactionId) 512;
+TransactionId AmiTransactionId = (TransactionId) 512;
-TransactionId FirstTransactionId = (TransactionId) 514;
+TransactionId FirstTransactionId = (TransactionId) 514;
/* ----------------
- * transaction recovery state variables
- *
- * When the transaction system is initialized, we may
- * need to do recovery checking. This decision is decided
- * by the postmaster or the user by supplying the backend
- * with a special flag. In general, we want to do recovery
- * checking whenever we are running without a postmaster
- * or when the number of backends running under the postmaster
- * goes from zero to one. -cim 3/21/90
+ * transaction recovery state variables
+ *
+ * When the transaction system is initialized, we may
+ * need to do recovery checking. This decision is decided
+ * by the postmaster or the user by supplying the backend
+ * with a special flag. In general, we want to do recovery
+ * checking whenever we are running without a postmaster
+ * or when the number of backends running under the postmaster
+ * goes from zero to one. -cim 3/21/90
* ----------------
*/
-int RecoveryCheckingEnableState = 0;
+int RecoveryCheckingEnableState = 0;
/* ------------------
- * spinlock for oid generation
+ * spinlock for oid generation
* -----------------
*/
-extern int OidGenLockId;
+extern int OidGenLockId;
/* ----------------
- * globals that must be reset at abort
+ * globals that must be reset at abort
* ----------------
*/
-extern bool BuildingBtree;
+extern bool BuildingBtree;
/* ----------------
- * recovery checking accessors
+ * recovery checking accessors
* ----------------
*/
static int
RecoveryCheckingEnabled(void)
-{
- return RecoveryCheckingEnableState;
+{
+ return RecoveryCheckingEnableState;
}
#ifdef NOT_USED
static void
SetRecoveryCheckingEnabled(bool state)
-{
- RecoveryCheckingEnableState = (state == true);
+{
+ RecoveryCheckingEnableState = (state == true);
}
+
#endif
/* ----------------------------------------------------------------
- * postgres log/time access method interface
- *
- * TransactionLogTest
- * TransactionLogUpdate
- * ========
- * these functions do work for the interface
- * functions - they search/retrieve and append/update
- * information in the log and time relations.
+ * postgres log/time access method interface
+ *
+ * TransactionLogTest
+ * TransactionLogUpdate
+ * ========
+ * these functions do work for the interface
+ * functions - they search/retrieve and append/update
+ * information in the log and time relations.
* ----------------------------------------------------------------
*/
/* --------------------------------
- * TransactionLogTest
+ * TransactionLogTest
* --------------------------------
*/
-static bool /* true/false: does transaction id have specified status? */
-TransactionLogTest(TransactionId transactionId, /* transaction id to test */
- XidStatus status) /* transaction status */
+static bool /* true/false: does transaction id have
+ * specified status? */
+TransactionLogTest(TransactionId transactionId, /* transaction id to test */
+ XidStatus status) /* transaction status */
{
- BlockNumber blockNumber;
- XidStatus xidstatus; /* recorded status of xid */
- bool fail = false; /* success/failure */
-
- /* ----------------
- * during initialization consider all transactions
- * as having been committed
- * ----------------
- */
- if (! RelationIsValid(LogRelation))
- return (bool) (status == XID_COMMIT);
-
- /* ----------------
- * before going to the buffer manager, check our single
- * item cache to see if we didn't just check the transaction
- * status a moment ago.
- * ----------------
- */
- if (TransactionIdEquals(transactionId, cachedTestXid))
- return (bool)
- (status == cachedTestXidStatus);
-
- /* ----------------
- * compute the item pointer corresponding to the
- * page containing our transaction id. We save the item in
- * our cache to speed up things if we happen to ask for the
- * same xid's status more than once.
- * ----------------
- */
- TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
- xidstatus = TransBlockNumberGetXidStatus(LogRelation,
- blockNumber,
- transactionId,
- &fail);
-
- if (! fail) {
- TransactionIdStore(transactionId, &cachedTestXid);
- cachedTestXidStatus = xidstatus;
- return (bool)
- (status == xidstatus);
- }
-
- /* ----------------
- * here the block didn't contain the information we wanted
- * ----------------
- */
- elog(WARN, "TransactionLogTest: failed to get xidstatus");
-
- /*
- * so lint is happy...
- */
- return(false);
+ BlockNumber blockNumber;
+ XidStatus xidstatus; /* recorded status of xid */
+ bool fail = false; /* success/failure */
+
+ /* ----------------
+ * during initialization consider all transactions
+ * as having been committed
+ * ----------------
+ */
+ if (!RelationIsValid(LogRelation))
+ return (bool) (status == XID_COMMIT);
+
+ /* ----------------
+ * before going to the buffer manager, check our single
+ * item cache to see if we didn't just check the transaction
+ * status a moment ago.
+ * ----------------
+ */
+ if (TransactionIdEquals(transactionId, cachedTestXid))
+ return (bool)
+ (status == cachedTestXidStatus);
+
+ /* ----------------
+ * compute the item pointer corresponding to the
+ * page containing our transaction id. We save the item in
+ * our cache to speed up things if we happen to ask for the
+ * same xid's status more than once.
+ * ----------------
+ */
+ TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
+ xidstatus = TransBlockNumberGetXidStatus(LogRelation,
+ blockNumber,
+ transactionId,
+ &fail);
+
+ if (!fail)
+ {
+ TransactionIdStore(transactionId, &cachedTestXid);
+ cachedTestXidStatus = xidstatus;
+ return (bool)
+ (status == xidstatus);
+ }
+
+ /* ----------------
+ * here the block didn't contain the information we wanted
+ * ----------------
+ */
+ elog(WARN, "TransactionLogTest: failed to get xidstatus");
+
+ /*
+ * so lint is happy...
+ */
+ return (false);
}
/* --------------------------------
- * TransactionLogUpdate
+ * TransactionLogUpdate
* --------------------------------
*/
static void
-TransactionLogUpdate(TransactionId transactionId, /* trans id to update */
- XidStatus status) /* new trans status */
+TransactionLogUpdate(TransactionId transactionId, /* trans id to update */
+ XidStatus status) /* new trans status */
{
- BlockNumber blockNumber;
- bool fail = false; /* success/failure */
- AbsoluteTime currentTime; /* time of this transaction */
-
- /* ----------------
- * during initialization we don't record any updates.
- * ----------------
- */
- if (! RelationIsValid(LogRelation))
- return;
-
- /* ----------------
- * get the transaction commit time
- * ----------------
- */
- currentTime = getSystemTime();
-
- /* ----------------
- * update the log relation
- * ----------------
- */
- TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
- TransBlockNumberSetXidStatus(LogRelation,
- blockNumber,
- transactionId,
- status,
- &fail);
-
- /* ----------------
- * update (invalidate) our single item TransactionLogTest cache.
- * ----------------
- */
- TransactionIdStore(transactionId, &cachedTestXid);
- cachedTestXidStatus = status;
-
- /* ----------------
- * now we update the time relation, if necessary
- * (we only record commit times)
- * ----------------
- */
- if (RelationIsValid(TimeRelation) && status == XID_COMMIT) {
- TransComputeBlockNumber(TimeRelation, transactionId, &blockNumber);
- TransBlockNumberSetCommitTime(TimeRelation,
- blockNumber,
- transactionId,
- currentTime,
- &fail);
+ BlockNumber blockNumber;
+ bool fail = false; /* success/failure */
+ AbsoluteTime currentTime;/* time of this transaction */
+
+ /* ----------------
+ * during initialization we don't record any updates.
+ * ----------------
+ */
+ if (!RelationIsValid(LogRelation))
+ return;
+
/* ----------------
- * update (invalidate) our single item GetCommitTime cache.
+ * get the transaction commit time
* ----------------
*/
- TransactionIdStore(transactionId, &cachedGetCommitTimeXid);
- cachedGetCommitTime = currentTime;
- }
-
- /* ----------------
- * now we update the "last committed transaction" field
- * in the variable relation if we are recording a commit.
- * ----------------
- */
- if (RelationIsValid(VariableRelation) && status == XID_COMMIT)
- UpdateLastCommittedXid(transactionId);
+ currentTime = getSystemTime();
+
+ /* ----------------
+ * update the log relation
+ * ----------------
+ */
+ TransComputeBlockNumber(LogRelation, transactionId, &blockNumber);
+ TransBlockNumberSetXidStatus(LogRelation,
+ blockNumber,
+ transactionId,
+ status,
+ &fail);
+
+ /* ----------------
+ * update (invalidate) our single item TransactionLogTest cache.
+ * ----------------
+ */
+ TransactionIdStore(transactionId, &cachedTestXid);
+ cachedTestXidStatus = status;
+
+ /* ----------------
+ * now we update the time relation, if necessary
+ * (we only record commit times)
+ * ----------------
+ */
+ if (RelationIsValid(TimeRelation) && status == XID_COMMIT)
+ {
+ TransComputeBlockNumber(TimeRelation, transactionId, &blockNumber);
+ TransBlockNumberSetCommitTime(TimeRelation,
+ blockNumber,
+ transactionId,
+ currentTime,
+ &fail);
+ /* ----------------
+ * update (invalidate) our single item GetCommitTime cache.
+ * ----------------
+ */
+ TransactionIdStore(transactionId, &cachedGetCommitTimeXid);
+ cachedGetCommitTime = currentTime;
+ }
+
+ /* ----------------
+ * now we update the "last committed transaction" field
+ * in the variable relation if we are recording a commit.
+ * ----------------
+ */
+ if (RelationIsValid(VariableRelation) && status == XID_COMMIT)
+ UpdateLastCommittedXid(transactionId);
}
/* --------------------------------
- * TransactionIdGetCommitTime
+ * TransactionIdGetCommitTime
* --------------------------------
*/
-AbsoluteTime /* commit time of transaction id */
-TransactionIdGetCommitTime(TransactionId transactionId) /* transaction id to test */
+AbsoluteTime /* commit time of transaction id */
+TransactionIdGetCommitTime(TransactionId transactionId) /* transaction id to
+ * test */
{
- BlockNumber blockNumber;
- AbsoluteTime commitTime; /* commit time */
- bool fail = false; /* success/failure */
-
- /* ----------------
- * return invalid if we aren't running yet...
- * ----------------
- */
- if (! RelationIsValid(TimeRelation))
- return INVALID_ABSTIME;
-
- /* ----------------
- * before going to the buffer manager, check our single
- * item cache to see if we didn't just get the commit time
- * a moment ago.
- * ----------------
- */
- if (TransactionIdEquals(transactionId, cachedGetCommitTimeXid))
- return cachedGetCommitTime;
-
- /* ----------------
- * compute the item pointer corresponding to the
- * page containing our transaction commit time
- * ----------------
- */
- TransComputeBlockNumber(TimeRelation, transactionId, &blockNumber);
- commitTime = TransBlockNumberGetCommitTime(TimeRelation,
- blockNumber,
- transactionId,
- &fail);
-
- /* ----------------
- * update our cache and return the transaction commit time
- * ----------------
- */
- if (! fail) {
- TransactionIdStore(transactionId, &cachedGetCommitTimeXid);
- cachedGetCommitTime = commitTime;
- return commitTime;
- } else
- return INVALID_ABSTIME;
+ BlockNumber blockNumber;
+ AbsoluteTime commitTime; /* commit time */
+ bool fail = false; /* success/failure */
+
+ /* ----------------
+ * return invalid if we aren't running yet...
+ * ----------------
+ */
+ if (!RelationIsValid(TimeRelation))
+ return INVALID_ABSTIME;
+
+ /* ----------------
+ * before going to the buffer manager, check our single
+ * item cache to see if we didn't just get the commit time
+ * a moment ago.
+ * ----------------
+ */
+ if (TransactionIdEquals(transactionId, cachedGetCommitTimeXid))
+ return cachedGetCommitTime;
+
+ /* ----------------
+ * compute the item pointer corresponding to the
+ * page containing our transaction commit time
+ * ----------------
+ */
+ TransComputeBlockNumber(TimeRelation, transactionId, &blockNumber);
+ commitTime = TransBlockNumberGetCommitTime(TimeRelation,
+ blockNumber,
+ transactionId,
+ &fail);
+
+ /* ----------------
+ * update our cache and return the transaction commit time
+ * ----------------
+ */
+ if (!fail)
+ {
+ TransactionIdStore(transactionId, &cachedGetCommitTimeXid);
+ cachedGetCommitTime = commitTime;
+ return commitTime;
+ }
+ else
+ return INVALID_ABSTIME;
}
/* ----------------------------------------------------------------
- * transaction recovery code
+ * transaction recovery code
* ----------------------------------------------------------------
*/
/* --------------------------------
- * TransRecover
+ * TransRecover
*
- * preform transaction recovery checking.
+ * preform transaction recovery checking.
*
- * Note: this should only be preformed if no other backends
- * are running. This is known by the postmaster and
- * conveyed by the postmaster passing a "do recovery checking"
- * flag to the backend.
+ * Note: this should only be preformed if no other backends
+ * are running. This is known by the postmaster and
+ * conveyed by the postmaster passing a "do recovery checking"
+ * flag to the backend.
*
- * here we get the last recorded transaction from the log,
- * get the "last" and "next" transactions from the variable relation
- * and then preform some integrity tests:
+ * here we get the last recorded transaction from the log,
+ * get the "last" and "next" transactions from the variable relation
+ * and then preform some integrity tests:
*
- * 1) No transaction may exist higher then the "next" available
- * transaction recorded in the variable relation. If this is the
- * case then it means either the log or the variable relation
- * has become corrupted.
+ * 1) No transaction may exist higher then the "next" available
+ * transaction recorded in the variable relation. If this is the
+ * case then it means either the log or the variable relation
+ * has become corrupted.
*
- * 2) The last committed transaction may not be higher then the
- * next available transaction for the same reason.
+ * 2) The last committed transaction may not be higher then the
+ * next available transaction for the same reason.
*
- * 3) The last recorded transaction may not be lower then the
- * last committed transaction. (the reverse is ok - it means
- * that some transactions have aborted since the last commit)
+ * 3) The last recorded transaction may not be lower then the
+ * last committed transaction. (the reverse is ok - it means
+ * that some transactions have aborted since the last commit)
*
- * Here is what the proper situation looks like. The line
- * represents the data stored in the log. 'c' indicates the
- * transaction was recorded as committed, 'a' indicates an
- * abortted transaction and '.' represents information not
- * recorded. These may correspond to in progress transactions.
+ * Here is what the proper situation looks like. The line
+ * represents the data stored in the log. 'c' indicates the
+ * transaction was recorded as committed, 'a' indicates an
+ * abortted transaction and '.' represents information not
+ * recorded. These may correspond to in progress transactions.
*
- * c c a c . . a . . . . . . . . . .
- * | |
- * last next
+ * c c a c . . a . . . . . . . . . .
+ * | |
+ * last next
*
- * Since "next" is only incremented by GetNewTransactionId() which
- * is called when transactions are started. Hence if there
- * are commits or aborts after "next", then it means we committed
- * or aborted BEFORE we started the transaction. This is the
- * rational behind constraint (1).
+ * Since "next" is only incremented by GetNewTransactionId() which
+ * is called when transactions are started. Hence if there
+ * are commits or aborts after "next", then it means we committed
+ * or aborted BEFORE we started the transaction. This is the
+ * rational behind constraint (1).
*
- * Likewise, "last" should never greater then "next" for essentially
- * the same reason - it would imply we committed before we started.
- * This is the reasoning for (2).
+ * Likewise, "last" should never greater then "next" for essentially
+ * the same reason - it would imply we committed before we started.
+ * This is the reasoning for (2).
*
- * (3) implies we may never have a situation such as:
+ * (3) implies we may never have a situation such as:
*
- * c c a c . . a c . . . . . . . . .
- * | |
- * last next
+ * c c a c . . a c . . . . . . . . .
+ * | |
+ * last next
*
- * where there is a 'c' greater then "last".
+ * where there is a 'c' greater then "last".
*
- * Recovery checking is more difficult in the case where
- * several backends are executing concurrently because the
- * transactions may be executing in the other backends.
- * So, we only do recovery stuff when the backend is explicitly
- * passed a flag on the command line.
+ * Recovery checking is more difficult in the case where
+ * several backends are executing concurrently because the
+ * transactions may be executing in the other backends.
+ * So, we only do recovery stuff when the backend is explicitly
+ * passed a flag on the command line.
* --------------------------------
*/
static void
TransRecover(Relation logRelation)
{
-#if 0
- /* ----------------
- * first get the last recorded transaction in the log.
- * ----------------
- */
- TransGetLastRecordedTransaction(logRelation, logLastXid, &fail);
- if (fail == true)
- elog(WARN, "TransRecover: failed TransGetLastRecordedTransaction");
-
- /* ----------------
- * next get the "last" and "next" variables
- * ----------------
- */
- VariableRelationGetLastXid(&varLastXid);
- VariableRelationGetNextXid(&varNextXid);
-
- /* ----------------
- * intregity test (1)
- * ----------------
- */
- if (TransactionIdIsLessThan(varNextXid, logLastXid))
- elog(WARN, "TransRecover: varNextXid < logLastXid");
-
- /* ----------------
- * intregity test (2)
- * ----------------
- */
-
- /* ----------------
- * intregity test (3)
- * ----------------
- */
-
- /* ----------------
- * here we have a valid "
- *
- * **** RESUME HERE ****
- * ----------------
- */
- varNextXid = TransactionIdDup(varLastXid);
- TransactionIdIncrement(&varNextXid);
-
- VarPut(var, VAR_PUT_LASTXID, varLastXid);
- VarPut(var, VAR_PUT_NEXTXID, varNextXid);
+#if 0
+ /* ----------------
+ * first get the last recorded transaction in the log.
+ * ----------------
+ */
+ TransGetLastRecordedTransaction(logRelation, logLastXid, &fail);
+ if (fail == true)
+ elog(WARN, "TransRecover: failed TransGetLastRecordedTransaction");
+
+ /* ----------------
+ * next get the "last" and "next" variables
+ * ----------------
+ */
+ VariableRelationGetLastXid(&varLastXid);
+ VariableRelationGetNextXid(&varNextXid);
+
+ /* ----------------
+ * intregity test (1)
+ * ----------------
+ */
+ if (TransactionIdIsLessThan(varNextXid, logLastXid))
+ elog(WARN, "TransRecover: varNextXid < logLastXid");
+
+ /* ----------------
+ * intregity test (2)
+ * ----------------
+ */
+
+ /* ----------------
+ * intregity test (3)
+ * ----------------
+ */
+
+ /* ----------------
+ * here we have a valid "
+ *
+ * **** RESUME HERE ****
+ * ----------------
+ */
+ varNextXid = TransactionIdDup(varLastXid);
+ TransactionIdIncrement(&varNextXid);
+
+ VarPut(var, VAR_PUT_LASTXID, varLastXid);
+ VarPut(var, VAR_PUT_NEXTXID, varNextXid);
#endif
}
/* ----------------------------------------------------------------
- * Interface functions
- *
- * InitializeTransactionLog
- * ========
- * this function (called near cinit) initializes
- * the transaction log, time and variable relations.
- *
- * TransactionId DidCommit
- * TransactionId DidAbort
- * TransactionId IsInProgress
- * ========
- * these functions test the transaction status of
- * a specified transaction id.
- *
- * TransactionId Commit
- * TransactionId Abort
- * TransactionId SetInProgress
- * ========
- * these functions set the transaction status
- * of the specified xid. TransactionIdCommit() also
- * records the current time in the time relation
- * and updates the variable relation counter.
+ * Interface functions
+ *
+ * InitializeTransactionLog
+ * ========
+ * this function (called near cinit) initializes
+ * the transaction log, time and variable relations.
+ *
+ * TransactionId DidCommit
+ * TransactionId DidAbort
+ * TransactionId IsInProgress
+ * ========
+ * these functions test the transaction status of
+ * a specified transaction id.
+ *
+ * TransactionId Commit
+ * TransactionId Abort
+ * TransactionId SetInProgress
+ * ========
+ * these functions set the transaction status
+ * of the specified xid. TransactionIdCommit() also
+ * records the current time in the time relation
+ * and updates the variable relation counter.
*
* ----------------------------------------------------------------
*/
/*
* InitializeTransactionLog --
- * Initializes transaction logging.
+ * Initializes transaction logging.
*/
void
InitializeTransactionLog(void)
{
- Relation logRelation;
- Relation timeRelation;
- MemoryContext oldContext;
-
- /* ----------------
- * don't do anything during bootstrapping
- * ----------------
- */
- if (AMI_OVERRIDE)
- return;
-
- /* ----------------
- * disable the transaction system so the access methods
- * don't interfere during initialization.
- * ----------------
- */
- OverrideTransactionSystem(true);
-
- /* ----------------
- * make sure allocations occur within the top memory context
- * so that our log management structures are protected from
- * garbage collection at the end of every transaction.
- * ----------------
- */
- oldContext = MemoryContextSwitchTo(TopMemoryContext);
-
- /* ----------------
- * first open the log and time relations
- * (these are created by amiint so they are guaranteed to exist)
- * ----------------
- */
- logRelation = heap_openr(LogRelationName);
- timeRelation = heap_openr(TimeRelationName);
- VariableRelation = heap_openr(VariableRelationName);
- /* ----------------
- * XXX TransactionLogUpdate requires that LogRelation
- * and TimeRelation are valid so we temporarily set
- * them so we can initialize things properly.
- * This could be done cleaner.
- * ----------------
- */
- LogRelation = logRelation;
- TimeRelation = timeRelation;
-
- /* ----------------
- * if we have a virgin database, we initialize the log and time
- * relation by committing the AmiTransactionId (id 512) and we
- * initialize the variable relation by setting the next available
- * transaction id to FirstTransactionId (id 514). OID initialization
- * happens as a side effect of bootstrapping in varsup.c.
- * ----------------
- */
- SpinAcquire(OidGenLockId);
- if (!TransactionIdDidCommit(AmiTransactionId)) {
-
+ Relation logRelation;
+ Relation timeRelation;
+ MemoryContext oldContext;
+
+ /* ----------------
+ * don't do anything during bootstrapping
+ * ----------------
+ */
+ if (AMI_OVERRIDE)
+ return;
+
+ /* ----------------
+ * disable the transaction system so the access methods
+ * don't interfere during initialization.
+ * ----------------
+ */
+ OverrideTransactionSystem(true);
+
/* ----------------
- * SOMEDAY initialize the information stored in
- * the headers of the log/time/variable relations.
+ * make sure allocations occur within the top memory context
+ * so that our log management structures are protected from
+ * garbage collection at the end of every transaction.
* ----------------
*/
- TransactionLogUpdate(AmiTransactionId, XID_COMMIT);
- VariableRelationPutNextXid(FirstTransactionId);
-
- } else if (RecoveryCheckingEnabled()) {
+ oldContext = MemoryContextSwitchTo(TopMemoryContext);
+
/* ----------------
- * if we have a pre-initialized database and if the
- * perform recovery checking flag was passed then we
- * do our database integrity checking.
+ * first open the log and time relations
+ * (these are created by amiint so they are guaranteed to exist)
* ----------------
*/
- TransRecover(logRelation);
- }
- LogRelation = (Relation) NULL;
- TimeRelation = (Relation) NULL;
- SpinRelease(OidGenLockId);
-
- /* ----------------
- * now re-enable the transaction system
- * ----------------
- */
- OverrideTransactionSystem(false);
-
- /* ----------------
- * instantiate the global variables
- * ----------------
- */
- LogRelation = logRelation;
- TimeRelation = timeRelation;
-
- /* ----------------
- * restore the memory context to the previous context
- * before we return from initialization.
- * ----------------
- */
- MemoryContextSwitchTo(oldContext);
+ logRelation = heap_openr(LogRelationName);
+ timeRelation = heap_openr(TimeRelationName);
+ VariableRelation = heap_openr(VariableRelationName);
+ /* ----------------
+ * XXX TransactionLogUpdate requires that LogRelation
+ * and TimeRelation are valid so we temporarily set
+ * them so we can initialize things properly.
+ * This could be done cleaner.
+ * ----------------
+ */
+ LogRelation = logRelation;
+ TimeRelation = timeRelation;
+
+ /* ----------------
+ * if we have a virgin database, we initialize the log and time
+ * relation by committing the AmiTransactionId (id 512) and we
+ * initialize the variable relation by setting the next available
+ * transaction id to FirstTransactionId (id 514). OID initialization
+ * happens as a side effect of bootstrapping in varsup.c.
+ * ----------------
+ */
+ SpinAcquire(OidGenLockId);
+ if (!TransactionIdDidCommit(AmiTransactionId))
+ {
+
+ /* ----------------
+ * SOMEDAY initialize the information stored in
+ * the headers of the log/time/variable relations.
+ * ----------------
+ */
+ TransactionLogUpdate(AmiTransactionId, XID_COMMIT);
+ VariableRelationPutNextXid(FirstTransactionId);
+
+ }
+ else if (RecoveryCheckingEnabled())
+ {
+ /* ----------------
+ * if we have a pre-initialized database and if the
+ * perform recovery checking flag was passed then we
+ * do our database integrity checking.
+ * ----------------
+ */
+ TransRecover(logRelation);
+ }
+ LogRelation = (Relation) NULL;
+ TimeRelation = (Relation) NULL;
+ SpinRelease(OidGenLockId);
+
+ /* ----------------
+ * now re-enable the transaction system
+ * ----------------
+ */
+ OverrideTransactionSystem(false);
+
+ /* ----------------
+ * instantiate the global variables
+ * ----------------
+ */
+ LogRelation = logRelation;
+ TimeRelation = timeRelation;
+
+ /* ----------------
+ * restore the memory context to the previous context
+ * before we return from initialization.
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldContext);
}
/* --------------------------------
- * TransactionId DidCommit
- * TransactionId DidAbort
- * TransactionId IsInProgress
+ * TransactionId DidCommit
+ * TransactionId DidAbort
+ * TransactionId IsInProgress
* --------------------------------
*/
/*
* TransactionIdDidCommit --
- * True iff transaction associated with the identifier did commit.
+ * True iff transaction associated with the identifier did commit.
*
* Note:
- * Assumes transaction identifier is valid.
+ * Assumes transaction identifier is valid.
*/
-bool /* true if given transaction committed */
+bool /* true if given transaction committed */
TransactionIdDidCommit(TransactionId transactionId)
{
- if (AMI_OVERRIDE)
- return true;
-
- return
- TransactionLogTest(transactionId, XID_COMMIT);
+ if (AMI_OVERRIDE)
+ return true;
+
+ return
+ TransactionLogTest(transactionId, XID_COMMIT);
}
/*
* TransactionIdDidAborted --
- * True iff transaction associated with the identifier did abort.
+ * True iff transaction associated with the identifier did abort.
*
* Note:
- * Assumes transaction identifier is valid.
- * XXX Is this unneeded?
+ * Assumes transaction identifier is valid.
+ * XXX Is this unneeded?
*/
-bool /* true if given transaction aborted */
+bool /* true if given transaction aborted */
TransactionIdDidAbort(TransactionId transactionId)
{
- if (AMI_OVERRIDE)
- return false;
-
- return
- TransactionLogTest(transactionId, XID_ABORT);
+ if (AMI_OVERRIDE)
+ return false;
+
+ return
+ TransactionLogTest(transactionId, XID_ABORT);
}
-/*
+/*
* Now this func in shmem.c and gives quality answer by scanning
* PROC structures of all running backend. - vadim 11/26/96
*
* Old comments:
- * true if given transaction neither committed nor aborted
-
+ * true if given transaction neither committed nor aborted
+
bool
TransactionIdIsInProgress(TransactionId transactionId)
{
- if (AMI_OVERRIDE)
- return false;
-
- return
- TransactionLogTest(transactionId, XID_INPROGRESS);
+ if (AMI_OVERRIDE)
+ return false;
+
+ return
+ TransactionLogTest(transactionId, XID_INPROGRESS);
}
*/
/* --------------------------------
- * TransactionId Commit
- * TransactionId Abort
- * TransactionId SetInProgress
+ * TransactionId Commit
+ * TransactionId Abort
+ * TransactionId SetInProgress
* --------------------------------
*/
/*
* TransactionIdCommit --
- * Commits the transaction associated with the identifier.
+ * Commits the transaction associated with the identifier.
*
* Note:
- * Assumes transaction identifier is valid.
+ * Assumes transaction identifier is valid.
*/
void
TransactionIdCommit(TransactionId transactionId)
{
- if (AMI_OVERRIDE)
- return;
-
- /*
- * Within TransactionLogUpdate we call UpdateLastCommited()
- * which assumes we have exclusive access to pg_variable.
- * Therefore we need to get exclusive access before calling
- * TransactionLogUpdate. -mer 18 Aug 1992
- */
- SpinAcquire(OidGenLockId);
- TransactionLogUpdate(transactionId, XID_COMMIT);
- SpinRelease(OidGenLockId);
+ if (AMI_OVERRIDE)
+ return;
+
+ /*
+ * Within TransactionLogUpdate we call UpdateLastCommited() which
+ * assumes we have exclusive access to pg_variable. Therefore we need
+ * to get exclusive access before calling TransactionLogUpdate. -mer
+ * 18 Aug 1992
+ */
+ SpinAcquire(OidGenLockId);
+ TransactionLogUpdate(transactionId, XID_COMMIT);
+ SpinRelease(OidGenLockId);
}
/*
* TransactionIdAbort --
- * Aborts the transaction associated with the identifier.
+ * Aborts the transaction associated with the identifier.
*
* Note:
- * Assumes transaction identifier is valid.
+ * Assumes transaction identifier is valid.
*/
void
TransactionIdAbort(TransactionId transactionId)
{
- BuildingBtree = false;
-
- if (VacuumRunning)
- vc_abort();
-
- if (AMI_OVERRIDE)
- return;
-
- TransactionLogUpdate(transactionId, XID_ABORT);
+ BuildingBtree = false;
+
+ if (VacuumRunning)
+ vc_abort();
+
+ if (AMI_OVERRIDE)
+ return;
+
+ TransactionLogUpdate(transactionId, XID_ABORT);
}
#ifdef NOT_USED
void
TransactionIdSetInProgress(TransactionId transactionId)
{
- if (AMI_OVERRIDE)
- return;
-
- TransactionLogUpdate(transactionId, XID_INPROGRESS);
+ if (AMI_OVERRIDE)
+ return;
+
+ TransactionLogUpdate(transactionId, XID_INPROGRESS);
}
+
#endif
diff --git a/src/backend/access/transam/transsup.c b/src/backend/access/transam/transsup.c
index c3f1d4fc9fc..9809190c942 100644
--- a/src/backend/access/transam/transsup.c
+++ b/src/backend/access/transam/transsup.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* transsup.c--
- * postgres transaction access method support code
+ * postgres transaction access method support code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.9 1997/08/19 21:30:12 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.10 1997/09/07 04:39:32 momjian Exp $
*
* NOTES
- * This file contains support functions for the high
- * level access method interface routines found in transam.c
+ * This file contains support functions for the high
+ * level access method interface routines found in transam.c
*
*-------------------------------------------------------------------------
*/
@@ -23,644 +23,659 @@
#include <access/xact.h>
#include <storage/lmgr.h>
-static AbsoluteTime TransBlockGetCommitTime(Block tblock,
- TransactionId transactionId);
-static XidStatus TransBlockGetXidStatus(Block tblock,
- TransactionId transactionId);
-static void TransBlockSetCommitTime(Block tblock,
- TransactionId transactionId, AbsoluteTime commitTime);
-static void TransBlockSetXidStatus(Block tblock,
- TransactionId transactionId, XidStatus xstatus);
+static AbsoluteTime
+TransBlockGetCommitTime(Block tblock,
+ TransactionId transactionId);
+static XidStatus
+TransBlockGetXidStatus(Block tblock,
+ TransactionId transactionId);
+static void
+TransBlockSetCommitTime(Block tblock,
+ TransactionId transactionId, AbsoluteTime commitTime);
+static void
+TransBlockSetXidStatus(Block tblock,
+ TransactionId transactionId, XidStatus xstatus);
/* ----------------------------------------------------------------
- * general support routines
+ * general support routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * AmiTransactionOverride
+ * AmiTransactionOverride
*
- * This function is used to manipulate the bootstrap flag.
+ * This function is used to manipulate the bootstrap flag.
* --------------------------------
*/
void
AmiTransactionOverride(bool flag)
{
- AMI_OVERRIDE = flag;
+ AMI_OVERRIDE = flag;
}
/* --------------------------------
- * TransComputeBlockNumber
+ * TransComputeBlockNumber
* --------------------------------
*/
void
-TransComputeBlockNumber(Relation relation, /* relation to test */
- TransactionId transactionId, /* transaction id to test */
- BlockNumber *blockNumberOutP)
+TransComputeBlockNumber(Relation relation, /* relation to test */
+ TransactionId transactionId, /* transaction id to
+ * test */
+ BlockNumber * blockNumberOutP)
{
- long itemsPerBlock = 0;
-
- /* ----------------
- * we calculate the block number of our transaction
- * by dividing the transaction id by the number of
- * transaction things per block.
- * ----------------
- */
- if (relation == LogRelation)
- itemsPerBlock = TP_NumXidStatusPerBlock;
- else if (relation == TimeRelation)
- itemsPerBlock = TP_NumTimePerBlock;
- else
- elog(WARN, "TransComputeBlockNumber: unknown relation");
-
- /* ----------------
- * warning! if the transaction id's get too large
- * then a BlockNumber may not be large enough to hold the results
- * of our division.
- *
- * XXX this will all vanish soon when we implement an improved
- * transaction id schema -cim 3/23/90
- *
- * This has vanished now that xid's are 4 bytes (no longer 5).
- * -mer 5/24/92
- * ----------------
- */
- (*blockNumberOutP) = transactionId / itemsPerBlock;
+ long itemsPerBlock = 0;
+
+ /* ----------------
+ * we calculate the block number of our transaction
+ * by dividing the transaction id by the number of
+ * transaction things per block.
+ * ----------------
+ */
+ if (relation == LogRelation)
+ itemsPerBlock = TP_NumXidStatusPerBlock;
+ else if (relation == TimeRelation)
+ itemsPerBlock = TP_NumTimePerBlock;
+ else
+ elog(WARN, "TransComputeBlockNumber: unknown relation");
+
+ /* ----------------
+ * warning! if the transaction id's get too large
+ * then a BlockNumber may not be large enough to hold the results
+ * of our division.
+ *
+ * XXX this will all vanish soon when we implement an improved
+ * transaction id schema -cim 3/23/90
+ *
+ * This has vanished now that xid's are 4 bytes (no longer 5).
+ * -mer 5/24/92
+ * ----------------
+ */
+ (*blockNumberOutP) = transactionId / itemsPerBlock;
}
/* ----------------------------------------------------------------
- * trans block support routines
+ * trans block support routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * TransBlockGetLastTransactionIdStatus
+ * TransBlockGetLastTransactionIdStatus
*
- * This returns the status and transaction id of the last
- * transaction information recorded on the given TransBlock.
+ * This returns the status and transaction id of the last
+ * transaction information recorded on the given TransBlock.
* --------------------------------
*/
#ifdef NOT_USED
-static XidStatus
+static XidStatus
TransBlockGetLastTransactionIdStatus(Block tblock,
- TransactionId baseXid,
- TransactionId *returnXidP)
+ TransactionId baseXid,
+ TransactionId * returnXidP)
{
- Index index;
- Index maxIndex;
- bits8 bit1;
- bits8 bit2;
- BitIndex offset;
- XidStatus xstatus;
-
- /* ----------------
- * sanity check
- * ----------------
- */
- Assert((tblock != NULL));
-
- /* ----------------
- * search downward from the top of the block data, looking
- * for the first Non-in progress transaction status. Since we
- * are scanning backward, this will be last recorded transaction
- * status on the block.
- * ----------------
- */
- maxIndex = TP_NumXidStatusPerBlock;
- for (index = maxIndex; index > 0; index--) {
- offset = BitIndexOf(index-1);
- bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
- bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
-
- xstatus = (bit1 | bit2) ;
-
- /* ----------------
- * here we have the status of some transaction, so test
- * if the status is recorded as "in progress". If so, then
- * we save the transaction id in the place specified by the caller.
- * ----------------
- */
- if (xstatus != XID_INPROGRESS) {
- if (returnXidP != NULL) {
- TransactionIdStore(baseXid, returnXidP);
- TransactionIdAdd(returnXidP, index - 1);
- }
- break;
+ Index index;
+ Index maxIndex;
+ bits8 bit1;
+ bits8 bit2;
+ BitIndex offset;
+ XidStatus xstatus;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ Assert((tblock != NULL));
+
+ /* ----------------
+ * search downward from the top of the block data, looking
+ * for the first Non-in progress transaction status. Since we
+ * are scanning backward, this will be last recorded transaction
+ * status on the block.
+ * ----------------
+ */
+ maxIndex = TP_NumXidStatusPerBlock;
+ for (index = maxIndex; index > 0; index--)
+ {
+ offset = BitIndexOf(index - 1);
+ bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
+ bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
+
+ xstatus = (bit1 | bit2);
+
+ /* ----------------
+ * here we have the status of some transaction, so test
+ * if the status is recorded as "in progress". If so, then
+ * we save the transaction id in the place specified by the caller.
+ * ----------------
+ */
+ if (xstatus != XID_INPROGRESS)
+ {
+ if (returnXidP != NULL)
+ {
+ TransactionIdStore(baseXid, returnXidP);
+ TransactionIdAdd(returnXidP, index - 1);
+ }
+ break;
+ }
}
- }
-
- /* ----------------
- * if we get here and index is 0 it means we couldn't find
- * a non-inprogress transaction on the block. For now we just
- * return this info to the user. They can check if the return
- * status is "in progress" to know this condition has arisen.
- * ----------------
- */
- if (index == 0) {
- if (returnXidP != NULL)
- TransactionIdStore(baseXid, returnXidP);
- }
-
- /* ----------------
- * return the status to the user
- * ----------------
- */
- return xstatus;
+
+ /* ----------------
+ * if we get here and index is 0 it means we couldn't find
+ * a non-inprogress transaction on the block. For now we just
+ * return this info to the user. They can check if the return
+ * status is "in progress" to know this condition has arisen.
+ * ----------------
+ */
+ if (index == 0)
+ {
+ if (returnXidP != NULL)
+ TransactionIdStore(baseXid, returnXidP);
+ }
+
+ /* ----------------
+ * return the status to the user
+ * ----------------
+ */
+ return xstatus;
}
+
#endif
/* --------------------------------
- * TransBlockGetXidStatus
+ * TransBlockGetXidStatus
*
- * This returns the status of the desired transaction
+ * This returns the status of the desired transaction
* --------------------------------
*/
-static XidStatus
+static XidStatus
TransBlockGetXidStatus(Block tblock,
- TransactionId transactionId)
+ TransactionId transactionId)
{
- Index index;
- bits8 bit1;
- bits8 bit2;
- BitIndex offset;
-
- /* ----------------
- * sanity check
- * ----------------
- */
- if (tblock == NULL) {
- return XID_INVALID;
- }
-
- /* ----------------
- * calculate the index into the transaction data where
- * our transaction status is located
- *
- * XXX this will be replaced soon when we move to the
- * new transaction id scheme -cim 3/23/90
- *
- * The old system has now been replaced. -mer 5/24/92
- * ----------------
- */
- index = transactionId % TP_NumXidStatusPerBlock;
-
- /* ----------------
- * get the data at the specified index
- * ----------------
- */
- offset = BitIndexOf(index);
- bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
- bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
-
- /* ----------------
- * return the transaction status to the caller
- * ----------------
- */
- return (XidStatus)
- (bit1 | bit2);
+ Index index;
+ bits8 bit1;
+ bits8 bit2;
+ BitIndex offset;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ if (tblock == NULL)
+ {
+ return XID_INVALID;
+ }
+
+ /* ----------------
+ * calculate the index into the transaction data where
+ * our transaction status is located
+ *
+ * XXX this will be replaced soon when we move to the
+ * new transaction id scheme -cim 3/23/90
+ *
+ * The old system has now been replaced. -mer 5/24/92
+ * ----------------
+ */
+ index = transactionId % TP_NumXidStatusPerBlock;
+
+ /* ----------------
+ * get the data at the specified index
+ * ----------------
+ */
+ offset = BitIndexOf(index);
+ bit1 = ((bits8) BitArrayBitIsSet((BitArray) tblock, offset++)) << 1;
+ bit2 = (bits8) BitArrayBitIsSet((BitArray) tblock, offset);
+
+ /* ----------------
+ * return the transaction status to the caller
+ * ----------------
+ */
+ return (XidStatus)
+ (bit1 | bit2);
}
/* --------------------------------
- * TransBlockSetXidStatus
+ * TransBlockSetXidStatus
*
- * This sets the status of the desired transaction
+ * This sets the status of the desired transaction
* --------------------------------
*/
static void
TransBlockSetXidStatus(Block tblock,
- TransactionId transactionId,
- XidStatus xstatus)
+ TransactionId transactionId,
+ XidStatus xstatus)
{
- Index index;
- BitIndex offset;
-
- /* ----------------
- * sanity check
- * ----------------
- */
- if (tblock == NULL)
- return;
-
- /* ----------------
- * calculate the index into the transaction data where
- * we sould store our transaction status.
- *
- * XXX this will be replaced soon when we move to the
- * new transaction id scheme -cim 3/23/90
- *
- * The new scheme is here -mer 5/24/92
- * ----------------
- */
- index = transactionId % TP_NumXidStatusPerBlock;
-
- offset = BitIndexOf(index);
-
- /* ----------------
- * store the transaction value at the specified offset
- * ----------------
- */
- switch(xstatus) {
- case XID_COMMIT: /* set 10 */
- BitArraySetBit((BitArray) tblock, offset);
- BitArrayClearBit((BitArray) tblock, offset + 1);
- break;
- case XID_ABORT: /* set 01 */
- BitArrayClearBit((BitArray) tblock, offset);
- BitArraySetBit((BitArray) tblock, offset + 1);
- break;
- case XID_INPROGRESS: /* set 00 */
- BitArrayClearBit((BitArray) tblock, offset);
- BitArrayClearBit((BitArray) tblock, offset + 1);
- break;
- default:
- elog(NOTICE,
- "TransBlockSetXidStatus: invalid status: %d (ignored)",
- xstatus);
- break;
- }
+ Index index;
+ BitIndex offset;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ if (tblock == NULL)
+ return;
+
+ /* ----------------
+ * calculate the index into the transaction data where
+ * we sould store our transaction status.
+ *
+ * XXX this will be replaced soon when we move to the
+ * new transaction id scheme -cim 3/23/90
+ *
+ * The new scheme is here -mer 5/24/92
+ * ----------------
+ */
+ index = transactionId % TP_NumXidStatusPerBlock;
+
+ offset = BitIndexOf(index);
+
+ /* ----------------
+ * store the transaction value at the specified offset
+ * ----------------
+ */
+ switch (xstatus)
+ {
+ case XID_COMMIT: /* set 10 */
+ BitArraySetBit((BitArray) tblock, offset);
+ BitArrayClearBit((BitArray) tblock, offset + 1);
+ break;
+ case XID_ABORT: /* set 01 */
+ BitArrayClearBit((BitArray) tblock, offset);
+ BitArraySetBit((BitArray) tblock, offset + 1);
+ break;
+ case XID_INPROGRESS: /* set 00 */
+ BitArrayClearBit((BitArray) tblock, offset);
+ BitArrayClearBit((BitArray) tblock, offset + 1);
+ break;
+ default:
+ elog(NOTICE,
+ "TransBlockSetXidStatus: invalid status: %d (ignored)",
+ xstatus);
+ break;
+ }
}
/* --------------------------------
- * TransBlockGetCommitTime
+ * TransBlockGetCommitTime
*
- * This returns the transaction commit time for the
- * specified transaction id in the trans block.
+ * This returns the transaction commit time for the
+ * specified transaction id in the trans block.
* --------------------------------
*/
-static AbsoluteTime
+static AbsoluteTime
TransBlockGetCommitTime(Block tblock,
- TransactionId transactionId)
+ TransactionId transactionId)
{
- Index index;
- AbsoluteTime *timeArray;
-
- /* ----------------
- * sanity check
- * ----------------
- */
- if (tblock == NULL)
- return INVALID_ABSTIME;
-
- /* ----------------
- * calculate the index into the transaction data where
- * our transaction commit time is located
- *
- * XXX this will be replaced soon when we move to the
- * new transaction id scheme -cim 3/23/90
- *
- * The new scheme is here. -mer 5/24/92
- * ----------------
- */
- index = transactionId % TP_NumTimePerBlock;
-
- /* ----------------
- * return the commit time to the caller
- * ----------------
- */
- timeArray = (AbsoluteTime *) tblock;
- return (AbsoluteTime)
- timeArray[ index ];
+ Index index;
+ AbsoluteTime *timeArray;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ if (tblock == NULL)
+ return INVALID_ABSTIME;
+
+ /* ----------------
+ * calculate the index into the transaction data where
+ * our transaction commit time is located
+ *
+ * XXX this will be replaced soon when we move to the
+ * new transaction id scheme -cim 3/23/90
+ *
+ * The new scheme is here. -mer 5/24/92
+ * ----------------
+ */
+ index = transactionId % TP_NumTimePerBlock;
+
+ /* ----------------
+ * return the commit time to the caller
+ * ----------------
+ */
+ timeArray = (AbsoluteTime *) tblock;
+ return (AbsoluteTime)
+ timeArray[index];
}
/* --------------------------------
- * TransBlockSetCommitTime
+ * TransBlockSetCommitTime
*
- * This sets the commit time of the specified transaction
+ * This sets the commit time of the specified transaction
* --------------------------------
*/
static void
TransBlockSetCommitTime(Block tblock,
- TransactionId transactionId,
- AbsoluteTime commitTime)
+ TransactionId transactionId,
+ AbsoluteTime commitTime)
{
- Index index;
- AbsoluteTime *timeArray;
-
- /* ----------------
- * sanity check
- * ----------------
- */
- if (tblock == NULL)
- return;
-
-
- /* ----------------
- * calculate the index into the transaction data where
- * we sould store our transaction status.
- *
- * XXX this will be replaced soon when we move to the
- * new transaction id scheme -cim 3/23/90
- *
- * The new scheme is here. -mer 5/24/92
- * ----------------
- */
- index = transactionId % TP_NumTimePerBlock;
-
- /* ----------------
- * store the transaction commit time at the specified index
- * ----------------
- */
- timeArray = (AbsoluteTime *) tblock;
- timeArray[ index ] = commitTime;
+ Index index;
+ AbsoluteTime *timeArray;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ if (tblock == NULL)
+ return;
+
+
+ /* ----------------
+ * calculate the index into the transaction data where
+ * we sould store our transaction status.
+ *
+ * XXX this will be replaced soon when we move to the
+ * new transaction id scheme -cim 3/23/90
+ *
+ * The new scheme is here. -mer 5/24/92
+ * ----------------
+ */
+ index = transactionId % TP_NumTimePerBlock;
+
+ /* ----------------
+ * store the transaction commit time at the specified index
+ * ----------------
+ */
+ timeArray = (AbsoluteTime *) tblock;
+ timeArray[index] = commitTime;
}
/* ----------------------------------------------------------------
- * transam i/o support routines
+ * transam i/o support routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * TransBlockNumberGetXidStatus
+ * TransBlockNumberGetXidStatus
* --------------------------------
*/
XidStatus
TransBlockNumberGetXidStatus(Relation relation,
- BlockNumber blockNumber,
- TransactionId xid,
- bool *failP)
+ BlockNumber blockNumber,
+ TransactionId xid,
+ bool * failP)
{
- Buffer buffer; /* buffer associated with block */
- Block block; /* block containing xstatus */
- XidStatus xstatus; /* recorded status of xid */
- bool localfail; /* bool used if failP = NULL */
-
- /* ----------------
- * SOMEDAY place a read lock on the log relation
- * That someday is today 5 Aug 1991 -mer
- * ----------------
- */
- RelationSetLockForRead(relation);
-
- /* ----------------
- * get the page containing the transaction information
- * ----------------
- */
- buffer = ReadBuffer(relation, blockNumber);
- block = BufferGetBlock(buffer);
-
- /* ----------------
- * get the status from the block. note, for now we always
- * return false in failP.
- * ----------------
- */
- if (failP == NULL)
- failP = &localfail;
- (*failP) = false;
-
- xstatus = TransBlockGetXidStatus(block, xid);
-
- /* ----------------
- * release the buffer and return the status
- * ----------------
- */
- ReleaseBuffer(buffer);
-
- /* ----------------
- * SOMEDAY release our lock on the log relation
- * ----------------
- */
- RelationUnsetLockForRead(relation);
-
- return
- xstatus;
+ Buffer buffer; /* buffer associated with block */
+ Block block; /* block containing xstatus */
+ XidStatus xstatus; /* recorded status of xid */
+ bool localfail; /* bool used if failP = NULL */
+
+ /* ----------------
+ * SOMEDAY place a read lock on the log relation
+ * That someday is today 5 Aug 1991 -mer
+ * ----------------
+ */
+ RelationSetLockForRead(relation);
+
+ /* ----------------
+ * get the page containing the transaction information
+ * ----------------
+ */
+ buffer = ReadBuffer(relation, blockNumber);
+ block = BufferGetBlock(buffer);
+
+ /* ----------------
+ * get the status from the block. note, for now we always
+ * return false in failP.
+ * ----------------
+ */
+ if (failP == NULL)
+ failP = &localfail;
+ (*failP) = false;
+
+ xstatus = TransBlockGetXidStatus(block, xid);
+
+ /* ----------------
+ * release the buffer and return the status
+ * ----------------
+ */
+ ReleaseBuffer(buffer);
+
+ /* ----------------
+ * SOMEDAY release our lock on the log relation
+ * ----------------
+ */
+ RelationUnsetLockForRead(relation);
+
+ return
+ xstatus;
}
/* --------------------------------
- * TransBlockNumberSetXidStatus
+ * TransBlockNumberSetXidStatus
* --------------------------------
*/
void
TransBlockNumberSetXidStatus(Relation relation,
- BlockNumber blockNumber,
- TransactionId xid,
- XidStatus xstatus,
- bool *failP)
+ BlockNumber blockNumber,
+ TransactionId xid,
+ XidStatus xstatus,
+ bool * failP)
{
- Buffer buffer; /* buffer associated with block */
- Block block; /* block containing xstatus */
- bool localfail; /* bool used if failP = NULL */
-
- /* ----------------
- * SOMEDAY gain exclusive access to the log relation
- *
- * That someday is today 5 Aug 1991 -mer
- * ----------------
- */
- RelationSetLockForWrite(relation);
-
- /* ----------------
- * get the block containing the transaction status
- * ----------------
- */
- buffer = ReadBuffer(relation, blockNumber);
- block = BufferGetBlock(buffer);
-
- /* ----------------
- * attempt to update the status of the transaction on the block.
- * if we are successful, write the block. otherwise release the buffer.
- * note, for now we always return false in failP.
- * ----------------
- */
- if (failP == NULL)
- failP = &localfail;
- (*failP) = false;
-
- TransBlockSetXidStatus(block, xid, xstatus);
-
- if ((*failP) == false)
- WriteBuffer(buffer);
- else
- ReleaseBuffer(buffer);
-
- /* ----------------
- * SOMEDAY release our lock on the log relation
- * ----------------
- */
- RelationUnsetLockForWrite(relation);
+ Buffer buffer; /* buffer associated with block */
+ Block block; /* block containing xstatus */
+ bool localfail; /* bool used if failP = NULL */
+
+ /* ----------------
+ * SOMEDAY gain exclusive access to the log relation
+ *
+ * That someday is today 5 Aug 1991 -mer
+ * ----------------
+ */
+ RelationSetLockForWrite(relation);
+
+ /* ----------------
+ * get the block containing the transaction status
+ * ----------------
+ */
+ buffer = ReadBuffer(relation, blockNumber);
+ block = BufferGetBlock(buffer);
+
+ /* ----------------
+ * attempt to update the status of the transaction on the block.
+ * if we are successful, write the block. otherwise release the buffer.
+ * note, for now we always return false in failP.
+ * ----------------
+ */
+ if (failP == NULL)
+ failP = &localfail;
+ (*failP) = false;
+
+ TransBlockSetXidStatus(block, xid, xstatus);
+
+ if ((*failP) == false)
+ WriteBuffer(buffer);
+ else
+ ReleaseBuffer(buffer);
+
+ /* ----------------
+ * SOMEDAY release our lock on the log relation
+ * ----------------
+ */
+ RelationUnsetLockForWrite(relation);
}
/* --------------------------------
- * TransBlockNumberGetCommitTime
+ * TransBlockNumberGetCommitTime
* --------------------------------
*/
AbsoluteTime
TransBlockNumberGetCommitTime(Relation relation,
- BlockNumber blockNumber,
- TransactionId xid,
- bool *failP)
+ BlockNumber blockNumber,
+ TransactionId xid,
+ bool * failP)
{
- Buffer buffer; /* buffer associated with block */
- Block block; /* block containing commit time */
- bool localfail; /* bool used if failP = NULL */
- AbsoluteTime xtime; /* commit time */
-
- /* ----------------
- * SOMEDAY place a read lock on the time relation
- *
- * That someday is today 5 Aug. 1991 -mer
- * ----------------
- */
- RelationSetLockForRead(relation);
-
- /* ----------------
- * get the block containing the transaction information
- * ----------------
- */
- buffer = ReadBuffer(relation, blockNumber);
- block = BufferGetBlock(buffer);
-
- /* ----------------
- * get the commit time from the block
- * note, for now we always return false in failP.
- * ----------------
- */
- if (failP == NULL)
- failP = &localfail;
- (*failP) = false;
-
- xtime = TransBlockGetCommitTime(block, xid);
-
- /* ----------------
- * release the buffer and return the commit time
- * ----------------
- */
- ReleaseBuffer(buffer);
-
- /* ----------------
- * SOMEDAY release our lock on the time relation
- * ----------------
- */
- RelationUnsetLockForRead(relation);
-
- if ((*failP) == false)
- return xtime;
- else
- return INVALID_ABSTIME;
-
+ Buffer buffer; /* buffer associated with block */
+ Block block; /* block containing commit time */
+ bool localfail; /* bool used if failP = NULL */
+ AbsoluteTime xtime; /* commit time */
+
+ /* ----------------
+ * SOMEDAY place a read lock on the time relation
+ *
+ * That someday is today 5 Aug. 1991 -mer
+ * ----------------
+ */
+ RelationSetLockForRead(relation);
+
+ /* ----------------
+ * get the block containing the transaction information
+ * ----------------
+ */
+ buffer = ReadBuffer(relation, blockNumber);
+ block = BufferGetBlock(buffer);
+
+ /* ----------------
+ * get the commit time from the block
+ * note, for now we always return false in failP.
+ * ----------------
+ */
+ if (failP == NULL)
+ failP = &localfail;
+ (*failP) = false;
+
+ xtime = TransBlockGetCommitTime(block, xid);
+
+ /* ----------------
+ * release the buffer and return the commit time
+ * ----------------
+ */
+ ReleaseBuffer(buffer);
+
+ /* ----------------
+ * SOMEDAY release our lock on the time relation
+ * ----------------
+ */
+ RelationUnsetLockForRead(relation);
+
+ if ((*failP) == false)
+ return xtime;
+ else
+ return INVALID_ABSTIME;
+
}
/* --------------------------------
- * TransBlockNumberSetCommitTime
+ * TransBlockNumberSetCommitTime
* --------------------------------
*/
void
TransBlockNumberSetCommitTime(Relation relation,
- BlockNumber blockNumber,
- TransactionId xid,
- AbsoluteTime xtime,
- bool *failP)
+ BlockNumber blockNumber,
+ TransactionId xid,
+ AbsoluteTime xtime,
+ bool * failP)
{
- Buffer buffer; /* buffer associated with block */
- Block block; /* block containing commit time */
- bool localfail; /* bool used if failP = NULL */
-
- /* ----------------
- * SOMEDAY gain exclusive access to the time relation
- *
- * That someday is today 5 Aug. 1991 -mer
- * ----------------
- */
- RelationSetLockForWrite(relation);
-
- /* ----------------
- * get the block containing our commit time
- * ----------------
- */
- buffer = ReadBuffer(relation, blockNumber);
- block = BufferGetBlock(buffer);
-
- /* ----------------
- * attempt to update the commit time of the transaction on the block.
- * if we are successful, write the block. otherwise release the buffer.
- * note, for now we always return false in failP.
- * ----------------
- */
- if (failP == NULL)
- failP = &localfail;
- (*failP) = false;
-
- TransBlockSetCommitTime(block, xid, xtime);
-
- if ((*failP) == false)
- WriteBuffer(buffer);
- else
- ReleaseBuffer(buffer);
-
- /* ----------------
- * SOMEDAY release our lock on the time relation
- * ----------------
- */
- RelationUnsetLockForWrite(relation);
-
+ Buffer buffer; /* buffer associated with block */
+ Block block; /* block containing commit time */
+ bool localfail; /* bool used if failP = NULL */
+
+ /* ----------------
+ * SOMEDAY gain exclusive access to the time relation
+ *
+ * That someday is today 5 Aug. 1991 -mer
+ * ----------------
+ */
+ RelationSetLockForWrite(relation);
+
+ /* ----------------
+ * get the block containing our commit time
+ * ----------------
+ */
+ buffer = ReadBuffer(relation, blockNumber);
+ block = BufferGetBlock(buffer);
+
+ /* ----------------
+ * attempt to update the commit time of the transaction on the block.
+ * if we are successful, write the block. otherwise release the buffer.
+ * note, for now we always return false in failP.
+ * ----------------
+ */
+ if (failP == NULL)
+ failP = &localfail;
+ (*failP) = false;
+
+ TransBlockSetCommitTime(block, xid, xtime);
+
+ if ((*failP) == false)
+ WriteBuffer(buffer);
+ else
+ ReleaseBuffer(buffer);
+
+ /* ----------------
+ * SOMEDAY release our lock on the time relation
+ * ----------------
+ */
+ RelationUnsetLockForWrite(relation);
+
}
/* --------------------------------
- * TransGetLastRecordedTransaction
+ * TransGetLastRecordedTransaction
* --------------------------------
*/
#ifdef NOT_USED
void
TransGetLastRecordedTransaction(Relation relation,
- TransactionId xid, /* return: transaction id */
- bool *failP)
+ TransactionId xid, /* return: transaction
+ * id */
+ bool * failP)
{
- BlockNumber blockNumber; /* block number */
- Buffer buffer; /* buffer associated with block */
- Block block; /* block containing xid status */
- BlockNumber n; /* number of blocks in the relation */
- TransactionId baseXid;
-
- (*failP) = false;
-
- /* ----------------
- * SOMEDAY gain exclusive access to the log relation
- *
- * That someday is today 5 Aug. 1991 -mer
- * It looks to me like we only need to set a read lock here, despite
- * the above comment about exclusive access. The block is never
- * actually written into, we only check status bits.
- * ----------------
- */
- RelationSetLockForRead(relation);
-
- /* ----------------
- * we assume the last block of the log contains the last
- * recorded transaction. If the relation is empty we return
- * failure to the user.
- * ----------------
- */
- n = RelationGetNumberOfBlocks(relation);
- if (n == 0) {
- (*failP) = true;
- return;
- }
-
- /* ----------------
- * get the block containing the transaction information
- * ----------------
- */
- blockNumber = n-1;
- buffer = ReadBuffer(relation, blockNumber);
- block = BufferGetBlock(buffer);
-
- /* ----------------
- * get the last xid on the block
- * ----------------
- */
- baseXid = blockNumber * TP_NumXidStatusPerBlock;
+ BlockNumber blockNumber;/* block number */
+ Buffer buffer; /* buffer associated with block */
+ Block block; /* block containing xid status */
+ BlockNumber n; /* number of blocks in the relation */
+ TransactionId baseXid;
+
+ (*failP) = false;
+
+ /* ----------------
+ * SOMEDAY gain exclusive access to the log relation
+ *
+ * That someday is today 5 Aug. 1991 -mer
+ * It looks to me like we only need to set a read lock here, despite
+ * the above comment about exclusive access. The block is never
+ * actually written into, we only check status bits.
+ * ----------------
+ */
+ RelationSetLockForRead(relation);
+
+ /* ----------------
+ * we assume the last block of the log contains the last
+ * recorded transaction. If the relation is empty we return
+ * failure to the user.
+ * ----------------
+ */
+ n = RelationGetNumberOfBlocks(relation);
+ if (n == 0)
+ {
+ (*failP) = true;
+ return;
+ }
+
+ /* ----------------
+ * get the block containing the transaction information
+ * ----------------
+ */
+ blockNumber = n - 1;
+ buffer = ReadBuffer(relation, blockNumber);
+ block = BufferGetBlock(buffer);
+
+ /* ----------------
+ * get the last xid on the block
+ * ----------------
+ */
+ baseXid = blockNumber * TP_NumXidStatusPerBlock;
/* XXX ???? xid won't get returned! - AY '94 */
- TransBlockGetLastTransactionIdStatus(block, baseXid, &xid);
-
- ReleaseBuffer(buffer);
-
- /* ----------------
- * SOMEDAY release our lock on the log relation
- * ----------------
- */
- RelationUnsetLockForRead(relation);
+ TransBlockGetLastTransactionIdStatus(block, baseXid, &xid);
+
+ ReleaseBuffer(buffer);
+
+ /* ----------------
+ * SOMEDAY release our lock on the log relation
+ * ----------------
+ */
+ RelationUnsetLockForRead(relation);
}
+
#endif
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index ba60ca35941..8b4b8557eb2 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* varsup.c--
- * postgres variable relation support routines
+ * postgres variable relation support routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.9 1997/08/19 21:30:16 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.10 1997/09/07 04:39:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,640 +20,647 @@
#include <access/heapam.h>
#include <catalog/catname.h>
-static void GetNewObjectIdBlock(Oid *oid_return, int oid_block_size);
-static void VariableRelationGetNextOid(Oid *oid_return);
-static void VariableRelationGetNextXid(TransactionId *xidP);
-static void VariableRelationPutLastXid(TransactionId xid);
-static void VariableRelationPutNextOid(Oid *oidP);
-static void VariableRelationGetLastXid(TransactionId *xidP);
+static void GetNewObjectIdBlock(Oid * oid_return, int oid_block_size);
+static void VariableRelationGetNextOid(Oid * oid_return);
+static void VariableRelationGetNextXid(TransactionId * xidP);
+static void VariableRelationPutLastXid(TransactionId xid);
+static void VariableRelationPutNextOid(Oid * oidP);
+static void VariableRelationGetLastXid(TransactionId * xidP);
/* ---------------------
- * spin lock for oid generation
+ * spin lock for oid generation
* ---------------------
*/
-int OidGenLockId;
+int OidGenLockId;
/* ----------------------------------------------------------------
- * variable relation query/update routines
+ * variable relation query/update routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * VariableRelationGetNextXid
+ * VariableRelationGetNextXid
* --------------------------------
*/
static void
-VariableRelationGetNextXid(TransactionId *xidP)
+VariableRelationGetNextXid(TransactionId * xidP)
{
- Buffer buf;
- VariableRelationContents var;
-
- /* ----------------
- * We assume that a spinlock has been acquire to guarantee
- * exclusive access to the variable relation.
- * ----------------
- */
-
- /* ----------------
- * do nothing before things are initialized
- * ----------------
- */
- if (! RelationIsValid(VariableRelation))
- return;
-
- /* ----------------
- * read the variable page, get the the nextXid field and
- * release the buffer
- * ----------------
- */
- buf = ReadBuffer(VariableRelation, 0);
-
- if (! BufferIsValid(buf))
+ Buffer buf;
+ VariableRelationContents var;
+
+ /* ----------------
+ * We assume that a spinlock has been acquire to guarantee
+ * exclusive access to the variable relation.
+ * ----------------
+ */
+
+ /* ----------------
+ * do nothing before things are initialized
+ * ----------------
+ */
+ if (!RelationIsValid(VariableRelation))
+ return;
+
+ /* ----------------
+ * read the variable page, get the the nextXid field and
+ * release the buffer
+ * ----------------
+ */
+ buf = ReadBuffer(VariableRelation, 0);
+
+ if (!BufferIsValid(buf))
{
- SpinRelease(OidGenLockId);
- elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
+ SpinRelease(OidGenLockId);
+ elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
}
-
- var = (VariableRelationContents) BufferGetBlock(buf);
-
- TransactionIdStore(var->nextXidData, xidP);
- ReleaseBuffer(buf);
+
+ var = (VariableRelationContents) BufferGetBlock(buf);
+
+ TransactionIdStore(var->nextXidData, xidP);
+ ReleaseBuffer(buf);
}
/* --------------------------------
- * VariableRelationGetLastXid
+ * VariableRelationGetLastXid
* --------------------------------
*/
static void
-VariableRelationGetLastXid(TransactionId *xidP)
+VariableRelationGetLastXid(TransactionId * xidP)
{
- Buffer buf;
- VariableRelationContents var;
-
- /* ----------------
- * We assume that a spinlock has been acquire to guarantee
- * exclusive access to the variable relation.
- * ----------------
- */
-
- /* ----------------
- * do nothing before things are initialized
- * ----------------
- */
- if (! RelationIsValid(VariableRelation))
- return;
-
- /* ----------------
- * read the variable page, get the the lastXid field and
- * release the buffer
- * ----------------
- */
- buf = ReadBuffer(VariableRelation, 0);
-
- if (! BufferIsValid(buf))
+ Buffer buf;
+ VariableRelationContents var;
+
+ /* ----------------
+ * We assume that a spinlock has been acquire to guarantee
+ * exclusive access to the variable relation.
+ * ----------------
+ */
+
+ /* ----------------
+ * do nothing before things are initialized
+ * ----------------
+ */
+ if (!RelationIsValid(VariableRelation))
+ return;
+
+ /* ----------------
+ * read the variable page, get the the lastXid field and
+ * release the buffer
+ * ----------------
+ */
+ buf = ReadBuffer(VariableRelation, 0);
+
+ if (!BufferIsValid(buf))
{
- SpinRelease(OidGenLockId);
- elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
+ SpinRelease(OidGenLockId);
+ elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
}
-
- var = (VariableRelationContents) BufferGetBlock(buf);
-
- TransactionIdStore(var->lastXidData, xidP);
-
- ReleaseBuffer(buf);
+
+ var = (VariableRelationContents) BufferGetBlock(buf);
+
+ TransactionIdStore(var->lastXidData, xidP);
+
+ ReleaseBuffer(buf);
}
/* --------------------------------
- * VariableRelationPutNextXid
+ * VariableRelationPutNextXid
* --------------------------------
*/
void
VariableRelationPutNextXid(TransactionId xid)
{
- Buffer buf;
- VariableRelationContents var;
- int flushmode;
-
- /* ----------------
- * We assume that a spinlock has been acquire to guarantee
- * exclusive access to the variable relation.
- * ----------------
- */
-
- /* ----------------
- * do nothing before things are initialized
- * ----------------
- */
- if (! RelationIsValid(VariableRelation))
- return;
-
- /* ----------------
- * read the variable page, update the nextXid field and
- * write the page back out to disk.
- * ----------------
- */
- buf = ReadBuffer(VariableRelation, 0);
-
- if (! BufferIsValid(buf))
+ Buffer buf;
+ VariableRelationContents var;
+ int flushmode;
+
+ /* ----------------
+ * We assume that a spinlock has been acquire to guarantee
+ * exclusive access to the variable relation.
+ * ----------------
+ */
+
+ /* ----------------
+ * do nothing before things are initialized
+ * ----------------
+ */
+ if (!RelationIsValid(VariableRelation))
+ return;
+
+ /* ----------------
+ * read the variable page, update the nextXid field and
+ * write the page back out to disk.
+ * ----------------
+ */
+ buf = ReadBuffer(VariableRelation, 0);
+
+ if (!BufferIsValid(buf))
{
- SpinRelease(OidGenLockId);
- elog(WARN, "VariableRelationPutNextXid: ReadBuffer failed");
+ SpinRelease(OidGenLockId);
+ elog(WARN, "VariableRelationPutNextXid: ReadBuffer failed");
}
-
- var = (VariableRelationContents) BufferGetBlock(buf);
-
- TransactionIdStore(xid, &(var->nextXidData));
-
- flushmode = SetBufferWriteMode (BUFFER_FLUSH_WRITE);
- WriteBuffer(buf);
- SetBufferWriteMode (flushmode);
+
+ var = (VariableRelationContents) BufferGetBlock(buf);
+
+ TransactionIdStore(xid, &(var->nextXidData));
+
+ flushmode = SetBufferWriteMode(BUFFER_FLUSH_WRITE);
+ WriteBuffer(buf);
+ SetBufferWriteMode(flushmode);
}
/* --------------------------------
- * VariableRelationPutLastXid
+ * VariableRelationPutLastXid
* --------------------------------
*/
static void
VariableRelationPutLastXid(TransactionId xid)
{
- Buffer buf;
- VariableRelationContents var;
-
- /* ----------------
- * We assume that a spinlock has been acquire to guarantee
- * exclusive access to the variable relation.
- * ----------------
- */
-
- /* ----------------
- * do nothing before things are initialized
- * ----------------
- */
- if (! RelationIsValid(VariableRelation))
- return;
-
- /* ----------------
- * read the variable page, update the lastXid field and
- * force the page back out to disk.
- * ----------------
- */
- buf = ReadBuffer(VariableRelation, 0);
-
- if (! BufferIsValid(buf))
+ Buffer buf;
+ VariableRelationContents var;
+
+ /* ----------------
+ * We assume that a spinlock has been acquire to guarantee
+ * exclusive access to the variable relation.
+ * ----------------
+ */
+
+ /* ----------------
+ * do nothing before things are initialized
+ * ----------------
+ */
+ if (!RelationIsValid(VariableRelation))
+ return;
+
+ /* ----------------
+ * read the variable page, update the lastXid field and
+ * force the page back out to disk.
+ * ----------------
+ */
+ buf = ReadBuffer(VariableRelation, 0);
+
+ if (!BufferIsValid(buf))
{
- SpinRelease(OidGenLockId);
- elog(WARN, "VariableRelationPutLastXid: ReadBuffer failed");
+ SpinRelease(OidGenLockId);
+ elog(WARN, "VariableRelationPutLastXid: ReadBuffer failed");
}
-
- var = (VariableRelationContents) BufferGetBlock(buf);
-
- TransactionIdStore(xid, &(var->lastXidData));
-
- WriteBuffer(buf);
+
+ var = (VariableRelationContents) BufferGetBlock(buf);
+
+ TransactionIdStore(xid, &(var->lastXidData));
+
+ WriteBuffer(buf);
}
/* --------------------------------
- * VariableRelationGetNextOid
+ * VariableRelationGetNextOid
* --------------------------------
*/
static void
-VariableRelationGetNextOid(Oid *oid_return)
+VariableRelationGetNextOid(Oid * oid_return)
{
- Buffer buf;
- VariableRelationContents var;
-
- /* ----------------
- * We assume that a spinlock has been acquire to guarantee
- * exclusive access to the variable relation.
- * ----------------
- */
-
- /* ----------------
- * if the variable relation is not initialized, then we
- * assume we are running at bootstrap time and so we return
- * an invalid object id -- during this time GetNextBootstrapObjectId
- * should be called instead..
- * ----------------
- */
- if (! RelationIsValid(VariableRelation)) {
+ Buffer buf;
+ VariableRelationContents var;
+
+ /* ----------------
+ * We assume that a spinlock has been acquire to guarantee
+ * exclusive access to the variable relation.
+ * ----------------
+ */
+
+ /* ----------------
+ * if the variable relation is not initialized, then we
+ * assume we are running at bootstrap time and so we return
+ * an invalid object id -- during this time GetNextBootstrapObjectId
+ * should be called instead..
+ * ----------------
+ */
+ if (!RelationIsValid(VariableRelation))
+ {
+ if (PointerIsValid(oid_return))
+ (*oid_return) = InvalidOid;
+ return;
+ }
+
+ /* ----------------
+ * read the variable page, get the the nextOid field and
+ * release the buffer
+ * ----------------
+ */
+ buf = ReadBuffer(VariableRelation, 0);
+
+ if (!BufferIsValid(buf))
+ {
+ SpinRelease(OidGenLockId);
+ elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
+ }
+
+ var = (VariableRelationContents) BufferGetBlock(buf);
+
if (PointerIsValid(oid_return))
- (*oid_return) = InvalidOid;
- return;
- }
-
- /* ----------------
- * read the variable page, get the the nextOid field and
- * release the buffer
- * ----------------
- */
- buf = ReadBuffer(VariableRelation, 0);
-
- if (! BufferIsValid(buf))
{
- SpinRelease(OidGenLockId);
- elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
+
+ /* ----------------
+ * nothing up my sleeve... what's going on here is that this code
+ * is guaranteed never to be called until all files in data/base/
+ * are created, and the template database exists. at that point,
+ * we want to append a pg_database tuple. the first time we do
+ * this, the oid stored in pg_variable will be bogus, so we use
+ * a bootstrap value defined at the top of this file.
+ *
+ * this comment no longer holds true. This code is called before
+ * all of the files in data/base are created and you can't rely
+ * on system oid's to be less than BootstrapObjectIdData. mer 9/18/91
+ * ----------------
+ */
+ if (OidIsValid(var->nextOid))
+ (*oid_return) = var->nextOid;
+ else
+ (*oid_return) = BootstrapObjectIdData;
}
-
- var = (VariableRelationContents) BufferGetBlock(buf);
-
- if (PointerIsValid(oid_return)) {
-
- /* ----------------
- * nothing up my sleeve... what's going on here is that this code
- * is guaranteed never to be called until all files in data/base/
- * are created, and the template database exists. at that point,
- * we want to append a pg_database tuple. the first time we do
- * this, the oid stored in pg_variable will be bogus, so we use
- * a bootstrap value defined at the top of this file.
- *
- * this comment no longer holds true. This code is called before
- * all of the files in data/base are created and you can't rely
- * on system oid's to be less than BootstrapObjectIdData. mer 9/18/91
- * ----------------
- */
- if (OidIsValid(var->nextOid))
- (*oid_return) = var->nextOid;
- else
- (*oid_return) = BootstrapObjectIdData;
- }
-
- ReleaseBuffer(buf);
+
+ ReleaseBuffer(buf);
}
/* --------------------------------
- * VariableRelationPutNextOid
+ * VariableRelationPutNextOid
* --------------------------------
*/
static void
-VariableRelationPutNextOid(Oid *oidP)
+VariableRelationPutNextOid(Oid * oidP)
{
- Buffer buf;
- VariableRelationContents var;
-
- /* ----------------
- * We assume that a spinlock has been acquire to guarantee
- * exclusive access to the variable relation.
- * ----------------
- */
-
- /* ----------------
- * do nothing before things are initialized
- * ----------------
- */
- if (! RelationIsValid(VariableRelation))
- return;
-
- /* ----------------
- * sanity check
- * ----------------
- */
- if (! PointerIsValid(oidP))
+ Buffer buf;
+ VariableRelationContents var;
+
+ /* ----------------
+ * We assume that a spinlock has been acquire to guarantee
+ * exclusive access to the variable relation.
+ * ----------------
+ */
+
+ /* ----------------
+ * do nothing before things are initialized
+ * ----------------
+ */
+ if (!RelationIsValid(VariableRelation))
+ return;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ if (!PointerIsValid(oidP))
{
- SpinRelease(OidGenLockId);
- elog(WARN, "VariableRelationPutNextOid: invalid oid pointer");
+ SpinRelease(OidGenLockId);
+ elog(WARN, "VariableRelationPutNextOid: invalid oid pointer");
}
-
- /* ----------------
- * read the variable page, update the nextXid field and
- * write the page back out to disk.
- * ----------------
- */
- buf = ReadBuffer(VariableRelation, 0);
-
- if (! BufferIsValid(buf))
+
+ /* ----------------
+ * read the variable page, update the nextXid field and
+ * write the page back out to disk.
+ * ----------------
+ */
+ buf = ReadBuffer(VariableRelation, 0);
+
+ if (!BufferIsValid(buf))
{
- SpinRelease(OidGenLockId);
- elog(WARN, "VariableRelationPutNextOid: ReadBuffer failed");
+ SpinRelease(OidGenLockId);
+ elog(WARN, "VariableRelationPutNextOid: ReadBuffer failed");
}
-
- var = (VariableRelationContents) BufferGetBlock(buf);
-
- var->nextOid = (*oidP);
-
- WriteBuffer(buf);
+
+ var = (VariableRelationContents) BufferGetBlock(buf);
+
+ var->nextOid = (*oidP);
+
+ WriteBuffer(buf);
}
/* ----------------------------------------------------------------
- * transaction id generation support
+ * transaction id generation support
* ----------------------------------------------------------------
*/
/* ----------------
- * GetNewTransactionId
+ * GetNewTransactionId
*
- * In the version 2 transaction system, transaction id's are
- * restricted in several ways.
+ * In the version 2 transaction system, transaction id's are
+ * restricted in several ways.
*
- * First, all transaction id's are even numbers (4, 88, 121342, etc).
- * This means the binary representation of the number will never
- * have the least significent bit set. This bit is reserved to
- * indicate that the transaction id does not in fact hold an XID,
- * but rather a commit time. This makes it possible for the
- * vaccuum daemon to disgard information from the log and time
- * relations for committed tuples. This is important when archiving
- * tuples to an optical disk because tuples with commit times
- * stored in their xid fields will not need to consult the log
- * and time relations.
+ * First, all transaction id's are even numbers (4, 88, 121342, etc).
+ * This means the binary representation of the number will never
+ * have the least significent bit set. This bit is reserved to
+ * indicate that the transaction id does not in fact hold an XID,
+ * but rather a commit time. This makes it possible for the
+ * vaccuum daemon to disgard information from the log and time
+ * relations for committed tuples. This is important when archiving
+ * tuples to an optical disk because tuples with commit times
+ * stored in their xid fields will not need to consult the log
+ * and time relations.
*
- * Second, since we may someday preform compression of the data
- * in the log and time relations, we cause the numbering of the
- * transaction ids to begin at 512. This means that some space
- * on the page of the log and time relations corresponding to
- * transaction id's 0 - 510 will never be used. This space is
- * in fact used to store the version number of the postgres
- * transaction log and will someday store compression information
- * about the log.
+ * Second, since we may someday preform compression of the data
+ * in the log and time relations, we cause the numbering of the
+ * transaction ids to begin at 512. This means that some space
+ * on the page of the log and time relations corresponding to
+ * transaction id's 0 - 510 will never be used. This space is
+ * in fact used to store the version number of the postgres
+ * transaction log and will someday store compression information
+ * about the log.
*
- * Lastly, rather then access the variable relation each time
- * a backend requests a new transction id, we "prefetch" 32
- * transaction id's by incrementing the nextXid stored in the
- * var relation by 64 (remember only even xid's are legal) and then
- * returning these id's one at a time until they are exhausted.
- * This means we reduce the number of accesses to the variable
- * relation by 32 for each backend.
+ * Lastly, rather then access the variable relation each time
+ * a backend requests a new transction id, we "prefetch" 32
+ * transaction id's by incrementing the nextXid stored in the
+ * var relation by 64 (remember only even xid's are legal) and then
+ * returning these id's one at a time until they are exhausted.
+ * This means we reduce the number of accesses to the variable
+ * relation by 32 for each backend.
*
- * Note: 32 has no special significance. We don't want the
- * number to be too large because if when the backend
- * terminates, we lose the xid's we cached.
+ * Note: 32 has no special significance. We don't want the
+ * number to be too large because if when the backend
+ * terminates, we lose the xid's we cached.
*
* ----------------
*/
-#define VAR_XID_PREFETCH 32
+#define VAR_XID_PREFETCH 32
-static int prefetched_xid_count = 0;
+static int prefetched_xid_count = 0;
static TransactionId next_prefetched_xid;
void
-GetNewTransactionId(TransactionId *xid)
+GetNewTransactionId(TransactionId * xid)
{
- TransactionId nextid;
-
- /* ----------------
- * during bootstrap initialization, we return the special
- * bootstrap transaction id.
- * ----------------
- */
- if (AMI_OVERRIDE) {
- TransactionIdStore(AmiTransactionId, xid);
- return;
- }
-
- /* ----------------
- * if we run out of prefetched xids, then we get some
- * more before handing them out to the caller.
- * ----------------
- */
-
- if (prefetched_xid_count == 0) {
- /* ----------------
- * obtain exclusive access to the variable relation page
- *
- * get the "next" xid from the variable relation
- * and save it in the prefetched id.
+ TransactionId nextid;
+
+ /* ----------------
+ * during bootstrap initialization, we return the special
+ * bootstrap transaction id.
* ----------------
*/
- SpinAcquire(OidGenLockId);
- VariableRelationGetNextXid(&nextid);
- TransactionIdStore(nextid, &next_prefetched_xid);
-
+ if (AMI_OVERRIDE)
+ {
+ TransactionIdStore(AmiTransactionId, xid);
+ return;
+ }
+
/* ----------------
- * now increment the variable relation's next xid
- * and reset the prefetched_xid_count. We multiply
- * the id by two because our xid's are always even.
+ * if we run out of prefetched xids, then we get some
+ * more before handing them out to the caller.
* ----------------
*/
- prefetched_xid_count = VAR_XID_PREFETCH;
- TransactionIdAdd(&nextid, prefetched_xid_count);
- VariableRelationPutNextXid(nextid);
- SpinRelease(OidGenLockId);
- }
-
- /* ----------------
- * return the next prefetched xid in the pointer passed by
- * the user and decrement the prefetch count. We add two
- * to id we return the next time this is called because our
- * transaction ids are always even.
- *
- * XXX Transaction Ids used to be even as the low order bit was
- * used to determine commit status. This is no long true so
- * we now use even and odd transaction ids. -mer 5/26/92
- * ----------------
- */
- TransactionIdStore(next_prefetched_xid, xid);
- TransactionIdAdd(&next_prefetched_xid, 1);
- prefetched_xid_count--;
+
+ if (prefetched_xid_count == 0)
+ {
+ /* ----------------
+ * obtain exclusive access to the variable relation page
+ *
+ * get the "next" xid from the variable relation
+ * and save it in the prefetched id.
+ * ----------------
+ */
+ SpinAcquire(OidGenLockId);
+ VariableRelationGetNextXid(&nextid);
+ TransactionIdStore(nextid, &next_prefetched_xid);
+
+ /* ----------------
+ * now increment the variable relation's next xid
+ * and reset the prefetched_xid_count. We multiply
+ * the id by two because our xid's are always even.
+ * ----------------
+ */
+ prefetched_xid_count = VAR_XID_PREFETCH;
+ TransactionIdAdd(&nextid, prefetched_xid_count);
+ VariableRelationPutNextXid(nextid);
+ SpinRelease(OidGenLockId);
+ }
+
+ /* ----------------
+ * return the next prefetched xid in the pointer passed by
+ * the user and decrement the prefetch count. We add two
+ * to id we return the next time this is called because our
+ * transaction ids are always even.
+ *
+ * XXX Transaction Ids used to be even as the low order bit was
+ * used to determine commit status. This is no long true so
+ * we now use even and odd transaction ids. -mer 5/26/92
+ * ----------------
+ */
+ TransactionIdStore(next_prefetched_xid, xid);
+ TransactionIdAdd(&next_prefetched_xid, 1);
+ prefetched_xid_count--;
}
/* ----------------
- * UpdateLastCommittedXid
+ * UpdateLastCommittedXid
* ----------------
*/
void
UpdateLastCommittedXid(TransactionId xid)
{
- TransactionId lastid;
-
-
- /* we assume that spinlock OidGenLockId has been acquired
- * prior to entering this function
- */
-
- /* ----------------
- * get the "last committed" transaction id from
- * the variable relation page.
- * ----------------
- */
- VariableRelationGetLastXid(&lastid);
-
- /* ----------------
- * if the transaction id is greater than the last committed
- * transaction then we update the last committed transaction
- * in the variable relation.
- * ----------------
- */
- if (TransactionIdIsLessThan(lastid, xid))
- VariableRelationPutLastXid(xid);
-
+ TransactionId lastid;
+
+
+ /*
+ * we assume that spinlock OidGenLockId has been acquired prior to
+ * entering this function
+ */
+
+ /* ----------------
+ * get the "last committed" transaction id from
+ * the variable relation page.
+ * ----------------
+ */
+ VariableRelationGetLastXid(&lastid);
+
+ /* ----------------
+ * if the transaction id is greater than the last committed
+ * transaction then we update the last committed transaction
+ * in the variable relation.
+ * ----------------
+ */
+ if (TransactionIdIsLessThan(lastid, xid))
+ VariableRelationPutLastXid(xid);
+
}
/* ----------------------------------------------------------------
- * object id generation support
+ * object id generation support
* ----------------------------------------------------------------
*/
/* ----------------
- * GetNewObjectIdBlock
+ * GetNewObjectIdBlock
*
- * This support function is used to allocate a block of object ids
- * of the given size. applications wishing to do their own object
- * id assignments should use this
+ * This support function is used to allocate a block of object ids
+ * of the given size. applications wishing to do their own object
+ * id assignments should use this
* ----------------
*/
static void
-GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object id */
- int oid_block_size) /* number of oids desired */
+GetNewObjectIdBlock(Oid * oid_return, /* place to return the new object
+ * id */
+ int oid_block_size) /* number of oids desired */
{
- Oid nextoid;
-
- /* ----------------
- * SOMEDAY obtain exclusive access to the variable relation page
- * That someday is today -mer 6 Aug 1992
- * ----------------
- */
- SpinAcquire(OidGenLockId);
-
- /* ----------------
- * get the "next" oid from the variable relation
- * and give it to the caller.
- * ----------------
- */
- VariableRelationGetNextOid(&nextoid);
- if (PointerIsValid(oid_return))
- (*oid_return) = nextoid;
-
- /* ----------------
- * now increment the variable relation's next oid
- * field by the size of the oid block requested.
- * ----------------
- */
- nextoid += oid_block_size;
- VariableRelationPutNextOid(&nextoid);
-
- /* ----------------
- * SOMEDAY relinquish our lock on the variable relation page
- * That someday is today -mer 6 Apr 1992
- * ----------------
- */
- SpinRelease(OidGenLockId);
+ Oid nextoid;
+
+ /* ----------------
+ * SOMEDAY obtain exclusive access to the variable relation page
+ * That someday is today -mer 6 Aug 1992
+ * ----------------
+ */
+ SpinAcquire(OidGenLockId);
+
+ /* ----------------
+ * get the "next" oid from the variable relation
+ * and give it to the caller.
+ * ----------------
+ */
+ VariableRelationGetNextOid(&nextoid);
+ if (PointerIsValid(oid_return))
+ (*oid_return) = nextoid;
+
+ /* ----------------
+ * now increment the variable relation's next oid
+ * field by the size of the oid block requested.
+ * ----------------
+ */
+ nextoid += oid_block_size;
+ VariableRelationPutNextOid(&nextoid);
+
+ /* ----------------
+ * SOMEDAY relinquish our lock on the variable relation page
+ * That someday is today -mer 6 Apr 1992
+ * ----------------
+ */
+ SpinRelease(OidGenLockId);
}
/* ----------------
- * GetNewObjectId
+ * GetNewObjectId
*
- * This function allocates and parses out object ids. Like
- * GetNewTransactionId(), it "prefetches" 32 object ids by
- * incrementing the nextOid stored in the var relation by 32 and then
- * returning these id's one at a time until they are exhausted.
- * This means we reduce the number of accesses to the variable
- * relation by 32 for each backend.
+ * This function allocates and parses out object ids. Like
+ * GetNewTransactionId(), it "prefetches" 32 object ids by
+ * incrementing the nextOid stored in the var relation by 32 and then
+ * returning these id's one at a time until they are exhausted.
+ * This means we reduce the number of accesses to the variable
+ * relation by 32 for each backend.
*
- * Note: 32 has no special significance. We don't want the
- * number to be too large because if when the backend
- * terminates, we lose the oids we cached.
+ * Note: 32 has no special significance. We don't want the
+ * number to be too large because if when the backend
+ * terminates, we lose the oids we cached.
*
* ----------------
*/
-#define VAR_OID_PREFETCH 32
+#define VAR_OID_PREFETCH 32
-static int prefetched_oid_count = 0;
-static Oid next_prefetched_oid;
+static int prefetched_oid_count = 0;
+static Oid next_prefetched_oid;
void
-GetNewObjectId(Oid *oid_return) /* place to return the new object id */
+GetNewObjectId(Oid * oid_return)/* place to return the new object id */
{
- /* ----------------
- * if we run out of prefetched oids, then we get some
- * more before handing them out to the caller.
- * ----------------
- */
-
- if (prefetched_oid_count == 0) {
- int oid_block_size = VAR_OID_PREFETCH;
-
- /* ----------------
- * during bootstrap time, we want to allocate oids
- * one at a time. Otherwise there might be some
- * bootstrap oid's left in the block we prefetch which
- * would be passed out after the variable relation was
- * initialized. This would be bad.
- * ----------------
- */
- if (! RelationIsValid(VariableRelation))
- VariableRelation = heap_openr(VariableRelationName);
-
- /* ----------------
- * get a new block of prefetched object ids.
- * ----------------
- */
- GetNewObjectIdBlock(&next_prefetched_oid, oid_block_size);
-
- /* ----------------
- * now reset the prefetched_oid_count.
- * ----------------
- */
- prefetched_oid_count = oid_block_size;
- }
-
- /* ----------------
- * return the next prefetched oid in the pointer passed by
- * the user and decrement the prefetch count.
- * ----------------
- */
- if (PointerIsValid(oid_return))
- (*oid_return) = next_prefetched_oid;
-
- next_prefetched_oid++;
- prefetched_oid_count--;
+ /* ----------------
+ * if we run out of prefetched oids, then we get some
+ * more before handing them out to the caller.
+ * ----------------
+ */
+
+ if (prefetched_oid_count == 0)
+ {
+ int oid_block_size = VAR_OID_PREFETCH;
+
+ /* ----------------
+ * during bootstrap time, we want to allocate oids
+ * one at a time. Otherwise there might be some
+ * bootstrap oid's left in the block we prefetch which
+ * would be passed out after the variable relation was
+ * initialized. This would be bad.
+ * ----------------
+ */
+ if (!RelationIsValid(VariableRelation))
+ VariableRelation = heap_openr(VariableRelationName);
+
+ /* ----------------
+ * get a new block of prefetched object ids.
+ * ----------------
+ */
+ GetNewObjectIdBlock(&next_prefetched_oid, oid_block_size);
+
+ /* ----------------
+ * now reset the prefetched_oid_count.
+ * ----------------
+ */
+ prefetched_oid_count = oid_block_size;
+ }
+
+ /* ----------------
+ * return the next prefetched oid in the pointer passed by
+ * the user and decrement the prefetch count.
+ * ----------------
+ */
+ if (PointerIsValid(oid_return))
+ (*oid_return) = next_prefetched_oid;
+
+ next_prefetched_oid++;
+ prefetched_oid_count--;
}
void
CheckMaxObjectId(Oid assigned_oid)
{
-Oid pass_oid;
-
-
- if (prefetched_oid_count == 0) /* make sure next/max is set, or reload */
- GetNewObjectId(&pass_oid);
-
- /* ----------------
- * If we are below prefetched limits, do nothing
- * ----------------
- */
-
- if (assigned_oid < next_prefetched_oid)
- return;
-
- /* ----------------
- * If we are here, we are coming from a 'copy from' with oid's
- *
- * If we are in the prefetched oid range, just bump it up
- *
- * ----------------
- */
-
- if (assigned_oid <= next_prefetched_oid + prefetched_oid_count - 1)
- {
- prefetched_oid_count -= assigned_oid - next_prefetched_oid + 1;
- next_prefetched_oid = assigned_oid + 1;
- return;
- }
-
- /* ----------------
- * We have exceeded the prefetch oid range
- *
- * We should lock the database and kill all other backends
- * but we are loading oid's that we can not guarantee are unique
- * anyway, so we must rely on the user
- *
- *
- * We now:
- * set the variable relation with the new max oid
- * force the backend to reload its oid cache
- *
- * We use the oid cache so we don't have to update the variable
- * relation every time
- *
- * ----------------
- */
-
- pass_oid = assigned_oid;
- VariableRelationPutNextOid(&pass_oid); /* not modified */
- prefetched_oid_count = 0; /* force reload */
- pass_oid = assigned_oid;
- GetNewObjectId(&pass_oid); /* throw away returned oid */
+ Oid pass_oid;
-}
+ if (prefetched_oid_count == 0) /* make sure next/max is set, or
+ * reload */
+ GetNewObjectId(&pass_oid);
+
+ /* ----------------
+ * If we are below prefetched limits, do nothing
+ * ----------------
+ */
+
+ if (assigned_oid < next_prefetched_oid)
+ return;
+
+ /* ----------------
+ * If we are here, we are coming from a 'copy from' with oid's
+ *
+ * If we are in the prefetched oid range, just bump it up
+ *
+ * ----------------
+ */
+
+ if (assigned_oid <= next_prefetched_oid + prefetched_oid_count - 1)
+ {
+ prefetched_oid_count -= assigned_oid - next_prefetched_oid + 1;
+ next_prefetched_oid = assigned_oid + 1;
+ return;
+ }
+
+ /* ----------------
+ * We have exceeded the prefetch oid range
+ *
+ * We should lock the database and kill all other backends
+ * but we are loading oid's that we can not guarantee are unique
+ * anyway, so we must rely on the user
+ *
+ *
+ * We now:
+ * set the variable relation with the new max oid
+ * force the backend to reload its oid cache
+ *
+ * We use the oid cache so we don't have to update the variable
+ * relation every time
+ *
+ * ----------------
+ */
+
+ pass_oid = assigned_oid;
+ VariableRelationPutNextOid(&pass_oid); /* not modified */
+ prefetched_oid_count = 0; /* force reload */
+ pass_oid = assigned_oid;
+ GetNewObjectId(&pass_oid); /* throw away returned oid */
+
+}
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 5ac4a42c7c7..da32570d87b 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -1,138 +1,138 @@
/*-------------------------------------------------------------------------
*
* xact.c--
- * top level transaction system support routines
+ * top level transaction system support routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.13 1997/08/29 09:02:11 vadim Exp $
- *
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.14 1997/09/07 04:39:38 momjian Exp $
+ *
* NOTES
- * Transaction aborts can now occur two ways:
+ * Transaction aborts can now occur two ways:
*
- * 1) system dies from some internal cause (Assert, etc..)
- * 2) user types abort
+ * 1) system dies from some internal cause (Assert, etc..)
+ * 2) user types abort
*
- * These two cases used to be treated identically, but now
- * we need to distinguish them. Why? consider the following
- * two situatuons:
+ * These two cases used to be treated identically, but now
+ * we need to distinguish them. Why? consider the following
+ * two situatuons:
*
- * case 1 case 2
- * ------ ------
- * 1) user types BEGIN 1) user types BEGIN
- * 2) user does something 2) user does something
- * 3) user does not like what 3) system aborts for some reason
- * she shes and types ABORT
+ * case 1 case 2
+ * ------ ------
+ * 1) user types BEGIN 1) user types BEGIN
+ * 2) user does something 2) user does something
+ * 3) user does not like what 3) system aborts for some reason
+ * she shes and types ABORT
*
- * In case 1, we want to abort the transaction and return to the
- * default state. In case 2, there may be more commands coming
- * our way which are part of the same transaction block and we have
- * to ignore these commands until we see an END transaction.
- * (or an ABORT! --djm)
+ * In case 1, we want to abort the transaction and return to the
+ * default state. In case 2, there may be more commands coming
+ * our way which are part of the same transaction block and we have
+ * to ignore these commands until we see an END transaction.
+ * (or an ABORT! --djm)
*
- * Internal aborts are now handled by AbortTransactionBlock(), just as
- * they always have been, and user aborts are now handled by
- * UserAbortTransactionBlock(). Both of them rely on AbortTransaction()
- * to do all the real work. The only difference is what state we
- * enter after AbortTransaction() does it's work:
- *
- * * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
- * * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
- *
- * NOTES
- * This file is an attempt at a redesign of the upper layer
- * of the V1 transaction system which was too poorly thought
- * out to describe. This new system hopes to be both simpler
- * in design, simpler to extend and needs to contain added
- * functionality to solve problems beyond the scope of the V1
- * system. (In particuler, communication of transaction
- * information between parallel backends has to be supported)
+ * Internal aborts are now handled by AbortTransactionBlock(), just as
+ * they always have been, and user aborts are now handled by
+ * UserAbortTransactionBlock(). Both of them rely on AbortTransaction()
+ * to do all the real work. The only difference is what state we
+ * enter after AbortTransaction() does it's work:
*
- * The essential aspects of the transaction system are:
+ * * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
+ * * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
*
- * o transaction id generation
- * o transaction log updating
- * o memory cleanup
- * o cache invalidation
- * o lock cleanup
+ * NOTES
+ * This file is an attempt at a redesign of the upper layer
+ * of the V1 transaction system which was too poorly thought
+ * out to describe. This new system hopes to be both simpler
+ * in design, simpler to extend and needs to contain added
+ * functionality to solve problems beyond the scope of the V1
+ * system. (In particuler, communication of transaction
+ * information between parallel backends has to be supported)
*
- * Hence, the functional division of the transaction code is
- * based on what of the above things need to be done during
- * a start/commit/abort transaction. For instance, the
- * routine AtCommit_Memory() takes care of all the memory
- * cleanup stuff done at commit time.
+ * The essential aspects of the transaction system are:
*
- * The code is layered as follows:
+ * o transaction id generation
+ * o transaction log updating
+ * o memory cleanup
+ * o cache invalidation
+ * o lock cleanup
*
- * StartTransaction
- * CommitTransaction
- * AbortTransaction
- * UserAbortTransaction
+ * Hence, the functional division of the transaction code is
+ * based on what of the above things need to be done during
+ * a start/commit/abort transaction. For instance, the
+ * routine AtCommit_Memory() takes care of all the memory
+ * cleanup stuff done at commit time.
*
- * are provided to do the lower level work like recording
- * the transaction status in the log and doing memory cleanup.
- * above these routines are another set of functions:
+ * The code is layered as follows:
*
- * StartTransactionCommand
- * CommitTransactionCommand
- * AbortCurrentTransaction
+ * StartTransaction
+ * CommitTransaction
+ * AbortTransaction
+ * UserAbortTransaction
*
- * These are the routines used in the postgres main processing
- * loop. They are sensitive to the current transaction block state
- * and make calls to the lower level routines appropriately.
+ * are provided to do the lower level work like recording
+ * the transaction status in the log and doing memory cleanup.
+ * above these routines are another set of functions:
*
- * Support for transaction blocks is provided via the functions:
+ * StartTransactionCommand
+ * CommitTransactionCommand
+ * AbortCurrentTransaction
*
- * StartTransactionBlock
- * CommitTransactionBlock
- * AbortTransactionBlock
+ * These are the routines used in the postgres main processing
+ * loop. They are sensitive to the current transaction block state
+ * and make calls to the lower level routines appropriately.
+ *
+ * Support for transaction blocks is provided via the functions:
+ *
+ * StartTransactionBlock
+ * CommitTransactionBlock
+ * AbortTransactionBlock
*
- * These are invoked only in responce to a user "BEGIN", "END",
- * or "ABORT" command. The tricky part about these functions
- * is that they are called within the postgres main loop, in between
- * the StartTransactionCommand() and CommitTransactionCommand().
+ * These are invoked only in responce to a user "BEGIN", "END",
+ * or "ABORT" command. The tricky part about these functions
+ * is that they are called within the postgres main loop, in between
+ * the StartTransactionCommand() and CommitTransactionCommand().
*
- * For example, consider the following sequence of user commands:
+ * For example, consider the following sequence of user commands:
*
- * 1) begin
- * 2) retrieve (foo.all)
- * 3) append foo (bar = baz)
- * 4) end
+ * 1) begin
+ * 2) retrieve (foo.all)
+ * 3) append foo (bar = baz)
+ * 4) end
*
- * in the main processing loop, this results in the following
- * transaction sequence:
+ * in the main processing loop, this results in the following
+ * transaction sequence:
*
- * / StartTransactionCommand();
- * 1) / ProcessUtility(); << begin
- * \ StartTransactionBlock();
- * \ CommitTransactionCommand();
+ * / StartTransactionCommand();
+ * 1) / ProcessUtility(); << begin
+ * \ StartTransactionBlock();
+ * \ CommitTransactionCommand();
*
- * / StartTransactionCommand();
- * 2) < ProcessQuery(); << retrieve (foo.all)
- * \ CommitTransactionCommand();
+ * / StartTransactionCommand();
+ * 2) < ProcessQuery(); << retrieve (foo.all)
+ * \ CommitTransactionCommand();
*
- * / StartTransactionCommand();
- * 3) < ProcessQuery(); << append foo (bar = baz)
- * \ CommitTransactionCommand();
+ * / StartTransactionCommand();
+ * 3) < ProcessQuery(); << append foo (bar = baz)
+ * \ CommitTransactionCommand();
*
- * / StartTransactionCommand();
- * 4) / ProcessUtility(); << end
- * \ CommitTransactionBlock();
- * \ CommitTransactionCommand();
+ * / StartTransactionCommand();
+ * 4) / ProcessUtility(); << end
+ * \ CommitTransactionBlock();
+ * \ CommitTransactionCommand();
*
- * The point of this example is to demonstrate the need for
- * StartTransactionCommand() and CommitTransactionCommand() to
- * be state smart -- they should do nothing in between the calls
- * to StartTransactionBlock() and EndTransactionBlock() and
- * outside these calls they need to do normal start/commit
- * processing.
+ * The point of this example is to demonstrate the need for
+ * StartTransactionCommand() and CommitTransactionCommand() to
+ * be state smart -- they should do nothing in between the calls
+ * to StartTransactionBlock() and EndTransactionBlock() and
+ * outside these calls they need to do normal start/commit
+ * processing.
*
- * Furthermore, suppose the "retrieve (foo.all)" caused an abort
- * condition. We would then want to abort the transaction and
- * ignore all subsequent commands up to the "end".
- * -cim 3/23/90
+ * Furthermore, suppose the "retrieve (foo.all)" caused an abort
+ * condition. We would then want to abort the transaction and
+ * ignore all subsequent commands up to the "end".
+ * -cim 3/23/90
*
*-------------------------------------------------------------------------
*/
@@ -142,7 +142,7 @@
#include <access/xact.h>
#include <utils/inval.h>
#include <utils/portal.h>
-#include <access/transam.h>
+#include <access/transam.h>
#include <storage/proc.h>
#include <utils/mcxt.h>
#include <catalog/heap.h>
@@ -151,683 +151,700 @@
#include <commands/async.h>
#include <commands/sequence.h>
-static void AbortTransaction(void);
-static void AtAbort_Cache(void);
-static void AtAbort_Locks(void);
-static void AtAbort_Memory(void);
-static void AtCommit_Cache(void);
-static void AtCommit_Locks(void);
-static void AtCommit_Memory(void);
-static void AtStart_Cache(void);
-static void AtStart_Locks(void);
-static void AtStart_Memory(void);
-static void CommitTransaction(void);
-static void RecordTransactionAbort(void);
-static void RecordTransactionCommit(void);
-static void StartTransaction(void);
+static void AbortTransaction(void);
+static void AtAbort_Cache(void);
+static void AtAbort_Locks(void);
+static void AtAbort_Memory(void);
+static void AtCommit_Cache(void);
+static void AtCommit_Locks(void);
+static void AtCommit_Memory(void);
+static void AtStart_Cache(void);
+static void AtStart_Locks(void);
+static void AtStart_Memory(void);
+static void CommitTransaction(void);
+static void RecordTransactionAbort(void);
+static void RecordTransactionCommit(void);
+static void StartTransaction(void);
/* ----------------
- * global variables holding the current transaction state.
+ * global variables holding the current transaction state.
*
- * Note: when we are running several slave processes, the
- * current transaction state data is copied into shared memory
- * and the CurrentTransactionState pointer changed to
- * point to the shared copy. All this occurrs in slaves.c
+ * Note: when we are running several slave processes, the
+ * current transaction state data is copied into shared memory
+ * and the CurrentTransactionState pointer changed to
+ * point to the shared copy. All this occurrs in slaves.c
* ----------------
*/
TransactionStateData CurrentTransactionStateData = {
- 0, /* transaction id */
- FirstCommandId, /* command id */
- 0x0, /* start time */
- TRANS_DEFAULT, /* transaction state */
- TBLOCK_DEFAULT /* transaction block state */
- };
+ 0, /* transaction id */
+ FirstCommandId, /* command id */
+ 0x0, /* start time */
+ TRANS_DEFAULT, /* transaction state */
+ TBLOCK_DEFAULT /* transaction block state */
+};
TransactionState CurrentTransactionState =
- &CurrentTransactionStateData;
+&CurrentTransactionStateData;
/* ----------------
- * info returned when the system is disabled
+ * info returned when the system is disabled
*
* Apparently a lot of this code is inherited from other prototype systems.
* For DisabledStartTime, use a symbolic value to make the relationships clearer.
* The old value of 1073741823 corresponds to a date in y2004, which is coming closer
- * every day. It appears that if we return a value guaranteed larger than
- * any real time associated with a transaction then comparisons in other
- * modules will still be correct. Let's use BIG_ABSTIME for this. tgl 2/14/97
+ * every day. It appears that if we return a value guaranteed larger than
+ * any real time associated with a transaction then comparisons in other
+ * modules will still be correct. Let's use BIG_ABSTIME for this. tgl 2/14/97
*
- * Note: I have no idea what the significance of the
- * 1073741823 in DisabledStartTime.. I just carried
- * this over when converting things from the old
- * V1 transaction system. -cim 3/18/90
+ * Note: I have no idea what the significance of the
+ * 1073741823 in DisabledStartTime.. I just carried
+ * this over when converting things from the old
+ * V1 transaction system. -cim 3/18/90
* ----------------
*/
-TransactionId DisabledTransactionId = (TransactionId)-1;
-
-CommandId DisabledCommandId = (CommandId) -1;
-
-AbsoluteTime DisabledStartTime = (AbsoluteTime) BIG_ABSTIME; /* 1073741823; */
-
+TransactionId DisabledTransactionId = (TransactionId) - 1;
+
+CommandId DisabledCommandId = (CommandId) - 1;
+
+AbsoluteTime DisabledStartTime = (AbsoluteTime) BIG_ABSTIME; /* 1073741823; */
+
/* ----------------
- * overflow flag
+ * overflow flag
* ----------------
*/
-bool CommandIdCounterOverflowFlag;
-
+bool CommandIdCounterOverflowFlag;
+
/* ----------------
- * catalog creation transaction bootstrapping flag.
- * This should be eliminated and added to the transaction
- * state stuff. -cim 3/19/90
+ * catalog creation transaction bootstrapping flag.
+ * This should be eliminated and added to the transaction
+ * state stuff. -cim 3/19/90
* ----------------
*/
-bool AMI_OVERRIDE = false;
-
+bool AMI_OVERRIDE = false;
+
/* ----------------------------------------------------------------
- * transaction state accessors
+ * transaction state accessors
* ----------------------------------------------------------------
*/
-
+
/* --------------------------------
- * TranactionFlushEnabled()
- * SetTranactionFlushEnabled()
+ * TranactionFlushEnabled()
+ * SetTranactionFlushEnabled()
*
- * These are used to test and set the "TransactionFlushState"
- * varable. If this variable is true (the default), then
- * the system will flush all dirty buffers to disk at the end
- * of each transaction. If false then we are assuming the
- * buffer pool resides in stable main memory, in which case we
- * only do writes as necessary.
+ * These are used to test and set the "TransactionFlushState"
+ * varable. If this variable is true (the default), then
+ * the system will flush all dirty buffers to disk at the end
+ * of each transaction. If false then we are assuming the
+ * buffer pool resides in stable main memory, in which case we
+ * only do writes as necessary.
* --------------------------------
*/
-static int TransactionFlushState = 1;
+static int TransactionFlushState = 1;
int
TransactionFlushEnabled(void)
-{
- return TransactionFlushState;
+{
+ return TransactionFlushState;
}
#ifdef NOT_USED
void
SetTransactionFlushEnabled(bool state)
-{
- TransactionFlushState = (state == true);
+{
+ TransactionFlushState = (state == true);
}
+
#endif
/* --------------------------------
- * IsTransactionState
+ * IsTransactionState
*
- * This returns true if we are currently running a query
- * within an executing transaction.
+ * This returns true if we are currently running a query
+ * within an executing transaction.
* --------------------------------
*/
bool
IsTransactionState(void)
{
- TransactionState s = CurrentTransactionState;
-
- switch (s->state) {
- case TRANS_DEFAULT: return false;
- case TRANS_START: return true;
- case TRANS_INPROGRESS: return true;
- case TRANS_COMMIT: return true;
- case TRANS_ABORT: return true;
- case TRANS_DISABLED: return false;
- }
- /*
- * Shouldn't get here, but lint is not happy with this...
- */
- return(false);
+ TransactionState s = CurrentTransactionState;
+
+ switch (s->state)
+ {
+ case TRANS_DEFAULT:
+ return false;
+ case TRANS_START:
+ return true;
+ case TRANS_INPROGRESS:
+ return true;
+ case TRANS_COMMIT:
+ return true;
+ case TRANS_ABORT:
+ return true;
+ case TRANS_DISABLED:
+ return false;
+ }
+
+ /*
+ * Shouldn't get here, but lint is not happy with this...
+ */
+ return (false);
}
/* --------------------------------
- * IsAbortedTransactionBlockState
+ * IsAbortedTransactionBlockState
*
- * This returns true if we are currently running a query
- * within an aborted transaction block.
+ * This returns true if we are currently running a query
+ * within an aborted transaction block.
* --------------------------------
*/
bool
IsAbortedTransactionBlockState()
{
- TransactionState s = CurrentTransactionState;
-
- if (s->blockState == TBLOCK_ABORT)
- return true;
-
- return false;
+ TransactionState s = CurrentTransactionState;
+
+ if (s->blockState == TBLOCK_ABORT)
+ return true;
+
+ return false;
}
/* --------------------------------
- * OverrideTransactionSystem
+ * OverrideTransactionSystem
*
- * This is used to temporarily disable the transaction
- * processing system in order to do initialization of
- * the transaction system data structures and relations
- * themselves.
+ * This is used to temporarily disable the transaction
+ * processing system in order to do initialization of
+ * the transaction system data structures and relations
+ * themselves.
* --------------------------------
*/
-int SavedTransactionState;
+int SavedTransactionState;
void
OverrideTransactionSystem(bool flag)
{
- TransactionState s = CurrentTransactionState;
-
- if (flag == true) {
- if (s->state == TRANS_DISABLED)
- return;
-
- SavedTransactionState = s->state;
- s->state = TRANS_DISABLED;
- } else {
- if (s->state != TRANS_DISABLED)
- return;
-
- s->state = SavedTransactionState;
- }
+ TransactionState s = CurrentTransactionState;
+
+ if (flag == true)
+ {
+ if (s->state == TRANS_DISABLED)
+ return;
+
+ SavedTransactionState = s->state;
+ s->state = TRANS_DISABLED;
+ }
+ else
+ {
+ if (s->state != TRANS_DISABLED)
+ return;
+
+ s->state = SavedTransactionState;
+ }
}
/* --------------------------------
- * GetCurrentTransactionId
+ * GetCurrentTransactionId
*
- * This returns the id of the current transaction, or
- * the id of the "disabled" transaction.
+ * This returns the id of the current transaction, or
+ * the id of the "disabled" transaction.
* --------------------------------
*/
TransactionId
GetCurrentTransactionId()
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * if the transaction system is disabled, we return
- * the special "disabled" transaction id.
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return (TransactionId) DisabledTransactionId;
-
- /* ----------------
- * otherwise return the current transaction id.
- * ----------------
- */
- return (TransactionId) s->transactionIdData;
+ TransactionState s = CurrentTransactionState;
+
+ /* ----------------
+ * if the transaction system is disabled, we return
+ * the special "disabled" transaction id.
+ * ----------------
+ */
+ if (s->state == TRANS_DISABLED)
+ return (TransactionId) DisabledTransactionId;
+
+ /* ----------------
+ * otherwise return the current transaction id.
+ * ----------------
+ */
+ return (TransactionId) s->transactionIdData;
}
/* --------------------------------
- * GetCurrentCommandId
+ * GetCurrentCommandId
* --------------------------------
*/
CommandId
GetCurrentCommandId()
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * if the transaction system is disabled, we return
- * the special "disabled" command id.
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return (CommandId) DisabledCommandId;
-
- return s->commandId;
+ TransactionState s = CurrentTransactionState;
+
+ /* ----------------
+ * if the transaction system is disabled, we return
+ * the special "disabled" command id.
+ * ----------------
+ */
+ if (s->state == TRANS_DISABLED)
+ return (CommandId) DisabledCommandId;
+
+ return s->commandId;
}
CommandId
GetScanCommandId()
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * if the transaction system is disabled, we return
- * the special "disabled" command id.
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return (CommandId) DisabledCommandId;
-
- return s->scanCommandId;
+ TransactionState s = CurrentTransactionState;
+
+ /* ----------------
+ * if the transaction system is disabled, we return
+ * the special "disabled" command id.
+ * ----------------
+ */
+ if (s->state == TRANS_DISABLED)
+ return (CommandId) DisabledCommandId;
+
+ return s->scanCommandId;
}
/* --------------------------------
- * GetCurrentTransactionStartTime
+ * GetCurrentTransactionStartTime
* --------------------------------
*/
AbsoluteTime
GetCurrentTransactionStartTime()
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * if the transaction system is disabled, we return
- * the special "disabled" starting time.
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return (AbsoluteTime) DisabledStartTime;
-
- return s->startTime;
+ TransactionState s = CurrentTransactionState;
+
+ /* ----------------
+ * if the transaction system is disabled, we return
+ * the special "disabled" starting time.
+ * ----------------
+ */
+ if (s->state == TRANS_DISABLED)
+ return (AbsoluteTime) DisabledStartTime;
+
+ return s->startTime;
}
/* --------------------------------
- * TransactionIdIsCurrentTransactionId
+ * TransactionIdIsCurrentTransactionId
* --------------------------------
*/
bool
TransactionIdIsCurrentTransactionId(TransactionId xid)
{
- TransactionState s = CurrentTransactionState;
-
- if (AMI_OVERRIDE)
- return false;
-
- return (bool)
- TransactionIdEquals(xid, s->transactionIdData);
+ TransactionState s = CurrentTransactionState;
+
+ if (AMI_OVERRIDE)
+ return false;
+
+ return (bool)
+ TransactionIdEquals(xid, s->transactionIdData);
}
/* --------------------------------
- * CommandIdIsCurrentCommandId
+ * CommandIdIsCurrentCommandId
* --------------------------------
*/
bool
CommandIdIsCurrentCommandId(CommandId cid)
{
- TransactionState s = CurrentTransactionState;
-
- if (AMI_OVERRIDE)
- return false;
-
- return
- (cid == s->commandId) ? true : false;
+ TransactionState s = CurrentTransactionState;
+
+ if (AMI_OVERRIDE)
+ return false;
+
+ return
+ (cid == s->commandId) ? true : false;
}
bool
CommandIdGEScanCommandId(CommandId cid)
{
- TransactionState s = CurrentTransactionState;
-
- if (AMI_OVERRIDE)
- return false;
-
- return
- (cid >= s->scanCommandId) ? true : false;
+ TransactionState s = CurrentTransactionState;
+
+ if (AMI_OVERRIDE)
+ return false;
+
+ return
+ (cid >= s->scanCommandId) ? true : false;
}
/* --------------------------------
- * ClearCommandIdCounterOverflowFlag
+ * ClearCommandIdCounterOverflowFlag
* --------------------------------
*/
#ifdef NOT_USED
void
ClearCommandIdCounterOverflowFlag()
{
- CommandIdCounterOverflowFlag = false;
+ CommandIdCounterOverflowFlag = false;
}
+
#endif
/* --------------------------------
- * CommandCounterIncrement
+ * CommandCounterIncrement
* --------------------------------
*/
void
CommandCounterIncrement()
{
- CurrentTransactionStateData.commandId += 1;
- if (CurrentTransactionStateData.commandId == FirstCommandId) {
- CommandIdCounterOverflowFlag = true;
- elog(WARN, "You may only have 65535 commands per transaction");
- }
-
- CurrentTransactionStateData.scanCommandId =
- CurrentTransactionStateData.commandId;
-
- /* make cache changes visible to me */
- AtCommit_Cache();
- AtStart_Cache();
+ CurrentTransactionStateData.commandId += 1;
+ if (CurrentTransactionStateData.commandId == FirstCommandId)
+ {
+ CommandIdCounterOverflowFlag = true;
+ elog(WARN, "You may only have 65535 commands per transaction");
+ }
+
+ CurrentTransactionStateData.scanCommandId =
+ CurrentTransactionStateData.commandId;
+
+ /* make cache changes visible to me */
+ AtCommit_Cache();
+ AtStart_Cache();
}
-void
-SetScanCommandId (CommandId savedId)
+void
+SetScanCommandId(CommandId savedId)
{
- CurrentTransactionStateData.scanCommandId = savedId;
-
+ CurrentTransactionStateData.scanCommandId = savedId;
+
}
/* ----------------------------------------------------------------
- * initialization stuff
+ * initialization stuff
* ----------------------------------------------------------------
*/
void
InitializeTransactionSystem()
{
- InitializeTransactionLog();
+ InitializeTransactionLog();
}
/* ----------------------------------------------------------------
- * StartTransaction stuff
+ * StartTransaction stuff
* ----------------------------------------------------------------
*/
/* --------------------------------
- * AtStart_Cache
+ * AtStart_Cache
* --------------------------------
*/
static void
-AtStart_Cache()
+AtStart_Cache()
{
- DiscardInvalid();
+ DiscardInvalid();
}
/* --------------------------------
- * AtStart_Locks
+ * AtStart_Locks
* --------------------------------
*/
static void
-AtStart_Locks()
+AtStart_Locks()
{
- /*
- * at present, it is unknown to me what belongs here -cim 3/18/90
- *
- * There isn't anything to do at the start of a xact for locks.
- * -mer 5/24/92
- */
+
+ /*
+ * at present, it is unknown to me what belongs here -cim 3/18/90
+ *
+ * There isn't anything to do at the start of a xact for locks. -mer
+ * 5/24/92
+ */
}
/* --------------------------------
- * AtStart_Memory
+ * AtStart_Memory
* --------------------------------
*/
static void
-AtStart_Memory()
+AtStart_Memory()
{
- Portal portal;
- MemoryContext portalContext;
-
- /* ----------------
- * get the blank portal and its memory context
- * ----------------
- */
- portal = GetPortalByName(NULL);
- portalContext = (MemoryContext) PortalGetHeapMemory(portal);
-
- /* ----------------
- * tell system to allocate in the blank portal context
- * ----------------
- */
- MemoryContextSwitchTo(portalContext);
- StartPortalAllocMode(DefaultAllocMode, 0);
+ Portal portal;
+ MemoryContext portalContext;
+
+ /* ----------------
+ * get the blank portal and its memory context
+ * ----------------
+ */
+ portal = GetPortalByName(NULL);
+ portalContext = (MemoryContext) PortalGetHeapMemory(portal);
+
+ /* ----------------
+ * tell system to allocate in the blank portal context
+ * ----------------
+ */
+ MemoryContextSwitchTo(portalContext);
+ StartPortalAllocMode(DefaultAllocMode, 0);
}
/* ----------------------------------------------------------------
- * CommitTransaction stuff
+ * CommitTransaction stuff
* ----------------------------------------------------------------
*/
/* --------------------------------
- * RecordTransactionCommit
+ * RecordTransactionCommit
*
- * Note: the two calls to BufferManagerFlush() exist to ensure
- * that data pages are written before log pages. These
- * explicit calls should be replaced by a more efficient
- * ordered page write scheme in the buffer manager
- * -cim 3/18/90
+ * Note: the two calls to BufferManagerFlush() exist to ensure
+ * that data pages are written before log pages. These
+ * explicit calls should be replaced by a more efficient
+ * ordered page write scheme in the buffer manager
+ * -cim 3/18/90
* --------------------------------
*/
static void
-RecordTransactionCommit()
+RecordTransactionCommit()
{
- TransactionId xid;
- int leak;
-
- /* ----------------
- * get the current transaction id
- * ----------------
- */
- xid = GetCurrentTransactionId();
-
- /* ----------------
- * flush the buffer manager pages. Note: if we have stable
- * main memory, dirty shared buffers are not flushed
- * plai 8/7/90
- * ----------------
- */
- leak = BufferPoolCheckLeak();
- FlushBufferPool(!TransactionFlushEnabled());
- if (leak) ResetBufferPool();
-
- /* ----------------
- * have the transaction access methods record the status
- * of this transaction id in the pg_log / pg_time relations.
- * ----------------
- */
- TransactionIdCommit(xid);
-
- /* ----------------
- * Now write the log/time info to the disk too.
- * ----------------
- */
- leak = BufferPoolCheckLeak();
- FlushBufferPool(!TransactionFlushEnabled());
- if (leak) ResetBufferPool();
+ TransactionId xid;
+ int leak;
+
+ /* ----------------
+ * get the current transaction id
+ * ----------------
+ */
+ xid = GetCurrentTransactionId();
+
+ /* ----------------
+ * flush the buffer manager pages. Note: if we have stable
+ * main memory, dirty shared buffers are not flushed
+ * plai 8/7/90
+ * ----------------
+ */
+ leak = BufferPoolCheckLeak();
+ FlushBufferPool(!TransactionFlushEnabled());
+ if (leak)
+ ResetBufferPool();
+
+ /* ----------------
+ * have the transaction access methods record the status
+ * of this transaction id in the pg_log / pg_time relations.
+ * ----------------
+ */
+ TransactionIdCommit(xid);
+
+ /* ----------------
+ * Now write the log/time info to the disk too.
+ * ----------------
+ */
+ leak = BufferPoolCheckLeak();
+ FlushBufferPool(!TransactionFlushEnabled());
+ if (leak)
+ ResetBufferPool();
}
/* --------------------------------
- * AtCommit_Cache
+ * AtCommit_Cache
* --------------------------------
*/
static void
AtCommit_Cache()
{
- /* ----------------
- * Make catalog changes visible to me for the next command.
- * Other backends will not process my invalidation messages until
- * after I commit and free my locks--though they will do
- * unnecessary work if I abort.
- * ----------------
- */
- RegisterInvalid(true);
+ /* ----------------
+ * Make catalog changes visible to me for the next command.
+ * Other backends will not process my invalidation messages until
+ * after I commit and free my locks--though they will do
+ * unnecessary work if I abort.
+ * ----------------
+ */
+ RegisterInvalid(true);
}
/* --------------------------------
- * AtCommit_Locks
+ * AtCommit_Locks
* --------------------------------
*/
static void
-AtCommit_Locks()
+AtCommit_Locks()
{
- /* ----------------
- * XXX What if ProcReleaseLocks fails? (race condition?)
- *
- * Then you're up a creek! -mer 5/24/92
- * ----------------
- */
- ProcReleaseLocks();
+ /* ----------------
+ * XXX What if ProcReleaseLocks fails? (race condition?)
+ *
+ * Then you're up a creek! -mer 5/24/92
+ * ----------------
+ */
+ ProcReleaseLocks();
}
/* --------------------------------
- * AtCommit_Memory
+ * AtCommit_Memory
* --------------------------------
*/
static void
-AtCommit_Memory()
+AtCommit_Memory()
{
- /* ----------------
- * now that we're "out" of a transaction, have the
- * system allocate things in the top memory context instead
- * of the blank portal memory context.
- * ----------------
- */
- EndPortalAllocMode();
- MemoryContextSwitchTo(TopMemoryContext);
+ /* ----------------
+ * now that we're "out" of a transaction, have the
+ * system allocate things in the top memory context instead
+ * of the blank portal memory context.
+ * ----------------
+ */
+ EndPortalAllocMode();
+ MemoryContextSwitchTo(TopMemoryContext);
}
/* ----------------------------------------------------------------
- * AbortTransaction stuff
+ * AbortTransaction stuff
* ----------------------------------------------------------------
*/
/* --------------------------------
- * RecordTransactionAbort
+ * RecordTransactionAbort
* --------------------------------
*/
static void
-RecordTransactionAbort()
+RecordTransactionAbort()
{
- TransactionId xid;
-
- /* ----------------
- * get the current transaction id
- * ----------------
- */
- xid = GetCurrentTransactionId();
-
- /* ----------------
- * have the transaction access methods record the status
- * of this transaction id in the pg_log / pg_time relations.
- * ----------------
- */
- TransactionIdAbort(xid);
-
- /* ----------------
- * flush the buffer manager pages. Note: if we have stable
- * main memory, dirty shared buffers are not flushed
- * plai 8/7/90
- * ----------------
- */
- ResetBufferPool();
+ TransactionId xid;
+
+ /* ----------------
+ * get the current transaction id
+ * ----------------
+ */
+ xid = GetCurrentTransactionId();
+
+ /* ----------------
+ * have the transaction access methods record the status
+ * of this transaction id in the pg_log / pg_time relations.
+ * ----------------
+ */
+ TransactionIdAbort(xid);
+
+ /* ----------------
+ * flush the buffer manager pages. Note: if we have stable
+ * main memory, dirty shared buffers are not flushed
+ * plai 8/7/90
+ * ----------------
+ */
+ ResetBufferPool();
}
/* --------------------------------
- * AtAbort_Cache
+ * AtAbort_Cache
* --------------------------------
*/
static void
-AtAbort_Cache()
+AtAbort_Cache()
{
- RegisterInvalid(false);
+ RegisterInvalid(false);
}
/* --------------------------------
- * AtAbort_Locks
+ * AtAbort_Locks
* --------------------------------
*/
static void
-AtAbort_Locks()
+AtAbort_Locks()
{
- /* ----------------
- * XXX What if ProcReleaseLocks() fails? (race condition?)
- *
- * Then you're up a creek without a paddle! -mer
- * ----------------
- */
- ProcReleaseLocks();
+ /* ----------------
+ * XXX What if ProcReleaseLocks() fails? (race condition?)
+ *
+ * Then you're up a creek without a paddle! -mer
+ * ----------------
+ */
+ ProcReleaseLocks();
}
/* --------------------------------
- * AtAbort_Memory
+ * AtAbort_Memory
* --------------------------------
*/
static void
-AtAbort_Memory()
+AtAbort_Memory()
{
- /* ----------------
- * after doing an abort transaction, make certain the
- * system uses the top memory context rather then the
- * portal memory context (until the next transaction).
- * ----------------
- */
- MemoryContextSwitchTo(TopMemoryContext);
+ /* ----------------
+ * after doing an abort transaction, make certain the
+ * system uses the top memory context rather then the
+ * portal memory context (until the next transaction).
+ * ----------------
+ */
+ MemoryContextSwitchTo(TopMemoryContext);
}
/* ----------------------------------------------------------------
- * interface routines
+ * interface routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * StartTransaction
+ * StartTransaction
*
* --------------------------------
*/
static void
StartTransaction()
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * Check the current transaction state. If the transaction system
- * is switched off, or if we're already in a transaction, do nothing.
- * We're already in a transaction when the monitor sends a null
- * command to the backend to flush the comm channel. This is a
- * hacky fix to a communications problem, and we keep having to
- * deal with it here. We should fix the comm channel code. mao 080891
- * ----------------
- */
- if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
- return;
-
- /* ----------------
- * set the current transaction state information
- * appropriately during start processing
- * ----------------
- */
- s->state = TRANS_START;
-
- /* ----------------
- * generate a new transaction id
- * ----------------
- */
- GetNewTransactionId(&(s->transactionIdData));
-
- /* ----------------
- * initialize current transaction state fields
- * ----------------
- */
- s->commandId = FirstCommandId;
- s->scanCommandId = FirstCommandId;
- s->startTime = GetCurrentAbsoluteTime();
-
- /* ----------------
- * initialize the various transaction subsystems
- * ----------------
- */
- AtStart_Cache();
- AtStart_Locks();
- AtStart_Memory();
-
- /* --------------
- initialize temporary relations list
- the tempRelList is a list of temporary relations that
- are created in the course of the transactions
- they need to be destroyed properly at the end of the transactions
- */
- InitTempRelList();
-
- /* ----------------
- * done with start processing, set current transaction
- * state to "in progress"
- * ----------------
- */
- s->state = TRANS_INPROGRESS;
-
- /*
- * Let others to know about current transaction is in progress
- * - vadim 11/26/96
- */
- if ( MyProc != (PROC*) NULL )
- MyProc->xid = s->transactionIdData;
+ TransactionState s = CurrentTransactionState;
+
+ /* ----------------
+ * Check the current transaction state. If the transaction system
+ * is switched off, or if we're already in a transaction, do nothing.
+ * We're already in a transaction when the monitor sends a null
+ * command to the backend to flush the comm channel. This is a
+ * hacky fix to a communications problem, and we keep having to
+ * deal with it here. We should fix the comm channel code. mao 080891
+ * ----------------
+ */
+ if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
+ return;
+
+ /* ----------------
+ * set the current transaction state information
+ * appropriately during start processing
+ * ----------------
+ */
+ s->state = TRANS_START;
+
+ /* ----------------
+ * generate a new transaction id
+ * ----------------
+ */
+ GetNewTransactionId(&(s->transactionIdData));
+
+ /* ----------------
+ * initialize current transaction state fields
+ * ----------------
+ */
+ s->commandId = FirstCommandId;
+ s->scanCommandId = FirstCommandId;
+ s->startTime = GetCurrentAbsoluteTime();
+
+ /* ----------------
+ * initialize the various transaction subsystems
+ * ----------------
+ */
+ AtStart_Cache();
+ AtStart_Locks();
+ AtStart_Memory();
+
+ /* --------------
+ initialize temporary relations list
+ the tempRelList is a list of temporary relations that
+ are created in the course of the transactions
+ they need to be destroyed properly at the end of the transactions
+ */
+ InitTempRelList();
+
+ /* ----------------
+ * done with start processing, set current transaction
+ * state to "in progress"
+ * ----------------
+ */
+ s->state = TRANS_INPROGRESS;
+
+ /*
+ * Let others to know about current transaction is in progress - vadim
+ * 11/26/96
+ */
+ if (MyProc != (PROC *) NULL)
+ MyProc->xid = s->transactionIdData;
}
@@ -838,591 +855,604 @@ StartTransaction()
bool
CurrentXactInProgress()
{
- return (CurrentTransactionState->state == TRANS_INPROGRESS);
+ return (CurrentTransactionState->state == TRANS_INPROGRESS);
}
/* --------------------------------
- * CommitTransaction
+ * CommitTransaction
*
* --------------------------------
*/
static void
CommitTransaction()
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * check the current transaction state
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return;
-
- if (s->state != TRANS_INPROGRESS)
- elog(NOTICE, "CommitTransaction and not in in-progress state ");
-
- /* ----------------
- * set the current transaction state information
- * appropriately during the abort processing
- * ----------------
- */
- s->state = TRANS_COMMIT;
-
- /* ----------------
- * do commit processing
- * ----------------
- */
- CloseSequences ();
- DestroyTempRels();
- AtEOXact_portals();
- RecordTransactionCommit();
- RelationPurgeLocalRelation(true);
- AtCommit_Cache();
- AtCommit_Locks();
- AtCommit_Memory();
-
- /* ----------------
- * done with commit processing, set current transaction
- * state back to default
- * ----------------
- */
- s->state = TRANS_DEFAULT;
- { /* want this after commit */
- if (IsNormalProcessingMode())
- Async_NotifyAtCommit();
- }
-
- /*
- * Let others to know about no transaction in progress
- * - vadim 11/26/96
- */
- if ( MyProc != (PROC*) NULL )
- MyProc->xid = InvalidTransactionId;
-}
+ TransactionState s = CurrentTransactionState;
-/* --------------------------------
- * AbortTransaction
- *
- * --------------------------------
- */
-static void
-AbortTransaction()
-{
- TransactionState s = CurrentTransactionState;
-
- /*
- * Let others to know about no transaction in progress
- * - vadim 11/26/96
- */
- if ( MyProc != (PROC*) NULL )
- MyProc->xid = InvalidTransactionId;
-
- /* ----------------
- * check the current transaction state
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return;
-
- if (s->state != TRANS_INPROGRESS)
- elog(NOTICE, "AbortTransaction and not in in-progress state ");
-
- /* ----------------
- * set the current transaction state information
- * appropriately during the abort processing
- * ----------------
- */
- s->state = TRANS_ABORT;
-
- /* ----------------
- * do abort processing
- * ----------------
- */
- CloseSequences ();
- AtEOXact_portals();
- RecordTransactionAbort();
- RelationPurgeLocalRelation(false);
- DestroyTempRels();
- AtAbort_Cache();
- AtAbort_Locks();
- AtAbort_Memory();
-
- /* ----------------
- * done with abort processing, set current transaction
- * state back to default
- * ----------------
- */
- s->state = TRANS_DEFAULT;
- {
- /* We need to do this in case another process notified us while
- we are in the middle of an aborted transaction. We need to
- notify our frontend after we finish the current transaction.
- -- jw, 1/3/94
- */
- if (IsNormalProcessingMode())
- Async_NotifyAtAbort();
- }
-}
-
-/* --------------------------------
- * StartTransactionCommand
- * --------------------------------
- */
-void
-StartTransactionCommand()
-{
- TransactionState s = CurrentTransactionState;
-
- switch(s->blockState) {
/* ----------------
- * if we aren't in a transaction block, we
- * just do our usual start transaction.
+ * check the current transaction state
* ----------------
*/
- case TBLOCK_DEFAULT:
- StartTransaction();
- break;
-
- /* ----------------
- * We should never experience this -- if we do it
- * means the BEGIN state was not changed in the previous
- * CommitTransactionCommand(). If we get it, we print
- * a warning and change to the in-progress state.
- * ----------------
- */
- case TBLOCK_BEGIN:
- elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
- s->blockState = TBLOCK_INPROGRESS;
- break;
-
+ if (s->state == TRANS_DISABLED)
+ return;
+
+ if (s->state != TRANS_INPROGRESS)
+ elog(NOTICE, "CommitTransaction and not in in-progress state ");
+
/* ----------------
- * This is the case when are somewhere in a transaction
- * block and about to start a new command. For now we
- * do nothing but someday we may do command-local resource
- * initialization.
+ * set the current transaction state information
+ * appropriately during the abort processing
* ----------------
*/
- case TBLOCK_INPROGRESS:
- break;
-
+ s->state = TRANS_COMMIT;
+
/* ----------------
- * As with BEGIN, we should never experience this --
- * if we do it means the END state was not changed in the
- * previous CommitTransactionCommand(). If we get it, we
- * print a warning, commit the transaction, start a new
- * transaction and change to the default state.
+ * do commit processing
* ----------------
*/
- case TBLOCK_END:
- elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
- s->blockState = TBLOCK_DEFAULT;
- CommitTransaction();
- StartTransaction();
- break;
-
+ CloseSequences();
+ DestroyTempRels();
+ AtEOXact_portals();
+ RecordTransactionCommit();
+ RelationPurgeLocalRelation(true);
+ AtCommit_Cache();
+ AtCommit_Locks();
+ AtCommit_Memory();
+
/* ----------------
- * Here we are in the middle of a transaction block but
- * one of the commands caused an abort so we do nothing
- * but remain in the abort state. Eventually we will get
- * to the "END TRANSACTION" which will set things straight.
+ * done with commit processing, set current transaction
+ * state back to default
* ----------------
*/
- case TBLOCK_ABORT:
- break;
-
- /* ----------------
- * This means we somehow aborted and the last call to
- * CommitTransactionCommand() didn't clear the state so
- * we remain in the ENDABORT state and mabey next time
- * we get to CommitTransactionCommand() the state will
- * get reset to default.
- * ----------------
+ s->state = TRANS_DEFAULT;
+ { /* want this after commit */
+ if (IsNormalProcessingMode())
+ Async_NotifyAtCommit();
+ }
+
+ /*
+ * Let others to know about no transaction in progress - vadim
+ * 11/26/96
*/
- case TBLOCK_ENDABORT:
- elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
- break;
- }
+ if (MyProc != (PROC *) NULL)
+ MyProc->xid = InvalidTransactionId;
}
+
/* --------------------------------
- * CommitTransactionCommand
+ * AbortTransaction
+ *
* --------------------------------
*/
-void
-CommitTransactionCommand()
+static void
+AbortTransaction()
{
- TransactionState s = CurrentTransactionState;
-
- switch(s->blockState) {
- /* ----------------
- * if we aren't in a transaction block, we
- * just do our usual transaction commit
- * ----------------
- */
- case TBLOCK_DEFAULT:
- CommitTransaction();
- break;
-
- /* ----------------
- * This is the case right after we get a "BEGIN TRANSACTION"
- * command, but the user hasn't done anything else yet, so
- * we change to the "transaction block in progress" state
- * and return.
- * ----------------
+ TransactionState s = CurrentTransactionState;
+
+ /*
+ * Let others to know about no transaction in progress - vadim
+ * 11/26/96
*/
- case TBLOCK_BEGIN:
- s->blockState = TBLOCK_INPROGRESS;
- break;
-
+ if (MyProc != (PROC *) NULL)
+ MyProc->xid = InvalidTransactionId;
+
/* ----------------
- * This is the case when we have finished executing a command
- * someplace within a transaction block. We increment the
- * command counter and return. Someday we may free resources
- * local to the command.
- *
- * That someday is today, at least for memory allocated by
- * command in the BlankPortal' HeapMemory context.
- * - vadim 03/25/97
+ * check the current transaction state
* ----------------
*/
- case TBLOCK_INPROGRESS:
- CommandCounterIncrement();
-#ifdef TBL_FREE_CMD_MEMORY
- EndPortalAllocMode ();
- StartPortalAllocMode (DefaultAllocMode, 0);
-#endif
- break;
-
+ if (s->state == TRANS_DISABLED)
+ return;
+
+ if (s->state != TRANS_INPROGRESS)
+ elog(NOTICE, "AbortTransaction and not in in-progress state ");
+
/* ----------------
- * This is the case when we just got the "END TRANSACTION"
- * statement, so we go back to the default state and
- * commit the transaction.
+ * set the current transaction state information
+ * appropriately during the abort processing
* ----------------
*/
- case TBLOCK_END:
- s->blockState = TBLOCK_DEFAULT;
- CommitTransaction();
- break;
-
+ s->state = TRANS_ABORT;
+
/* ----------------
- * Here we are in the middle of a transaction block but
- * one of the commands caused an abort so we do nothing
- * but remain in the abort state. Eventually we will get
- * to the "END TRANSACTION" which will set things straight.
+ * do abort processing
* ----------------
*/
- case TBLOCK_ABORT:
- break;
-
+ CloseSequences();
+ AtEOXact_portals();
+ RecordTransactionAbort();
+ RelationPurgeLocalRelation(false);
+ DestroyTempRels();
+ AtAbort_Cache();
+ AtAbort_Locks();
+ AtAbort_Memory();
+
/* ----------------
- * Here we were in an aborted transaction block which
- * just processed the "END TRANSACTION" command from the
- * user, so now we return the to default state.
+ * done with abort processing, set current transaction
+ * state back to default
* ----------------
*/
- case TBLOCK_ENDABORT:
- s->blockState = TBLOCK_DEFAULT;
- break;
- }
+ s->state = TRANS_DEFAULT;
+ {
+
+ /*
+ * We need to do this in case another process notified us while we
+ * are in the middle of an aborted transaction. We need to notify
+ * our frontend after we finish the current transaction. -- jw,
+ * 1/3/94
+ */
+ if (IsNormalProcessingMode())
+ Async_NotifyAtAbort();
+ }
+}
+
+/* --------------------------------
+ * StartTransactionCommand
+ * --------------------------------
+ */
+void
+StartTransactionCommand()
+{
+ TransactionState s = CurrentTransactionState;
+
+ switch (s->blockState)
+ {
+ /* ----------------
+ * if we aren't in a transaction block, we
+ * just do our usual start transaction.
+ * ----------------
+ */
+ case TBLOCK_DEFAULT:
+ StartTransaction();
+ break;
+
+ /* ----------------
+ * We should never experience this -- if we do it
+ * means the BEGIN state was not changed in the previous
+ * CommitTransactionCommand(). If we get it, we print
+ * a warning and change to the in-progress state.
+ * ----------------
+ */
+ case TBLOCK_BEGIN:
+ elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
+ s->blockState = TBLOCK_INPROGRESS;
+ break;
+
+ /* ----------------
+ * This is the case when are somewhere in a transaction
+ * block and about to start a new command. For now we
+ * do nothing but someday we may do command-local resource
+ * initialization.
+ * ----------------
+ */
+ case TBLOCK_INPROGRESS:
+ break;
+
+ /* ----------------
+ * As with BEGIN, we should never experience this --
+ * if we do it means the END state was not changed in the
+ * previous CommitTransactionCommand(). If we get it, we
+ * print a warning, commit the transaction, start a new
+ * transaction and change to the default state.
+ * ----------------
+ */
+ case TBLOCK_END:
+ elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
+ s->blockState = TBLOCK_DEFAULT;
+ CommitTransaction();
+ StartTransaction();
+ break;
+
+ /* ----------------
+ * Here we are in the middle of a transaction block but
+ * one of the commands caused an abort so we do nothing
+ * but remain in the abort state. Eventually we will get
+ * to the "END TRANSACTION" which will set things straight.
+ * ----------------
+ */
+ case TBLOCK_ABORT:
+ break;
+
+ /* ----------------
+ * This means we somehow aborted and the last call to
+ * CommitTransactionCommand() didn't clear the state so
+ * we remain in the ENDABORT state and mabey next time
+ * we get to CommitTransactionCommand() the state will
+ * get reset to default.
+ * ----------------
+ */
+ case TBLOCK_ENDABORT:
+ elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
+ break;
+ }
+}
+
+/* --------------------------------
+ * CommitTransactionCommand
+ * --------------------------------
+ */
+void
+CommitTransactionCommand()
+{
+ TransactionState s = CurrentTransactionState;
+
+ switch (s->blockState)
+ {
+ /* ----------------
+ * if we aren't in a transaction block, we
+ * just do our usual transaction commit
+ * ----------------
+ */
+ case TBLOCK_DEFAULT:
+ CommitTransaction();
+ break;
+
+ /* ----------------
+ * This is the case right after we get a "BEGIN TRANSACTION"
+ * command, but the user hasn't done anything else yet, so
+ * we change to the "transaction block in progress" state
+ * and return.
+ * ----------------
+ */
+ case TBLOCK_BEGIN:
+ s->blockState = TBLOCK_INPROGRESS;
+ break;
+
+ /* ----------------
+ * This is the case when we have finished executing a command
+ * someplace within a transaction block. We increment the
+ * command counter and return. Someday we may free resources
+ * local to the command.
+ *
+ * That someday is today, at least for memory allocated by
+ * command in the BlankPortal' HeapMemory context.
+ * - vadim 03/25/97
+ * ----------------
+ */
+ case TBLOCK_INPROGRESS:
+ CommandCounterIncrement();
+#ifdef TBL_FREE_CMD_MEMORY
+ EndPortalAllocMode();
+ StartPortalAllocMode(DefaultAllocMode, 0);
+#endif
+ break;
+
+ /* ----------------
+ * This is the case when we just got the "END TRANSACTION"
+ * statement, so we go back to the default state and
+ * commit the transaction.
+ * ----------------
+ */
+ case TBLOCK_END:
+ s->blockState = TBLOCK_DEFAULT;
+ CommitTransaction();
+ break;
+
+ /* ----------------
+ * Here we are in the middle of a transaction block but
+ * one of the commands caused an abort so we do nothing
+ * but remain in the abort state. Eventually we will get
+ * to the "END TRANSACTION" which will set things straight.
+ * ----------------
+ */
+ case TBLOCK_ABORT:
+ break;
+
+ /* ----------------
+ * Here we were in an aborted transaction block which
+ * just processed the "END TRANSACTION" command from the
+ * user, so now we return the to default state.
+ * ----------------
+ */
+ case TBLOCK_ENDABORT:
+ s->blockState = TBLOCK_DEFAULT;
+ break;
+ }
}
/* --------------------------------
- * AbortCurrentTransaction
+ * AbortCurrentTransaction
* --------------------------------
*/
void
AbortCurrentTransaction()
{
- TransactionState s = CurrentTransactionState;
-
- switch(s->blockState) {
- /* ----------------
- * if we aren't in a transaction block, we
- * just do our usual abort transaction.
- * ----------------
- */
- case TBLOCK_DEFAULT:
- AbortTransaction();
- break;
-
- /* ----------------
- * If we are in the TBLOCK_BEGIN it means something
- * screwed up right after reading "BEGIN TRANSACTION"
- * so we enter the abort state. Eventually an "END
- * TRANSACTION" will fix things.
- * ----------------
- */
- case TBLOCK_BEGIN:
- s->blockState = TBLOCK_ABORT;
- AbortTransaction();
- break;
-
+ TransactionState s = CurrentTransactionState;
+
+ switch (s->blockState)
+ {
+ /* ----------------
+ * if we aren't in a transaction block, we
+ * just do our usual abort transaction.
+ * ----------------
+ */
+ case TBLOCK_DEFAULT:
+ AbortTransaction();
+ break;
+
+ /* ----------------
+ * If we are in the TBLOCK_BEGIN it means something
+ * screwed up right after reading "BEGIN TRANSACTION"
+ * so we enter the abort state. Eventually an "END
+ * TRANSACTION" will fix things.
+ * ----------------
+ */
+ case TBLOCK_BEGIN:
+ s->blockState = TBLOCK_ABORT;
+ AbortTransaction();
+ break;
+
+ /* ----------------
+ * This is the case when are somewhere in a transaction
+ * block which aborted so we abort the transaction and
+ * set the ABORT state. Eventually an "END TRANSACTION"
+ * will fix things and restore us to a normal state.
+ * ----------------
+ */
+ case TBLOCK_INPROGRESS:
+ s->blockState = TBLOCK_ABORT;
+ AbortTransaction();
+ break;
+
+ /* ----------------
+ * Here, the system was fouled up just after the
+ * user wanted to end the transaction block so we
+ * abort the transaction and put us back into the
+ * default state.
+ * ----------------
+ */
+ case TBLOCK_END:
+ s->blockState = TBLOCK_DEFAULT;
+ AbortTransaction();
+ break;
+
+ /* ----------------
+ * Here, we are already in an aborted transaction
+ * state and are waiting for an "END TRANSACTION" to
+ * come along and lo and behold, we abort again!
+ * So we just remain in the abort state.
+ * ----------------
+ */
+ case TBLOCK_ABORT:
+ break;
+
+ /* ----------------
+ * Here we were in an aborted transaction block which
+ * just processed the "END TRANSACTION" command but somehow
+ * aborted again.. since we must have done the abort
+ * processing, we return to the default state.
+ * ----------------
+ */
+ case TBLOCK_ENDABORT:
+ s->blockState = TBLOCK_DEFAULT;
+ break;
+ }
+}
+
+/* ----------------------------------------------------------------
+ * transaction block support
+ * ----------------------------------------------------------------
+ */
+/* --------------------------------
+ * BeginTransactionBlock
+ * --------------------------------
+ */
+void
+BeginTransactionBlock(void)
+{
+ TransactionState s = CurrentTransactionState;
+
/* ----------------
- * This is the case when are somewhere in a transaction
- * block which aborted so we abort the transaction and
- * set the ABORT state. Eventually an "END TRANSACTION"
- * will fix things and restore us to a normal state.
+ * check the current transaction state
* ----------------
*/
- case TBLOCK_INPROGRESS:
- s->blockState = TBLOCK_ABORT;
- AbortTransaction();
- break;
-
+ if (s->state == TRANS_DISABLED)
+ return;
+
+ if (s->blockState != TBLOCK_DEFAULT)
+ elog(NOTICE, "BeginTransactionBlock and not in default state ");
+
/* ----------------
- * Here, the system was fouled up just after the
- * user wanted to end the transaction block so we
- * abort the transaction and put us back into the
- * default state.
+ * set the current transaction block state information
+ * appropriately during begin processing
* ----------------
*/
- case TBLOCK_END:
- s->blockState = TBLOCK_DEFAULT;
- AbortTransaction();
- break;
-
+ s->blockState = TBLOCK_BEGIN;
+
/* ----------------
- * Here, we are already in an aborted transaction
- * state and are waiting for an "END TRANSACTION" to
- * come along and lo and behold, we abort again!
- * So we just remain in the abort state.
+ * do begin processing
* ----------------
*/
- case TBLOCK_ABORT:
- break;
-
+
/* ----------------
- * Here we were in an aborted transaction block which
- * just processed the "END TRANSACTION" command but somehow
- * aborted again.. since we must have done the abort
- * processing, we return to the default state.
+ * done with begin processing, set block state to inprogress
* ----------------
*/
- case TBLOCK_ENDABORT:
- s->blockState = TBLOCK_DEFAULT;
- break;
- }
-}
-
-/* ----------------------------------------------------------------
- * transaction block support
- * ----------------------------------------------------------------
- */
-/* --------------------------------
- * BeginTransactionBlock
- * --------------------------------
- */
-void
-BeginTransactionBlock(void)
-{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * check the current transaction state
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return;
-
- if (s->blockState != TBLOCK_DEFAULT)
- elog(NOTICE, "BeginTransactionBlock and not in default state ");
-
- /* ----------------
- * set the current transaction block state information
- * appropriately during begin processing
- * ----------------
- */
- s->blockState = TBLOCK_BEGIN;
-
- /* ----------------
- * do begin processing
- * ----------------
- */
-
- /* ----------------
- * done with begin processing, set block state to inprogress
- * ----------------
- */
- s->blockState = TBLOCK_INPROGRESS;
+ s->blockState = TBLOCK_INPROGRESS;
}
/* --------------------------------
- * EndTransactionBlock
+ * EndTransactionBlock
* --------------------------------
*/
void
EndTransactionBlock(void)
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * check the current transaction state
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return;
-
- if (s->blockState == TBLOCK_INPROGRESS) {
+ TransactionState s = CurrentTransactionState;
+
/* ----------------
- * here we are in a transaction block which should commit
- * when we get to the upcoming CommitTransactionCommand()
- * so we set the state to "END". CommitTransactionCommand()
- * will recognize this and commit the transaction and return
- * us to the default state
+ * check the current transaction state
* ----------------
*/
- s->blockState = TBLOCK_END;
- return;
- }
-
- if (s->blockState == TBLOCK_ABORT) {
+ if (s->state == TRANS_DISABLED)
+ return;
+
+ if (s->blockState == TBLOCK_INPROGRESS)
+ {
+ /* ----------------
+ * here we are in a transaction block which should commit
+ * when we get to the upcoming CommitTransactionCommand()
+ * so we set the state to "END". CommitTransactionCommand()
+ * will recognize this and commit the transaction and return
+ * us to the default state
+ * ----------------
+ */
+ s->blockState = TBLOCK_END;
+ return;
+ }
+
+ if (s->blockState == TBLOCK_ABORT)
+ {
+ /* ----------------
+ * here, we are in a transaction block which aborted
+ * and since the AbortTransaction() was already done,
+ * we do whatever is needed and change to the special
+ * "END ABORT" state. The upcoming CommitTransactionCommand()
+ * will recognise this and then put us back in the default
+ * state.
+ * ----------------
+ */
+ s->blockState = TBLOCK_ENDABORT;
+ return;
+ }
+
/* ----------------
- * here, we are in a transaction block which aborted
- * and since the AbortTransaction() was already done,
- * we do whatever is needed and change to the special
- * "END ABORT" state. The upcoming CommitTransactionCommand()
- * will recognise this and then put us back in the default
- * state.
+ * We should not get here, but if we do, we go to the ENDABORT
+ * state after printing a warning. The upcoming call to
+ * CommitTransactionCommand() will then put us back into the
+ * default state.
* ----------------
*/
+ elog(NOTICE, "EndTransactionBlock and not inprogress/abort state ");
s->blockState = TBLOCK_ENDABORT;
- return;
- }
-
- /* ----------------
- * We should not get here, but if we do, we go to the ENDABORT
- * state after printing a warning. The upcoming call to
- * CommitTransactionCommand() will then put us back into the
- * default state.
- * ----------------
- */
- elog(NOTICE, "EndTransactionBlock and not inprogress/abort state ");
- s->blockState = TBLOCK_ENDABORT;
}
/* --------------------------------
- * AbortTransactionBlock
+ * AbortTransactionBlock
* --------------------------------
*/
#ifdef NOT_USED
static void
AbortTransactionBlock(void)
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * check the current transaction state
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return;
-
- if (s->blockState == TBLOCK_INPROGRESS) {
+ TransactionState s = CurrentTransactionState;
+
/* ----------------
- * here we were inside a transaction block something
- * screwed up inside the system so we enter the abort state,
- * do the abort processing and then return.
- * We remain in the abort state until we see the upcoming
- * END TRANSACTION command.
+ * check the current transaction state
* ----------------
*/
- s->blockState = TBLOCK_ABORT;
-
+ if (s->state == TRANS_DISABLED)
+ return;
+
+ if (s->blockState == TBLOCK_INPROGRESS)
+ {
+ /* ----------------
+ * here we were inside a transaction block something
+ * screwed up inside the system so we enter the abort state,
+ * do the abort processing and then return.
+ * We remain in the abort state until we see the upcoming
+ * END TRANSACTION command.
+ * ----------------
+ */
+ s->blockState = TBLOCK_ABORT;
+
+ /* ----------------
+ * do abort processing and return
+ * ----------------
+ */
+ AbortTransaction();
+ return;
+ }
+
/* ----------------
- * do abort processing and return
+ * this case should not be possible, because it would mean
+ * the user entered an "abort" from outside a transaction block.
+ * So we print an error message, abort the transaction and
+ * enter the "ENDABORT" state so we will end up in the default
+ * state after the upcoming CommitTransactionCommand().
* ----------------
*/
+ elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
AbortTransaction();
- return;
- }
-
- /* ----------------
- * this case should not be possible, because it would mean
- * the user entered an "abort" from outside a transaction block.
- * So we print an error message, abort the transaction and
- * enter the "ENDABORT" state so we will end up in the default
- * state after the upcoming CommitTransactionCommand().
- * ----------------
- */
- elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
- AbortTransaction();
- s->blockState = TBLOCK_ENDABORT;
+ s->blockState = TBLOCK_ENDABORT;
}
+
#endif
/* --------------------------------
- * UserAbortTransactionBlock
+ * UserAbortTransactionBlock
* --------------------------------
*/
void
UserAbortTransactionBlock()
{
- TransactionState s = CurrentTransactionState;
-
- /* ----------------
- * check the current transaction state
- * ----------------
- */
- if (s->state == TRANS_DISABLED)
- return;
-
- /*
- * if the transaction has already been automatically aborted with an error,
- * and the user subsequently types 'abort', allow it. (the behavior is
- * the same as if they had typed 'end'.)
- */
- if (s->blockState == TBLOCK_ABORT) {
- s->blockState = TBLOCK_ENDABORT;
- return;
- }
-
- if (s->blockState == TBLOCK_INPROGRESS) {
+ TransactionState s = CurrentTransactionState;
+
/* ----------------
- * here we were inside a transaction block and we
- * got an abort command from the user, so we move to
- * the abort state, do the abort processing and
- * then change to the ENDABORT state so we will end up
- * in the default state after the upcoming
- * CommitTransactionCommand().
+ * check the current transaction state
* ----------------
*/
- s->blockState = TBLOCK_ABORT;
-
- /* ----------------
- * do abort processing
- * ----------------
+ if (s->state == TRANS_DISABLED)
+ return;
+
+ /*
+ * if the transaction has already been automatically aborted with an
+ * error, and the user subsequently types 'abort', allow it. (the
+ * behavior is the same as if they had typed 'end'.)
*/
- AbortTransaction();
-
+ if (s->blockState == TBLOCK_ABORT)
+ {
+ s->blockState = TBLOCK_ENDABORT;
+ return;
+ }
+
+ if (s->blockState == TBLOCK_INPROGRESS)
+ {
+ /* ----------------
+ * here we were inside a transaction block and we
+ * got an abort command from the user, so we move to
+ * the abort state, do the abort processing and
+ * then change to the ENDABORT state so we will end up
+ * in the default state after the upcoming
+ * CommitTransactionCommand().
+ * ----------------
+ */
+ s->blockState = TBLOCK_ABORT;
+
+ /* ----------------
+ * do abort processing
+ * ----------------
+ */
+ AbortTransaction();
+
+ /* ----------------
+ * change to the end abort state and return
+ * ----------------
+ */
+ s->blockState = TBLOCK_ENDABORT;
+ return;
+ }
+
/* ----------------
- * change to the end abort state and return
+ * this case should not be possible, because it would mean
+ * the user entered an "abort" from outside a transaction block.
+ * So we print an error message, abort the transaction and
+ * enter the "ENDABORT" state so we will end up in the default
+ * state after the upcoming CommitTransactionCommand().
* ----------------
*/
+ elog(NOTICE, "UserAbortTransactionBlock and not in in-progress state");
+ AbortTransaction();
s->blockState = TBLOCK_ENDABORT;
- return;
- }
-
- /* ----------------
- * this case should not be possible, because it would mean
- * the user entered an "abort" from outside a transaction block.
- * So we print an error message, abort the transaction and
- * enter the "ENDABORT" state so we will end up in the default
- * state after the upcoming CommitTransactionCommand().
- * ----------------
- */
- elog(NOTICE, "UserAbortTransactionBlock and not in in-progress state");
- AbortTransaction();
- s->blockState = TBLOCK_ENDABORT;
}
bool
IsTransactionBlock()
{
- TransactionState s = CurrentTransactionState;
-
- if (s->blockState == TBLOCK_INPROGRESS
- || s->blockState == TBLOCK_ENDABORT) {
- return (true);
- }
-
- return (false);
+ TransactionState s = CurrentTransactionState;
+
+ if (s->blockState == TBLOCK_INPROGRESS
+ || s->blockState == TBLOCK_ENDABORT)
+ {
+ return (true);
+ }
+
+ return (false);
}
diff --git a/src/backend/access/transam/xid.c b/src/backend/access/transam/xid.c
index 16e55e26411..910d6ac7320 100644
--- a/src/backend/access/transam/xid.c
+++ b/src/backend/access/transam/xid.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* xid.c--
- * POSTGRES transaction identifier code.
+ * POSTGRES transaction identifier code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/xid.c,v 1.7 1997/08/19 21:30:20 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/xid.c,v 1.8 1997/09/07 04:39:40 momjian Exp $
*
* OLD COMMENTS
* XXX WARNING
- * Much of this file will change when we change our representation
- * of transaction ids -cim 3/23/90
+ * Much of this file will change when we change our representation
+ * of transaction ids -cim 3/23/90
*
* It is time to make the switch from 5 byte to 4 byte transaction ids
* This file was totally reworked. -mer 5/22/92
@@ -31,127 +31,127 @@ extern TransactionId AmiTransactionId;
extern TransactionId FirstTransactionId;
/* ----------------------------------------------------------------
- * TransactionIdIsValid
+ * TransactionIdIsValid
*
- * Macro-ize me.
+ * Macro-ize me.
* ----------------------------------------------------------------
*/
bool
TransactionIdIsValid(TransactionId transactionId)
{
- return ((bool) (transactionId != NullTransactionId) );
+ return ((bool) (transactionId != NullTransactionId));
}
/* XXX char16 name for catalogs */
TransactionId
xidin(char *representation)
{
- return (atol(representation));
+ return (atol(representation));
}
/* XXX char16 name for catalogs */
-char*
+char *
xidout(TransactionId transactionId)
{
-/* return(TransactionIdFormString(transactionId)); */
- char *representation;
-
- /* maximum 32 bit unsigned integer representation takes 10 chars */
- representation = palloc(11);
-
- sprintf(representation, "%u", transactionId);
-
- return (representation);
+/* return(TransactionIdFormString(transactionId)); */
+ char *representation;
+
+ /* maximum 32 bit unsigned integer representation takes 10 chars */
+ representation = palloc(11);
+
+ sprintf(representation, "%u", transactionId);
+
+ return (representation);
}
/* ----------------------------------------------------------------
- * StoreInvalidTransactionId
+ * StoreInvalidTransactionId
*
- * Maybe do away with Pointer types in these routines.
- * Macro-ize this one.
+ * Maybe do away with Pointer types in these routines.
+ * Macro-ize this one.
* ----------------------------------------------------------------
*/
void
-StoreInvalidTransactionId(TransactionId *destination)
+StoreInvalidTransactionId(TransactionId * destination)
{
- *destination = NullTransactionId;
+ *destination = NullTransactionId;
}
/* ----------------------------------------------------------------
- * TransactionIdStore
+ * TransactionIdStore
*
- * Macro-ize this one.
+ * Macro-ize this one.
* ----------------------------------------------------------------
*/
void
TransactionIdStore(TransactionId transactionId,
- TransactionId *destination)
+ TransactionId * destination)
{
- *destination = transactionId;
+ *destination = transactionId;
}
/* ----------------------------------------------------------------
- * TransactionIdEquals
+ * TransactionIdEquals
* ----------------------------------------------------------------
*/
bool
TransactionIdEquals(TransactionId id1, TransactionId id2)
{
- return ((bool) (id1 == id2));
+ return ((bool) (id1 == id2));
}
/* ----------------------------------------------------------------
- * TransactionIdIsLessThan
+ * TransactionIdIsLessThan
* ----------------------------------------------------------------
*/
bool
TransactionIdIsLessThan(TransactionId id1, TransactionId id2)
{
- return ((bool)(id1 < id2));
+ return ((bool) (id1 < id2));
}
/* ----------------------------------------------------------------
- * xideq
+ * xideq
* ----------------------------------------------------------------
*/
/*
- * xideq - returns 1, iff xid1 == xid2
- * 0 else;
+ * xideq - returns 1, iff xid1 == xid2
+ * 0 else;
*/
bool
xideq(TransactionId xid1, TransactionId xid2)
{
- return( (bool) (xid1 == xid2) );
+ return ((bool) (xid1 == xid2));
}
/* ----------------------------------------------------------------
- * TransactionIdIncrement
+ * TransactionIdIncrement
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
void
-TransactionIdIncrement(TransactionId *transactionId)
+TransactionIdIncrement(TransactionId * transactionId)
{
-
- (*transactionId)++;
- if (*transactionId == DisabledTransactionId)
- elog(FATAL, "TransactionIdIncrement: exhausted XID's");
- return;
+
+ (*transactionId)++;
+ if (*transactionId == DisabledTransactionId)
+ elog(FATAL, "TransactionIdIncrement: exhausted XID's");
+ return;
}
+
#endif
/* ----------------------------------------------------------------
- * TransactionIdAdd
+ * TransactionIdAdd
* ----------------------------------------------------------------
*/
void
-TransactionIdAdd(TransactionId *xid, int value)
+TransactionIdAdd(TransactionId * xid, int value)
{
- *xid += value;
- return;
+ *xid += value;
+ return;
}
-
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6b27010d3a9..9fd4bf719b3 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -1,23 +1,23 @@
/*-------------------------------------------------------------------------
*
* bootstrap.c--
- * routines to support running postgres in 'bootstrap' mode
- * bootstrap mode is used to create the initial template database
+ * routines to support running postgres in 'bootstrap' mode
+ * bootstrap mode is used to create the initial template database
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.21 1997/08/19 21:30:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.22 1997/09/07 04:39:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <unistd.h> /* For getopt() */
+#include <unistd.h> /* For getopt() */
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
-#define BOOTSTRAP_INCLUDE /* mask out stuff in tcop/tcopprot.h */
+#define BOOTSTRAP_INCLUDE /* mask out stuff in tcop/tcopprot.h */
#include "postgres.h"
@@ -41,7 +41,7 @@
#include "utils/nabstime.h"
#include "access/htup.h"
#include "utils/tqual.h"
-#include "storage/buf.h"
+#include "storage/buf.h"
#include "access/relscan.h"
#include "access/heapam.h"
@@ -55,7 +55,7 @@
#include "catalog/pg_type.h"
-#include "access/itup.h"
+#include "access/itup.h"
#include "bootstrap/bootstrap.h"
#include "tcop/tcopprot.h"
@@ -69,7 +69,7 @@
#include "access/xact.h"
#ifndef HAVE_MEMMOVE
-# include "regex/utils.h"
+#include "regex/utils.h"
#endif
#include <string.h>
@@ -100,20 +100,20 @@
#include "utils/palloc.h"
-#define ALLOC(t, c) (t *)calloc((unsigned)(c), sizeof(t))
-#define FIRST_TYPE_OID 16 /* OID of the first type */
+#define ALLOC(t, c) (t *)calloc((unsigned)(c), sizeof(t))
+#define FIRST_TYPE_OID 16 /* OID of the first type */
-extern int Int_yyparse (void);
+extern int Int_yyparse(void);
static hashnode *AddStr(char *str, int strlength, int mderef);
static AttributeTupleForm AllocateAttribute(void);
-static bool BootstrapAlreadySeen(Oid id);
-static int CompHash (char *str, int len);
-static hashnode *FindStr (char *str, int length, hashnode *mderef);
-static int gettype(char *type);
-static void cleanup(void);
+static bool BootstrapAlreadySeen(Oid id);
+static int CompHash(char *str, int len);
+static hashnode *FindStr(char *str, int length, hashnode * mderef);
+static int gettype(char *type);
+static void cleanup(void);
/* ----------------
- * global variables
+ * global variables
* ----------------
*/
/*
@@ -126,130 +126,138 @@ static void cleanup(void);
* position of its string pointer in the array of string pointers.
*/
-#define STRTABLESIZE 10000
-#define HASHTABLESIZE 503
+#define STRTABLESIZE 10000
+#define HASHTABLESIZE 503
/* Hash function numbers */
-#define NUM 23
-#define NUMSQR 529
+#define NUM 23
+#define NUMSQR 529
#define NUMCUBE 12167
-char *strtable [STRTABLESIZE];
-hashnode *hashtable [HASHTABLESIZE];
+char *strtable[STRTABLESIZE];
+hashnode *hashtable[HASHTABLESIZE];
-static int strtable_end = -1; /* Tells us last occupied string space */
+static int strtable_end = -1; /* Tells us last occupied string
+ * space */
/*-
* Basic information associated with each type. This is used before
* pg_type is created.
*
- * XXX several of these input/output functions do catalog scans
- * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some
- * order dependencies in the catalog creation process.
+ * XXX several of these input/output functions do catalog scans
+ * (e.g., F_REGPROCIN scans pg_proc). this obviously creates some
+ * order dependencies in the catalog creation process.
*/
-struct typinfo {
- char name[NAMEDATALEN];
- Oid oid;
- Oid elem;
- int16 len;
- Oid inproc;
- Oid outproc;
+struct typinfo
+{
+ char name[NAMEDATALEN];
+ Oid oid;
+ Oid elem;
+ int16 len;
+ Oid inproc;
+ Oid outproc;
};
static struct typinfo Procid[] = {
- { "bool", 16, 0, 1, F_BOOLIN, F_BOOLOUT },
- { "bytea", 17, 0, -1, F_BYTEAIN, F_BYTEAOUT },
- { "char", 18, 0, 1, F_CHARIN, F_CHAROUT },
- { "name", 19, 0, NAMEDATALEN, F_NAMEIN, F_NAMEOUT },
- { "char16", 20, 0, 16, F_CHAR16IN, F_CHAR16OUT},
-/* { "dt", 20, 0, 4, F_DTIN, F_DTOUT}, */
- { "int2", 21, 0, 2, F_INT2IN, F_INT2OUT },
- { "int28", 22, 0, 16, F_INT28IN, F_INT28OUT },
- { "int4", 23, 0, 4, F_INT4IN, F_INT4OUT },
- { "regproc", 24, 0, 4, F_REGPROCIN, F_REGPROCOUT },
- { "text", 25, 0, -1, F_TEXTIN, F_TEXTOUT },
- { "oid", 26, 0, 4, F_INT4IN, F_INT4OUT },
- { "tid", 27, 0, 6, F_TIDIN, F_TIDOUT },
- { "xid", 28, 0, 5, F_XIDIN, F_XIDOUT },
- { "iid", 29, 0, 1, F_CIDIN, F_CIDOUT },
- { "oid8", 30, 0, 32, F_OID8IN, F_OID8OUT },
- { "smgr", 210, 0, 2, F_SMGRIN, F_SMGROUT },
- { "_int4", 1007, 23, -1, F_ARRAY_IN, F_ARRAY_OUT },
- { "_aclitem", 1034, 1033, -1, F_ARRAY_IN, F_ARRAY_OUT }
+ {"bool", 16, 0, 1, F_BOOLIN, F_BOOLOUT},
+ {"bytea", 17, 0, -1, F_BYTEAIN, F_BYTEAOUT},
+ {"char", 18, 0, 1, F_CHARIN, F_CHAROUT},
+ {"name", 19, 0, NAMEDATALEN, F_NAMEIN, F_NAMEOUT},
+ {"char16", 20, 0, 16, F_CHAR16IN, F_CHAR16OUT},
+/* { "dt", 20, 0, 4, F_DTIN, F_DTOUT}, */
+ {"int2", 21, 0, 2, F_INT2IN, F_INT2OUT},
+ {"int28", 22, 0, 16, F_INT28IN, F_INT28OUT},
+ {"int4", 23, 0, 4, F_INT4IN, F_INT4OUT},
+ {"regproc", 24, 0, 4, F_REGPROCIN, F_REGPROCOUT},
+ {"text", 25, 0, -1, F_TEXTIN, F_TEXTOUT},
+ {"oid", 26, 0, 4, F_INT4IN, F_INT4OUT},
+ {"tid", 27, 0, 6, F_TIDIN, F_TIDOUT},
+ {"xid", 28, 0, 5, F_XIDIN, F_XIDOUT},
+ {"iid", 29, 0, 1, F_CIDIN, F_CIDOUT},
+ {"oid8", 30, 0, 32, F_OID8IN, F_OID8OUT},
+ {"smgr", 210, 0, 2, F_SMGRIN, F_SMGROUT},
+ {"_int4", 1007, 23, -1, F_ARRAY_IN, F_ARRAY_OUT},
+ {"_aclitem", 1034, 1033, -1, F_ARRAY_IN, F_ARRAY_OUT}
};
-static int n_types = sizeof(Procid) / sizeof(struct typinfo);
+static int n_types = sizeof(Procid) / sizeof(struct typinfo);
-struct typmap { /* a hack */
- Oid am_oid;
- TypeTupleFormData am_typ;
+struct typmap
+{ /* a hack */
+ Oid am_oid;
+ TypeTupleFormData am_typ;
};
-static struct typmap **Typ = (struct typmap **)NULL;
-static struct typmap *Ap = (struct typmap *)NULL;
-
-static int Warnings = 0;
-static char Blanks[MAXATTR];
-
-static char *relname; /* current relation name */
+static struct typmap **Typ = (struct typmap **) NULL;
+static struct typmap *Ap = (struct typmap *) NULL;
+
+static int Warnings = 0;
+static char Blanks[MAXATTR];
+
+static char *relname; /* current relation name */
-AttributeTupleForm attrtypes[MAXATTR]; /* points to attribute info */
-static char *values[MAXATTR]; /* cooresponding attribute values */
-int numattr; /* number of attributes for cur. rel */
-extern int fsyncOff; /* do not fsync the database */
+AttributeTupleForm attrtypes[MAXATTR]; /* points to attribute info */
+static char *values[MAXATTR];/* cooresponding attribute values */
+int numattr; /* number of attributes for cur. rel */
+extern int fsyncOff; /* do not fsync the database */
#ifndef HAVE_SIGSETJMP
-static jmp_buf Warn_restart;
-#define sigsetjmp(x,y) setjmp(x)
+static jmp_buf Warn_restart;
+
+#define sigsetjmp(x,y) setjmp(x)
#define siglongjmp longjmp
#else
static sigjmp_buf Warn_restart;
+
#endif
-int DebugMode;
-static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem context */
+int DebugMode;
+static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
+ * context */
+
+extern int optind;
+extern char *optarg;
-extern int optind;
-extern char *optarg;
-
/*
- * At bootstrap time, we first declare all the indices to be built, and
- * then build them. The IndexList structure stores enough information
- * to allow us to build the indices after they've been declared.
+ * At bootstrap time, we first declare all the indices to be built, and
+ * then build them. The IndexList structure stores enough information
+ * to allow us to build the indices after they've been declared.
*/
-typedef struct _IndexList {
- char* il_heap;
- char* il_ind;
- int il_natts;
- AttrNumber *il_attnos;
- uint16 il_nparams;
- Datum * il_params;
- FuncIndexInfo *il_finfo;
- PredInfo *il_predInfo;
- struct _IndexList *il_next;
-} IndexList;
+typedef struct _IndexList
+{
+ char *il_heap;
+ char *il_ind;
+ int il_natts;
+ AttrNumber *il_attnos;
+ uint16 il_nparams;
+ Datum *il_params;
+ FuncIndexInfo *il_finfo;
+ PredInfo *il_predInfo;
+ struct _IndexList *il_next;
+} IndexList;
static IndexList *ILHead = (IndexList *) NULL;
-
-typedef void (*sig_func)();
+
+typedef void (*sig_func) ();
+
+
-
/* ----------------------------------------------------------------
- * misc functions
+ * misc functions
* ----------------------------------------------------------------
*/
/* ----------------
- * error handling / abort routines
+ * error handling / abort routines
* ----------------
*/
void
err_out(void)
{
- Warnings++;
- cleanup();
+ Warnings++;
+ cleanup();
}
/* usage:
@@ -258,15 +266,15 @@ err_out(void)
static void
usage(void)
{
- fprintf(stderr,"Usage: postgres -boot [-d] [-C] [-F] [-O] [-Q] ");
- fprintf(stderr,"[-P portno] [dbName]\n");
- fprintf(stderr," d: debug mode\n");
- fprintf(stderr," C: disable version checking\n");
- fprintf(stderr," F: turn off fsync\n");
- fprintf(stderr," O: set BootstrapProcessing mode\n");
- fprintf(stderr," P portno: specify port number\n");
-
- exitpg(1);
+ fprintf(stderr, "Usage: postgres -boot [-d] [-C] [-F] [-O] [-Q] ");
+ fprintf(stderr, "[-P portno] [dbName]\n");
+ fprintf(stderr, " d: debug mode\n");
+ fprintf(stderr, " C: disable version checking\n");
+ fprintf(stderr, " F: turn off fsync\n");
+ fprintf(stderr, " O: set BootstrapProcessing mode\n");
+ fprintf(stderr, " P portno: specify port number\n");
+
+ exitpg(1);
}
@@ -274,286 +282,316 @@ usage(void)
int
BootstrapMain(int argc, char *argv[])
/* ----------------------------------------------------------------
- * The main loop for handling the backend in bootstrap mode
- * the bootstrap mode is used to initialize the template database
- * the bootstrap backend doesn't speak SQL, but instead expects
- * commands in a special bootstrap language.
+ * The main loop for handling the backend in bootstrap mode
+ * the bootstrap mode is used to initialize the template database
+ * the bootstrap backend doesn't speak SQL, but instead expects
+ * commands in a special bootstrap language.
*
- * The arguments passed in to BootstrapMain are the run-time arguments
- * without the argument '-boot', the caller is required to have
- * removed -boot from the run-time args
+ * The arguments passed in to BootstrapMain are the run-time arguments
+ * without the argument '-boot', the caller is required to have
+ * removed -boot from the run-time args
* ----------------------------------------------------------------
*/
{
- int i;
- int portFd = -1;
- char *dbName;
- int flag;
- int override = 1; /* use BootstrapProcessing or InitProcessing mode */
-
- extern int optind;
- extern char *optarg;
-
- /* ----------------
- * initialize signal handlers
- * ----------------
- */
- pqsignal(SIGINT, (sig_func) die);
+ int i;
+ int portFd = -1;
+ char *dbName;
+ int flag;
+ int override = 1; /* use BootstrapProcessing or
+ * InitProcessing mode */
+
+ extern int optind;
+ extern char *optarg;
+
+ /* ----------------
+ * initialize signal handlers
+ * ----------------
+ */
+ pqsignal(SIGINT, (sig_func) die);
#ifndef win32
- pqsignal(SIGHUP, (sig_func) die);
- pqsignal(SIGTERM, (sig_func) die);
-#endif /* win32 */
-
- /* --------------------
- * initialize globals
- * -------------------
- */
-
- MasterPid = getpid();
-
- /* ----------------
- * process command arguments
- * ----------------
- */
-
- /* Set defaults, to be overriden by explicit options below */
- Quiet = 0;
- Noversion = 0;
- dbName = NULL;
- DataDir = getenv("PGDATA"); /* Null if no PGDATA variable */
-
- while ((flag = getopt(argc, argv, "D:dCOQP:F")) != EOF) {
- switch (flag) {
- case 'D':
- DataDir = optarg;
- break;
- case 'd':
- DebugMode = 1; /* print out debugging info while parsing */
- break;
- case 'C':
- Noversion = 1;
- break;
- case 'F':
- fsyncOff = 1;
- break;
- case 'O':
- override = true;
- break;
- case 'Q':
- Quiet = 1;
- break;
- case 'P':/* specify port */
- portFd = atoi(optarg);
- break;
- default:
- usage();
- break;
- }
- } /* while */
-
- if (argc - optind > 1) {
- usage();
- } else
- if (argc - optind == 1) {
- dbName = argv[optind];
- }
-
- if (!DataDir) {
- fprintf(stderr, "%s does not know where to find the database system "
- "data. You must specify the directory that contains the "
- "database system either by specifying the -D invocation "
- "option or by setting the PGDATA environment variable.\n\n",
- argv[0]);
- exitpg(1);
- }
-
- if (dbName == NULL) {
- dbName = getenv("USER");
- if (dbName == NULL) {
- fputs("bootstrap backend: failed, no db name specified\n", stderr);
- fputs(" and no USER enviroment variable\n", stderr);
- exitpg(1);
- }
- }
-
- /* ----------------
- * initialize input fd
- * ----------------
- */
- if (IsUnderPostmaster == true && portFd < 0) {
- fputs("backend: failed, no -P option with -postmaster opt.\n", stderr);
- exitpg(1);
- }
-
+ pqsignal(SIGHUP, (sig_func) die);
+ pqsignal(SIGTERM, (sig_func) die);
+#endif /* win32 */
+
+ /* --------------------
+ * initialize globals
+ * -------------------
+ */
+
+ MasterPid = getpid();
+
+ /* ----------------
+ * process command arguments
+ * ----------------
+ */
+
+ /* Set defaults, to be overriden by explicit options below */
+ Quiet = 0;
+ Noversion = 0;
+ dbName = NULL;
+ DataDir = getenv("PGDATA"); /* Null if no PGDATA variable */
+
+ while ((flag = getopt(argc, argv, "D:dCOQP:F")) != EOF)
+ {
+ switch (flag)
+ {
+ case 'D':
+ DataDir = optarg;
+ break;
+ case 'd':
+ DebugMode = 1; /* print out debugging info while parsing */
+ break;
+ case 'C':
+ Noversion = 1;
+ break;
+ case 'F':
+ fsyncOff = 1;
+ break;
+ case 'O':
+ override = true;
+ break;
+ case 'Q':
+ Quiet = 1;
+ break;
+ case 'P': /* specify port */
+ portFd = atoi(optarg);
+ break;
+ default:
+ usage();
+ break;
+ }
+ } /* while */
+
+ if (argc - optind > 1)
+ {
+ usage();
+ }
+ else if (argc - optind == 1)
+ {
+ dbName = argv[optind];
+ }
+
+ if (!DataDir)
+ {
+ fprintf(stderr, "%s does not know where to find the database system "
+ "data. You must specify the directory that contains the "
+ "database system either by specifying the -D invocation "
+ "option or by setting the PGDATA environment variable.\n\n",
+ argv[0]);
+ exitpg(1);
+ }
+
+ if (dbName == NULL)
+ {
+ dbName = getenv("USER");
+ if (dbName == NULL)
+ {
+ fputs("bootstrap backend: failed, no db name specified\n", stderr);
+ fputs(" and no USER enviroment variable\n", stderr);
+ exitpg(1);
+ }
+ }
+
+ /* ----------------
+ * initialize input fd
+ * ----------------
+ */
+ if (IsUnderPostmaster == true && portFd < 0)
+ {
+ fputs("backend: failed, no -P option with -postmaster opt.\n", stderr);
+ exitpg(1);
+ }
+
#ifdef win32
- _nt_init();
- _nt_attach();
-#endif /* win32 */
-
-
- /* ----------------
- * backend initialization
- * ----------------
- */
- SetProcessingMode((override) ? BootstrapProcessing : InitProcessing);
- InitPostgres(dbName);
- LockDisable(true);
-
- for (i = 0 ; i < MAXATTR; i++) {
- attrtypes[i]=(AttributeTupleForm )NULL;
- Blanks[i] = ' ';
- }
- for(i = 0; i < STRTABLESIZE; ++i)
- strtable[i] = NULL;
- for(i = 0; i < HASHTABLESIZE; ++i)
- hashtable[i] = NULL;
-
- /* ----------------
- * abort processing resumes here - What to do in WIN32?
- * ----------------
- */
-#ifndef win32
- pqsignal(SIGHUP, handle_warn);
-
- if (sigsetjmp(Warn_restart, 1) != 0) {
+ _nt_init();
+ _nt_attach();
+#endif /* win32 */
+
+
+ /* ----------------
+ * backend initialization
+ * ----------------
+ */
+ SetProcessingMode((override) ? BootstrapProcessing : InitProcessing);
+ InitPostgres(dbName);
+ LockDisable(true);
+
+ for (i = 0; i < MAXATTR; i++)
+ {
+ attrtypes[i] = (AttributeTupleForm) NULL;
+ Blanks[i] = ' ';
+ }
+ for (i = 0; i < STRTABLESIZE; ++i)
+ strtable[i] = NULL;
+ for (i = 0; i < HASHTABLESIZE; ++i)
+ hashtable[i] = NULL;
+
+ /* ----------------
+ * abort processing resumes here - What to do in WIN32?
+ * ----------------
+ */
+#ifndef win32
+ pqsignal(SIGHUP, handle_warn);
+
+ if (sigsetjmp(Warn_restart, 1) != 0)
+ {
#else
- if (setjmp(Warn_restart) != 0) {
-#endif /* win32 */
- Warnings++;
- AbortCurrentTransaction();
- }
-
- /* ----------------
- * process input.
- * ----------------
- */
-
- /* the sed script boot.sed renamed yyparse to Int_yyparse
- for the bootstrap parser to avoid conflicts with the normal SQL
- parser */
- Int_yyparse();
-
- /* clean up processing */
- StartTransactionCommand();
- cleanup();
-
- /* not reached, here to make compiler happy */
- return 0;
+ if (setjmp(Warn_restart) != 0)
+ {
+#endif /* win32 */
+ Warnings++;
+ AbortCurrentTransaction();
+ }
+
+ /* ----------------
+ * process input.
+ * ----------------
+ */
+
+ /*
+ * the sed script boot.sed renamed yyparse to Int_yyparse for the
+ * bootstrap parser to avoid conflicts with the normal SQL parser
+ */
+ Int_yyparse();
+
+ /* clean up processing */
+ StartTransactionCommand();
+ cleanup();
+
+ /* not reached, here to make compiler happy */
+ return 0;
}
/* ----------------------------------------------------------------
- * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
+ * MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
* ----------------------------------------------------------------
*/
/* ----------------
- * boot_openrel
+ * boot_openrel
* ----------------
*/
void
boot_openrel(char *relname)
{
- int i;
- struct typmap **app;
- Relation rdesc;
- HeapScanDesc sdesc;
- HeapTuple tup;
-
- if (strlen(relname) > 15)
- relname[15] ='\000';
-
- if (Typ == (struct typmap **)NULL) {
- StartPortalAllocMode(DefaultAllocMode, 0);
- rdesc = heap_openr(TypeRelationName);
- sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
- for (i=0; PointerIsValid(tup=heap_getnext(sdesc,0,(Buffer *)NULL)); ++i);
- heap_endscan(sdesc);
- app = Typ = ALLOC(struct typmap *, i + 1);
- while (i-- > 0)
- *app++ = ALLOC(struct typmap, 1);
- *app = (struct typmap *)NULL;
- sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
- app = Typ;
- while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL))) {
- (*app)->am_oid = tup->t_oid;
- memmove((char *)&(*app++)->am_typ,
- (char *)GETSTRUCT(tup),
- sizeof ((*app)->am_typ));
- }
- heap_endscan(sdesc);
- heap_close(rdesc);
- EndPortalAllocMode();
- }
-
- if (reldesc != NULL) {
- closerel(NULL);
- }
-
- if (!Quiet)
- printf("Amopen: relation %s. attrsize %d\n", relname ? relname : "(null)",
- (int)ATTRIBUTE_TUPLE_SIZE);
-
- reldesc = heap_openr(relname);
- Assert(reldesc);
- numattr = reldesc->rd_rel->relnatts;
- for (i = 0; i < numattr; i++) {
- if (attrtypes[i] == NULL) {
- attrtypes[i] = AllocateAttribute();
- }
- memmove((char *)attrtypes[i],
- (char *)reldesc->rd_att->attrs[i],
- ATTRIBUTE_TUPLE_SIZE);
-
- /* Some old pg_attribute tuples might not have attisset. */
- /* If the attname is attisset, don't look for it - it may
- not be defined yet.
- */
- if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0)
- attrtypes[i]->attisset = get_attisset(reldesc->rd_id,
- attrtypes[i]->attname.data);
- else
- attrtypes[i]->attisset = false;
-
- if (DebugMode) {
- AttributeTupleForm at = attrtypes[i];
- printf("create attribute %d name %s len %d num %d type %d\n",
- i, at->attname.data, at->attlen, at->attnum,
- at->atttypid
- );
- fflush(stdout);
- }
- }
+ int i;
+ struct typmap **app;
+ Relation rdesc;
+ HeapScanDesc sdesc;
+ HeapTuple tup;
+
+ if (strlen(relname) > 15)
+ relname[15] = '\000';
+
+ if (Typ == (struct typmap **) NULL)
+ {
+ StartPortalAllocMode(DefaultAllocMode, 0);
+ rdesc = heap_openr(TypeRelationName);
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey) NULL);
+ for (i = 0; PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *) NULL)); ++i);
+ heap_endscan(sdesc);
+ app = Typ = ALLOC(struct typmap *, i + 1);
+ while (i-- > 0)
+ *app++ = ALLOC(struct typmap, 1);
+ *app = (struct typmap *) NULL;
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey) NULL);
+ app = Typ;
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *) NULL)))
+ {
+ (*app)->am_oid = tup->t_oid;
+ memmove((char *) &(*app++)->am_typ,
+ (char *) GETSTRUCT(tup),
+ sizeof((*app)->am_typ));
+ }
+ heap_endscan(sdesc);
+ heap_close(rdesc);
+ EndPortalAllocMode();
+ }
+
+ if (reldesc != NULL)
+ {
+ closerel(NULL);
+ }
+
+ if (!Quiet)
+ printf("Amopen: relation %s. attrsize %d\n", relname ? relname : "(null)",
+ (int) ATTRIBUTE_TUPLE_SIZE);
+
+ reldesc = heap_openr(relname);
+ Assert(reldesc);
+ numattr = reldesc->rd_rel->relnatts;
+ for (i = 0; i < numattr; i++)
+ {
+ if (attrtypes[i] == NULL)
+ {
+ attrtypes[i] = AllocateAttribute();
+ }
+ memmove((char *) attrtypes[i],
+ (char *) reldesc->rd_att->attrs[i],
+ ATTRIBUTE_TUPLE_SIZE);
+
+ /* Some old pg_attribute tuples might not have attisset. */
+
+ /*
+ * If the attname is attisset, don't look for it - it may not be
+ * defined yet.
+ */
+ if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0)
+ attrtypes[i]->attisset = get_attisset(reldesc->rd_id,
+ attrtypes[i]->attname.data);
+ else
+ attrtypes[i]->attisset = false;
+
+ if (DebugMode)
+ {
+ AttributeTupleForm at = attrtypes[i];
+
+ printf("create attribute %d name %s len %d num %d type %d\n",
+ i, at->attname.data, at->attlen, at->attnum,
+ at->atttypid
+ );
+ fflush(stdout);
+ }
+ }
}
/* ----------------
- * closerel
+ * closerel
* ----------------
*/
void
closerel(char *name)
{
- if (name) {
- if (reldesc) {
- if (namestrcmp(RelationGetRelationName(reldesc), name) != 0)
- elog(WARN,"closerel: close of '%s' when '%s' was expected",
- name, relname ? relname : "(null)");
- } else
- elog(WARN,"closerel: close of '%s' before any relation was opened",
- name);
-
- }
-
- if (reldesc == NULL) {
- elog(WARN,"Warning: no opened relation to close.\n");
- } else {
- if (!Quiet) printf("Amclose: relation %s.\n", relname ? relname : "(null)");
- heap_close(reldesc);
- reldesc = (Relation)NULL;
- }
+ if (name)
+ {
+ if (reldesc)
+ {
+ if (namestrcmp(RelationGetRelationName(reldesc), name) != 0)
+ elog(WARN, "closerel: close of '%s' when '%s' was expected",
+ name, relname ? relname : "(null)");
+ }
+ else
+ elog(WARN, "closerel: close of '%s' before any relation was opened",
+ name);
+
+ }
+
+ if (reldesc == NULL)
+ {
+ elog(WARN, "Warning: no opened relation to close.\n");
+ }
+ else
+ {
+ if (!Quiet)
+ printf("Amclose: relation %s.\n", relname ? relname : "(null)");
+ heap_close(reldesc);
+ reldesc = (Relation) NULL;
+ }
}
-
+
+
/* ----------------
* DEFINEATTR()
*
@@ -565,563 +603,626 @@ closerel(char *name)
void
DefineAttr(char *name, char *type, int attnum)
{
- int attlen;
- int t;
-
- if (reldesc != NULL) {
- fputs("Warning: no open relations allowed with 't' command.\n",stderr);
- closerel(relname);
- }
-
- t = gettype(type);
- if (attrtypes[attnum] == (AttributeTupleForm )NULL)
- attrtypes[attnum] = AllocateAttribute();
- if (Typ != (struct typmap **)NULL) {
- attrtypes[attnum]->atttypid = Ap->am_oid;
- namestrcpy(&attrtypes[attnum]->attname, name);
- if (!Quiet) printf("<%s %s> ", attrtypes[attnum]->attname.data, type);
- attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
- attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
- attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
- } else {
- attrtypes[attnum]->atttypid = Procid[t].oid;
- namestrcpy(&attrtypes[attnum]->attname,name);
- if (!Quiet) printf("<%s %s> ", attrtypes[attnum]->attname.data, type);
- attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
- attlen = attrtypes[attnum]->attlen = Procid[t].len;
- attrtypes[attnum]->attbyval = (attlen==1) || (attlen==2)||(attlen==4);
- }
+ int attlen;
+ int t;
+
+ if (reldesc != NULL)
+ {
+ fputs("Warning: no open relations allowed with 't' command.\n", stderr);
+ closerel(relname);
+ }
+
+ t = gettype(type);
+ if (attrtypes[attnum] == (AttributeTupleForm) NULL)
+ attrtypes[attnum] = AllocateAttribute();
+ if (Typ != (struct typmap **) NULL)
+ {
+ attrtypes[attnum]->atttypid = Ap->am_oid;
+ namestrcpy(&attrtypes[attnum]->attname, name);
+ if (!Quiet)
+ printf("<%s %s> ", attrtypes[attnum]->attname.data, type);
+ attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
+ attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
+ attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
+ }
+ else
+ {
+ attrtypes[attnum]->atttypid = Procid[t].oid;
+ namestrcpy(&attrtypes[attnum]->attname, name);
+ if (!Quiet)
+ printf("<%s %s> ", attrtypes[attnum]->attname.data, type);
+ attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
+ attlen = attrtypes[attnum]->attlen = Procid[t].len;
+ attrtypes[attnum]->attbyval = (attlen == 1) || (attlen == 2) || (attlen == 4);
+ }
}
/* ----------------
- * InsertOneTuple
- * assumes that 'oid' will not be zero.
+ * InsertOneTuple
+ * assumes that 'oid' will not be zero.
* ----------------
*/
void
InsertOneTuple(Oid objectid)
{
- HeapTuple tuple;
- TupleDesc tupDesc;
-
- int i;
-
- if (DebugMode) {
- printf("InsertOneTuple oid %d, %d attrs\n", objectid, numattr);
- fflush(stdout);
- }
-
- tupDesc = CreateTupleDesc(numattr,attrtypes);
- tuple = heap_formtuple(tupDesc,(Datum*)values,Blanks);
- pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
-
- if(objectid !=(Oid)0) {
- tuple->t_oid=objectid;
- }
- heap_insert(reldesc, tuple);
- pfree(tuple);
- if (DebugMode) {
- printf("End InsertOneTuple, objectid=%d\n", objectid);
- fflush(stdout);
- }
- /*
- * Reset blanks for next tuple
- */
- for (i = 0; i<numattr; i++)
- Blanks[i] = ' ';
+ HeapTuple tuple;
+ TupleDesc tupDesc;
+
+ int i;
+
+ if (DebugMode)
+ {
+ printf("InsertOneTuple oid %d, %d attrs\n", objectid, numattr);
+ fflush(stdout);
+ }
+
+ tupDesc = CreateTupleDesc(numattr, attrtypes);
+ tuple = heap_formtuple(tupDesc, (Datum *) values, Blanks);
+ pfree(tupDesc); /* just free's tupDesc, not the attrtypes */
+
+ if (objectid != (Oid) 0)
+ {
+ tuple->t_oid = objectid;
+ }
+ heap_insert(reldesc, tuple);
+ pfree(tuple);
+ if (DebugMode)
+ {
+ printf("End InsertOneTuple, objectid=%d\n", objectid);
+ fflush(stdout);
+ }
+
+ /*
+ * Reset blanks for next tuple
+ */
+ for (i = 0; i < numattr; i++)
+ Blanks[i] = ' ';
}
/* ----------------
- * InsertOneValue
+ * InsertOneValue
* ----------------
*/
void
InsertOneValue(Oid objectid, char *value, int i)
{
- int typeindex;
- char *prt;
- struct typmap **app;
-
- if (DebugMode)
- printf("Inserting value: '%s'\n", value);
- if (i < 0 || i >= MAXATTR) {
- printf("i out of range: %d\n", i);
- Assert(0);
- }
-
- if (Typ != (struct typmap **)NULL) {
- struct typmap *ap;
- if (DebugMode)
- puts("Typ != NULL");
- app = Typ;
- while (*app && (*app)->am_oid != reldesc->rd_att->attrs[i]->atttypid)
- ++app;
- ap = *app;
- if (ap == NULL) {
- printf("Unable to find atttypid in Typ list! %d\n",
- reldesc->rd_att->attrs[i]->atttypid
- );
- Assert(0);
- }
- values[i] = fmgr(ap->am_typ.typinput,
- value,
- ap->am_typ.typelem,
- -1); /* shouldn't have char() or varchar() types
- during boostrapping but just to be safe */
- prt = fmgr(ap->am_typ.typoutput, values[i],
- ap->am_typ.typelem);
- if (!Quiet) printf("%s ", prt);
- pfree(prt);
- } else {
- typeindex = attrtypes[i]->atttypid - FIRST_TYPE_OID;
- if (DebugMode)
- printf("Typ == NULL, typeindex = %d idx = %d\n", typeindex, i);
- values[i] = fmgr(Procid[typeindex].inproc, value,
- Procid[typeindex].elem, -1);
- prt = fmgr(Procid[typeindex].outproc, values[i],
- Procid[typeindex].elem);
- if (!Quiet) printf("%s ", prt);
- pfree(prt);
- }
- if (DebugMode) {
- puts("End InsertValue");
- fflush(stdout);
- }
+ int typeindex;
+ char *prt;
+ struct typmap **app;
+
+ if (DebugMode)
+ printf("Inserting value: '%s'\n", value);
+ if (i < 0 || i >= MAXATTR)
+ {
+ printf("i out of range: %d\n", i);
+ Assert(0);
+ }
+
+ if (Typ != (struct typmap **) NULL)
+ {
+ struct typmap *ap;
+
+ if (DebugMode)
+ puts("Typ != NULL");
+ app = Typ;
+ while (*app && (*app)->am_oid != reldesc->rd_att->attrs[i]->atttypid)
+ ++app;
+ ap = *app;
+ if (ap == NULL)
+ {
+ printf("Unable to find atttypid in Typ list! %d\n",
+ reldesc->rd_att->attrs[i]->atttypid
+ );
+ Assert(0);
+ }
+ values[i] = fmgr(ap->am_typ.typinput,
+ value,
+ ap->am_typ.typelem,
+ -1); /* shouldn't have char() or varchar()
+ * types during boostrapping but just to
+ * be safe */
+ prt = fmgr(ap->am_typ.typoutput, values[i],
+ ap->am_typ.typelem);
+ if (!Quiet)
+ printf("%s ", prt);
+ pfree(prt);
+ }
+ else
+ {
+ typeindex = attrtypes[i]->atttypid - FIRST_TYPE_OID;
+ if (DebugMode)
+ printf("Typ == NULL, typeindex = %d idx = %d\n", typeindex, i);
+ values[i] = fmgr(Procid[typeindex].inproc, value,
+ Procid[typeindex].elem, -1);
+ prt = fmgr(Procid[typeindex].outproc, values[i],
+ Procid[typeindex].elem);
+ if (!Quiet)
+ printf("%s ", prt);
+ pfree(prt);
+ }
+ if (DebugMode)
+ {
+ puts("End InsertValue");
+ fflush(stdout);
+ }
}
/* ----------------
- * InsertOneNull
+ * InsertOneNull
* ----------------
*/
void
InsertOneNull(int i)
{
- if (DebugMode)
- printf("Inserting null\n");
- if (i < 0 || i >= MAXATTR) {
- elog(FATAL, "i out of range (too many attrs): %d\n", i);
- }
- values[i] = (char *)NULL;
- Blanks[i] = 'n';
+ if (DebugMode)
+ printf("Inserting null\n");
+ if (i < 0 || i >= MAXATTR)
+ {
+ elog(FATAL, "i out of range (too many attrs): %d\n", i);
+ }
+ values[i] = (char *) NULL;
+ Blanks[i] = 'n';
}
#define MORE_THAN_THE_NUMBER_OF_CATALOGS 256
-static bool
+static bool
BootstrapAlreadySeen(Oid id)
{
- static Oid seenArray[MORE_THAN_THE_NUMBER_OF_CATALOGS];
- static int nseen = 0;
- bool seenthis;
- int i;
-
- seenthis = false;
-
- for (i=0; i < nseen; i++) {
- if (seenArray[i] == id) {
- seenthis = true;
- break;
- }
- }
- if (!seenthis) {
- seenArray[nseen] = id;
- nseen++;
- }
- return (seenthis);
+ static Oid seenArray[MORE_THAN_THE_NUMBER_OF_CATALOGS];
+ static int nseen = 0;
+ bool seenthis;
+ int i;
+
+ seenthis = false;
+
+ for (i = 0; i < nseen; i++)
+ {
+ if (seenArray[i] == id)
+ {
+ seenthis = true;
+ break;
+ }
+ }
+ if (!seenthis)
+ {
+ seenArray[nseen] = id;
+ nseen++;
+ }
+ return (seenthis);
}
/* ----------------
- * cleanup
+ * cleanup
* ----------------
*/
static void
cleanup()
{
- static int beenhere = 0;
-
- if (!beenhere)
- beenhere = 1;
- else {
- elog(FATAL,"Memory manager fault: cleanup called twice.\n", stderr);
- exitpg(1);
- }
- if (reldesc != (Relation)NULL) {
- heap_close(reldesc);
- }
- CommitTransactionCommand();
- exitpg(Warnings);
+ static int beenhere = 0;
+
+ if (!beenhere)
+ beenhere = 1;
+ else
+ {
+ elog(FATAL, "Memory manager fault: cleanup called twice.\n", stderr);
+ exitpg(1);
+ }
+ if (reldesc != (Relation) NULL)
+ {
+ heap_close(reldesc);
+ }
+ CommitTransactionCommand();
+ exitpg(Warnings);
}
/* ----------------
- * gettype
+ * gettype
* ----------------
*/
static int
gettype(char *type)
{
- int i;
- Relation rdesc;
- HeapScanDesc sdesc;
- HeapTuple tup;
- struct typmap **app;
-
- if (Typ != (struct typmap **)NULL) {
- for (app = Typ; *app != (struct typmap *)NULL; app++) {
- if (strncmp((*app)->am_typ.typname.data, type, NAMEDATALEN) == 0) {
- Ap = *app;
- return((*app)->am_oid);
- }
- }
- } else {
- for (i = 0; i <= n_types; i++) {
- if (strncmp(type, Procid[i].name, NAMEDATALEN) == 0) {
- return(i);
- }
- }
- if (DebugMode)
- printf("bootstrap.c: External Type: %s\n", type);
- rdesc = heap_openr(TypeRelationName);
- sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
- i = 0;
- while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL)))
- ++i;
- heap_endscan(sdesc);
- app = Typ = ALLOC(struct typmap *, i + 1);
- while (i-- > 0)
- *app++ = ALLOC(struct typmap, 1);
- *app = (struct typmap *)NULL;
- sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey)NULL);
- app = Typ;
- while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *)NULL))) {
- (*app)->am_oid = tup->t_oid;
- memmove((char *)&(*app++)->am_typ,
- (char *)GETSTRUCT(tup),
- sizeof ((*app)->am_typ));
- }
- heap_endscan(sdesc);
- heap_close(rdesc);
- return(gettype(type));
- }
- elog(WARN, "Error: unknown type '%s'.\n", type);
- err_out();
- /* not reached, here to make compiler happy */
- return 0;
+ int i;
+ Relation rdesc;
+ HeapScanDesc sdesc;
+ HeapTuple tup;
+ struct typmap **app;
+
+ if (Typ != (struct typmap **) NULL)
+ {
+ for (app = Typ; *app != (struct typmap *) NULL; app++)
+ {
+ if (strncmp((*app)->am_typ.typname.data, type, NAMEDATALEN) == 0)
+ {
+ Ap = *app;
+ return ((*app)->am_oid);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i <= n_types; i++)
+ {
+ if (strncmp(type, Procid[i].name, NAMEDATALEN) == 0)
+ {
+ return (i);
+ }
+ }
+ if (DebugMode)
+ printf("bootstrap.c: External Type: %s\n", type);
+ rdesc = heap_openr(TypeRelationName);
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey) NULL);
+ i = 0;
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *) NULL)))
+ ++i;
+ heap_endscan(sdesc);
+ app = Typ = ALLOC(struct typmap *, i + 1);
+ while (i-- > 0)
+ *app++ = ALLOC(struct typmap, 1);
+ *app = (struct typmap *) NULL;
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0, (ScanKey) NULL);
+ app = Typ;
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, (Buffer *) NULL)))
+ {
+ (*app)->am_oid = tup->t_oid;
+ memmove((char *) &(*app++)->am_typ,
+ (char *) GETSTRUCT(tup),
+ sizeof((*app)->am_typ));
+ }
+ heap_endscan(sdesc);
+ heap_close(rdesc);
+ return (gettype(type));
+ }
+ elog(WARN, "Error: unknown type '%s'.\n", type);
+ err_out();
+ /* not reached, here to make compiler happy */
+ return 0;
}
/* ----------------
- * AllocateAttribute
+ * AllocateAttribute
* ----------------
*/
-static AttributeTupleForm /* XXX */
+static AttributeTupleForm /* XXX */
AllocateAttribute()
{
- AttributeTupleForm attribute =
- (AttributeTupleForm)malloc(ATTRIBUTE_TUPLE_SIZE);
-
- if (!PointerIsValid(attribute)) {
- elog(FATAL, "AllocateAttribute: malloc failed");
- }
- memset(attribute, 0, ATTRIBUTE_TUPLE_SIZE);
-
- return (attribute);
+ AttributeTupleForm attribute =
+ (AttributeTupleForm) malloc(ATTRIBUTE_TUPLE_SIZE);
+
+ if (!PointerIsValid(attribute))
+ {
+ elog(FATAL, "AllocateAttribute: malloc failed");
+ }
+ memset(attribute, 0, ATTRIBUTE_TUPLE_SIZE);
+
+ return (attribute);
}
/* ----------------
- * MapArrayTypeName
+ * MapArrayTypeName
* XXX arrays of "basetype" are always "_basetype".
- * this is an evil hack inherited from rel. 3.1.
+ * this is an evil hack inherited from rel. 3.1.
* XXX array dimension is thrown away because we
- * don't support fixed-dimension arrays. again,
- * sickness from 3.1.
- *
- * the string passed in must have a '[' character in it
+ * don't support fixed-dimension arrays. again,
+ * sickness from 3.1.
+ *
+ * the string passed in must have a '[' character in it
*
* the string returned is a pointer to static storage and should NOT
* be freed by the CALLER.
* ----------------
*/
-char*
+char *
MapArrayTypeName(char *s)
{
- int i, j;
- static char newStr[NAMEDATALEN]; /* array type names < NAMEDATALEN long */
+ int i,
+ j;
+ static char newStr[NAMEDATALEN]; /* array type names <
+ * NAMEDATALEN long */
- if (s == NULL || s[0] == '\0')
- return s;
+ if (s == NULL || s[0] == '\0')
+ return s;
- j = 1;
- newStr[0] = '_';
- for (i=0; i<NAMEDATALEN-1 && s[i] != '['; i++, j++)
- newStr[j] = s[i];
-
- newStr[j] = '\0';
+ j = 1;
+ newStr[0] = '_';
+ for (i = 0; i < NAMEDATALEN - 1 && s[i] != '['; i++, j++)
+ newStr[j] = s[i];
- return newStr;
+ newStr[j] = '\0';
+
+ return newStr;
}
/* ----------------
- * EnterString
- * returns the string table position of the identifier
- * passed to it. We add it to the table if we can't find it.
+ * EnterString
+ * returns the string table position of the identifier
+ * passed to it. We add it to the table if we can't find it.
* ----------------
*/
int
-EnterString (char *str)
+EnterString(char *str)
{
- hashnode *node;
- int len;
-
- len= strlen(str);
-
- node = FindStr(str, len, 0);
- if (node) {
- return (node->strnum);
- } else {
- node = AddStr(str, len, 0);
- return (node->strnum);
- }
+ hashnode *node;
+ int len;
+
+ len = strlen(str);
+
+ node = FindStr(str, len, 0);
+ if (node)
+ {
+ return (node->strnum);
+ }
+ else
+ {
+ node = AddStr(str, len, 0);
+ return (node->strnum);
+ }
}
/* ----------------
- * LexIDStr
- * when given an idnum into the 'string-table' return the string
- * associated with the idnum
+ * LexIDStr
+ * when given an idnum into the 'string-table' return the string
+ * associated with the idnum
* ----------------
*/
-char *
-LexIDStr(int ident_num)
+char *
+LexIDStr(int ident_num)
{
- return(strtable[ident_num]);
-}
+ return (strtable[ident_num]);
+}
/* ----------------
- * CompHash
+ * CompHash
*
- * Compute a hash function for a given string. We look at the first,
- * the last, and the middle character of a string to try to get spread
- * the strings out. The function is rather arbitrary, except that we
- * are mod'ing by a prime number.
+ * Compute a hash function for a given string. We look at the first,
+ * the last, and the middle character of a string to try to get spread
+ * the strings out. The function is rather arbitrary, except that we
+ * are mod'ing by a prime number.
* ----------------
*/
static int
CompHash(char *str, int len)
{
- register int result;
-
- result =(NUM * str[0] + NUMSQR * str[len-1] + NUMCUBE * str[(len-1)/2]);
-
- return (result % HASHTABLESIZE);
-
+ register int result;
+
+ result = (NUM * str[0] + NUMSQR * str[len - 1] + NUMCUBE * str[(len - 1) / 2]);
+
+ return (result % HASHTABLESIZE);
+
}
/* ----------------
- * FindStr
+ * FindStr
*
- * This routine looks for the specified string in the hash
- * table. It returns a pointer to the hash node found,
- * or NULL if the string is not in the table.
+ * This routine looks for the specified string in the hash
+ * table. It returns a pointer to the hash node found,
+ * or NULL if the string is not in the table.
* ----------------
*/
static hashnode *
-FindStr(char *str, int length, hashnode *mderef)
+FindStr(char *str, int length, hashnode * mderef)
{
- hashnode *node;
- node = hashtable [CompHash (str, length)];
- while (node != NULL) {
- /*
- * We must differentiate between string constants that
- * might have the same value as a identifier
- * and the identifier itself.
- */
- if (!strcmp(str, strtable[node->strnum])) {
- return(node); /* no need to check */
- } else {
- node = node->next;
- }
- }
- /* Couldn't find it in the list */
- return (NULL);
+ hashnode *node;
+
+ node = hashtable[CompHash(str, length)];
+ while (node != NULL)
+ {
+
+ /*
+ * We must differentiate between string constants that might have
+ * the same value as a identifier and the identifier itself.
+ */
+ if (!strcmp(str, strtable[node->strnum]))
+ {
+ return (node); /* no need to check */
+ }
+ else
+ {
+ node = node->next;
+ }
+ }
+ /* Couldn't find it in the list */
+ return (NULL);
}
/* ----------------
- * AddStr
+ * AddStr
*
- * This function adds the specified string, along with its associated
- * data, to the hash table and the string table. We return the node
- * so that the calling routine can find out the unique id that AddStr
- * has assigned to this string.
+ * This function adds the specified string, along with its associated
+ * data, to the hash table and the string table. We return the node
+ * so that the calling routine can find out the unique id that AddStr
+ * has assigned to this string.
* ----------------
*/
static hashnode *
AddStr(char *str, int strlength, int mderef)
{
- hashnode *temp, *trail, *newnode;
- int hashresult;
- int len;
-
- if (++strtable_end == STRTABLESIZE) {
- /* Error, string table overflow, so we Punt */
- elog(FATAL,
- "There are too many string constants and identifiers for the compiler to handle.");
-
-
- }
-
- /*
- * Some of the utilites (eg, define type, create relation) assume
- * that the string they're passed is a NAMEDATALEN. We get array bound
- * read violations from purify if we don't allocate at least NAMEDATALEN
- * bytes for strings of this sort. Because we're lazy, we allocate
- * at least NAMEDATALEN bytes all the time.
- */
-
- if ((len = strlength + 1) < NAMEDATALEN)
- len = NAMEDATALEN;
-
- strtable [strtable_end] = malloc((unsigned) len);
- strcpy (strtable[strtable_end], str);
-
- /* Now put a node in the hash table */
-
- newnode = (hashnode*)malloc(sizeof(hashnode)*1);
- newnode->strnum = strtable_end;
- newnode->next = NULL;
-
- /* Find out where it goes */
-
- hashresult = CompHash (str, strlength);
- if (hashtable [hashresult] == NULL) {
- hashtable [hashresult] = newnode;
- } else { /* There is something in the list */
- trail = hashtable [hashresult];
- temp = trail->next;
- while (temp != NULL) {
- trail = temp;
- temp = temp->next;
- }
- trail->next = newnode;
- }
- return (newnode);
+ hashnode *temp,
+ *trail,
+ *newnode;
+ int hashresult;
+ int len;
+
+ if (++strtable_end == STRTABLESIZE)
+ {
+ /* Error, string table overflow, so we Punt */
+ elog(FATAL,
+ "There are too many string constants and identifiers for the compiler to handle.");
+
+
+ }
+
+ /*
+ * Some of the utilites (eg, define type, create relation) assume that
+ * the string they're passed is a NAMEDATALEN. We get array bound
+ * read violations from purify if we don't allocate at least
+ * NAMEDATALEN bytes for strings of this sort. Because we're lazy, we
+ * allocate at least NAMEDATALEN bytes all the time.
+ */
+
+ if ((len = strlength + 1) < NAMEDATALEN)
+ len = NAMEDATALEN;
+
+ strtable[strtable_end] = malloc((unsigned) len);
+ strcpy(strtable[strtable_end], str);
+
+ /* Now put a node in the hash table */
+
+ newnode = (hashnode *) malloc(sizeof(hashnode) * 1);
+ newnode->strnum = strtable_end;
+ newnode->next = NULL;
+
+ /* Find out where it goes */
+
+ hashresult = CompHash(str, strlength);
+ if (hashtable[hashresult] == NULL)
+ {
+ hashtable[hashresult] = newnode;
+ }
+ else
+ { /* There is something in the list */
+ trail = hashtable[hashresult];
+ temp = trail->next;
+ while (temp != NULL)
+ {
+ trail = temp;
+ temp = temp->next;
+ }
+ trail->next = newnode;
+ }
+ return (newnode);
}
/*
- * index_register() -- record an index that has been set up for building
- * later.
+ * index_register() -- record an index that has been set up for building
+ * later.
*
- * At bootstrap time, we define a bunch of indices on system catalogs.
- * We postpone actually building the indices until just before we're
- * finished with initialization, however. This is because more classes
- * and indices may be defined, and we want to be sure that all of them
- * are present in the index.
+ * At bootstrap time, we define a bunch of indices on system catalogs.
+ * We postpone actually building the indices until just before we're
+ * finished with initialization, however. This is because more classes
+ * and indices may be defined, and we want to be sure that all of them
+ * are present in the index.
*/
void
index_register(char *heap,
- char *ind,
- int natts,
- AttrNumber *attnos,
- uint16 nparams,
- Datum *params,
- FuncIndexInfo *finfo,
- PredInfo *predInfo)
+ char *ind,
+ int natts,
+ AttrNumber * attnos,
+ uint16 nparams,
+ Datum * params,
+ FuncIndexInfo * finfo,
+ PredInfo * predInfo)
{
- Datum *v;
- IndexList *newind;
- int len;
- MemoryContext oldcxt;
-
- /*
- * XXX mao 10/31/92 -- don't gc index reldescs, associated info
- * at bootstrap time. we'll declare the indices now, but want to
- * create them later.
- */
-
- if (nogc == (GlobalMemory) NULL)
- nogc = CreateGlobalMemory("BootstrapNoGC");
-
- oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
-
- newind = (IndexList *) palloc(sizeof(IndexList));
- newind->il_heap = pstrdup(heap);
- newind->il_ind = pstrdup(ind);
- newind->il_natts = natts;
-
- if (PointerIsValid(finfo))
- len = FIgetnArgs(finfo) * sizeof(AttrNumber);
- else
- len = natts * sizeof(AttrNumber);
-
- newind->il_attnos = (AttrNumber *) palloc(len);
- memmove(newind->il_attnos, attnos, len);
-
- if ((newind->il_nparams = nparams) > 0) {
- v = newind->il_params = (Datum *) palloc(2 * nparams * sizeof(Datum));
- nparams *= 2;
- while (nparams-- > 0) {
- *v = (Datum) palloc(strlen((char *)(*params)) + 1);
- strcpy((char *) *v++, (char *) *params++);
- }
- } else {
- newind->il_params = (Datum *) NULL;
- }
-
- if (finfo != (FuncIndexInfo *) NULL) {
- newind->il_finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
- memmove(newind->il_finfo, finfo, sizeof(FuncIndexInfo));
- } else {
- newind->il_finfo = (FuncIndexInfo *) NULL;
- }
-
- if (predInfo != NULL) {
- newind->il_predInfo = (PredInfo*)palloc(sizeof(PredInfo));
- newind->il_predInfo->pred = predInfo->pred;
- newind->il_predInfo->oldPred = predInfo->oldPred;
- } else {
- newind->il_predInfo = NULL;
- }
-
- newind->il_next = ILHead;
-
- ILHead = newind;
-
- MemoryContextSwitchTo(oldcxt);
+ Datum *v;
+ IndexList *newind;
+ int len;
+ MemoryContext oldcxt;
+
+ /*
+ * XXX mao 10/31/92 -- don't gc index reldescs, associated info at
+ * bootstrap time. we'll declare the indices now, but want to create
+ * them later.
+ */
+
+ if (nogc == (GlobalMemory) NULL)
+ nogc = CreateGlobalMemory("BootstrapNoGC");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
+
+ newind = (IndexList *) palloc(sizeof(IndexList));
+ newind->il_heap = pstrdup(heap);
+ newind->il_ind = pstrdup(ind);
+ newind->il_natts = natts;
+
+ if (PointerIsValid(finfo))
+ len = FIgetnArgs(finfo) * sizeof(AttrNumber);
+ else
+ len = natts * sizeof(AttrNumber);
+
+ newind->il_attnos = (AttrNumber *) palloc(len);
+ memmove(newind->il_attnos, attnos, len);
+
+ if ((newind->il_nparams = nparams) > 0)
+ {
+ v = newind->il_params = (Datum *) palloc(2 * nparams * sizeof(Datum));
+ nparams *= 2;
+ while (nparams-- > 0)
+ {
+ *v = (Datum) palloc(strlen((char *) (*params)) + 1);
+ strcpy((char *) *v++, (char *) *params++);
+ }
+ }
+ else
+ {
+ newind->il_params = (Datum *) NULL;
+ }
+
+ if (finfo != (FuncIndexInfo *) NULL)
+ {
+ newind->il_finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
+ memmove(newind->il_finfo, finfo, sizeof(FuncIndexInfo));
+ }
+ else
+ {
+ newind->il_finfo = (FuncIndexInfo *) NULL;
+ }
+
+ if (predInfo != NULL)
+ {
+ newind->il_predInfo = (PredInfo *) palloc(sizeof(PredInfo));
+ newind->il_predInfo->pred = predInfo->pred;
+ newind->il_predInfo->oldPred = predInfo->oldPred;
+ }
+ else
+ {
+ newind->il_predInfo = NULL;
+ }
+
+ newind->il_next = ILHead;
+
+ ILHead = newind;
+
+ MemoryContextSwitchTo(oldcxt);
}
void
build_indices()
{
- Relation heap;
- Relation ind;
-
- for ( ; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next) {
- heap = heap_openr(ILHead->il_heap);
- ind = index_openr(ILHead->il_ind);
- index_build(heap, ind, ILHead->il_natts, ILHead->il_attnos,
- ILHead->il_nparams, ILHead->il_params, ILHead->il_finfo,
- ILHead->il_predInfo);
-
- /*
- * All of the rest of this routine is needed only because in bootstrap
- * processing we don't increment xact id's. The normal DefineIndex
- * code replaces a pg_class tuple with updated info including the
- * relhasindex flag (which we need to have updated). Unfortunately,
- * there are always two indices defined on each catalog causing us to
- * update the same pg_class tuple twice for each catalog getting an
- * index during bootstrap resulting in the ghost tuple problem (see
- * heap_replace). To get around this we change the relhasindex
- * field ourselves in this routine keeping track of what catalogs we
- * already changed so that we don't modify those tuples twice. The
- * normal mechanism for updating pg_class is disabled during bootstrap.
- *
- * -mer
- */
- heap = heap_openr(ILHead->il_heap);
-
- if (!BootstrapAlreadySeen(heap->rd_id))
- UpdateStats(heap->rd_id, 0, true);
- }
+ Relation heap;
+ Relation ind;
+
+ for (; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next)
+ {
+ heap = heap_openr(ILHead->il_heap);
+ ind = index_openr(ILHead->il_ind);
+ index_build(heap, ind, ILHead->il_natts, ILHead->il_attnos,
+ ILHead->il_nparams, ILHead->il_params, ILHead->il_finfo,
+ ILHead->il_predInfo);
+
+ /*
+ * All of the rest of this routine is needed only because in
+ * bootstrap processing we don't increment xact id's. The normal
+ * DefineIndex code replaces a pg_class tuple with updated info
+ * including the relhasindex flag (which we need to have updated).
+ * Unfortunately, there are always two indices defined on each
+ * catalog causing us to update the same pg_class tuple twice for
+ * each catalog getting an index during bootstrap resulting in the
+ * ghost tuple problem (see heap_replace). To get around this we
+ * change the relhasindex field ourselves in this routine keeping
+ * track of what catalogs we already changed so that we don't
+ * modify those tuples twice. The normal mechanism for updating
+ * pg_class is disabled during bootstrap.
+ *
+ * -mer
+ */
+ heap = heap_openr(ILHead->il_heap);
+
+ if (!BootstrapAlreadySeen(heap->rd_id))
+ UpdateStats(heap->rd_id, 0, true);
+ }
}
-
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index 90e6dedc18d..a8abbb01eee 100644
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* catalog.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.7 1997/08/18 20:51:59 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.8 1997/09/07 04:40:00 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -15,7 +15,7 @@
#include <postgres.h>
-#include <miscadmin.h> /* for DataDir */
+#include <miscadmin.h> /* for DataDir */
#include <utils/syscache.h>
#include <catalog/catname.h> /* NameIs{,Shared}SystemRelationName */
#include <catalog/pg_type.h>
@@ -23,175 +23,188 @@
#include <access/transam.h>
/*
- * relpath - path to the relation
- * Perhaps this should be in-line code in relopen().
+ * relpath - path to the relation
+ * Perhaps this should be in-line code in relopen().
*/
-char *
+char *
relpath(char relname[])
{
- char *path;
-
- if (IsSharedSystemRelationName(relname)) {
- path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2);
- sprintf(path, "%s/%s", DataDir, relname);
- return (path);
- }
- return(relname);
+ char *path;
+
+ if (IsSharedSystemRelationName(relname))
+ {
+ path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2);
+ sprintf(path, "%s/%s", DataDir, relname);
+ return (path);
+ }
+ return (relname);
}
#ifdef NOT_USED
/*
- * issystem - returns non-zero iff relname is a system catalog
+ * issystem - returns non-zero iff relname is a system catalog
*
- * We now make a new requirement where system catalog relns must begin
- * with pg_ while user relns are forbidden to do so. Make the test
- * trivial and instantaneous.
+ * We now make a new requirement where system catalog relns must begin
+ * with pg_ while user relns are forbidden to do so. Make the test
+ * trivial and instantaneous.
*
- * XXX this is way bogus. -- pma
+ * XXX this is way bogus. -- pma
*/
bool
issystem(char relname[])
{
- if (relname[0] && relname[1] && relname[2])
- return (relname[0] == 'p' &&
- relname[1] == 'g' &&
- relname[2] == '_');
- else
- return FALSE;
+ if (relname[0] && relname[1] && relname[2])
+ return (relname[0] == 'p' &&
+ relname[1] == 'g' &&
+ relname[2] == '_');
+ else
+ return FALSE;
}
+
#endif
/*
* IsSystemRelationName --
- * True iff name is the name of a system catalog relation.
+ * True iff name is the name of a system catalog relation.
*
- * We now make a new requirement where system catalog relns must begin
- * with pg_ while user relns are forbidden to do so. Make the test
- * trivial and instantaneous.
+ * We now make a new requirement where system catalog relns must begin
+ * with pg_ while user relns are forbidden to do so. Make the test
+ * trivial and instantaneous.
*
- * XXX this is way bogus. -- pma
+ * XXX this is way bogus. -- pma
*/
bool
IsSystemRelationName(char *relname)
{
- if (relname[0] && relname[1] && relname[2])
- return (relname[0] == 'p' &&
- relname[1] == 'g' &&
- relname[2] == '_');
- else
- return FALSE;
+ if (relname[0] && relname[1] && relname[2])
+ return (relname[0] == 'p' &&
+ relname[1] == 'g' &&
+ relname[2] == '_');
+ else
+ return FALSE;
}
/*
* IsSharedSystemRelationName --
- * True iff name is the name of a shared system catalog relation.
+ * True iff name is the name of a shared system catalog relation.
*/
bool
IsSharedSystemRelationName(char *relname)
{
- int i;
-
- /*
- * Quick out: if it's not a system relation, it can't be a shared
- * system relation.
- */
- if (!IsSystemRelationName(relname))
+ int i;
+
+ /*
+ * Quick out: if it's not a system relation, it can't be a shared
+ * system relation.
+ */
+ if (!IsSystemRelationName(relname))
+ return FALSE;
+
+ i = 0;
+ while (SharedSystemRelationNames[i] != NULL)
+ {
+ if (strcmp(SharedSystemRelationNames[i], relname) == 0)
+ return TRUE;
+ i++;
+ }
return FALSE;
-
- i = 0;
- while ( SharedSystemRelationNames[i] != NULL) {
- if (strcmp(SharedSystemRelationNames[i],relname) == 0)
- return TRUE;
- i++;
- }
- return FALSE;
}
/*
- * newoid - returns a unique identifier across all catalogs.
+ * newoid - returns a unique identifier across all catalogs.
*
- * Object Id allocation is now done by GetNewObjectID in
- * access/transam/varsup.c. oids are now allocated correctly.
+ * Object Id allocation is now done by GetNewObjectID in
+ * access/transam/varsup.c. oids are now allocated correctly.
*
* old comments:
- * This needs to change soon, it fails if there are too many more
- * than one call per second when postgres restarts after it dies.
+ * This needs to change soon, it fails if there are too many more
+ * than one call per second when postgres restarts after it dies.
*
- * The distribution of OID's should be done by the POSTMASTER.
- * Also there needs to be a facility to preallocate OID's. Ie.,
- * for a block of OID's to be declared as invalid ones to allow
- * user programs to use them for temporary object identifiers.
+ * The distribution of OID's should be done by the POSTMASTER.
+ * Also there needs to be a facility to preallocate OID's. Ie.,
+ * for a block of OID's to be declared as invalid ones to allow
+ * user programs to use them for temporary object identifiers.
*/
-Oid newoid()
+Oid
+newoid()
{
- Oid lastoid;
-
- GetNewObjectId(&lastoid);
- if (! OidIsValid(lastoid))
- elog(WARN, "newoid: GetNewObjectId returns invalid oid");
- return lastoid;
+ Oid lastoid;
+
+ GetNewObjectId(&lastoid);
+ if (!OidIsValid(lastoid))
+ elog(WARN, "newoid: GetNewObjectId returns invalid oid");
+ return lastoid;
}
/*
- * fillatt - fills the ATTRIBUTE relation fields from the TYP
+ * fillatt - fills the ATTRIBUTE relation fields from the TYP
*
- * Expects that the atttypid domain is set for each att[].
- * Returns with the attnum, and attlen domains set.
- * attnum, attproc, atttyparg, ... should be set by the user.
+ * Expects that the atttypid domain is set for each att[].
+ * Returns with the attnum, and attlen domains set.
+ * attnum, attproc, atttyparg, ... should be set by the user.
*
- * In the future, attnum may not be set?!? or may be passed as an arg?!?
+ * In the future, attnum may not be set?!? or may be passed as an arg?!?
*
- * Current implementation is very inefficient--should cashe the
- * information if this is at all possible.
+ * Current implementation is very inefficient--should cashe the
+ * information if this is at all possible.
*
- * Check to see if this is really needed, and especially in the case
- * of index tuples.
+ * Check to see if this is really needed, and especially in the case
+ * of index tuples.
*/
void
fillatt(TupleDesc tupleDesc)
{
- AttributeTupleForm *attributeP;
- register TypeTupleForm typp;
- HeapTuple tuple;
- int i;
- int natts = tupleDesc->natts;
- AttributeTupleForm *att = tupleDesc->attrs;
-
- if (natts < 0 || natts > MaxHeapAttributeNumber)
- elog(WARN, "fillatt: %d attributes is too large", natts);
- if (natts == 0) {
- elog(DEBUG, "fillatt: called with natts == 0");
- return;
- }
-
- attributeP = &att[0];
-
- for (i = 0; i < natts;) {
- tuple = SearchSysCacheTuple(TYPOID,
- Int32GetDatum((*attributeP)->atttypid),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "fillatt: unknown atttypid %ld",
- (*attributeP)->atttypid);
- } else {
- (*attributeP)->attnum = (int16) ++i;
- /* Check if the attr is a set before messing with the length
- and byval, since those were already set in
- TupleDescInitEntry. In fact, this seems redundant
- here, but who knows what I'll break if I take it out...
-
- same for char() and varchar() stuff. I share the same
- sentiments. This function is poorly written anyway. -ay 6/95
- */
- if (!(*attributeP)->attisset &&
- (*attributeP)->atttypid!=BPCHAROID &&
- (*attributeP)->atttypid!=VARCHAROID) {
-
- typp = (TypeTupleForm) GETSTRUCT(tuple); /* XXX */
- (*attributeP)->attlen = typp->typlen;
- (*attributeP)->attbyval = typp->typbyval;
- }
+ AttributeTupleForm *attributeP;
+ register TypeTupleForm typp;
+ HeapTuple tuple;
+ int i;
+ int natts = tupleDesc->natts;
+ AttributeTupleForm *att = tupleDesc->attrs;
+
+ if (natts < 0 || natts > MaxHeapAttributeNumber)
+ elog(WARN, "fillatt: %d attributes is too large", natts);
+ if (natts == 0)
+ {
+ elog(DEBUG, "fillatt: called with natts == 0");
+ return;
+ }
+
+ attributeP = &att[0];
+
+ for (i = 0; i < natts;)
+ {
+ tuple = SearchSysCacheTuple(TYPOID,
+ Int32GetDatum((*attributeP)->atttypid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "fillatt: unknown atttypid %ld",
+ (*attributeP)->atttypid);
+ }
+ else
+ {
+ (*attributeP)->attnum = (int16)++ i;
+
+ /*
+ * Check if the attr is a set before messing with the length
+ * and byval, since those were already set in
+ * TupleDescInitEntry. In fact, this seems redundant here,
+ * but who knows what I'll break if I take it out...
+ *
+ * same for char() and varchar() stuff. I share the same
+ * sentiments. This function is poorly written anyway. -ay
+ * 6/95
+ */
+ if (!(*attributeP)->attisset &&
+ (*attributeP)->atttypid != BPCHAROID &&
+ (*attributeP)->atttypid != VARCHAROID)
+ {
+
+ typp = (TypeTupleForm) GETSTRUCT(tuple); /* XXX */
+ (*attributeP)->attlen = typp->typlen;
+ (*attributeP)->attbyval = typp->typbyval;
+ }
+ }
+ attributeP += 1;
}
- attributeP += 1;
- }
}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index cbbbd9df004..c80ddb9727e 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1,26 +1,26 @@
/*-------------------------------------------------------------------------
*
* heap.c--
- * code to create and destroy POSTGRES heap relations
+ * code to create and destroy POSTGRES heap relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.24 1997/09/05 18:13:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.25 1997/09/07 04:40:10 momjian Exp $
*
* INTERFACE ROUTINES
- * heap_creatr() - Create an uncataloged heap relation
- * heap_create() - Create a cataloged relation
- * heap_destroy() - Removes named relation from catalogs
+ * heap_creatr() - Create an uncataloged heap relation
+ * heap_create() - Create a cataloged relation
+ * heap_destroy() - Removes named relation from catalogs
*
* NOTES
- * this code taken from access/heap/create.c, which contains
- * the old heap_creater, amcreate, and amdestroy. those routines
- * will soon call these routines using the function manager,
- * just like the poorly named "NewXXX" routines do. The
- * "New" routines are all going to die soon, once and for all!
- * -cim 1/13/91
+ * this code taken from access/heap/create.c, which contains
+ * the old heap_creater, amcreate, and amdestroy. those routines
+ * will soon call these routines using the function manager,
+ * just like the poorly named "NewXXX" routines do. The
+ * "New" routines are all going to die soon, once and for all!
+ * -cim 1/13/91
*
*-------------------------------------------------------------------------
*/
@@ -53,103 +53,104 @@
#include <utils/relcache.h>
#include <nodes/plannodes.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static void AddPgRelationTuple(Relation pg_class_desc,
- Relation new_rel_desc, Oid new_rel_oid, int arch, unsigned natts);
-static void AddToTempRelList(Relation r);
-static void DeletePgAttributeTuples(Relation rdesc);
-static void DeletePgRelationTuple(Relation rdesc);
-static void DeletePgTypeTuple(Relation rdesc);
-static int RelationAlreadyExists(Relation pg_class_desc, char relname[]);
-static void RelationRemoveIndexes(Relation relation);
-static void RelationRemoveInheritance(Relation relation);
-static void RemoveFromTempRelList(Relation r);
-static void addNewRelationType(char *typeName, Oid new_rel_oid);
-static void StoreConstraints (Relation rel);
-static void RemoveConstraints (Relation rel);
+static void
+AddPgRelationTuple(Relation pg_class_desc,
+ Relation new_rel_desc, Oid new_rel_oid, int arch, unsigned natts);
+static void AddToTempRelList(Relation r);
+static void DeletePgAttributeTuples(Relation rdesc);
+static void DeletePgRelationTuple(Relation rdesc);
+static void DeletePgTypeTuple(Relation rdesc);
+static int RelationAlreadyExists(Relation pg_class_desc, char relname[]);
+static void RelationRemoveIndexes(Relation relation);
+static void RelationRemoveInheritance(Relation relation);
+static void RemoveFromTempRelList(Relation r);
+static void addNewRelationType(char *typeName, Oid new_rel_oid);
+static void StoreConstraints(Relation rel);
+static void RemoveConstraints(Relation rel);
/* ----------------------------------------------------------------
- * XXX UGLY HARD CODED BADNESS FOLLOWS XXX
+ * XXX UGLY HARD CODED BADNESS FOLLOWS XXX
*
- * these should all be moved to someplace in the lib/catalog
- * module, if not obliterated first.
+ * these should all be moved to someplace in the lib/catalog
+ * module, if not obliterated first.
* ----------------------------------------------------------------
*/
/*
* Note:
- * Should the executor special case these attributes in the future?
- * Advantage: consume 1/2 the space in the ATTRIBUTE relation.
- * Disadvantage: having rules to compute values in these tuples may
- * be more difficult if not impossible.
+ * Should the executor special case these attributes in the future?
+ * Advantage: consume 1/2 the space in the ATTRIBUTE relation.
+ * Disadvantage: having rules to compute values in these tuples may
+ * be more difficult if not impossible.
*/
-static FormData_pg_attribute a1 = {
- 0xffffffff, {"ctid"}, 27l, 0l, sizeof (ItemPointerData),
- SelfItemPointerAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a1 = {
+ 0xffffffff, {"ctid"}, 27l, 0l, sizeof(ItemPointerData),
+ SelfItemPointerAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a2 = {
- 0xffffffff, {"oid"}, 26l, 0l, sizeof(Oid),
- ObjectIdAttributeNumber, 0, -1, '\001', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a2 = {
+ 0xffffffff, {"oid"}, 26l, 0l, sizeof(Oid),
+ ObjectIdAttributeNumber, 0, -1, '\001', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a3 = {
- 0xffffffff, {"xmin"}, 28l, 0l, sizeof (TransactionId),
- MinTransactionIdAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a3 = {
+ 0xffffffff, {"xmin"}, 28l, 0l, sizeof(TransactionId),
+ MinTransactionIdAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a4 = {
- 0xffffffff, {"cmin"}, 29l, 0l, sizeof (CommandId),
- MinCommandIdAttributeNumber, 0, -1, '\001', '\0', 's', '\0', '\0'
+static FormData_pg_attribute a4 = {
+ 0xffffffff, {"cmin"}, 29l, 0l, sizeof(CommandId),
+ MinCommandIdAttributeNumber, 0, -1, '\001', '\0', 's', '\0', '\0'
};
-static FormData_pg_attribute a5 = {
- 0xffffffff, {"xmax"}, 28l, 0l, sizeof (TransactionId),
- MaxTransactionIdAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a5 = {
+ 0xffffffff, {"xmax"}, 28l, 0l, sizeof(TransactionId),
+ MaxTransactionIdAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a6 = {
- 0xffffffff, {"cmax"}, 29l, 0l, sizeof (CommandId),
- MaxCommandIdAttributeNumber, 0, -1, '\001', '\0', 's', '\0', '\0'
+static FormData_pg_attribute a6 = {
+ 0xffffffff, {"cmax"}, 29l, 0l, sizeof(CommandId),
+ MaxCommandIdAttributeNumber, 0, -1, '\001', '\0', 's', '\0', '\0'
};
-static FormData_pg_attribute a7 = {
- 0xffffffff, {"chain"}, 27l, 0l, sizeof (ItemPointerData),
- ChainItemPointerAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a7 = {
+ 0xffffffff, {"chain"}, 27l, 0l, sizeof(ItemPointerData),
+ ChainItemPointerAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a8 = {
- 0xffffffff, {"anchor"}, 27l, 0l, sizeof (ItemPointerData),
- AnchorItemPointerAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a8 = {
+ 0xffffffff, {"anchor"}, 27l, 0l, sizeof(ItemPointerData),
+ AnchorItemPointerAttributeNumber, 0, -1, '\0', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a9 = {
- 0xffffffff, {"tmin"}, 702l, 0l, sizeof (AbsoluteTime),
- MinAbsoluteTimeAttributeNumber, 0, -1, '\001', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a9 = {
+ 0xffffffff, {"tmin"}, 702l, 0l, sizeof(AbsoluteTime),
+ MinAbsoluteTimeAttributeNumber, 0, -1, '\001', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a10 = {
- 0xffffffff, {"tmax"}, 702l, 0l, sizeof (AbsoluteTime),
- MaxAbsoluteTimeAttributeNumber, 0, -1, '\001', '\0', 'i', '\0', '\0'
+static FormData_pg_attribute a10 = {
+ 0xffffffff, {"tmax"}, 702l, 0l, sizeof(AbsoluteTime),
+ MaxAbsoluteTimeAttributeNumber, 0, -1, '\001', '\0', 'i', '\0', '\0'
};
-static FormData_pg_attribute a11 = {
- 0xffffffff, {"vtype"}, 18l, 0l, sizeof (char),
- VersionTypeAttributeNumber, 0, -1, '\001', '\0', 'c', '\0', '\0'
+static FormData_pg_attribute a11 = {
+ 0xffffffff, {"vtype"}, 18l, 0l, sizeof(char),
+ VersionTypeAttributeNumber, 0, -1, '\001', '\0', 'c', '\0', '\0'
};
-static AttributeTupleForm HeapAtt[] =
-{ &a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11 };
+static AttributeTupleForm HeapAtt[] =
+{&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8, &a9, &a10, &a11};
/* ----------------------------------------------------------------
- * XXX END OF UGLY HARD CODED BADNESS XXX
+ * XXX END OF UGLY HARD CODED BADNESS XXX
* ----------------------------------------------------------------
*/
@@ -157,1227 +158,1261 @@ static AttributeTupleForm HeapAtt[] =
the list of temporary uncatalogued relations that are created.
these relations should be destroyed at the end of transactions
*/
-typedef struct tempRelList {
- Relation *rels; /* array of relation descriptors */
- int num; /* number of temporary relations */
- int size; /* size of space allocated for the rels array */
-} TempRelList;
+typedef struct tempRelList
+{
+ Relation *rels; /* array of relation descriptors */
+ int num; /* number of temporary relations */
+ int size; /* size of space allocated for the rels
+ * array */
+} TempRelList;
-#define TEMP_REL_LIST_SIZE 32
+#define TEMP_REL_LIST_SIZE 32
-static TempRelList *tempRels = NULL;
+static TempRelList *tempRels = NULL;
/* ----------------------------------------------------------------
- * heap_creatr - Create an uncataloged heap relation
+ * heap_creatr - Create an uncataloged heap relation
*
- * Fields relpages, reltuples, reltuples, relkeys, relhistory,
- * relisindexed, and relkind of rdesc->rd_rel are initialized
- * to all zeros, as are rd_last and rd_hook. Rd_refcnt is set to 1.
+ * Fields relpages, reltuples, reltuples, relkeys, relhistory,
+ * relisindexed, and relkind of rdesc->rd_rel are initialized
+ * to all zeros, as are rd_last and rd_hook. Rd_refcnt is set to 1.
*
- * Remove the system relation specific code to elsewhere eventually.
+ * Remove the system relation specific code to elsewhere eventually.
+ *
+ * Eventually, must place information about this temporary relation
+ * into the transaction context block.
*
- * Eventually, must place information about this temporary relation
- * into the transaction context block.
*
- *
* if heap_creatr is called with "" as the name, then heap_creatr will create a
- * temporary name "temp_$RELOID" for the relation
+ * temporary name "temp_$RELOID" for the relation
* ----------------------------------------------------------------
*/
Relation
-heap_creatr(char *name,
- unsigned smgr,
- TupleDesc tupDesc)
+heap_creatr(char *name,
+ unsigned smgr,
+ TupleDesc tupDesc)
{
- register unsigned i;
- Oid relid;
- Relation rdesc;
- int len;
- bool nailme = false;
- char* relname = name;
- char tempname[40];
- int isTemp = 0;
- int natts = tupDesc->natts;
-/* AttributeTupleForm *att = tupDesc->attrs; */
-
- extern GlobalMemory CacheCxt;
- MemoryContext oldcxt;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertArg(natts > 0);
-
- if (IsSystemRelationName(relname) && IsNormalProcessingMode())
+ register unsigned i;
+ Oid relid;
+ Relation rdesc;
+ int len;
+ bool nailme = false;
+ char *relname = name;
+ char tempname[40];
+ int isTemp = 0;
+ int natts = tupDesc->natts;
+
+/* AttributeTupleForm *att = tupDesc->attrs; */
+
+ extern GlobalMemory CacheCxt;
+ MemoryContext oldcxt;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ AssertArg(natts > 0);
+
+ if (IsSystemRelationName(relname) && IsNormalProcessingMode())
{
- elog(WARN,
+ elog(WARN,
"Illegal class name: %s -- pg_ is reserved for system catalogs",
- relname);
+ relname);
+ }
+
+ /* ----------------
+ * switch to the cache context so that we don't lose
+ * allocations at the end of this transaction, I guess.
+ * -cim 6/14/90
+ * ----------------
+ */
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * real ugly stuff to assign the proper relid in the relation
+ * descriptor follows.
+ * ----------------
+ */
+ if (!strcmp(RelationRelationName, relname))
+ {
+ relid = RelOid_pg_class;
+ nailme = true;
}
-
- /* ----------------
- * switch to the cache context so that we don't lose
- * allocations at the end of this transaction, I guess.
- * -cim 6/14/90
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * real ugly stuff to assign the proper relid in the relation
- * descriptor follows.
- * ----------------
- */
- if (! strcmp(RelationRelationName,relname))
+ else if (!strcmp(AttributeRelationName, relname))
{
- relid = RelOid_pg_class;
- nailme = true;
+ relid = RelOid_pg_attribute;
+ nailme = true;
}
- else if (! strcmp(AttributeRelationName,relname))
+ else if (!strcmp(ProcedureRelationName, relname))
{
- relid = RelOid_pg_attribute;
- nailme = true;
+ relid = RelOid_pg_proc;
+ nailme = true;
}
- else if (! strcmp(ProcedureRelationName, relname))
+ else if (!strcmp(TypeRelationName, relname))
{
- relid = RelOid_pg_proc;
- nailme = true;
+ relid = RelOid_pg_type;
+ nailme = true;
}
- else if (! strcmp(TypeRelationName,relname))
+ else
{
- relid = RelOid_pg_type;
- nailme = true;
+ relid = newoid();
+
+ if (name[0] == '\0')
+ {
+ sprintf(tempname, "temp_%d", relid);
+ relname = tempname;
+ isTemp = 1;
+ }
}
- else
- {
- relid = newoid();
-
- if (name[0] == '\0')
- {
- sprintf(tempname, "temp_%d", relid);
- relname = tempname;
- isTemp = 1;
- }
- }
-
- /* ----------------
- * allocate a new relation descriptor.
- *
- * XXX the length computation may be incorrect, handle elsewhere
- * ----------------
- */
- len = sizeof(RelationData);
-
- rdesc = (Relation) palloc(len);
- memset((char *)rdesc, 0,len);
-
- /* ----------
- create a new tuple descriptor from the one passed in
- */
- rdesc->rd_att = CreateTupleDescCopyConstr(tupDesc);
-
- /* ----------------
- * initialize the fields of our new relation descriptor
- * ----------------
- */
-
- /* ----------------
- * nail the reldesc if this is a bootstrap create reln and
- * we may need it in the cache later on in the bootstrap
- * process so we don't ever want it kicked out. e.g. pg_attribute!!!
- * ----------------
- */
- if (nailme)
- rdesc->rd_isnailed = true;
-
- RelationSetReferenceCount(rdesc, 1);
-
- rdesc->rd_rel = (Form_pg_class)palloc(sizeof *rdesc->rd_rel);
-
- memset((char *)rdesc->rd_rel, 0,
- sizeof *rdesc->rd_rel);
- namestrcpy(&(rdesc->rd_rel->relname), relname);
- rdesc->rd_rel->relkind = RELKIND_UNCATALOGED;
- rdesc->rd_rel->relnatts = natts;
- rdesc->rd_rel->relsmgr = smgr;
- if ( tupDesc->constr )
- rdesc->rd_rel->relchecks = tupDesc->constr->num_check;
-
- for (i = 0; i < natts; i++) {
- rdesc->rd_att->attrs[i]->attrelid = relid;
- }
-
- rdesc->rd_id = relid;
-
- if (nailme) {
- /* for system relations, set the reltype field here */
- rdesc->rd_rel->reltype = relid;
- }
-
- /* ----------------
- * remember if this is a temp relation
- * ----------------
- */
-
- rdesc->rd_istemp = isTemp;
-
- /* ----------------
- * have the storage manager create the relation.
- * ----------------
- */
-
- rdesc->rd_tmpunlinked = TRUE; /* change once table is created */
- rdesc->rd_fd = (File)smgrcreate(smgr, rdesc);
- rdesc->rd_tmpunlinked = FALSE;
-
- RelationRegisterRelation(rdesc);
-
- MemoryContextSwitchTo(oldcxt);
-
- /* add all temporary relations to the tempRels list
- so they can be properly disposed of at the end of transaction
- */
- if (isTemp)
- AddToTempRelList(rdesc);
-
- return (rdesc);
+
+ /* ----------------
+ * allocate a new relation descriptor.
+ *
+ * XXX the length computation may be incorrect, handle elsewhere
+ * ----------------
+ */
+ len = sizeof(RelationData);
+
+ rdesc = (Relation) palloc(len);
+ memset((char *) rdesc, 0, len);
+
+ /* ----------
+ create a new tuple descriptor from the one passed in
+ */
+ rdesc->rd_att = CreateTupleDescCopyConstr(tupDesc);
+
+ /* ----------------
+ * initialize the fields of our new relation descriptor
+ * ----------------
+ */
+
+ /* ----------------
+ * nail the reldesc if this is a bootstrap create reln and
+ * we may need it in the cache later on in the bootstrap
+ * process so we don't ever want it kicked out. e.g. pg_attribute!!!
+ * ----------------
+ */
+ if (nailme)
+ rdesc->rd_isnailed = true;
+
+ RelationSetReferenceCount(rdesc, 1);
+
+ rdesc->rd_rel = (Form_pg_class) palloc(sizeof *rdesc->rd_rel);
+
+ memset((char *) rdesc->rd_rel, 0,
+ sizeof *rdesc->rd_rel);
+ namestrcpy(&(rdesc->rd_rel->relname), relname);
+ rdesc->rd_rel->relkind = RELKIND_UNCATALOGED;
+ rdesc->rd_rel->relnatts = natts;
+ rdesc->rd_rel->relsmgr = smgr;
+ if (tupDesc->constr)
+ rdesc->rd_rel->relchecks = tupDesc->constr->num_check;
+
+ for (i = 0; i < natts; i++)
+ {
+ rdesc->rd_att->attrs[i]->attrelid = relid;
+ }
+
+ rdesc->rd_id = relid;
+
+ if (nailme)
+ {
+ /* for system relations, set the reltype field here */
+ rdesc->rd_rel->reltype = relid;
+ }
+
+ /* ----------------
+ * remember if this is a temp relation
+ * ----------------
+ */
+
+ rdesc->rd_istemp = isTemp;
+
+ /* ----------------
+ * have the storage manager create the relation.
+ * ----------------
+ */
+
+ rdesc->rd_tmpunlinked = TRUE; /* change once table is created */
+ rdesc->rd_fd = (File) smgrcreate(smgr, rdesc);
+ rdesc->rd_tmpunlinked = FALSE;
+
+ RelationRegisterRelation(rdesc);
+
+ MemoryContextSwitchTo(oldcxt);
+
+ /*
+ * add all temporary relations to the tempRels list so they can be
+ * properly disposed of at the end of transaction
+ */
+ if (isTemp)
+ AddToTempRelList(rdesc);
+
+ return (rdesc);
}
/* ----------------------------------------------------------------
- * heap_create - Create a cataloged relation
+ * heap_create - Create a cataloged relation
*
- * this is done in 6 steps:
+ * this is done in 6 steps:
*
- * 1) CheckAttributeNames() is used to make certain the tuple
- * descriptor contains a valid set of attribute names
+ * 1) CheckAttributeNames() is used to make certain the tuple
+ * descriptor contains a valid set of attribute names
*
- * 2) pg_class is opened and RelationAlreadyExists()
- * preforms a scan to ensure that no relation with the
- * same name already exists.
+ * 2) pg_class is opened and RelationAlreadyExists()
+ * preforms a scan to ensure that no relation with the
+ * same name already exists.
*
- * 3) heap_creater() is called to create the new relation on
- * disk.
+ * 3) heap_creater() is called to create the new relation on
+ * disk.
*
- * 4) TypeDefine() is called to define a new type corresponding
- * to the new relation.
+ * 4) TypeDefine() is called to define a new type corresponding
+ * to the new relation.
*
- * 5) AddNewAttributeTuples() is called to register the
- * new relation's schema in pg_attribute.
+ * 5) AddNewAttributeTuples() is called to register the
+ * new relation's schema in pg_attribute.
*
- * 6) AddPgRelationTuple() is called to register the
- * relation itself in the catalogs.
- *
- * 7) StoreConstraints is called () - vadim 08/22/97
+ * 6) AddPgRelationTuple() is called to register the
+ * relation itself in the catalogs.
*
- * 8) the relations are closed and the new relation's oid
- * is returned.
+ * 7) StoreConstraints is called () - vadim 08/22/97
+ *
+ * 8) the relations are closed and the new relation's oid
+ * is returned.
*
* old comments:
- * A new relation is inserted into the RELATION relation
- * with the specified attribute(s) (newly inserted into
- * the ATTRIBUTE relation). How does concurrency control
- * work? Is it automatic now? Expects the caller to have
- * attname, atttypid, atttyparg, attproc, and attlen domains filled.
- * Create fills the attnum domains sequentually from zero,
- * fills the attdisbursion domains with zeros, and fills the
- * attrelid fields with the relid.
+ * A new relation is inserted into the RELATION relation
+ * with the specified attribute(s) (newly inserted into
+ * the ATTRIBUTE relation). How does concurrency control
+ * work? Is it automatic now? Expects the caller to have
+ * attname, atttypid, atttyparg, attproc, and attlen domains filled.
+ * Create fills the attnum domains sequentually from zero,
+ * fills the attdisbursion domains with zeros, and fills the
+ * attrelid fields with the relid.
+ *
+ * scan relation catalog for name conflict
+ * scan type catalog for typids (if not arg)
+ * create and insert attribute(s) into attribute catalog
+ * create new relation
+ * insert new relation into attribute catalog
*
- * scan relation catalog for name conflict
- * scan type catalog for typids (if not arg)
- * create and insert attribute(s) into attribute catalog
- * create new relation
- * insert new relation into attribute catalog
+ * Should coordinate with heap_creater(). Either it should
+ * not be called or there should be a way to prevent
+ * the relation from being removed at the end of the
+ * transaction if it is successful ('u'/'r' may be enough).
+ * Also, if the transaction does not commit, then the
+ * relation should be removed.
*
- * Should coordinate with heap_creater(). Either it should
- * not be called or there should be a way to prevent
- * the relation from being removed at the end of the
- * transaction if it is successful ('u'/'r' may be enough).
- * Also, if the transaction does not commit, then the
- * relation should be removed.
+ * XXX amcreate ignores "off" when inserting (for now).
+ * XXX amcreate (like the other utilities) needs to understand indexes.
*
- * XXX amcreate ignores "off" when inserting (for now).
- * XXX amcreate (like the other utilities) needs to understand indexes.
- *
* ----------------------------------------------------------------
*/
/* --------------------------------
- * CheckAttributeNames
+ * CheckAttributeNames
*
- * this is used to make certain the tuple descriptor contains a
- * valid set of attribute names. a problem simply generates
- * elog(WARN) which aborts the current transaction.
+ * this is used to make certain the tuple descriptor contains a
+ * valid set of attribute names. a problem simply generates
+ * elog(WARN) which aborts the current transaction.
* --------------------------------
*/
static void
CheckAttributeNames(TupleDesc tupdesc)
{
- unsigned i;
- unsigned j;
- int natts = tupdesc->natts;
-
- /* ----------------
- * first check for collision with system attribute names
- * ----------------
- *
- * also, warn user if attribute to be created has
- * an unknown typid (usually as a result of a 'retrieve into'
- * - jolly
- */
- for (i = 0; i < natts; i += 1) {
- for (j = 0; j < sizeof HeapAtt / sizeof HeapAtt[0]; j += 1) {
- if (nameeq(&(HeapAtt[j]->attname),
- &(tupdesc->attrs[i]->attname))) {
- elog(WARN,
- "create: system attribute named \"%s\"",
- HeapAtt[j]->attname.data);
- }
+ unsigned i;
+ unsigned j;
+ int natts = tupdesc->natts;
+
+ /* ----------------
+ * first check for collision with system attribute names
+ * ----------------
+ *
+ * also, warn user if attribute to be created has
+ * an unknown typid (usually as a result of a 'retrieve into'
+ * - jolly
+ */
+ for (i = 0; i < natts; i += 1)
+ {
+ for (j = 0; j < sizeof HeapAtt / sizeof HeapAtt[0]; j += 1)
+ {
+ if (nameeq(&(HeapAtt[j]->attname),
+ &(tupdesc->attrs[i]->attname)))
+ {
+ elog(WARN,
+ "create: system attribute named \"%s\"",
+ HeapAtt[j]->attname.data);
+ }
+ }
+ if (tupdesc->attrs[i]->atttypid == UNKNOWNOID)
+ {
+ elog(NOTICE,
+ "create: attribute named \"%s\" has an unknown type",
+ tupdesc->attrs[i]->attname.data);
+ }
}
- if (tupdesc->attrs[i]->atttypid == UNKNOWNOID)
- {
- elog(NOTICE,
- "create: attribute named \"%s\" has an unknown type",
- tupdesc->attrs[i]->attname.data);
- }
- }
-
- /* ----------------
- * next check for repeated attribute names
- * ----------------
- */
- for (i = 1; i < natts; i += 1) {
- for (j = 0; j < i; j += 1) {
- if (nameeq(&(tupdesc->attrs[j]->attname),
- &(tupdesc->attrs[i]->attname))) {
- elog(WARN,
- "create: repeated attribute \"%s\"",
- tupdesc->attrs[j]->attname.data);
- }
+
+ /* ----------------
+ * next check for repeated attribute names
+ * ----------------
+ */
+ for (i = 1; i < natts; i += 1)
+ {
+ for (j = 0; j < i; j += 1)
+ {
+ if (nameeq(&(tupdesc->attrs[j]->attname),
+ &(tupdesc->attrs[i]->attname)))
+ {
+ elog(WARN,
+ "create: repeated attribute \"%s\"",
+ tupdesc->attrs[j]->attname.data);
+ }
+ }
}
- }
}
/* --------------------------------
- * RelationAlreadyExists
+ * RelationAlreadyExists
*
- * this preforms a scan of pg_class to ensure that
- * no relation with the same name already exists. The caller
- * has to open pg_class and pass an open descriptor.
+ * this preforms a scan of pg_class to ensure that
+ * no relation with the same name already exists. The caller
+ * has to open pg_class and pass an open descriptor.
* --------------------------------
*/
static int
RelationAlreadyExists(Relation pg_class_desc, char relname[])
{
- ScanKeyData key;
- HeapScanDesc pg_class_scan;
- HeapTuple tup;
-
- /*
- * If this is not bootstrap (initdb) time, use the catalog index
- * on pg_class.
- */
-
- if (!IsBootstrapProcessingMode()) {
- tup = ClassNameIndexScan(pg_class_desc, relname);
- if (HeapTupleIsValid(tup)) {
- pfree(tup);
- return ((int) true);
- } else
- return ((int) false);
- }
-
- /* ----------------
- * At bootstrap time, we have to do this the hard way. Form the
- * scan key.
- * ----------------
- */
- ScanKeyEntryInitialize(&key,
- 0,
- (AttrNumber)Anum_pg_class_relname,
- (RegProcedure)NameEqualRegProcedure,
- (Datum) relname);
-
- /* ----------------
- * begin the scan
- * ----------------
- */
- pg_class_scan = heap_beginscan(pg_class_desc,
- 0,
- NowTimeQual,
- 1,
- &key);
-
- /* ----------------
- * get a tuple. if the tuple is NULL then it means we
- * didn't find an existing relation.
- * ----------------
- */
- tup = heap_getnext(pg_class_scan, 0, (Buffer *)NULL);
-
- /* ----------------
- * end the scan and return existance of relation.
- * ----------------
- */
- heap_endscan(pg_class_scan);
-
- return
- (PointerIsValid(tup) == true);
+ ScanKeyData key;
+ HeapScanDesc pg_class_scan;
+ HeapTuple tup;
+
+ /*
+ * If this is not bootstrap (initdb) time, use the catalog index on
+ * pg_class.
+ */
+
+ if (!IsBootstrapProcessingMode())
+ {
+ tup = ClassNameIndexScan(pg_class_desc, relname);
+ if (HeapTupleIsValid(tup))
+ {
+ pfree(tup);
+ return ((int) true);
+ }
+ else
+ return ((int) false);
+ }
+
+ /* ----------------
+ * At bootstrap time, we have to do this the hard way. Form the
+ * scan key.
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key,
+ 0,
+ (AttrNumber) Anum_pg_class_relname,
+ (RegProcedure) NameEqualRegProcedure,
+ (Datum) relname);
+
+ /* ----------------
+ * begin the scan
+ * ----------------
+ */
+ pg_class_scan = heap_beginscan(pg_class_desc,
+ 0,
+ NowTimeQual,
+ 1,
+ &key);
+
+ /* ----------------
+ * get a tuple. if the tuple is NULL then it means we
+ * didn't find an existing relation.
+ * ----------------
+ */
+ tup = heap_getnext(pg_class_scan, 0, (Buffer *) NULL);
+
+ /* ----------------
+ * end the scan and return existance of relation.
+ * ----------------
+ */
+ heap_endscan(pg_class_scan);
+
+ return
+ (PointerIsValid(tup) == true);
}
/* --------------------------------
- * AddNewAttributeTuples
+ * AddNewAttributeTuples
*
- * this registers the new relation's schema by adding
- * tuples to pg_attribute.
+ * this registers the new relation's schema by adding
+ * tuples to pg_attribute.
* --------------------------------
*/
static void
AddNewAttributeTuples(Oid new_rel_oid,
- TupleDesc tupdesc)
+ TupleDesc tupdesc)
{
- AttributeTupleForm *dpp;
- unsigned i;
- HeapTuple tup;
- Relation rdesc;
- bool hasindex;
- Relation idescs[Num_pg_attr_indices];
- int natts = tupdesc->natts;
-
- /* ----------------
- * open pg_attribute
- * ----------------
- */
- rdesc = heap_openr(AttributeRelationName);
-
- /* -----------------
- * Check if we have any indices defined on pg_attribute.
- * -----------------
- */
- Assert(rdesc);
- Assert(rdesc->rd_rel);
- hasindex = RelationGetRelationTupleForm(rdesc)->relhasindex;
- if (hasindex)
- CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
-
- /* ----------------
- * initialize tuple descriptor. Note we use setheapoverride()
- * so that we can see the effects of our TypeDefine() done
- * previously.
- * ----------------
- */
- setheapoverride(true);
- fillatt(tupdesc);
- setheapoverride(false);
-
- /* ----------------
- * first we add the user attributes..
- * ----------------
- */
- dpp = tupdesc->attrs;
- for (i = 0; i < natts; i++) {
- (*dpp)->attrelid = new_rel_oid;
- (*dpp)->attdisbursion = 0;
-
- tup = heap_addheader(Natts_pg_attribute,
- ATTRIBUTE_TUPLE_SIZE,
- (char *) *dpp);
-
- heap_insert(rdesc, tup);
+ AttributeTupleForm *dpp;
+ unsigned i;
+ HeapTuple tup;
+ Relation rdesc;
+ bool hasindex;
+ Relation idescs[Num_pg_attr_indices];
+ int natts = tupdesc->natts;
+
+ /* ----------------
+ * open pg_attribute
+ * ----------------
+ */
+ rdesc = heap_openr(AttributeRelationName);
+
+ /* -----------------
+ * Check if we have any indices defined on pg_attribute.
+ * -----------------
+ */
+ Assert(rdesc);
+ Assert(rdesc->rd_rel);
+ hasindex = RelationGetRelationTupleForm(rdesc)->relhasindex;
if (hasindex)
- CatalogIndexInsert(idescs, Num_pg_attr_indices, rdesc, tup);
-
- pfree(tup);
- dpp++;
- }
-
- /* ----------------
- * next we add the system attributes..
- * ----------------
- */
- dpp = HeapAtt;
- for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) {
- (*dpp)->attrelid = new_rel_oid;
- /* (*dpp)->attdisbursion = 0; unneeded */
-
- tup = heap_addheader(Natts_pg_attribute,
- ATTRIBUTE_TUPLE_SIZE,
- (char *)*dpp);
-
- heap_insert(rdesc, tup);
-
+ CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
+
+ /* ----------------
+ * initialize tuple descriptor. Note we use setheapoverride()
+ * so that we can see the effects of our TypeDefine() done
+ * previously.
+ * ----------------
+ */
+ setheapoverride(true);
+ fillatt(tupdesc);
+ setheapoverride(false);
+
+ /* ----------------
+ * first we add the user attributes..
+ * ----------------
+ */
+ dpp = tupdesc->attrs;
+ for (i = 0; i < natts; i++)
+ {
+ (*dpp)->attrelid = new_rel_oid;
+ (*dpp)->attdisbursion = 0;
+
+ tup = heap_addheader(Natts_pg_attribute,
+ ATTRIBUTE_TUPLE_SIZE,
+ (char *) *dpp);
+
+ heap_insert(rdesc, tup);
+ if (hasindex)
+ CatalogIndexInsert(idescs, Num_pg_attr_indices, rdesc, tup);
+
+ pfree(tup);
+ dpp++;
+ }
+
+ /* ----------------
+ * next we add the system attributes..
+ * ----------------
+ */
+ dpp = HeapAtt;
+ for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++)
+ {
+ (*dpp)->attrelid = new_rel_oid;
+ /* (*dpp)->attdisbursion = 0; unneeded */
+
+ tup = heap_addheader(Natts_pg_attribute,
+ ATTRIBUTE_TUPLE_SIZE,
+ (char *) *dpp);
+
+ heap_insert(rdesc, tup);
+
+ if (hasindex)
+ CatalogIndexInsert(idescs, Num_pg_attr_indices, rdesc, tup);
+
+ pfree(tup);
+ dpp++;
+ }
+
+ heap_close(rdesc);
+
+ /*
+ * close pg_attribute indices
+ */
if (hasindex)
- CatalogIndexInsert(idescs, Num_pg_attr_indices, rdesc, tup);
-
- pfree(tup);
- dpp++;
- }
-
- heap_close(rdesc);
-
- /*
- * close pg_attribute indices
- */
- if (hasindex)
- CatalogCloseIndices(Num_pg_attr_indices, idescs);
+ CatalogCloseIndices(Num_pg_attr_indices, idescs);
}
/* --------------------------------
- * AddPgRelationTuple
+ * AddPgRelationTuple
*
- * this registers the new relation in the catalogs by
- * adding a tuple to pg_class.
+ * this registers the new relation in the catalogs by
+ * adding a tuple to pg_class.
* --------------------------------
*/
static void
AddPgRelationTuple(Relation pg_class_desc,
- Relation new_rel_desc,
- Oid new_rel_oid,
- int arch,
- unsigned natts)
+ Relation new_rel_desc,
+ Oid new_rel_oid,
+ int arch,
+ unsigned natts)
{
- Form_pg_class new_rel_reltup;
- HeapTuple tup;
- Relation idescs[Num_pg_class_indices];
- bool isBootstrap;
- extern bool ItsSequenceCreation; /* It's hack, I know...
- * - vadim 03/28/97 */
- /* ----------------
- * first we munge some of the information in our
- * uncataloged relation's relation descriptor.
- * ----------------
- */
- new_rel_reltup = new_rel_desc->rd_rel;
-
- /* CHECK should get new_rel_oid first via an insert then use XXX */
- /* new_rel_reltup->reltuples = 1; */ /* XXX */
-
- new_rel_reltup->relowner = GetUserId();
- if ( ItsSequenceCreation )
- new_rel_reltup->relkind = RELKIND_SEQUENCE;
- else
- new_rel_reltup->relkind = RELKIND_RELATION;
- new_rel_reltup->relarch = arch;
- new_rel_reltup->relnatts = natts;
-
- /* ----------------
- * now form a tuple to add to pg_class
- * XXX Natts_pg_class_fixed is a hack - see pg_class.h
- * ----------------
- */
- tup = heap_addheader(Natts_pg_class_fixed,
- CLASS_TUPLE_SIZE,
- (char *) new_rel_reltup);
- tup->t_oid = new_rel_oid;
-
- /* ----------------
- * finally insert the new tuple and free it.
- *
- * Note: I have no idea why we do a
- * SetProcessingMode(BootstrapProcessing);
- * here -cim 6/14/90
- * ----------------
- */
- isBootstrap = IsBootstrapProcessingMode() ? true : false;
-
- SetProcessingMode(BootstrapProcessing);
-
- heap_insert(pg_class_desc, tup);
-
- if (! isBootstrap) {
- /*
- * First, open the catalog indices and insert index tuples for
- * the new relation.
- */
-
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class_desc, tup);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
-
- /* now restore processing mode */
- SetProcessingMode(NormalProcessing);
- }
-
- pfree(tup);
+ Form_pg_class new_rel_reltup;
+ HeapTuple tup;
+ Relation idescs[Num_pg_class_indices];
+ bool isBootstrap;
+ extern bool ItsSequenceCreation; /* It's hack, I know... -
+ * vadim 03/28/97 */
+
+ /* ----------------
+ * first we munge some of the information in our
+ * uncataloged relation's relation descriptor.
+ * ----------------
+ */
+ new_rel_reltup = new_rel_desc->rd_rel;
+
+ /* CHECK should get new_rel_oid first via an insert then use XXX */
+ /* new_rel_reltup->reltuples = 1; *//* XXX */
+
+ new_rel_reltup->relowner = GetUserId();
+ if (ItsSequenceCreation)
+ new_rel_reltup->relkind = RELKIND_SEQUENCE;
+ else
+ new_rel_reltup->relkind = RELKIND_RELATION;
+ new_rel_reltup->relarch = arch;
+ new_rel_reltup->relnatts = natts;
+
+ /* ----------------
+ * now form a tuple to add to pg_class
+ * XXX Natts_pg_class_fixed is a hack - see pg_class.h
+ * ----------------
+ */
+ tup = heap_addheader(Natts_pg_class_fixed,
+ CLASS_TUPLE_SIZE,
+ (char *) new_rel_reltup);
+ tup->t_oid = new_rel_oid;
+
+ /* ----------------
+ * finally insert the new tuple and free it.
+ *
+ * Note: I have no idea why we do a
+ * SetProcessingMode(BootstrapProcessing);
+ * here -cim 6/14/90
+ * ----------------
+ */
+ isBootstrap = IsBootstrapProcessingMode() ? true : false;
+
+ SetProcessingMode(BootstrapProcessing);
+
+ heap_insert(pg_class_desc, tup);
+
+ if (!isBootstrap)
+ {
+
+ /*
+ * First, open the catalog indices and insert index tuples for the
+ * new relation.
+ */
+
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class_desc, tup);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+ /* now restore processing mode */
+ SetProcessingMode(NormalProcessing);
+ }
+
+ pfree(tup);
}
/* --------------------------------
- * addNewRelationType -
+ * addNewRelationType -
*
- * define a complex type corresponding to the new relation
+ * define a complex type corresponding to the new relation
* --------------------------------
*/
static void
addNewRelationType(char *typeName, Oid new_rel_oid)
{
- Oid new_type_oid;
-
- /* The sizes are set to oid size because it makes implementing sets MUCH
- * easier, and no one (we hope) uses these fields to figure out
- * how much space to allocate for the type.
- * An oid is the type used for a set definition. When a user
- * requests a set, what they actually get is the oid of a tuple in
- * the pg_proc catalog, so the size of the "set" is the size
- * of an oid.
- * Similarly, byval being true makes sets much easier, and
- * it isn't used by anything else.
- * Note the assumption that OIDs are the same size as int4s.
- */
- new_type_oid = TypeCreate(typeName, /* type name */
- new_rel_oid, /* relation oid */
- tlen(type("oid")), /* internal size */
- tlen(type("oid")), /* external size */
- 'c', /* type-type (catalog) */
- ',', /* default array delimiter */
- "int4in", /* input procedure */
- "int4out", /* output procedure */
- "int4in", /* send procedure */
- "int4out", /* receive procedure */
- NULL, /* array element type - irrelevent */
- "-", /* default type value */
- (bool) 1, /* passed by value */
- 'i'); /* default alignment */
+ Oid new_type_oid;
+
+ /*
+ * The sizes are set to oid size because it makes implementing sets
+ * MUCH easier, and no one (we hope) uses these fields to figure out
+ * how much space to allocate for the type. An oid is the type used
+ * for a set definition. When a user requests a set, what they
+ * actually get is the oid of a tuple in the pg_proc catalog, so the
+ * size of the "set" is the size of an oid. Similarly, byval being
+ * true makes sets much easier, and it isn't used by anything else.
+ * Note the assumption that OIDs are the same size as int4s.
+ */
+ new_type_oid = TypeCreate(typeName, /* type name */
+ new_rel_oid, /* relation oid */
+ tlen(type("oid")), /* internal size */
+ tlen(type("oid")), /* external size */
+ 'c', /* type-type (catalog) */
+ ',', /* default array delimiter */
+ "int4in", /* input procedure */
+ "int4out", /* output procedure */
+ "int4in", /* send procedure */
+ "int4out", /* receive procedure */
+ NULL, /* array element type - irrelevent */
+ "-", /* default type value */
+ (bool) 1, /* passed by value */
+ 'i'); /* default alignment */
}
/* --------------------------------
- * heap_create
+ * heap_create
*
- * creates a new cataloged relation. see comments above.
+ * creates a new cataloged relation. see comments above.
* --------------------------------
*/
Oid
heap_create(char relname[],
- char *typename, /* not used currently */
- int arch,
- unsigned smgr,
- TupleDesc tupdesc)
+ char *typename, /* not used currently */
+ int arch,
+ unsigned smgr,
+ TupleDesc tupdesc)
{
- Relation pg_class_desc;
- Relation new_rel_desc;
- Oid new_rel_oid;
-/* NameData typeNameData; */
- int natts = tupdesc->natts;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertState(IsNormalProcessingMode() || IsBootstrapProcessingMode());
- if (natts == 0 || natts > MaxHeapAttributeNumber)
- elog(WARN, "amcreate: from 1 to %d attributes must be specified",
- MaxHeapAttributeNumber);
-
- CheckAttributeNames(tupdesc);
-
- /* ----------------
- * open pg_class and see that the relation doesn't
- * already exist.
- * ----------------
- */
- pg_class_desc = heap_openr(RelationRelationName);
-
- if (RelationAlreadyExists(pg_class_desc, relname)) {
+ Relation pg_class_desc;
+ Relation new_rel_desc;
+ Oid new_rel_oid;
+
+/* NameData typeNameData; */
+ int natts = tupdesc->natts;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ AssertState(IsNormalProcessingMode() || IsBootstrapProcessingMode());
+ if (natts == 0 || natts > MaxHeapAttributeNumber)
+ elog(WARN, "amcreate: from 1 to %d attributes must be specified",
+ MaxHeapAttributeNumber);
+
+ CheckAttributeNames(tupdesc);
+
+ /* ----------------
+ * open pg_class and see that the relation doesn't
+ * already exist.
+ * ----------------
+ */
+ pg_class_desc = heap_openr(RelationRelationName);
+
+ if (RelationAlreadyExists(pg_class_desc, relname))
+ {
+ heap_close(pg_class_desc);
+ elog(WARN, "amcreate: %s relation already exists", relname);
+ }
+
+ /* ----------------
+ * ok, relation does not already exist so now we
+ * create an uncataloged relation and pull its relation oid
+ * from the newly formed relation descriptor.
+ *
+ * Note: The call to heap_creatr() does all the "real" work
+ * of creating the disk file for the relation.
+ * ----------------
+ */
+ new_rel_desc = heap_creatr(relname, smgr, tupdesc);
+ new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid;
+
+ /* ----------------
+ * since defining a relation also defines a complex type,
+ * we add a new system type corresponding to the new relation.
+ * ----------------
+ */
+/* namestrcpy(&typeNameData, relname);*/
+/* addNewRelationType(&typeNameData, new_rel_oid);*/
+ addNewRelationType(relname, new_rel_oid);
+
+ /* ----------------
+ * now add tuples to pg_attribute for the attributes in
+ * our new relation.
+ * ----------------
+ */
+ AddNewAttributeTuples(new_rel_oid, tupdesc);
+
+ /* ----------------
+ * now update the information in pg_class.
+ * ----------------
+ */
+ AddPgRelationTuple(pg_class_desc,
+ new_rel_desc,
+ new_rel_oid,
+ arch,
+ natts);
+
+ StoreConstraints(new_rel_desc);
+
+ /* ----------------
+ * ok, the relation has been cataloged, so close our relations
+ * and return the oid of the newly created relation.
+ *
+ * SOMEDAY: fill the STATISTIC relation properly.
+ * ----------------
+ */
+ heap_close(new_rel_desc);
heap_close(pg_class_desc);
- elog(WARN, "amcreate: %s relation already exists", relname);
- }
-
- /* ----------------
- * ok, relation does not already exist so now we
- * create an uncataloged relation and pull its relation oid
- * from the newly formed relation descriptor.
- *
- * Note: The call to heap_creatr() does all the "real" work
- * of creating the disk file for the relation.
- * ----------------
- */
- new_rel_desc = heap_creatr(relname, smgr, tupdesc);
- new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid;
-
- /* ----------------
- * since defining a relation also defines a complex type,
- * we add a new system type corresponding to the new relation.
- * ----------------
- */
-/* namestrcpy(&typeNameData, relname);*/
-/* addNewRelationType(&typeNameData, new_rel_oid);*/
- addNewRelationType(relname, new_rel_oid);
-
- /* ----------------
- * now add tuples to pg_attribute for the attributes in
- * our new relation.
- * ----------------
- */
- AddNewAttributeTuples(new_rel_oid, tupdesc);
-
- /* ----------------
- * now update the information in pg_class.
- * ----------------
- */
- AddPgRelationTuple(pg_class_desc,
- new_rel_desc,
- new_rel_oid,
- arch,
- natts);
-
- StoreConstraints (new_rel_desc);
-
- /* ----------------
- * ok, the relation has been cataloged, so close our relations
- * and return the oid of the newly created relation.
- *
- * SOMEDAY: fill the STATISTIC relation properly.
- * ----------------
- */
- heap_close(new_rel_desc);
- heap_close(pg_class_desc);
-
- return new_rel_oid;
+
+ return new_rel_oid;
}
/* ----------------------------------------------------------------
- * heap_destroy - removes all record of named relation from catalogs
+ * heap_destroy - removes all record of named relation from catalogs
*
- * 1) open relation, check for existence, etc.
- * 2) remove inheritance information
- * 3) remove indexes
- * 4) remove pg_class tuple
- * 5) remove pg_attribute tuples
- * 6) remove pg_type tuples
- * 7) RemoveConstraints ()
- * 8) unlink relation
+ * 1) open relation, check for existence, etc.
+ * 2) remove inheritance information
+ * 3) remove indexes
+ * 4) remove pg_class tuple
+ * 5) remove pg_attribute tuples
+ * 6) remove pg_type tuples
+ * 7) RemoveConstraints ()
+ * 8) unlink relation
*
* old comments
- * Except for vital relations, removes relation from
- * relation catalog, and related attributes from
- * attribute catalog (needed?). (Anything else?)
+ * Except for vital relations, removes relation from
+ * relation catalog, and related attributes from
+ * attribute catalog (needed?). (Anything else?)
*
- * get proper relation from relation catalog (if not arg)
- * check if relation is vital (strcmp()/reltype?)
- * scan attribute catalog deleting attributes of reldesc
- * (necessary?)
- * delete relation from relation catalog
- * (How are the tuples of the relation discarded?)
+ * get proper relation from relation catalog (if not arg)
+ * check if relation is vital (strcmp()/reltype?)
+ * scan attribute catalog deleting attributes of reldesc
+ * (necessary?)
+ * delete relation from relation catalog
+ * (How are the tuples of the relation discarded?)
*
- * XXX Must fix to work with indexes.
- * There may be a better order for doing things.
- * Problems with destroying a deleted database--cannot create
- * a struct reldesc without having an open file descriptor.
+ * XXX Must fix to work with indexes.
+ * There may be a better order for doing things.
+ * Problems with destroying a deleted database--cannot create
+ * a struct reldesc without having an open file descriptor.
* ----------------------------------------------------------------
*/
/* --------------------------------
- * RelationRemoveInheritance
+ * RelationRemoveInheritance
*
- * Note: for now, we cause an exception if relation is a
- * superclass. Someday, we may want to allow this and merge
- * the type info into subclass procedures.... this seems like
- * lots of work.
+ * Note: for now, we cause an exception if relation is a
+ * superclass. Someday, we may want to allow this and merge
+ * the type info into subclass procedures.... this seems like
+ * lots of work.
* --------------------------------
*/
static void
RelationRemoveInheritance(Relation relation)
{
- Relation catalogRelation;
- HeapTuple tuple;
- HeapScanDesc scan;
- ScanKeyData entry;
-
- /* ----------------
- * open pg_inherits
- * ----------------
- */
- catalogRelation = heap_openr(InheritsRelationName);
-
- /* ----------------
- * form a scan key for the subclasses of this class
- * and begin scanning
- * ----------------
- */
- ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_inherits_inhparent,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(RelationGetRelationId(relation)));
-
- scan = heap_beginscan(catalogRelation,
- false,
- NowTimeQual,
- 1,
- &entry);
-
- /* ----------------
- * if any subclasses exist, then we disallow the deletion.
- * ----------------
- */
- tuple = heap_getnext(scan, 0, (Buffer *)NULL);
- if (HeapTupleIsValid(tuple)) {
+ Relation catalogRelation;
+ HeapTuple tuple;
+ HeapScanDesc scan;
+ ScanKeyData entry;
+
+ /* ----------------
+ * open pg_inherits
+ * ----------------
+ */
+ catalogRelation = heap_openr(InheritsRelationName);
+
+ /* ----------------
+ * form a scan key for the subclasses of this class
+ * and begin scanning
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_inherits_inhparent,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(RelationGetRelationId(relation)));
+
+ scan = heap_beginscan(catalogRelation,
+ false,
+ NowTimeQual,
+ 1,
+ &entry);
+
+ /* ----------------
+ * if any subclasses exist, then we disallow the deletion.
+ * ----------------
+ */
+ tuple = heap_getnext(scan, 0, (Buffer *) NULL);
+ if (HeapTupleIsValid(tuple))
+ {
+ heap_endscan(scan);
+ heap_close(catalogRelation);
+
+ elog(WARN, "relation <%d> inherits \"%s\"",
+ ((InheritsTupleForm) GETSTRUCT(tuple))->inhrel,
+ RelationGetRelationName(relation));
+ }
+
+ /* ----------------
+ * If we get here, it means the relation has no subclasses
+ * so we can trash it. First we remove dead INHERITS tuples.
+ * ----------------
+ */
+ entry.sk_attno = Anum_pg_inherits_inhrel;
+
+ scan = heap_beginscan(catalogRelation,
+ false,
+ NowTimeQual,
+ 1,
+ &entry);
+
+ for (;;)
+ {
+ tuple = heap_getnext(scan, 0, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ break;
+ }
+ heap_delete(catalogRelation, &tuple->t_ctid);
+ }
+
heap_endscan(scan);
heap_close(catalogRelation);
-
- elog(WARN, "relation <%d> inherits \"%s\"",
- ((InheritsTupleForm) GETSTRUCT(tuple))->inhrel,
- RelationGetRelationName(relation));
- }
-
- /* ----------------
- * If we get here, it means the relation has no subclasses
- * so we can trash it. First we remove dead INHERITS tuples.
- * ----------------
- */
- entry.sk_attno = Anum_pg_inherits_inhrel;
-
- scan = heap_beginscan(catalogRelation,
- false,
- NowTimeQual,
- 1,
- &entry);
-
- for (;;) {
- tuple = heap_getnext(scan, 0, (Buffer *)NULL);
- if (!HeapTupleIsValid(tuple)) {
- break;
- }
- heap_delete(catalogRelation, &tuple->t_ctid);
- }
-
- heap_endscan(scan);
- heap_close(catalogRelation);
-
- /* ----------------
- * now remove dead IPL tuples
- * ----------------
- */
- catalogRelation =
- heap_openr(InheritancePrecidenceListRelationName);
-
- entry.sk_attno = Anum_pg_ipl_iplrel;
-
- scan = heap_beginscan(catalogRelation,
- false,
- NowTimeQual,
- 1,
- &entry);
-
- for (;;) {
- tuple = heap_getnext(scan, 0, (Buffer *)NULL);
- if (!HeapTupleIsValid(tuple)) {
- break;
+
+ /* ----------------
+ * now remove dead IPL tuples
+ * ----------------
+ */
+ catalogRelation =
+ heap_openr(InheritancePrecidenceListRelationName);
+
+ entry.sk_attno = Anum_pg_ipl_iplrel;
+
+ scan = heap_beginscan(catalogRelation,
+ false,
+ NowTimeQual,
+ 1,
+ &entry);
+
+ for (;;)
+ {
+ tuple = heap_getnext(scan, 0, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ break;
+ }
+ heap_delete(catalogRelation, &tuple->t_ctid);
}
- heap_delete(catalogRelation, &tuple->t_ctid);
- }
-
- heap_endscan(scan);
- heap_close(catalogRelation);
+
+ heap_endscan(scan);
+ heap_close(catalogRelation);
}
/* --------------------------------
- * RelationRemoveIndexes
- *
+ * RelationRemoveIndexes
+ *
* --------------------------------
*/
static void
RelationRemoveIndexes(Relation relation)
{
- Relation indexRelation;
- HeapTuple tuple;
- HeapScanDesc scan;
- ScanKeyData entry;
-
- indexRelation = heap_openr(IndexRelationName);
-
- ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(RelationGetRelationId(relation)));
-
- scan = heap_beginscan(indexRelation,
- false,
- NowTimeQual,
- 1,
- &entry);
-
- for (;;) {
- tuple = heap_getnext(scan, 0, (Buffer *)NULL);
- if (!HeapTupleIsValid(tuple)) {
- break;
+ Relation indexRelation;
+ HeapTuple tuple;
+ HeapScanDesc scan;
+ ScanKeyData entry;
+
+ indexRelation = heap_openr(IndexRelationName);
+
+ ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(RelationGetRelationId(relation)));
+
+ scan = heap_beginscan(indexRelation,
+ false,
+ NowTimeQual,
+ 1,
+ &entry);
+
+ for (;;)
+ {
+ tuple = heap_getnext(scan, 0, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ break;
+ }
+
+ index_destroy(((IndexTupleForm) GETSTRUCT(tuple))->indexrelid);
}
-
- index_destroy(((IndexTupleForm)GETSTRUCT(tuple))->indexrelid);
- }
-
- heap_endscan(scan);
- heap_close(indexRelation);
+
+ heap_endscan(scan);
+ heap_close(indexRelation);
}
/* --------------------------------
- * DeletePgRelationTuple
+ * DeletePgRelationTuple
*
* --------------------------------
*/
static void
DeletePgRelationTuple(Relation rdesc)
{
- Relation pg_class_desc;
- HeapScanDesc pg_class_scan;
- ScanKeyData key;
- HeapTuple tup;
-
- /* ----------------
- * open pg_class
- * ----------------
- */
- pg_class_desc = heap_openr(RelationRelationName);
-
- /* ----------------
- * create a scan key to locate the relation oid of the
- * relation to delete
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
- F_INT4EQ, rdesc->rd_att->attrs[0]->attrelid);
-
- pg_class_scan = heap_beginscan(pg_class_desc,
- 0,
- NowTimeQual,
- 1,
- &key);
-
- /* ----------------
- * use heap_getnext() to fetch the pg_class tuple. If this
- * tuple is not valid then something's wrong.
- * ----------------
- */
- tup = heap_getnext(pg_class_scan, 0, (Buffer *) NULL);
-
- if (! PointerIsValid(tup)) {
+ Relation pg_class_desc;
+ HeapScanDesc pg_class_scan;
+ ScanKeyData key;
+ HeapTuple tup;
+
+ /* ----------------
+ * open pg_class
+ * ----------------
+ */
+ pg_class_desc = heap_openr(RelationRelationName);
+
+ /* ----------------
+ * create a scan key to locate the relation oid of the
+ * relation to delete
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
+ F_INT4EQ, rdesc->rd_att->attrs[0]->attrelid);
+
+ pg_class_scan = heap_beginscan(pg_class_desc,
+ 0,
+ NowTimeQual,
+ 1,
+ &key);
+
+ /* ----------------
+ * use heap_getnext() to fetch the pg_class tuple. If this
+ * tuple is not valid then something's wrong.
+ * ----------------
+ */
+ tup = heap_getnext(pg_class_scan, 0, (Buffer *) NULL);
+
+ if (!PointerIsValid(tup))
+ {
+ heap_endscan(pg_class_scan);
+ heap_close(pg_class_desc);
+ elog(WARN, "DeletePgRelationTuple: %s relation nonexistent",
+ &rdesc->rd_rel->relname);
+ }
+
+ /* ----------------
+ * delete the relation tuple from pg_class, and finish up.
+ * ----------------
+ */
heap_endscan(pg_class_scan);
+ heap_delete(pg_class_desc, &tup->t_ctid);
+
heap_close(pg_class_desc);
- elog(WARN, "DeletePgRelationTuple: %s relation nonexistent",
- &rdesc->rd_rel->relname);
- }
-
- /* ----------------
- * delete the relation tuple from pg_class, and finish up.
- * ----------------
- */
- heap_endscan(pg_class_scan);
- heap_delete(pg_class_desc, &tup->t_ctid);
-
- heap_close(pg_class_desc);
}
/* --------------------------------
- * DeletePgAttributeTuples
+ * DeletePgAttributeTuples
*
* --------------------------------
*/
static void
DeletePgAttributeTuples(Relation rdesc)
{
- Relation pg_attribute_desc;
- HeapScanDesc pg_attribute_scan;
- ScanKeyData key;
- HeapTuple tup;
-
- /* ----------------
- * open pg_attribute
- * ----------------
- */
- pg_attribute_desc = heap_openr(AttributeRelationName);
-
- /* ----------------
- * create a scan key to locate the attribute tuples to delete
- * and begin the scan.
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0, Anum_pg_attribute_attrelid,
- F_INT4EQ, rdesc->rd_att->attrs[0]->attrelid);
-
- /* -----------------
- * Get a write lock _before_ getting the read lock in the scan
- * ----------------
- */
- RelationSetLockForWrite(pg_attribute_desc);
-
- pg_attribute_scan = heap_beginscan(pg_attribute_desc,
- 0,
- NowTimeQual,
- 1,
- &key);
-
- /* ----------------
- * use heap_getnext() / amdelete() until all attribute tuples
- * have been deleted.
- * ----------------
- */
- while (tup = heap_getnext(pg_attribute_scan, 0, (Buffer *)NULL),
- PointerIsValid(tup)) {
-
- heap_delete(pg_attribute_desc, &tup->t_ctid);
- }
-
- /* ----------------
- * finish up.
- * ----------------
- */
- heap_endscan(pg_attribute_scan);
-
- /* ----------------
- * Release the write lock
- * ----------------
- */
- RelationUnsetLockForWrite(pg_attribute_desc);
- heap_close(pg_attribute_desc);
+ Relation pg_attribute_desc;
+ HeapScanDesc pg_attribute_scan;
+ ScanKeyData key;
+ HeapTuple tup;
+
+ /* ----------------
+ * open pg_attribute
+ * ----------------
+ */
+ pg_attribute_desc = heap_openr(AttributeRelationName);
+
+ /* ----------------
+ * create a scan key to locate the attribute tuples to delete
+ * and begin the scan.
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_attribute_attrelid,
+ F_INT4EQ, rdesc->rd_att->attrs[0]->attrelid);
+
+ /* -----------------
+ * Get a write lock _before_ getting the read lock in the scan
+ * ----------------
+ */
+ RelationSetLockForWrite(pg_attribute_desc);
+
+ pg_attribute_scan = heap_beginscan(pg_attribute_desc,
+ 0,
+ NowTimeQual,
+ 1,
+ &key);
+
+ /* ----------------
+ * use heap_getnext() / amdelete() until all attribute tuples
+ * have been deleted.
+ * ----------------
+ */
+ while (tup = heap_getnext(pg_attribute_scan, 0, (Buffer *) NULL),
+ PointerIsValid(tup))
+ {
+
+ heap_delete(pg_attribute_desc, &tup->t_ctid);
+ }
+
+ /* ----------------
+ * finish up.
+ * ----------------
+ */
+ heap_endscan(pg_attribute_scan);
+
+ /* ----------------
+ * Release the write lock
+ * ----------------
+ */
+ RelationUnsetLockForWrite(pg_attribute_desc);
+ heap_close(pg_attribute_desc);
}
/* --------------------------------
- * DeletePgTypeTuple
+ * DeletePgTypeTuple
*
- * If the user attempts to destroy a relation and there
- * exists attributes in other relations of type
- * "relation we are deleting", then we have to do something
- * special. presently we disallow the destroy.
+ * If the user attempts to destroy a relation and there
+ * exists attributes in other relations of type
+ * "relation we are deleting", then we have to do something
+ * special. presently we disallow the destroy.
* --------------------------------
*/
static void
DeletePgTypeTuple(Relation rdesc)
{
- Relation pg_type_desc;
- HeapScanDesc pg_type_scan;
- Relation pg_attribute_desc;
- HeapScanDesc pg_attribute_scan;
- ScanKeyData key;
- ScanKeyData attkey;
- HeapTuple tup;
- HeapTuple atttup;
- Oid typoid;
-
- /* ----------------
- * open pg_type
- * ----------------
- */
- pg_type_desc = heap_openr(TypeRelationName);
-
- /* ----------------
- * create a scan key to locate the type tuple corresponding
- * to this relation.
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0, Anum_pg_type_typrelid, F_INT4EQ,
- rdesc->rd_att->attrs[0]->attrelid);
-
- pg_type_scan = heap_beginscan(pg_type_desc,
- 0,
- NowTimeQual,
- 1,
- &key);
-
- /* ----------------
- * use heap_getnext() to fetch the pg_type tuple. If this
- * tuple is not valid then something's wrong.
- * ----------------
- */
- tup = heap_getnext(pg_type_scan, 0, (Buffer *)NULL);
-
- if (! PointerIsValid(tup)) {
- heap_endscan(pg_type_scan);
- heap_close(pg_type_desc);
- elog(WARN, "DeletePgTypeTuple: %s type nonexistent",
- &rdesc->rd_rel->relname);
- }
-
- /* ----------------
- * now scan pg_attribute. if any other relations have
- * attributes of the type of the relation we are deleteing
- * then we have to disallow the deletion. should talk to
- * stonebraker about this. -cim 6/19/90
- * ----------------
- */
- typoid = tup->t_oid;
-
- pg_attribute_desc = heap_openr(AttributeRelationName);
-
- ScanKeyEntryInitialize(&attkey,
- 0, Anum_pg_attribute_atttypid, F_INT4EQ,
- typoid);
-
- pg_attribute_scan = heap_beginscan(pg_attribute_desc,
- 0,
- NowTimeQual,
- 1,
- &attkey);
-
- /* ----------------
- * try and get a pg_attribute tuple. if we succeed it means
- * we cant delete the relation because something depends on
- * the schema.
- * ----------------
- */
- atttup = heap_getnext(pg_attribute_scan, 0, (Buffer *)NULL);
-
- if (PointerIsValid(atttup)) {
- Oid relid = ((AttributeTupleForm) GETSTRUCT(atttup))->attrelid;
-
- heap_endscan(pg_type_scan);
- heap_close(pg_type_desc);
+ Relation pg_type_desc;
+ HeapScanDesc pg_type_scan;
+ Relation pg_attribute_desc;
+ HeapScanDesc pg_attribute_scan;
+ ScanKeyData key;
+ ScanKeyData attkey;
+ HeapTuple tup;
+ HeapTuple atttup;
+ Oid typoid;
+
+ /* ----------------
+ * open pg_type
+ * ----------------
+ */
+ pg_type_desc = heap_openr(TypeRelationName);
+
+ /* ----------------
+ * create a scan key to locate the type tuple corresponding
+ * to this relation.
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_type_typrelid, F_INT4EQ,
+ rdesc->rd_att->attrs[0]->attrelid);
+
+ pg_type_scan = heap_beginscan(pg_type_desc,
+ 0,
+ NowTimeQual,
+ 1,
+ &key);
+
+ /* ----------------
+ * use heap_getnext() to fetch the pg_type tuple. If this
+ * tuple is not valid then something's wrong.
+ * ----------------
+ */
+ tup = heap_getnext(pg_type_scan, 0, (Buffer *) NULL);
+
+ if (!PointerIsValid(tup))
+ {
+ heap_endscan(pg_type_scan);
+ heap_close(pg_type_desc);
+ elog(WARN, "DeletePgTypeTuple: %s type nonexistent",
+ &rdesc->rd_rel->relname);
+ }
+
+ /* ----------------
+ * now scan pg_attribute. if any other relations have
+ * attributes of the type of the relation we are deleteing
+ * then we have to disallow the deletion. should talk to
+ * stonebraker about this. -cim 6/19/90
+ * ----------------
+ */
+ typoid = tup->t_oid;
+
+ pg_attribute_desc = heap_openr(AttributeRelationName);
+
+ ScanKeyEntryInitialize(&attkey,
+ 0, Anum_pg_attribute_atttypid, F_INT4EQ,
+ typoid);
+
+ pg_attribute_scan = heap_beginscan(pg_attribute_desc,
+ 0,
+ NowTimeQual,
+ 1,
+ &attkey);
+
+ /* ----------------
+ * try and get a pg_attribute tuple. if we succeed it means
+ * we cant delete the relation because something depends on
+ * the schema.
+ * ----------------
+ */
+ atttup = heap_getnext(pg_attribute_scan, 0, (Buffer *) NULL);
+
+ if (PointerIsValid(atttup))
+ {
+ Oid relid = ((AttributeTupleForm) GETSTRUCT(atttup))->attrelid;
+
+ heap_endscan(pg_type_scan);
+ heap_close(pg_type_desc);
+ heap_endscan(pg_attribute_scan);
+ heap_close(pg_attribute_desc);
+
+ elog(WARN, "DeletePgTypeTuple: att of type %s exists in relation %d",
+ &rdesc->rd_rel->relname, relid);
+ }
heap_endscan(pg_attribute_scan);
heap_close(pg_attribute_desc);
-
- elog(WARN, "DeletePgTypeTuple: att of type %s exists in relation %d",
- &rdesc->rd_rel->relname, relid);
- }
- heap_endscan(pg_attribute_scan);
- heap_close(pg_attribute_desc);
-
- /* ----------------
- * Ok, it's safe so we delete the relation tuple
- * from pg_type and finish up. But first end the scan so that
- * we release the read lock on pg_type. -mer 13 Aug 1991
- * ----------------
- */
- heap_endscan(pg_type_scan);
- heap_delete(pg_type_desc, &tup->t_ctid);
-
- heap_close(pg_type_desc);
+
+ /* ----------------
+ * Ok, it's safe so we delete the relation tuple
+ * from pg_type and finish up. But first end the scan so that
+ * we release the read lock on pg_type. -mer 13 Aug 1991
+ * ----------------
+ */
+ heap_endscan(pg_type_scan);
+ heap_delete(pg_type_desc, &tup->t_ctid);
+
+ heap_close(pg_type_desc);
}
/* --------------------------------
- * heap_destroy
+ * heap_destroy
*
* --------------------------------
*/
void
heap_destroy(char *relname)
{
- Relation rdesc;
- Oid rid;
-
- /* ----------------
- * first open the relation. if the relation does exist,
- * heap_openr() returns NULL.
- * ----------------
- */
- rdesc = heap_openr(relname);
- if ( rdesc == NULL )
- elog (WARN, "Relation %s Does Not Exist!", relname);
-
- RelationSetLockForWrite(rdesc);
- rid = rdesc->rd_id;
-
- /* ----------------
- * prevent deletion of system relations
- * ----------------
- */
- if (IsSystemRelationName(RelationGetRelationName(rdesc)->data))
- elog(WARN, "amdestroy: cannot destroy %s relation",
- &rdesc->rd_rel->relname);
-
- /* ----------------
- * remove inheritance information
- * ----------------
- */
- RelationRemoveInheritance(rdesc);
-
- /* ----------------
- * remove indexes if necessary
- * ----------------
- */
- if (rdesc->rd_rel->relhasindex) {
- RelationRemoveIndexes(rdesc);
- }
-
- /* ----------------
- * remove rules if necessary
- * ----------------
- */
- if (rdesc->rd_rules != NULL) {
- RelationRemoveRules(rid);
- }
-
- /* triggers */
- if ( rdesc->rd_rel->reltriggers > 0 )
- RelationRemoveTriggers (rdesc);
-
- /* ----------------
- * delete attribute tuples
- * ----------------
- */
- DeletePgAttributeTuples(rdesc);
-
- /* ----------------
- * delete type tuple. here we want to see the effects
- * of the deletions we just did, so we use setheapoverride().
- * ----------------
- */
- setheapoverride(true);
- DeletePgTypeTuple(rdesc);
- setheapoverride(false);
-
- /* ----------------
- * delete relation tuple
- * ----------------
- */
- DeletePgRelationTuple(rdesc);
-
- /*
- * release dirty buffers of this relation
- */
- ReleaseRelationBuffers (rdesc);
-
- /* ----------------
- * flush the relation from the relcache
- * ----------------
- * Does nothing!!! Flushing moved below. - vadim 06/04/97
- RelationIdInvalidateRelationCacheByRelationId(rdesc->rd_id);
- */
-
- RemoveConstraints (rdesc);
-
- /* ----------------
- * unlink the relation and finish up.
- * ----------------
- */
- if ( !(rdesc->rd_istemp) || !(rdesc->rd_tmpunlinked) )
- {
- smgrunlink(rdesc->rd_rel->relsmgr, rdesc);
- }
- rdesc->rd_tmpunlinked = TRUE;
-
- RelationUnsetLockForWrite(rdesc);
-
- heap_close(rdesc);
-
- /* ok - flush the relation from the relcache */
- RelationForgetRelation (rid);
+ Relation rdesc;
+ Oid rid;
+
+ /* ----------------
+ * first open the relation. if the relation does exist,
+ * heap_openr() returns NULL.
+ * ----------------
+ */
+ rdesc = heap_openr(relname);
+ if (rdesc == NULL)
+ elog(WARN, "Relation %s Does Not Exist!", relname);
+
+ RelationSetLockForWrite(rdesc);
+ rid = rdesc->rd_id;
+
+ /* ----------------
+ * prevent deletion of system relations
+ * ----------------
+ */
+ if (IsSystemRelationName(RelationGetRelationName(rdesc)->data))
+ elog(WARN, "amdestroy: cannot destroy %s relation",
+ &rdesc->rd_rel->relname);
+
+ /* ----------------
+ * remove inheritance information
+ * ----------------
+ */
+ RelationRemoveInheritance(rdesc);
+
+ /* ----------------
+ * remove indexes if necessary
+ * ----------------
+ */
+ if (rdesc->rd_rel->relhasindex)
+ {
+ RelationRemoveIndexes(rdesc);
+ }
+
+ /* ----------------
+ * remove rules if necessary
+ * ----------------
+ */
+ if (rdesc->rd_rules != NULL)
+ {
+ RelationRemoveRules(rid);
+ }
+
+ /* triggers */
+ if (rdesc->rd_rel->reltriggers > 0)
+ RelationRemoveTriggers(rdesc);
+
+ /* ----------------
+ * delete attribute tuples
+ * ----------------
+ */
+ DeletePgAttributeTuples(rdesc);
+
+ /* ----------------
+ * delete type tuple. here we want to see the effects
+ * of the deletions we just did, so we use setheapoverride().
+ * ----------------
+ */
+ setheapoverride(true);
+ DeletePgTypeTuple(rdesc);
+ setheapoverride(false);
+
+ /* ----------------
+ * delete relation tuple
+ * ----------------
+ */
+ DeletePgRelationTuple(rdesc);
+
+ /*
+ * release dirty buffers of this relation
+ */
+ ReleaseRelationBuffers(rdesc);
+
+ /* ----------------
+ * flush the relation from the relcache
+ * ----------------
+ * Does nothing!!! Flushing moved below. - vadim 06/04/97
+ RelationIdInvalidateRelationCacheByRelationId(rdesc->rd_id);
+ */
+
+ RemoveConstraints(rdesc);
+
+ /* ----------------
+ * unlink the relation and finish up.
+ * ----------------
+ */
+ if (!(rdesc->rd_istemp) || !(rdesc->rd_tmpunlinked))
+ {
+ smgrunlink(rdesc->rd_rel->relsmgr, rdesc);
+ }
+ rdesc->rd_tmpunlinked = TRUE;
+
+ RelationUnsetLockForWrite(rdesc);
+
+ heap_close(rdesc);
+
+ /* ok - flush the relation from the relcache */
+ RelationForgetRelation(rid);
}
/*
* heap_destroyr
- * destroy and close temporary relations
+ * destroy and close temporary relations
*
*/
-void
+void
heap_destroyr(Relation rdesc)
{
- ReleaseRelationBuffers(rdesc);
- if ( !(rdesc->rd_istemp) || !(rdesc->rd_tmpunlinked) )
- {
- smgrunlink(rdesc->rd_rel->relsmgr, rdesc);
- }
- rdesc->rd_tmpunlinked = TRUE;
- heap_close(rdesc);
- RemoveFromTempRelList(rdesc);
+ ReleaseRelationBuffers(rdesc);
+ if (!(rdesc->rd_istemp) || !(rdesc->rd_tmpunlinked))
+ {
+ smgrunlink(rdesc->rd_rel->relsmgr, rdesc);
+ }
+ rdesc->rd_tmpunlinked = TRUE;
+ heap_close(rdesc);
+ RemoveFromTempRelList(rdesc);
}
/**************************************************************
- functions to deal with the list of temporary relations
+ functions to deal with the list of temporary relations
**************************************************************/
/* --------------
@@ -1393,46 +1428,49 @@ heap_destroyr(Relation rdesc)
>> NOTE <<
malloc is used instead of palloc because we KNOW when we are
- going to free these things. Keeps us away from the memory context
+ going to free these things. Keeps us away from the memory context
hairyness
*/
void
InitTempRelList(void)
{
- if (tempRels) {
- free(tempRels->rels);
- free(tempRels);
- }
+ if (tempRels)
+ {
+ free(tempRels->rels);
+ free(tempRels);
+ }
- tempRels = (TempRelList*)malloc(sizeof(TempRelList));
- tempRels->size = TEMP_REL_LIST_SIZE;
- tempRels->rels = (Relation*)malloc(sizeof(Relation) * tempRels->size);
- memset(tempRels->rels, 0, sizeof(Relation) * tempRels->size);
- tempRels->num = 0;
+ tempRels = (TempRelList *) malloc(sizeof(TempRelList));
+ tempRels->size = TEMP_REL_LIST_SIZE;
+ tempRels->rels = (Relation *) malloc(sizeof(Relation) * tempRels->size);
+ memset(tempRels->rels, 0, sizeof(Relation) * tempRels->size);
+ tempRels->num = 0;
}
/*
removes a relation from the TempRelList
MODIFIES the global variable tempRels
- we don't really remove it, just mark it as NULL
- and DestroyTempRels will look for NULLs
+ we don't really remove it, just mark it as NULL
+ and DestroyTempRels will look for NULLs
*/
static void
RemoveFromTempRelList(Relation r)
{
- int i;
+ int i;
- if (!tempRels)
- return;
+ if (!tempRels)
+ return;
- for (i=0; i<tempRels->num; i++) {
- if (tempRels->rels[i] == r) {
- tempRels->rels[i] = NULL;
- break;
+ for (i = 0; i < tempRels->num; i++)
+ {
+ if (tempRels->rels[i] == r)
+ {
+ tempRels->rels[i] = NULL;
+ break;
+ }
}
- }
}
/*
@@ -1443,16 +1481,17 @@ RemoveFromTempRelList(Relation r)
static void
AddToTempRelList(Relation r)
{
- if (!tempRels)
- return;
+ if (!tempRels)
+ return;
- if (tempRels->num == tempRels->size) {
- tempRels->size += TEMP_REL_LIST_SIZE;
- tempRels->rels = realloc(tempRels->rels,
- sizeof(Relation) * tempRels->size);
- }
- tempRels->rels[tempRels->num] = r;
- tempRels->num++;
+ if (tempRels->num == tempRels->size)
+ {
+ tempRels->size += TEMP_REL_LIST_SIZE;
+ tempRels->rels = realloc(tempRels->rels,
+ sizeof(Relation) * tempRels->size);
+ }
+ tempRels->rels[tempRels->num] = r;
+ tempRels->num++;
}
/*
@@ -1461,251 +1500,253 @@ AddToTempRelList(Relation r)
void
DestroyTempRels(void)
{
- int i;
- Relation rdesc;
+ int i;
+ Relation rdesc;
- if (!tempRels)
- return;
+ if (!tempRels)
+ return;
- for (i=0;i<tempRels->num;i++) {
- rdesc = tempRels->rels[i];
- /* rdesc may be NULL if it has been removed from the list already */
- if (rdesc)
- heap_destroyr(rdesc);
- }
- free(tempRels->rels);
- free(tempRels);
- tempRels = NULL;
+ for (i = 0; i < tempRels->num; i++)
+ {
+ rdesc = tempRels->rels[i];
+ /* rdesc may be NULL if it has been removed from the list already */
+ if (rdesc)
+ heap_destroyr(rdesc);
+ }
+ free(tempRels->rels);
+ free(tempRels);
+ tempRels = NULL;
}
-extern List *flatten_tlist(List *tlist);
-extern List *pg_plan(char *query_string, Oid *typev, int nargs,
- QueryTreeList **queryListP, CommandDest dest);
+extern List *flatten_tlist(List * tlist);
+extern List *
+pg_plan(char *query_string, Oid * typev, int nargs,
+ QueryTreeList ** queryListP, CommandDest dest);
-static void
-StoreAttrDefault (Relation rel, AttrDefault *attrdef)
+static void
+StoreAttrDefault(Relation rel, AttrDefault * attrdef)
{
- char str[MAX_PARSE_BUFFER];
- char cast[2*NAMEDATALEN] = {0};
- AttributeTupleForm atp = rel->rd_att->attrs[attrdef->adnum - 1];
- QueryTreeList *queryTree_list;
- Query *query;
- List *planTree_list;
- TargetEntry *te;
- Resdom *resdom;
- Node *expr;
- char *adbin;
- MemoryContext oldcxt;
- Relation adrel;
- Relation idescs[Num_pg_attrdef_indices];
- HeapTuple tuple;
- Datum values[4];
- char nulls[4] = {' ', ' ', ' ', ' '};
- extern GlobalMemory CacheCxt;
-
+ char str[MAX_PARSE_BUFFER];
+ char cast[2 * NAMEDATALEN] = {0};
+ AttributeTupleForm atp = rel->rd_att->attrs[attrdef->adnum - 1];
+ QueryTreeList *queryTree_list;
+ Query *query;
+ List *planTree_list;
+ TargetEntry *te;
+ Resdom *resdom;
+ Node *expr;
+ char *adbin;
+ MemoryContext oldcxt;
+ Relation adrel;
+ Relation idescs[Num_pg_attrdef_indices];
+ HeapTuple tuple;
+ Datum values[4];
+ char nulls[4] = {' ', ' ', ' ', ' '};
+ extern GlobalMemory CacheCxt;
+
start:;
- sprintf (str, "select %s%s from %.*s", attrdef->adsrc, cast,
- NAMEDATALEN, rel->rd_rel->relname.data);
- setheapoverride(true);
- planTree_list = (List*) pg_plan (str, NULL, 0, &queryTree_list, None);
- setheapoverride(false);
- query = (Query*) (queryTree_list->qtrees[0]);
-
- if ( length (query->rtable) > 1 ||
- flatten_tlist (query->targetList) != NIL )
- elog (WARN, "DEFAULT: cannot use attribute(s)");
- te = (TargetEntry *) lfirst (query->targetList);
- resdom = te->resdom;
- expr = te->expr;
-
- if ( IsA (expr, Const) )
- {
- if ( ((Const*)expr)->consttype != atp->atttypid )
- {
- if ( *cast != 0 )
- elog (WARN, "DEFAULT: const type mismatched");
- sprintf (cast, ":: %s", get_id_typname (atp->atttypid));
- goto start;
- }
- }
- else if ( exprType (expr) != atp->atttypid )
- elog (WARN, "DEFAULT: type mismatched");
-
- adbin = nodeToString (expr);
- oldcxt = MemoryContextSwitchTo ((MemoryContext) CacheCxt);
- attrdef->adbin = (char*) palloc (strlen (adbin) + 1);
- strcpy (attrdef->adbin, adbin);
- (void) MemoryContextSwitchTo (oldcxt);
- pfree (adbin);
-
- values[Anum_pg_attrdef_adrelid - 1] = rel->rd_id;
- values[Anum_pg_attrdef_adnum - 1] = attrdef->adnum;
- values[Anum_pg_attrdef_adbin - 1] = PointerGetDatum (textin (attrdef->adbin));
- values[Anum_pg_attrdef_adsrc - 1] = PointerGetDatum (textin (attrdef->adsrc));
- adrel = heap_openr (AttrDefaultRelationName);
- tuple = heap_formtuple (adrel->rd_att, values, nulls);
- CatalogOpenIndices (Num_pg_attrdef_indices, Name_pg_attrdef_indices, idescs);
- heap_insert (adrel, tuple);
- CatalogIndexInsert (idescs, Num_pg_attrdef_indices, adrel, tuple);
- CatalogCloseIndices (Num_pg_attrdef_indices, idescs);
- heap_close (adrel);
-
- pfree (DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
- pfree (DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
- pfree (tuple);
+ sprintf(str, "select %s%s from %.*s", attrdef->adsrc, cast,
+ NAMEDATALEN, rel->rd_rel->relname.data);
+ setheapoverride(true);
+ planTree_list = (List *) pg_plan(str, NULL, 0, &queryTree_list, None);
+ setheapoverride(false);
+ query = (Query *) (queryTree_list->qtrees[0]);
+
+ if (length(query->rtable) > 1 ||
+ flatten_tlist(query->targetList) != NIL)
+ elog(WARN, "DEFAULT: cannot use attribute(s)");
+ te = (TargetEntry *) lfirst(query->targetList);
+ resdom = te->resdom;
+ expr = te->expr;
+
+ if (IsA(expr, Const))
+ {
+ if (((Const *) expr)->consttype != atp->atttypid)
+ {
+ if (*cast != 0)
+ elog(WARN, "DEFAULT: const type mismatched");
+ sprintf(cast, ":: %s", get_id_typname(atp->atttypid));
+ goto start;
+ }
+ }
+ else if (exprType(expr) != atp->atttypid)
+ elog(WARN, "DEFAULT: type mismatched");
+
+ adbin = nodeToString(expr);
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ attrdef->adbin = (char *) palloc(strlen(adbin) + 1);
+ strcpy(attrdef->adbin, adbin);
+ (void) MemoryContextSwitchTo(oldcxt);
+ pfree(adbin);
+
+ values[Anum_pg_attrdef_adrelid - 1] = rel->rd_id;
+ values[Anum_pg_attrdef_adnum - 1] = attrdef->adnum;
+ values[Anum_pg_attrdef_adbin - 1] = PointerGetDatum(textin(attrdef->adbin));
+ values[Anum_pg_attrdef_adsrc - 1] = PointerGetDatum(textin(attrdef->adsrc));
+ adrel = heap_openr(AttrDefaultRelationName);
+ tuple = heap_formtuple(adrel->rd_att, values, nulls);
+ CatalogOpenIndices(Num_pg_attrdef_indices, Name_pg_attrdef_indices, idescs);
+ heap_insert(adrel, tuple);
+ CatalogIndexInsert(idescs, Num_pg_attrdef_indices, adrel, tuple);
+ CatalogCloseIndices(Num_pg_attrdef_indices, idescs);
+ heap_close(adrel);
+
+ pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));
+ pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));
+ pfree(tuple);
}
-static void
-StoreRelCheck (Relation rel, ConstrCheck *check)
+static void
+StoreRelCheck(Relation rel, ConstrCheck * check)
{
- char str[MAX_PARSE_BUFFER];
- QueryTreeList *queryTree_list;
- Query *query;
- List *planTree_list;
- Plan *plan;
- List *qual;
- char *ccbin;
- MemoryContext oldcxt;
- Relation rcrel;
- Relation idescs[Num_pg_relcheck_indices];
- HeapTuple tuple;
- Datum values[4];
- char nulls[4] = {' ', ' ', ' ', ' '};
- extern GlobalMemory CacheCxt;
-
- sprintf (str, "select 1 from %.*s where %s",
- NAMEDATALEN, rel->rd_rel->relname.data, check->ccsrc);
- setheapoverride(true);
- planTree_list = (List*) pg_plan (str, NULL, 0, &queryTree_list, None);
- setheapoverride(false);
- query = (Query*) (queryTree_list->qtrees[0]);
-
- if ( length (query->rtable) > 1 )
- elog (WARN, "CHECK: only relation %.*s can be referenced",
- NAMEDATALEN, rel->rd_rel->relname.data);
-
- plan = (Plan*) lfirst(planTree_list);
- qual = plan->qual;
-
- ccbin = nodeToString (qual);
- oldcxt = MemoryContextSwitchTo ((MemoryContext) CacheCxt);
- check->ccbin = (char*) palloc (strlen (ccbin) + 1);
- strcpy (check->ccbin, ccbin);
- (void) MemoryContextSwitchTo (oldcxt);
- pfree (ccbin);
-
- values[Anum_pg_relcheck_rcrelid - 1] = rel->rd_id;
- values[Anum_pg_relcheck_rcname - 1] = PointerGetDatum (namein (check->ccname));
- values[Anum_pg_relcheck_rcbin - 1] = PointerGetDatum (textin (check->ccbin));
- values[Anum_pg_relcheck_rcsrc - 1] = PointerGetDatum (textin (check->ccsrc));
- rcrel = heap_openr (RelCheckRelationName);
- tuple = heap_formtuple (rcrel->rd_att, values, nulls);
- CatalogOpenIndices (Num_pg_relcheck_indices, Name_pg_relcheck_indices, idescs);
- heap_insert (rcrel, tuple);
- CatalogIndexInsert (idescs, Num_pg_relcheck_indices, rcrel, tuple);
- CatalogCloseIndices (Num_pg_relcheck_indices, idescs);
- heap_close (rcrel);
-
- pfree (DatumGetPointer(values[Anum_pg_relcheck_rcname - 1]));
- pfree (DatumGetPointer(values[Anum_pg_relcheck_rcbin - 1]));
- pfree (DatumGetPointer(values[Anum_pg_relcheck_rcsrc - 1]));
- pfree (tuple);
-
- return;
+ char str[MAX_PARSE_BUFFER];
+ QueryTreeList *queryTree_list;
+ Query *query;
+ List *planTree_list;
+ Plan *plan;
+ List *qual;
+ char *ccbin;
+ MemoryContext oldcxt;
+ Relation rcrel;
+ Relation idescs[Num_pg_relcheck_indices];
+ HeapTuple tuple;
+ Datum values[4];
+ char nulls[4] = {' ', ' ', ' ', ' '};
+ extern GlobalMemory CacheCxt;
+
+ sprintf(str, "select 1 from %.*s where %s",
+ NAMEDATALEN, rel->rd_rel->relname.data, check->ccsrc);
+ setheapoverride(true);
+ planTree_list = (List *) pg_plan(str, NULL, 0, &queryTree_list, None);
+ setheapoverride(false);
+ query = (Query *) (queryTree_list->qtrees[0]);
+
+ if (length(query->rtable) > 1)
+ elog(WARN, "CHECK: only relation %.*s can be referenced",
+ NAMEDATALEN, rel->rd_rel->relname.data);
+
+ plan = (Plan *) lfirst(planTree_list);
+ qual = plan->qual;
+
+ ccbin = nodeToString(qual);
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ check->ccbin = (char *) palloc(strlen(ccbin) + 1);
+ strcpy(check->ccbin, ccbin);
+ (void) MemoryContextSwitchTo(oldcxt);
+ pfree(ccbin);
+
+ values[Anum_pg_relcheck_rcrelid - 1] = rel->rd_id;
+ values[Anum_pg_relcheck_rcname - 1] = PointerGetDatum(namein(check->ccname));
+ values[Anum_pg_relcheck_rcbin - 1] = PointerGetDatum(textin(check->ccbin));
+ values[Anum_pg_relcheck_rcsrc - 1] = PointerGetDatum(textin(check->ccsrc));
+ rcrel = heap_openr(RelCheckRelationName);
+ tuple = heap_formtuple(rcrel->rd_att, values, nulls);
+ CatalogOpenIndices(Num_pg_relcheck_indices, Name_pg_relcheck_indices, idescs);
+ heap_insert(rcrel, tuple);
+ CatalogIndexInsert(idescs, Num_pg_relcheck_indices, rcrel, tuple);
+ CatalogCloseIndices(Num_pg_relcheck_indices, idescs);
+ heap_close(rcrel);
+
+ pfree(DatumGetPointer(values[Anum_pg_relcheck_rcname - 1]));
+ pfree(DatumGetPointer(values[Anum_pg_relcheck_rcbin - 1]));
+ pfree(DatumGetPointer(values[Anum_pg_relcheck_rcsrc - 1]));
+ pfree(tuple);
+
+ return;
}
-static void
-StoreConstraints (Relation rel)
+static void
+StoreConstraints(Relation rel)
{
- TupleConstr *constr = rel->rd_att->constr;
- int i;
-
- if ( !constr )
- return;
-
- if ( constr->num_defval > 0 )
- {
- for (i = 0; i < constr->num_defval; i++)
- StoreAttrDefault (rel, &(constr->defval[i]));
- }
-
- if ( constr->num_check > 0 )
- {
- for (i = 0; i < constr->num_check; i++)
- StoreRelCheck (rel, &(constr->check[i]));
- }
-
- return;
+ TupleConstr *constr = rel->rd_att->constr;
+ int i;
+
+ if (!constr)
+ return;
+
+ if (constr->num_defval > 0)
+ {
+ for (i = 0; i < constr->num_defval; i++)
+ StoreAttrDefault(rel, &(constr->defval[i]));
+ }
+
+ if (constr->num_check > 0)
+ {
+ for (i = 0; i < constr->num_check; i++)
+ StoreRelCheck(rel, &(constr->check[i]));
+ }
+
+ return;
}
-static void
-RemoveAttrDefault (Relation rel)
+static void
+RemoveAttrDefault(Relation rel)
{
- Relation adrel;
- HeapScanDesc adscan;
- ScanKeyData key;
- HeapTuple tup;
-
- adrel = heap_openr (AttrDefaultRelationName);
-
- ScanKeyEntryInitialize(&key, 0, Anum_pg_attrdef_adrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
-
- RelationSetLockForWrite (adrel);
-
- adscan = heap_beginscan(adrel, 0, NowTimeQual, 1, &key);
-
- while (tup = heap_getnext (adscan, 0, (Buffer *)NULL), PointerIsValid(tup))
- heap_delete (adrel, &tup->t_ctid);
-
- heap_endscan (adscan);
-
- RelationUnsetLockForWrite (adrel);
- heap_close (adrel);
+ Relation adrel;
+ HeapScanDesc adscan;
+ ScanKeyData key;
+ HeapTuple tup;
+
+ adrel = heap_openr(AttrDefaultRelationName);
+
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_attrdef_adrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+
+ RelationSetLockForWrite(adrel);
+
+ adscan = heap_beginscan(adrel, 0, NowTimeQual, 1, &key);
+
+ while (tup = heap_getnext(adscan, 0, (Buffer *) NULL), PointerIsValid(tup))
+ heap_delete(adrel, &tup->t_ctid);
+
+ heap_endscan(adscan);
+
+ RelationUnsetLockForWrite(adrel);
+ heap_close(adrel);
}
-static void
-RemoveRelCheck (Relation rel)
+static void
+RemoveRelCheck(Relation rel)
{
- Relation rcrel;
- HeapScanDesc rcscan;
- ScanKeyData key;
- HeapTuple tup;
-
- rcrel = heap_openr (RelCheckRelationName);
-
- ScanKeyEntryInitialize(&key, 0, Anum_pg_relcheck_rcrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
-
- RelationSetLockForWrite (rcrel);
-
- rcscan = heap_beginscan(rcrel, 0, NowTimeQual, 1, &key);
-
- while (tup = heap_getnext (rcscan, 0, (Buffer *)NULL), PointerIsValid(tup))
- heap_delete (rcrel, &tup->t_ctid);
-
- heap_endscan (rcscan);
-
- RelationUnsetLockForWrite (rcrel);
- heap_close (rcrel);
+ Relation rcrel;
+ HeapScanDesc rcscan;
+ ScanKeyData key;
+ HeapTuple tup;
+
+ rcrel = heap_openr(RelCheckRelationName);
+
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_relcheck_rcrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+
+ RelationSetLockForWrite(rcrel);
+
+ rcscan = heap_beginscan(rcrel, 0, NowTimeQual, 1, &key);
+
+ while (tup = heap_getnext(rcscan, 0, (Buffer *) NULL), PointerIsValid(tup))
+ heap_delete(rcrel, &tup->t_ctid);
+
+ heap_endscan(rcscan);
+
+ RelationUnsetLockForWrite(rcrel);
+ heap_close(rcrel);
}
-static void
-RemoveConstraints (Relation rel)
+static void
+RemoveConstraints(Relation rel)
{
- TupleConstr *constr = rel->rd_att->constr;
-
- if ( !constr )
- return;
-
- if ( constr->num_defval > 0 )
- RemoveAttrDefault (rel);
-
- if ( constr->num_check > 0 )
- RemoveRelCheck (rel);
-
- return;
+ TupleConstr *constr = rel->rd_att->constr;
+
+ if (!constr)
+ return;
+
+ if (constr->num_defval > 0)
+ RemoveAttrDefault(rel);
+
+ if (constr->num_check > 0)
+ RemoveRelCheck(rel);
+
+ return;
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b2071f814f2..6dd75742798 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* index.c--
- * code to create and destroy POSTGRES index relations
+ * code to create and destroy POSTGRES index relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.19 1997/08/22 14:10:26 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.20 1997/09/07 04:40:19 momjian Exp $
*
*
* INTERFACE ROUTINES
- * index_create() - Create a cataloged index relation
- * index_destroy() - Removes index relation from catalogs
+ * index_create() - Create a cataloged index relation
+ * index_destroy() - Removes index relation from catalogs
*
* NOTES
- * Much of this code uses hardcoded sequential heap relation scans
- * to fetch information from the catalogs. These should all be
- * rewritten to use the system caches lookup routines like
- * SearchSysCacheTuple, which can do efficient lookup and
- * caching.
+ * Much of this code uses hardcoded sequential heap relation scans
+ * to fetch information from the catalogs. These should all be
+ * rewritten to use the system caches lookup routines like
+ * SearchSysCacheTuple, which can do efficient lookup and
+ * caching.
*
*-------------------------------------------------------------------------
*/
@@ -51,9 +51,9 @@
#include <access/istrat.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/*
@@ -63,70 +63,75 @@
#define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))
/* non-export function prototypes */
-static Oid RelationNameGetObjectId(char *relationName, Relation pg_class,
- bool setHasIndexAttribute);
-static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName);
-static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo);
-static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
- List *attributeList,
- int numatts, AttrNumber attNums[]);
-
-static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
-static Oid UpdateRelationRelation(Relation indexRelation);
-static void InitializeAttributeOids(Relation indexRelation,
- int numatts,
- Oid indexoid);
+static Oid
+RelationNameGetObjectId(char *relationName, Relation pg_class,
+ bool setHasIndexAttribute);
+static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName);
+static TupleDesc BuildFuncTupleDesc(FuncIndexInfo * funcInfo);
+static TupleDesc
+ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
+ List * attributeList,
+ int numatts, AttrNumber attNums[]);
+
+static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
+static Oid UpdateRelationRelation(Relation indexRelation);
+static void
+InitializeAttributeOids(Relation indexRelation,
+ int numatts,
+ Oid indexoid);
static void
-AppendAttributeTuples(Relation indexRelation, int numatts);
-static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
- FuncIndexInfo *funcInfo, int natts,
- AttrNumber attNums[], Oid classOids[], Node *predicate,
- List *attributeList, bool islossy, bool unique);
-static void DefaultBuild(Relation heapRelation, Relation indexRelation,
- int numberOfAttributes, AttrNumber attributeNumber[],
- IndexStrategy indexStrategy, uint16 parameterCount,
- Datum parameter[], FuncIndexInfoPtr funcInfo, PredInfo *predInfo);
+ AppendAttributeTuples(Relation indexRelation, int numatts);
+static void
+UpdateIndexRelation(Oid indexoid, Oid heapoid,
+ FuncIndexInfo * funcInfo, int natts,
+ AttrNumber attNums[], Oid classOids[], Node * predicate,
+ List * attributeList, bool islossy, bool unique);
+static void
+DefaultBuild(Relation heapRelation, Relation indexRelation,
+ int numberOfAttributes, AttrNumber attributeNumber[],
+ IndexStrategy indexStrategy, uint16 parameterCount,
+ Datum parameter[], FuncIndexInfoPtr funcInfo, PredInfo * predInfo);
/* ----------------------------------------------------------------
- * sysatts is a structure containing attribute tuple forms
- * for system attributes (numbered -1, -2, ...). This really
- * should be generated or eliminated or moved elsewhere. -cim 1/19/91
+ * sysatts is a structure containing attribute tuple forms
+ * for system attributes (numbered -1, -2, ...). This really
+ * should be generated or eliminated or moved elsewhere. -cim 1/19/91
*
* typedef struct FormData_pg_attribute {
- * Oid attrelid;
- * NameData attname;
- * Oid atttypid;
- * uint32 attnvals;
- * int16 attlen;
- * AttrNumber attnum;
- * uint32 attnelems;
- * int32 attcacheoff;
- * bool attbyval;
- * bool attisset;
- * char attalign;
- * bool attnotnull;
- * bool atthasdef;
+ * Oid attrelid;
+ * NameData attname;
+ * Oid atttypid;
+ * uint32 attnvals;
+ * int16 attlen;
+ * AttrNumber attnum;
+ * uint32 attnelems;
+ * int32 attcacheoff;
+ * bool attbyval;
+ * bool attisset;
+ * char attalign;
+ * bool attnotnull;
+ * bool atthasdef;
* } FormData_pg_attribute;
*
* ----------------------------------------------------------------
*/
-static FormData_pg_attribute sysatts[] = {
- { 0l, {"ctid"}, 27l, 0l, 6, -1, 0, -1, '\0', '\0', 'i', '\0', '\0' },
- { 0l, {"oid"}, 26l, 0l, 4, -2, 0, -1, '\001', '\0', 'i', '\0', '\0' },
- { 0l, {"xmin"}, 28l, 0l, 4, -3, 0, -1, '\0', '\0', 'i', '\0', '\0' },
- { 0l, {"cmin"}, 29l, 0l, 2, -4, 0, -1, '\001', '\0', 's', '\0', '\0' },
- { 0l, {"xmax"}, 28l, 0l, 4, -5, 0, -1, '\0', '\0', 'i', '\0', '\0' },
- { 0l, {"cmax"}, 29l, 0l, 2, -6, 0, -1, '\001', '\0', 's', '\0', '\0' },
- { 0l, {"chain"}, 27l, 0l, 6, -7, 0, -1, '\0', '\0', 'i', '\0', '\0' },
- { 0l, {"anchor"}, 27l, 0l, 6, -8, 0, -1, '\0', '\0', 'i', '\0', '\0' },
- { 0l, {"tmin"}, 702l, 0l, 4, -9, 0, -1, '\001', '\0', 'i', '\0', '\0' },
- { 0l, {"tmax"}, 702l, 0l, 4, -10, 0, -1, '\001', '\0', 'i', '\0', '\0' },
- { 0l, {"vtype"}, 18l, 0l, 1, -11, 0, -1, '\001', '\0', 'c', '\0', '\0' },
+static FormData_pg_attribute sysatts[] = {
+ {0l, {"ctid"}, 27l, 0l, 6, -1, 0, -1, '\0', '\0', 'i', '\0', '\0'},
+ {0l, {"oid"}, 26l, 0l, 4, -2, 0, -1, '\001', '\0', 'i', '\0', '\0'},
+ {0l, {"xmin"}, 28l, 0l, 4, -3, 0, -1, '\0', '\0', 'i', '\0', '\0'},
+ {0l, {"cmin"}, 29l, 0l, 2, -4, 0, -1, '\001', '\0', 's', '\0', '\0'},
+ {0l, {"xmax"}, 28l, 0l, 4, -5, 0, -1, '\0', '\0', 'i', '\0', '\0'},
+ {0l, {"cmax"}, 29l, 0l, 2, -6, 0, -1, '\001', '\0', 's', '\0', '\0'},
+ {0l, {"chain"}, 27l, 0l, 6, -7, 0, -1, '\0', '\0', 'i', '\0', '\0'},
+ {0l, {"anchor"}, 27l, 0l, 6, -8, 0, -1, '\0', '\0', 'i', '\0', '\0'},
+ {0l, {"tmin"}, 702l, 0l, 4, -9, 0, -1, '\001', '\0', 'i', '\0', '\0'},
+ {0l, {"tmax"}, 702l, 0l, 4, -10, 0, -1, '\001', '\0', 'i', '\0', '\0'},
+ {0l, {"vtype"}, 18l, 0l, 1, -11, 0, -1, '\001', '\0', 'c', '\0', '\0'},
};
/* ----------------------------------------------------------------
* RelationNameGetObjectId --
- * Returns the object identifier for a relation given its name.
+ * Returns the object identifier for a relation given its name.
*
* > The HASINDEX attribute for the relation with this name will
* > be set if it exists and if it is indicated by the call argument.
@@ -135,1574 +140,1638 @@ static FormData_pg_attribute sysatts[] = {
* probably be replaced by SearchSysCacheTuple. -cim 1/19/91
*
* Note:
- * Assumes relation name is valid.
- * Assumes relation descriptor is valid.
+ * Assumes relation name is valid.
+ * Assumes relation descriptor is valid.
* ----------------------------------------------------------------
*/
-static Oid
+static Oid
RelationNameGetObjectId(char *relationName,
- Relation pg_class,
- bool setHasIndexAttribute)
-{
- HeapScanDesc pg_class_scan;
- HeapTuple pg_class_tuple;
- Oid relationObjectId;
- Buffer buffer;
- ScanKeyData key;
-
- /*
- * If this isn't bootstrap time, we can use the system catalogs to
- * speed this up.
- */
-
- if (!IsBootstrapProcessingMode()) {
- pg_class_tuple = ClassNameIndexScan(pg_class, relationName);
- if (HeapTupleIsValid(pg_class_tuple)) {
- relationObjectId = pg_class_tuple->t_oid;
- pfree(pg_class_tuple);
- } else
- relationObjectId = InvalidOid;
-
- return (relationObjectId);
- }
-
- /* ----------------
- * Bootstrap time, do this the hard way.
- * begin a scan of pg_class for the named relation
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
- NameEqualRegProcedure,
- PointerGetDatum(relationName));
-
- pg_class_scan = heap_beginscan(pg_class, 0, NowTimeQual, 1, &key);
-
- /* ----------------
- * if we find the named relation, fetch its relation id
- * (the oid of the tuple we found).
- * ----------------
- */
- pg_class_tuple = heap_getnext(pg_class_scan, 0, &buffer);
-
- if (! HeapTupleIsValid(pg_class_tuple)) {
- relationObjectId = InvalidOid;
- } else {
- relationObjectId = pg_class_tuple->t_oid;
- ReleaseBuffer(buffer);
- }
-
- /* ----------------
- * cleanup and return results
- * ----------------
- */
- heap_endscan(pg_class_scan);
-
- return
- relationObjectId;
+ Relation pg_class,
+ bool setHasIndexAttribute)
+{
+ HeapScanDesc pg_class_scan;
+ HeapTuple pg_class_tuple;
+ Oid relationObjectId;
+ Buffer buffer;
+ ScanKeyData key;
+
+ /*
+ * If this isn't bootstrap time, we can use the system catalogs to
+ * speed this up.
+ */
+
+ if (!IsBootstrapProcessingMode())
+ {
+ pg_class_tuple = ClassNameIndexScan(pg_class, relationName);
+ if (HeapTupleIsValid(pg_class_tuple))
+ {
+ relationObjectId = pg_class_tuple->t_oid;
+ pfree(pg_class_tuple);
+ }
+ else
+ relationObjectId = InvalidOid;
+
+ return (relationObjectId);
+ }
+
+ /* ----------------
+ * Bootstrap time, do this the hard way.
+ * begin a scan of pg_class for the named relation
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_class_relname,
+ NameEqualRegProcedure,
+ PointerGetDatum(relationName));
+
+ pg_class_scan = heap_beginscan(pg_class, 0, NowTimeQual, 1, &key);
+
+ /* ----------------
+ * if we find the named relation, fetch its relation id
+ * (the oid of the tuple we found).
+ * ----------------
+ */
+ pg_class_tuple = heap_getnext(pg_class_scan, 0, &buffer);
+
+ if (!HeapTupleIsValid(pg_class_tuple))
+ {
+ relationObjectId = InvalidOid;
+ }
+ else
+ {
+ relationObjectId = pg_class_tuple->t_oid;
+ ReleaseBuffer(buffer);
+ }
+
+ /* ----------------
+ * cleanup and return results
+ * ----------------
+ */
+ heap_endscan(pg_class_scan);
+
+ return
+ relationObjectId;
}
/* ----------------------------------------------------------------
- * GetHeapRelationOid
+ * GetHeapRelationOid
* ----------------------------------------------------------------
*/
-static Oid
+static Oid
GetHeapRelationOid(char *heapRelationName, char *indexRelationName)
{
- Relation pg_class;
- Oid indoid;
- Oid heapoid;
-
- /* ----------------
- * XXX ADD INDEXING HERE
- * ----------------
- */
- /* ----------------
- * open pg_class and get the oid of the relation
- * corresponding to the name of the index relation.
- * ----------------
- */
- pg_class = heap_openr(RelationRelationName);
-
- indoid = RelationNameGetObjectId(indexRelationName,
- pg_class,
- false);
-
- if (OidIsValid(indoid))
- elog(WARN, "Cannot create index: '%s' already exists",
- indexRelationName);
-
- /* ----------------
- * get the object id of the heap relation
- * ----------------
- */
- heapoid = RelationNameGetObjectId(heapRelationName,
- pg_class,
- true);
-
- /* ----------------
- * check that the heap relation exists..
- * ----------------
- */
- if (! OidIsValid(heapoid))
- elog(WARN, "Cannot create index on '%s': relation does not exist",
- heapRelationName);
-
- /* ----------------
- * close pg_class and return the heap relation oid
- * ----------------
- */
- heap_close(pg_class);
-
- return heapoid;
+ Relation pg_class;
+ Oid indoid;
+ Oid heapoid;
+
+ /* ----------------
+ * XXX ADD INDEXING HERE
+ * ----------------
+ */
+ /* ----------------
+ * open pg_class and get the oid of the relation
+ * corresponding to the name of the index relation.
+ * ----------------
+ */
+ pg_class = heap_openr(RelationRelationName);
+
+ indoid = RelationNameGetObjectId(indexRelationName,
+ pg_class,
+ false);
+
+ if (OidIsValid(indoid))
+ elog(WARN, "Cannot create index: '%s' already exists",
+ indexRelationName);
+
+ /* ----------------
+ * get the object id of the heap relation
+ * ----------------
+ */
+ heapoid = RelationNameGetObjectId(heapRelationName,
+ pg_class,
+ true);
+
+ /* ----------------
+ * check that the heap relation exists..
+ * ----------------
+ */
+ if (!OidIsValid(heapoid))
+ elog(WARN, "Cannot create index on '%s': relation does not exist",
+ heapRelationName);
+
+ /* ----------------
+ * close pg_class and return the heap relation oid
+ * ----------------
+ */
+ heap_close(pg_class);
+
+ return heapoid;
}
-static TupleDesc
-BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
+static TupleDesc
+BuildFuncTupleDesc(FuncIndexInfo * funcInfo)
{
- HeapTuple tuple;
- TupleDesc funcTupDesc;
- Oid retType;
- char *funcname;
- int4 nargs;
- Oid *argtypes;
-
- /*
- * Allocate and zero a tuple descriptor.
- */
- funcTupDesc = CreateTemplateTupleDesc(1);
- funcTupDesc->attrs[0] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
- memset(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
-
- /*
- * Lookup the function for the return type.
- */
- funcname = FIgetname(funcInfo);
- nargs = FIgetnArgs(funcInfo);
- argtypes = FIgetArglist(funcInfo);
- tuple = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- Int32GetDatum(nargs),
- PointerGetDatum(argtypes),
- 0);
-
- if (!HeapTupleIsValid(tuple))
- func_error("BuildFuncTupleDesc", funcname, nargs, argtypes);
-
- retType = ((Form_pg_proc)GETSTRUCT(tuple))->prorettype;
-
- /*
- * Look up the return type in pg_type for the type length.
- */
- tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(retType),
- 0,0,0);
- if (!HeapTupleIsValid(tuple))
- elog(WARN,"Function %s return type does not exist",FIgetname(funcInfo));
-
- /*
- * Assign some of the attributes values. Leave the rest as 0.
- */
- funcTupDesc->attrs[0]->attlen = ((TypeTupleForm)GETSTRUCT(tuple))->typlen;
- funcTupDesc->attrs[0]->atttypid = retType;
- funcTupDesc->attrs[0]->attnum = 1;
- funcTupDesc->attrs[0]->attbyval = ((TypeTupleForm)GETSTRUCT(tuple))->typbyval;
-
- /*
- * make the attributes name the same as the functions
- */
- namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
-
- return (funcTupDesc);
+ HeapTuple tuple;
+ TupleDesc funcTupDesc;
+ Oid retType;
+ char *funcname;
+ int4 nargs;
+ Oid *argtypes;
+
+ /*
+ * Allocate and zero a tuple descriptor.
+ */
+ funcTupDesc = CreateTemplateTupleDesc(1);
+ funcTupDesc->attrs[0] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+ memset(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
+
+ /*
+ * Lookup the function for the return type.
+ */
+ funcname = FIgetname(funcInfo);
+ nargs = FIgetnArgs(funcInfo);
+ argtypes = FIgetArglist(funcInfo);
+ tuple = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(funcname),
+ Int32GetDatum(nargs),
+ PointerGetDatum(argtypes),
+ 0);
+
+ if (!HeapTupleIsValid(tuple))
+ func_error("BuildFuncTupleDesc", funcname, nargs, argtypes);
+
+ retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
+
+ /*
+ * Look up the return type in pg_type for the type length.
+ */
+ tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(retType),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(WARN, "Function %s return type does not exist", FIgetname(funcInfo));
+
+ /*
+ * Assign some of the attributes values. Leave the rest as 0.
+ */
+ funcTupDesc->attrs[0]->attlen = ((TypeTupleForm) GETSTRUCT(tuple))->typlen;
+ funcTupDesc->attrs[0]->atttypid = retType;
+ funcTupDesc->attrs[0]->attnum = 1;
+ funcTupDesc->attrs[0]->attbyval = ((TypeTupleForm) GETSTRUCT(tuple))->typbyval;
+
+ /*
+ * make the attributes name the same as the functions
+ */
+ namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
+
+ return (funcTupDesc);
}
/* ----------------------------------------------------------------
- * ConstructTupleDescriptor
+ * ConstructTupleDescriptor
* ----------------------------------------------------------------
*/
-static TupleDesc
+static TupleDesc
ConstructTupleDescriptor(Oid heapoid,
- Relation heapRelation,
- List *attributeList,
- int numatts,
- AttrNumber attNums[])
+ Relation heapRelation,
+ List * attributeList,
+ int numatts,
+ AttrNumber attNums[])
{
- TupleDesc heapTupDesc;
- TupleDesc indexTupDesc;
- IndexElem *IndexKey;
- TypeName *IndexKeyType;
- AttrNumber atnum; /* attributeNumber[attributeOffset] */
- AttrNumber atind;
- int natts; /* RelationTupleForm->relnatts */
- char *from; /* used to simplify memcpy below */
- char *to; /* used to simplify memcpy below */
- int i;
-
- /* ----------------
- * allocate the new tuple descriptor
- * ----------------
- */
- natts = RelationGetRelationTupleForm(heapRelation)->relnatts;
-
- indexTupDesc = CreateTemplateTupleDesc(numatts);
-
- /* ----------------
- *
- * ----------------
- */
-
- /* ----------------
- * for each attribute we are indexing, obtain its attribute
- * tuple form from either the static table of system attribute
- * tuple forms or the relation tuple descriptor
- * ----------------
- */
- for (i = 0; i < numatts; i += 1) {
-
+ TupleDesc heapTupDesc;
+ TupleDesc indexTupDesc;
+ IndexElem *IndexKey;
+ TypeName *IndexKeyType;
+ AttrNumber atnum; /* attributeNumber[attributeOffset] */
+ AttrNumber atind;
+ int natts; /* RelationTupleForm->relnatts */
+ char *from; /* used to simplify memcpy below */
+ char *to; /* used to simplify memcpy below */
+ int i;
+
/* ----------------
- * get the attribute number and make sure it's valid
+ * allocate the new tuple descriptor
* ----------------
*/
- atnum = attNums[i];
- if (atnum > natts)
- elog(WARN, "Cannot create index: attribute %d does not exist",
- atnum);
- if (attributeList) {
- IndexKey = (IndexElem*) lfirst(attributeList);
- attributeList = lnext(attributeList);
- IndexKeyType = IndexKey->tname;
- } else {
- IndexKeyType = NULL;
- }
-
- indexTupDesc->attrs[i] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
-
+ natts = RelationGetRelationTupleForm(heapRelation)->relnatts;
+
+ indexTupDesc = CreateTemplateTupleDesc(numatts);
+
/* ----------------
- * determine which tuple descriptor to copy
+ *
* ----------------
*/
- if (!AttrNumberIsForUserDefinedAttr(atnum)) {
-
- /* ----------------
- * here we are indexing on a system attribute (-1...-12)
- * so we convert atnum into a usable index 0...11 so we can
- * use it to dereference the array sysatts[] which stores
- * tuple descriptor information for system attributes.
- * ----------------
- */
- if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0 )
- elog(WARN, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
- atind = (-atnum) - 1;
-
- from = (char *) (& sysatts[atind]);
-
- } else {
- /* ----------------
- * here we are indexing on a normal attribute (1...n)
- * ----------------
- */
-
- heapTupDesc = RelationGetTupleDescriptor(heapRelation);
- atind = AttrNumberGetAttrOffset(atnum);
-
- from = (char *) (heapTupDesc->attrs[ atind ]);
- }
-
+
/* ----------------
- * now that we've determined the "from", let's copy
- * the tuple desc data...
+ * for each attribute we are indexing, obtain its attribute
+ * tuple form from either the static table of system attribute
+ * tuple forms or the relation tuple descriptor
* ----------------
*/
-
- to = (char *) (indexTupDesc->attrs[ i ]);
- memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
-
- ((AttributeTupleForm) to)->attnum = i+1;
- ((AttributeTupleForm) to)->attcacheoff = -1;
-
- ((AttributeTupleForm) to)->attnotnull = false;
- ((AttributeTupleForm) to)->atthasdef = false;
-
- /* if the keytype is defined, we need to change the tuple form's
- atttypid & attlen field to match that of the key's type */
- if (IndexKeyType != NULL) {
- HeapTuple tup;
-
- tup = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(IndexKeyType->name),
- 0,0,0);
- if(!HeapTupleIsValid(tup))
- elog(WARN, "create index: type '%s' undefined",
- IndexKeyType->name);
- ((AttributeTupleForm) to)->atttypid = tup->t_oid;
- ((AttributeTupleForm) to)->attbyval =
- ((TypeTupleForm) ((char *)tup + tup->t_hoff))->typbyval;
- if (IndexKeyType->typlen > 0)
- ((AttributeTupleForm) to)->attlen = IndexKeyType->typlen;
- else ((AttributeTupleForm) to)->attlen =
- ((TypeTupleForm) ((char *)tup + tup->t_hoff))->typlen;
+ for (i = 0; i < numatts; i += 1)
+ {
+
+ /* ----------------
+ * get the attribute number and make sure it's valid
+ * ----------------
+ */
+ atnum = attNums[i];
+ if (atnum > natts)
+ elog(WARN, "Cannot create index: attribute %d does not exist",
+ atnum);
+ if (attributeList)
+ {
+ IndexKey = (IndexElem *) lfirst(attributeList);
+ attributeList = lnext(attributeList);
+ IndexKeyType = IndexKey->tname;
+ }
+ else
+ {
+ IndexKeyType = NULL;
+ }
+
+ indexTupDesc->attrs[i] = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+
+ /* ----------------
+ * determine which tuple descriptor to copy
+ * ----------------
+ */
+ if (!AttrNumberIsForUserDefinedAttr(atnum))
+ {
+
+ /* ----------------
+ * here we are indexing on a system attribute (-1...-12)
+ * so we convert atnum into a usable index 0...11 so we can
+ * use it to dereference the array sysatts[] which stores
+ * tuple descriptor information for system attributes.
+ * ----------------
+ */
+ if (atnum <= FirstLowInvalidHeapAttributeNumber || atnum >= 0)
+ elog(WARN, "Cannot create index on system attribute: attribute number out of range (%d)", atnum);
+ atind = (-atnum) - 1;
+
+ from = (char *) (&sysatts[atind]);
+
+ }
+ else
+ {
+ /* ----------------
+ * here we are indexing on a normal attribute (1...n)
+ * ----------------
+ */
+
+ heapTupDesc = RelationGetTupleDescriptor(heapRelation);
+ atind = AttrNumberGetAttrOffset(atnum);
+
+ from = (char *) (heapTupDesc->attrs[atind]);
+ }
+
+ /* ----------------
+ * now that we've determined the "from", let's copy
+ * the tuple desc data...
+ * ----------------
+ */
+
+ to = (char *) (indexTupDesc->attrs[i]);
+ memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
+
+ ((AttributeTupleForm) to)->attnum = i + 1;
+ ((AttributeTupleForm) to)->attcacheoff = -1;
+
+ ((AttributeTupleForm) to)->attnotnull = false;
+ ((AttributeTupleForm) to)->atthasdef = false;
+
+ /*
+ * if the keytype is defined, we need to change the tuple form's
+ * atttypid & attlen field to match that of the key's type
+ */
+ if (IndexKeyType != NULL)
+ {
+ HeapTuple tup;
+
+ tup = SearchSysCacheTuple(TYPNAME,
+ PointerGetDatum(IndexKeyType->name),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "create index: type '%s' undefined",
+ IndexKeyType->name);
+ ((AttributeTupleForm) to)->atttypid = tup->t_oid;
+ ((AttributeTupleForm) to)->attbyval =
+ ((TypeTupleForm) ((char *) tup + tup->t_hoff))->typbyval;
+ if (IndexKeyType->typlen > 0)
+ ((AttributeTupleForm) to)->attlen = IndexKeyType->typlen;
+ else
+ ((AttributeTupleForm) to)->attlen =
+ ((TypeTupleForm) ((char *) tup + tup->t_hoff))->typlen;
+ }
+
+
+ /* ----------------
+ * now we have to drop in the proper relation descriptor
+ * into the copied tuple form's attrelid and we should be
+ * all set.
+ * ----------------
+ */
+ ((AttributeTupleForm) to)->attrelid = heapoid;
}
-
- /* ----------------
- * now we have to drop in the proper relation descriptor
- * into the copied tuple form's attrelid and we should be
- * all set.
- * ----------------
- */
- ((AttributeTupleForm) to)->attrelid = heapoid;
- }
-
- return indexTupDesc;
+ return indexTupDesc;
}
/* ----------------------------------------------------------------
* AccessMethodObjectIdGetAccessMethodTupleForm --
- * Returns the formated access method tuple given its object identifier.
+ * Returns the formated access method tuple given its object identifier.
*
* XXX ADD INDEXING
*
* Note:
- * Assumes object identifier is valid.
+ * Assumes object identifier is valid.
* ----------------------------------------------------------------
*/
Form_pg_am
AccessMethodObjectIdGetAccessMethodTupleForm(Oid accessMethodObjectId)
{
- Relation pg_am_desc;
- HeapScanDesc pg_am_scan;
- HeapTuple pg_am_tuple;
- ScanKeyData key;
- Form_pg_am form;
-
- /* ----------------
- * form a scan key for the pg_am relation
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(accessMethodObjectId));
-
- /* ----------------
- * fetch the desired access method tuple
- * ----------------
- */
- pg_am_desc = heap_openr(AccessMethodRelationName);
- pg_am_scan = heap_beginscan(pg_am_desc, 0, NowTimeQual, 1, &key);
-
- pg_am_tuple = heap_getnext(pg_am_scan, 0, (Buffer *)NULL);
-
- /* ----------------
- * return NULL if not found
- * ----------------
- */
- if (! HeapTupleIsValid(pg_am_tuple)) {
+ Relation pg_am_desc;
+ HeapScanDesc pg_am_scan;
+ HeapTuple pg_am_tuple;
+ ScanKeyData key;
+ Form_pg_am form;
+
+ /* ----------------
+ * form a scan key for the pg_am relation
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(accessMethodObjectId));
+
+ /* ----------------
+ * fetch the desired access method tuple
+ * ----------------
+ */
+ pg_am_desc = heap_openr(AccessMethodRelationName);
+ pg_am_scan = heap_beginscan(pg_am_desc, 0, NowTimeQual, 1, &key);
+
+ pg_am_tuple = heap_getnext(pg_am_scan, 0, (Buffer *) NULL);
+
+ /* ----------------
+ * return NULL if not found
+ * ----------------
+ */
+ if (!HeapTupleIsValid(pg_am_tuple))
+ {
+ heap_endscan(pg_am_scan);
+ heap_close(pg_am_desc);
+ return (NULL);
+ }
+
+ /* ----------------
+ * if found am tuple, then copy the form and return the copy
+ * ----------------
+ */
+ form = (Form_pg_am) palloc(sizeof *form);
+ memcpy(form, GETSTRUCT(pg_am_tuple), sizeof *form);
+
heap_endscan(pg_am_scan);
heap_close(pg_am_desc);
- return (NULL);
- }
-
- /* ----------------
- * if found am tuple, then copy the form and return the copy
- * ----------------
- */
- form = (Form_pg_am)palloc(sizeof *form);
- memcpy(form, GETSTRUCT(pg_am_tuple), sizeof *form);
-
- heap_endscan(pg_am_scan);
- heap_close(pg_am_desc);
-
- return (form);
+
+ return (form);
}
/* ----------------------------------------------------------------
- * ConstructIndexReldesc
+ * ConstructIndexReldesc
* ----------------------------------------------------------------
*/
static void
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
{
- extern GlobalMemory CacheCxt;
- MemoryContext oldcxt;
-
- /* ----------------
- * here we make certain to allocate the access method
- * tuple within the cache context lest it vanish when the
- * context changes
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- indexRelation->rd_am =
- AccessMethodObjectIdGetAccessMethodTupleForm(amoid);
-
- MemoryContextSwitchTo(oldcxt);
-
- /* ----------------
- * XXX missing the initialization of some other fields
- * ----------------
- */
-
- indexRelation->rd_rel->relowner = GetUserId();
-
- indexRelation->rd_rel->relam = amoid;
- indexRelation->rd_rel->reltuples = 1; /* XXX */
- indexRelation->rd_rel->relexpires = 0; /* XXX */
- indexRelation->rd_rel->relpreserved = 0; /* XXX */
- indexRelation->rd_rel->relkind = RELKIND_INDEX;
- indexRelation->rd_rel->relarch = 'n'; /* XXX */
+ extern GlobalMemory CacheCxt;
+ MemoryContext oldcxt;
+
+ /* ----------------
+ * here we make certain to allocate the access method
+ * tuple within the cache context lest it vanish when the
+ * context changes
+ * ----------------
+ */
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ indexRelation->rd_am =
+ AccessMethodObjectIdGetAccessMethodTupleForm(amoid);
+
+ MemoryContextSwitchTo(oldcxt);
+
+ /* ----------------
+ * XXX missing the initialization of some other fields
+ * ----------------
+ */
+
+ indexRelation->rd_rel->relowner = GetUserId();
+
+ indexRelation->rd_rel->relam = amoid;
+ indexRelation->rd_rel->reltuples = 1; /* XXX */
+ indexRelation->rd_rel->relexpires = 0; /* XXX */
+ indexRelation->rd_rel->relpreserved = 0; /* XXX */
+ indexRelation->rd_rel->relkind = RELKIND_INDEX;
+ indexRelation->rd_rel->relarch = 'n'; /* XXX */
}
/* ----------------------------------------------------------------
- * UpdateRelationRelation
+ * UpdateRelationRelation
* ----------------------------------------------------------------
*/
-static Oid
+static Oid
UpdateRelationRelation(Relation indexRelation)
{
- Relation pg_class;
- HeapTuple tuple;
- Oid tupleOid;
- Relation idescs[Num_pg_class_indices];
-
- pg_class = heap_openr(RelationRelationName);
-
- /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
- tuple = heap_addheader(Natts_pg_class_fixed,
- sizeof(*indexRelation->rd_rel),
- (char *) indexRelation->rd_rel);
-
- /* ----------------
- * the new tuple must have the same oid as the relcache entry for the
- * index. sure would be embarassing to do this sort of thing in polite
- * company.
- * ----------------
- */
- tuple->t_oid = indexRelation->rd_id;
- heap_insert(pg_class, tuple);
-
- /*
- * During normal processing, we need to make sure that the system
- * catalog indices are correct. Bootstrap (initdb) time doesn't
- * require this, because we make sure that the indices are correct
- * just before exiting.
- */
-
- if (!IsBootstrapProcessingMode()) {
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
- }
-
- tupleOid = tuple->t_oid;
- pfree(tuple);
- heap_close(pg_class);
-
- return(tupleOid);
+ Relation pg_class;
+ HeapTuple tuple;
+ Oid tupleOid;
+ Relation idescs[Num_pg_class_indices];
+
+ pg_class = heap_openr(RelationRelationName);
+
+ /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */
+ tuple = heap_addheader(Natts_pg_class_fixed,
+ sizeof(*indexRelation->rd_rel),
+ (char *) indexRelation->rd_rel);
+
+ /* ----------------
+ * the new tuple must have the same oid as the relcache entry for the
+ * index. sure would be embarassing to do this sort of thing in polite
+ * company.
+ * ----------------
+ */
+ tuple->t_oid = indexRelation->rd_id;
+ heap_insert(pg_class, tuple);
+
+ /*
+ * During normal processing, we need to make sure that the system
+ * catalog indices are correct. Bootstrap (initdb) time doesn't
+ * require this, because we make sure that the indices are correct
+ * just before exiting.
+ */
+
+ if (!IsBootstrapProcessingMode())
+ {
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, tuple);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+ }
+
+ tupleOid = tuple->t_oid;
+ pfree(tuple);
+ heap_close(pg_class);
+
+ return (tupleOid);
}
/* ----------------------------------------------------------------
- * InitializeAttributeOids
+ * InitializeAttributeOids
* ----------------------------------------------------------------
*/
static void
InitializeAttributeOids(Relation indexRelation,
- int numatts,
- Oid indexoid)
+ int numatts,
+ Oid indexoid)
{
- TupleDesc tupleDescriptor;
- int i;
-
- tupleDescriptor = RelationGetTupleDescriptor(indexRelation);
-
- for (i = 0; i < numatts; i += 1)
- tupleDescriptor->attrs[i]->attrelid = indexoid;
+ TupleDesc tupleDescriptor;
+ int i;
+
+ tupleDescriptor = RelationGetTupleDescriptor(indexRelation);
+
+ for (i = 0; i < numatts; i += 1)
+ tupleDescriptor->attrs[i]->attrelid = indexoid;
}
/* ----------------------------------------------------------------
- * AppendAttributeTuples
+ * AppendAttributeTuples
*
- * XXX For now, only change the ATTNUM attribute value
+ * XXX For now, only change the ATTNUM attribute value
* ----------------------------------------------------------------
*/
static void
AppendAttributeTuples(Relation indexRelation, int numatts)
{
- Relation pg_attribute;
- HeapTuple tuple;
- HeapTuple newtuple;
- bool hasind;
- Relation idescs[Num_pg_attr_indices];
-
- Datum value[ Natts_pg_attribute ];
- char nullv[ Natts_pg_attribute ];
- char replace[ Natts_pg_attribute ];
-
- TupleDesc indexTupDesc;
- int i;
-
- /* ----------------
- * open the attribute relation
- * XXX ADD INDEXING
- * ----------------
- */
- pg_attribute = heap_openr(AttributeRelationName);
-
- /* ----------------
- * initialize null[], replace[] and value[]
- * ----------------
- */
- memset(nullv, ' ', Natts_pg_attribute);
- memset(replace, ' ', Natts_pg_attribute);
-
- /* ----------------
- * create the first attribute tuple.
- * XXX For now, only change the ATTNUM attribute value
- * ----------------
- */
- replace[ Anum_pg_attribute_attnum - 1 ] = 'r';
- replace[ Anum_pg_attribute_attcacheoff - 1 ] = 'r';
-
- value[ Anum_pg_attribute_attnum - 1 ] = Int16GetDatum(1);
- value[ Anum_pg_attribute_attcacheoff - 1 ] = Int32GetDatum(-1);
-
- tuple = heap_addheader(Natts_pg_attribute,
- sizeof *(indexRelation->rd_att->attrs[0]),
- (char *)(indexRelation->rd_att->attrs[0]));
-
- hasind = false;
- if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex) {
- hasind = true;
- CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
- }
-
- /* ----------------
- * insert the first attribute tuple.
- * ----------------
- */
- tuple = heap_modifytuple(tuple,
- InvalidBuffer,
- pg_attribute,
- value,
- nullv,
- replace);
-
- heap_insert(pg_attribute, tuple);
- if (hasind)
- CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, tuple);
-
- /* ----------------
- * now we use the information in the index tuple
- * descriptor to form the remaining attribute tuples.
- * ----------------
- */
- indexTupDesc = RelationGetTupleDescriptor(indexRelation);
-
- for (i = 1; i < numatts; i += 1) {
+ Relation pg_attribute;
+ HeapTuple tuple;
+ HeapTuple newtuple;
+ bool hasind;
+ Relation idescs[Num_pg_attr_indices];
+
+ Datum value[Natts_pg_attribute];
+ char nullv[Natts_pg_attribute];
+ char replace[Natts_pg_attribute];
+
+ TupleDesc indexTupDesc;
+ int i;
+
/* ----------------
- * process the remaining attributes...
+ * open the attribute relation
+ * XXX ADD INDEXING
* ----------------
*/
- memmove(GETSTRUCT(tuple),
- (char *)indexTupDesc->attrs[i],
- sizeof (FormData_pg_attribute));
-
- value[ Anum_pg_attribute_attnum - 1 ] = Int16GetDatum(i + 1);
-
- newtuple = heap_modifytuple(tuple,
- InvalidBuffer,
- pg_attribute,
- value,
- nullv,
- replace);
-
- heap_insert(pg_attribute, newtuple);
+ pg_attribute = heap_openr(AttributeRelationName);
+
+ /* ----------------
+ * initialize null[], replace[] and value[]
+ * ----------------
+ */
+ memset(nullv, ' ', Natts_pg_attribute);
+ memset(replace, ' ', Natts_pg_attribute);
+
+ /* ----------------
+ * create the first attribute tuple.
+ * XXX For now, only change the ATTNUM attribute value
+ * ----------------
+ */
+ replace[Anum_pg_attribute_attnum - 1] = 'r';
+ replace[Anum_pg_attribute_attcacheoff - 1] = 'r';
+
+ value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(1);
+ value[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
+
+ tuple = heap_addheader(Natts_pg_attribute,
+ sizeof *(indexRelation->rd_att->attrs[0]),
+ (char *) (indexRelation->rd_att->attrs[0]));
+
+ hasind = false;
+ if (!IsBootstrapProcessingMode() && pg_attribute->rd_rel->relhasindex)
+ {
+ hasind = true;
+ CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
+ }
+
+ /* ----------------
+ * insert the first attribute tuple.
+ * ----------------
+ */
+ tuple = heap_modifytuple(tuple,
+ InvalidBuffer,
+ pg_attribute,
+ value,
+ nullv,
+ replace);
+
+ heap_insert(pg_attribute, tuple);
if (hasind)
- CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, newtuple);
-
+ CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, tuple);
+
+ /* ----------------
+ * now we use the information in the index tuple
+ * descriptor to form the remaining attribute tuples.
+ * ----------------
+ */
+ indexTupDesc = RelationGetTupleDescriptor(indexRelation);
+
+ for (i = 1; i < numatts; i += 1)
+ {
+ /* ----------------
+ * process the remaining attributes...
+ * ----------------
+ */
+ memmove(GETSTRUCT(tuple),
+ (char *) indexTupDesc->attrs[i],
+ sizeof(FormData_pg_attribute));
+
+ value[Anum_pg_attribute_attnum - 1] = Int16GetDatum(i + 1);
+
+ newtuple = heap_modifytuple(tuple,
+ InvalidBuffer,
+ pg_attribute,
+ value,
+ nullv,
+ replace);
+
+ heap_insert(pg_attribute, newtuple);
+ if (hasind)
+ CatalogIndexInsert(idescs, Num_pg_attr_indices, pg_attribute, newtuple);
+
+ /* ----------------
+ * ModifyHeapTuple returns a new copy of a tuple
+ * so we free the original and use the copy..
+ * ----------------
+ */
+ pfree(tuple);
+ tuple = newtuple;
+ }
+
/* ----------------
- * ModifyHeapTuple returns a new copy of a tuple
- * so we free the original and use the copy..
+ * close the attribute relation and free the tuple
* ----------------
*/
+ heap_close(pg_attribute);
+
+ if (hasind)
+ CatalogCloseIndices(Num_pg_attr_indices, idescs);
+
pfree(tuple);
- tuple = newtuple;
- }
-
- /* ----------------
- * close the attribute relation and free the tuple
- * ----------------
- */
- heap_close(pg_attribute);
-
- if (hasind)
- CatalogCloseIndices(Num_pg_attr_indices, idescs);
-
- pfree(tuple);
}
/* ----------------------------------------------------------------
- * UpdateIndexRelation
+ * UpdateIndexRelation
* ----------------------------------------------------------------
*/
static void
UpdateIndexRelation(Oid indexoid,
- Oid heapoid,
- FuncIndexInfo *funcInfo,
- int natts,
- AttrNumber attNums[],
- Oid classOids[],
- Node *predicate,
- List *attributeList,
- bool islossy,
- bool unique)
+ Oid heapoid,
+ FuncIndexInfo * funcInfo,
+ int natts,
+ AttrNumber attNums[],
+ Oid classOids[],
+ Node * predicate,
+ List * attributeList,
+ bool islossy,
+ bool unique)
{
- IndexTupleForm indexForm;
- IndexElem *IndexKey;
- char *predString;
- text *predText;
- int predLen, itupLen;
- Relation pg_index;
- HeapTuple tuple;
- int i;
-
- /* ----------------
- * allocate an IndexTupleForm big enough to hold the
- * index-predicate (if any) in string form
- * ----------------
- */
- if (predicate != NULL) {
- predString = nodeToString(predicate);
- predText = (text *)fmgr(F_TEXTIN, predString);
- pfree(predString);
- } else {
- predText = (text *)fmgr(F_TEXTIN, "");
- }
- predLen = VARSIZE(predText);
- itupLen = predLen + sizeof(FormData_pg_index);
- indexForm = (IndexTupleForm) palloc(itupLen);
-
- memmove((char *)& indexForm->indpred, (char *)predText, predLen);
-
- /* ----------------
- * store the oid information into the index tuple form
- * ----------------
- */
- indexForm->indrelid = heapoid;
- indexForm->indexrelid = indexoid;
- indexForm->indproc = (PointerIsValid(funcInfo)) ?
- FIgetProcOid(funcInfo) : InvalidOid;
- indexForm->indislossy = islossy;
- indexForm->indisunique = unique;
-
- indexForm->indhaskeytype = 0;
- while (attributeList != NIL )
- {
- IndexKey = (IndexElem*) lfirst(attributeList);
- if ( IndexKey->tname != NULL )
+ IndexTupleForm indexForm;
+ IndexElem *IndexKey;
+ char *predString;
+ text *predText;
+ int predLen,
+ itupLen;
+ Relation pg_index;
+ HeapTuple tuple;
+ int i;
+
+ /* ----------------
+ * allocate an IndexTupleForm big enough to hold the
+ * index-predicate (if any) in string form
+ * ----------------
+ */
+ if (predicate != NULL)
{
- indexForm->indhaskeytype = 1;
- break;
- }
- attributeList = lnext(attributeList);
- }
-
- memset((char *)& indexForm->indkey[0], 0, sizeof indexForm->indkey);
- memset((char *)& indexForm->indclass[0], 0, sizeof indexForm->indclass);
-
- /* ----------------
- * copy index key and op class information
- * ----------------
- */
- for (i = 0; i < natts; i += 1) {
- indexForm->indkey[i] = attNums[i];
- indexForm->indclass[i] = classOids[i];
- }
- /*
- * If we have a functional index, add all attribute arguments
- */
- if (PointerIsValid(funcInfo))
+ predString = nodeToString(predicate);
+ predText = (text *) fmgr(F_TEXTIN, predString);
+ pfree(predString);
+ }
+ else
{
- for (i=1; i < FIgetnArgs(funcInfo); i++)
- indexForm->indkey[i] = attNums[i];
+ predText = (text *) fmgr(F_TEXTIN, "");
}
-
- indexForm->indisclustered = '\0'; /* XXX constant */
- indexForm->indisarchived = '\0'; /* XXX constant */
-
- /* ----------------
- * open the system catalog index relation
- * ----------------
- */
- pg_index = heap_openr(IndexRelationName);
-
- /* ----------------
- * form a tuple to insert into pg_index
- * ----------------
- */
- tuple = heap_addheader(Natts_pg_index,
- itupLen,
- (char *)indexForm);
-
- /* ----------------
- * insert the tuple into the pg_index
- * XXX ADD INDEX TUPLES TOO
- * ----------------
- */
- heap_insert(pg_index, tuple);
-
- /* ----------------
- * close the relation and free the tuple
- * ----------------
- */
- heap_close(pg_index);
- pfree(predText);
- pfree(indexForm);
- pfree(tuple);
+ predLen = VARSIZE(predText);
+ itupLen = predLen + sizeof(FormData_pg_index);
+ indexForm = (IndexTupleForm) palloc(itupLen);
+
+ memmove((char *) &indexForm->indpred, (char *) predText, predLen);
+
+ /* ----------------
+ * store the oid information into the index tuple form
+ * ----------------
+ */
+ indexForm->indrelid = heapoid;
+ indexForm->indexrelid = indexoid;
+ indexForm->indproc = (PointerIsValid(funcInfo)) ?
+ FIgetProcOid(funcInfo) : InvalidOid;
+ indexForm->indislossy = islossy;
+ indexForm->indisunique = unique;
+
+ indexForm->indhaskeytype = 0;
+ while (attributeList != NIL)
+ {
+ IndexKey = (IndexElem *) lfirst(attributeList);
+ if (IndexKey->tname != NULL)
+ {
+ indexForm->indhaskeytype = 1;
+ break;
+ }
+ attributeList = lnext(attributeList);
+ }
+
+ memset((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
+ memset((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
+
+ /* ----------------
+ * copy index key and op class information
+ * ----------------
+ */
+ for (i = 0; i < natts; i += 1)
+ {
+ indexForm->indkey[i] = attNums[i];
+ indexForm->indclass[i] = classOids[i];
+ }
+
+ /*
+ * If we have a functional index, add all attribute arguments
+ */
+ if (PointerIsValid(funcInfo))
+ {
+ for (i = 1; i < FIgetnArgs(funcInfo); i++)
+ indexForm->indkey[i] = attNums[i];
+ }
+
+ indexForm->indisclustered = '\0'; /* XXX constant */
+ indexForm->indisarchived = '\0'; /* XXX constant */
+
+ /* ----------------
+ * open the system catalog index relation
+ * ----------------
+ */
+ pg_index = heap_openr(IndexRelationName);
+
+ /* ----------------
+ * form a tuple to insert into pg_index
+ * ----------------
+ */
+ tuple = heap_addheader(Natts_pg_index,
+ itupLen,
+ (char *) indexForm);
+
+ /* ----------------
+ * insert the tuple into the pg_index
+ * XXX ADD INDEX TUPLES TOO
+ * ----------------
+ */
+ heap_insert(pg_index, tuple);
+
+ /* ----------------
+ * close the relation and free the tuple
+ * ----------------
+ */
+ heap_close(pg_index);
+ pfree(predText);
+ pfree(indexForm);
+ pfree(tuple);
}
/* ----------------------------------------------------------------
- * UpdateIndexPredicate
+ * UpdateIndexPredicate
* ----------------------------------------------------------------
*/
void
-UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
+UpdateIndexPredicate(Oid indexoid, Node * oldPred, Node * predicate)
{
- Node *newPred;
- char *predString;
- text *predText;
- Relation pg_index;
- HeapTuple tuple;
- HeapTuple newtup;
- ScanKeyData entry;
- HeapScanDesc scan;
- Buffer buffer;
- int i;
- Datum values[Natts_pg_index];
- char nulls[Natts_pg_index];
- char replace[Natts_pg_index];
-
- /*
- * Construct newPred as a CNF expression equivalent to the OR of the
- * original partial-index predicate ("oldPred") and the extension
- * predicate ("predicate").
- *
- * This should really try to process the result to change things like
- * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
- * that if the extension predicate is NULL (i.e., it is being extended
- * to be a complete index), then newPred will be NULL - in effect,
- * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
- */
- newPred = NULL;
- if (predicate != NULL) {
- newPred =
- (Node*)make_orclause(lcons(make_andclause((List*)predicate),
- lcons(make_andclause((List*)oldPred),
- NIL)));
- newPred = (Node*)cnfify((Expr*)newPred, true);
- }
-
- /* translate the index-predicate to string form */
- if (newPred != NULL) {
- predString = nodeToString(newPred);
- predText = (text *)fmgr(F_TEXTIN, predString);
- pfree(predString);
- } else {
- predText = (text *)fmgr(F_TEXTIN, "");
- }
-
- /* open the index system catalog relation */
- pg_index = heap_openr(IndexRelationName);
-
- ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indexrelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(indexoid));
-
- scan = heap_beginscan(pg_index, 0, NowTimeQual, 1, &entry);
- tuple = heap_getnext(scan, 0, &buffer);
- heap_endscan(scan);
-
- for (i = 0; i < Natts_pg_index; i++) {
- nulls[i] = heap_attisnull(tuple, i+1) ? 'n' : ' ';
- replace[i] = ' ';
- values[i] = (Datum) NULL;
- }
-
- replace[Anum_pg_index_indpred - 1] = 'r';
- values[Anum_pg_index_indpred - 1] = (Datum) predText;
-
- newtup = heap_modifytuple(tuple, buffer, pg_index, values, nulls, replace);
-
- heap_replace(pg_index, &(newtup->t_ctid), newtup);
-
- heap_close(pg_index);
- pfree(predText);
+ Node *newPred;
+ char *predString;
+ text *predText;
+ Relation pg_index;
+ HeapTuple tuple;
+ HeapTuple newtup;
+ ScanKeyData entry;
+ HeapScanDesc scan;
+ Buffer buffer;
+ int i;
+ Datum values[Natts_pg_index];
+ char nulls[Natts_pg_index];
+ char replace[Natts_pg_index];
+
+ /*
+ * Construct newPred as a CNF expression equivalent to the OR of the
+ * original partial-index predicate ("oldPred") and the extension
+ * predicate ("predicate").
+ *
+ * This should really try to process the result to change things like
+ * "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
+ * that if the extension predicate is NULL (i.e., it is being extended
+ * to be a complete index), then newPred will be NULL - in effect,
+ * changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
+ */
+ newPred = NULL;
+ if (predicate != NULL)
+ {
+ newPred =
+ (Node *) make_orclause(lcons(make_andclause((List *) predicate),
+ lcons(make_andclause((List *) oldPred),
+ NIL)));
+ newPred = (Node *) cnfify((Expr *) newPred, true);
+ }
+
+ /* translate the index-predicate to string form */
+ if (newPred != NULL)
+ {
+ predString = nodeToString(newPred);
+ predText = (text *) fmgr(F_TEXTIN, predString);
+ pfree(predString);
+ }
+ else
+ {
+ predText = (text *) fmgr(F_TEXTIN, "");
+ }
+
+ /* open the index system catalog relation */
+ pg_index = heap_openr(IndexRelationName);
+
+ ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indexrelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(indexoid));
+
+ scan = heap_beginscan(pg_index, 0, NowTimeQual, 1, &entry);
+ tuple = heap_getnext(scan, 0, &buffer);
+ heap_endscan(scan);
+
+ for (i = 0; i < Natts_pg_index; i++)
+ {
+ nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
+ replace[i] = ' ';
+ values[i] = (Datum) NULL;
+ }
+
+ replace[Anum_pg_index_indpred - 1] = 'r';
+ values[Anum_pg_index_indpred - 1] = (Datum) predText;
+
+ newtup = heap_modifytuple(tuple, buffer, pg_index, values, nulls, replace);
+
+ heap_replace(pg_index, &(newtup->t_ctid), newtup);
+
+ heap_close(pg_index);
+ pfree(predText);
}
/* ----------------------------------------------------------------
- * InitIndexStrategy
+ * InitIndexStrategy
* ----------------------------------------------------------------
*/
void
InitIndexStrategy(int numatts,
- Relation indexRelation,
- Oid accessMethodObjectId)
+ Relation indexRelation,
+ Oid accessMethodObjectId)
{
- IndexStrategy strategy;
- RegProcedure *support;
- uint16 amstrategies;
- uint16 amsupport;
- Oid attrelid;
- Size strsize;
- extern GlobalMemory CacheCxt;
-
- /* ----------------
- * get information from the index relation descriptor
- * ----------------
- */
- attrelid = indexRelation->rd_att->attrs[0]->attrelid;
- amstrategies = indexRelation->rd_am->amstrategies;
- amsupport = indexRelation->rd_am->amsupport;
-
- /* ----------------
- * get the size of the strategy
- * ----------------
- */
- strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
-
- /* ----------------
- * allocate the new index strategy structure
- *
- * the index strategy has to be allocated in the same
- * context as the relation descriptor cache or else
- * it will be lost at the end of the transaction.
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
-
- strategy = (IndexStrategy)
- MemoryContextAlloc((MemoryContext)CacheCxt, strsize);
-
- if (amsupport > 0) {
- strsize = numatts * (amsupport * sizeof(RegProcedure));
- support = (RegProcedure *) MemoryContextAlloc((MemoryContext)CacheCxt,
- strsize);
- } else {
- support = (RegProcedure *) NULL;
- }
-
- /* ----------------
- * fill in the index strategy structure with information
- * from the catalogs. Note: we use heap override mode
- * in order to be allowed to see the correct information in the
- * catalogs, even though our transaction has not yet committed.
- * ----------------
- */
- setheapoverride(1);
-
- IndexSupportInitialize(strategy, support,
- attrelid, accessMethodObjectId,
- amstrategies, amsupport, numatts);
-
- setheapoverride(0);
-
- /* ----------------
- * store the strategy information in the index reldesc
- * ----------------
- */
- RelationSetIndexSupport(indexRelation, strategy, support);
+ IndexStrategy strategy;
+ RegProcedure *support;
+ uint16 amstrategies;
+ uint16 amsupport;
+ Oid attrelid;
+ Size strsize;
+ extern GlobalMemory CacheCxt;
+
+ /* ----------------
+ * get information from the index relation descriptor
+ * ----------------
+ */
+ attrelid = indexRelation->rd_att->attrs[0]->attrelid;
+ amstrategies = indexRelation->rd_am->amstrategies;
+ amsupport = indexRelation->rd_am->amsupport;
+
+ /* ----------------
+ * get the size of the strategy
+ * ----------------
+ */
+ strsize = AttributeNumberGetIndexStrategySize(numatts, amstrategies);
+
+ /* ----------------
+ * allocate the new index strategy structure
+ *
+ * the index strategy has to be allocated in the same
+ * context as the relation descriptor cache or else
+ * it will be lost at the end of the transaction.
+ * ----------------
+ */
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+
+ strategy = (IndexStrategy)
+ MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
+
+ if (amsupport > 0)
+ {
+ strsize = numatts * (amsupport * sizeof(RegProcedure));
+ support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
+ strsize);
+ }
+ else
+ {
+ support = (RegProcedure *) NULL;
+ }
+
+ /* ----------------
+ * fill in the index strategy structure with information
+ * from the catalogs. Note: we use heap override mode
+ * in order to be allowed to see the correct information in the
+ * catalogs, even though our transaction has not yet committed.
+ * ----------------
+ */
+ setheapoverride(1);
+
+ IndexSupportInitialize(strategy, support,
+ attrelid, accessMethodObjectId,
+ amstrategies, amsupport, numatts);
+
+ setheapoverride(0);
+
+ /* ----------------
+ * store the strategy information in the index reldesc
+ * ----------------
+ */
+ RelationSetIndexSupport(indexRelation, strategy, support);
}
/* ----------------------------------------------------------------
- * index_create
+ * index_create
* ----------------------------------------------------------------
*/
void
index_create(char *heapRelationName,
- char *indexRelationName,
- FuncIndexInfo *funcInfo,
- List *attributeList,
- Oid accessMethodObjectId,
- int numatts,
- AttrNumber attNums[],
- Oid classObjectId[],
- uint16 parameterCount,
- Datum *parameter,
- Node *predicate,
- bool islossy,
- bool unique)
+ char *indexRelationName,
+ FuncIndexInfo * funcInfo,
+ List * attributeList,
+ Oid accessMethodObjectId,
+ int numatts,
+ AttrNumber attNums[],
+ Oid classObjectId[],
+ uint16 parameterCount,
+ Datum * parameter,
+ Node * predicate,
+ bool islossy,
+ bool unique)
{
- Relation heapRelation;
- Relation indexRelation;
- TupleDesc indexTupDesc;
- Oid heapoid;
- Oid indexoid;
- PredInfo *predInfo;
-
- /* ----------------
- * check parameters
- * ----------------
- */
- if (numatts < 1)
- elog(WARN, "must index at least one attribute");
-
- /* ----------------
- * get heap relation oid and open the heap relation
- * XXX ADD INDEXING
- * ----------------
- */
- heapoid = GetHeapRelationOid(heapRelationName, indexRelationName);
-
- heapRelation = heap_open(heapoid);
-
- /* ----------------
- * write lock heap to guarantee exclusive access
- * ----------------
- */
-
- RelationSetLockForWrite(heapRelation);
-
- /* ----------------
- * construct new tuple descriptor
- * ----------------
- */
- if (PointerIsValid(funcInfo))
- indexTupDesc = BuildFuncTupleDesc(funcInfo);
- else
- indexTupDesc = ConstructTupleDescriptor(heapoid,
- heapRelation,
- attributeList,
- numatts,
- attNums);
-
- /* ----------------
- * create the index relation
- * ----------------
- */
- indexRelation = heap_creatr(indexRelationName,
- DEFAULT_SMGR,
- indexTupDesc);
-
- /* ----------------
- * construct the index relation descriptor
- *
- * XXX should have a proper way to create cataloged relations
- * ----------------
- */
- ConstructIndexReldesc(indexRelation, accessMethodObjectId);
-
- /* ----------------
- * add index to catalogs
- * (append RELATION tuple)
- * ----------------
- */
- indexoid = UpdateRelationRelation(indexRelation);
-
- /* ----------------
- * Now get the index procedure (only relevant for functional indices).
- * ----------------
- */
-
- if (PointerIsValid(funcInfo))
+ Relation heapRelation;
+ Relation indexRelation;
+ TupleDesc indexTupDesc;
+ Oid heapoid;
+ Oid indexoid;
+ PredInfo *predInfo;
+
+ /* ----------------
+ * check parameters
+ * ----------------
+ */
+ if (numatts < 1)
+ elog(WARN, "must index at least one attribute");
+
+ /* ----------------
+ * get heap relation oid and open the heap relation
+ * XXX ADD INDEXING
+ * ----------------
+ */
+ heapoid = GetHeapRelationOid(heapRelationName, indexRelationName);
+
+ heapRelation = heap_open(heapoid);
+
+ /* ----------------
+ * write lock heap to guarantee exclusive access
+ * ----------------
+ */
+
+ RelationSetLockForWrite(heapRelation);
+
+ /* ----------------
+ * construct new tuple descriptor
+ * ----------------
+ */
+ if (PointerIsValid(funcInfo))
+ indexTupDesc = BuildFuncTupleDesc(funcInfo);
+ else
+ indexTupDesc = ConstructTupleDescriptor(heapoid,
+ heapRelation,
+ attributeList,
+ numatts,
+ attNums);
+
+ /* ----------------
+ * create the index relation
+ * ----------------
+ */
+ indexRelation = heap_creatr(indexRelationName,
+ DEFAULT_SMGR,
+ indexTupDesc);
+
+ /* ----------------
+ * construct the index relation descriptor
+ *
+ * XXX should have a proper way to create cataloged relations
+ * ----------------
+ */
+ ConstructIndexReldesc(indexRelation, accessMethodObjectId);
+
+ /* ----------------
+ * add index to catalogs
+ * (append RELATION tuple)
+ * ----------------
+ */
+ indexoid = UpdateRelationRelation(indexRelation);
+
+ /* ----------------
+ * Now get the index procedure (only relevant for functional indices).
+ * ----------------
+ */
+
+ if (PointerIsValid(funcInfo))
{
- HeapTuple proc_tup;
-
- proc_tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(FIgetname(funcInfo)),
- Int32GetDatum(FIgetnArgs(funcInfo)),
- PointerGetDatum(FIgetArglist(funcInfo)),
- 0);
-
- if (!HeapTupleIsValid(proc_tup)) {
- func_error("index_create", FIgetname(funcInfo),
- FIgetnArgs(funcInfo),
- FIgetArglist(funcInfo));
- }
- FIgetProcOid(funcInfo) = proc_tup->t_oid;
+ HeapTuple proc_tup;
+
+ proc_tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(FIgetname(funcInfo)),
+ Int32GetDatum(FIgetnArgs(funcInfo)),
+ PointerGetDatum(FIgetArglist(funcInfo)),
+ 0);
+
+ if (!HeapTupleIsValid(proc_tup))
+ {
+ func_error("index_create", FIgetname(funcInfo),
+ FIgetnArgs(funcInfo),
+ FIgetArglist(funcInfo));
+ }
+ FIgetProcOid(funcInfo) = proc_tup->t_oid;
+ }
+
+ /* ----------------
+ * now update the object id's of all the attribute
+ * tuple forms in the index relation's tuple descriptor
+ * ----------------
+ */
+ InitializeAttributeOids(indexRelation, numatts, indexoid);
+
+ /* ----------------
+ * append ATTRIBUTE tuples
+ * ----------------
+ */
+ AppendAttributeTuples(indexRelation, numatts);
+
+ /* ----------------
+ * update pg_index
+ * (append INDEX tuple)
+ *
+ * Note that this stows away a representation of "predicate".
+ * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
+ * ----------------
+ */
+ UpdateIndexRelation(indexoid, heapoid, funcInfo,
+ numatts, attNums, classObjectId, predicate,
+ attributeList, islossy, unique);
+
+ predInfo = (PredInfo *) palloc(sizeof(PredInfo));
+ predInfo->pred = predicate;
+ predInfo->oldPred = NULL;
+
+ /* ----------------
+ * initialize the index strategy
+ * ----------------
+ */
+ InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
+
+ /*
+ * If this is bootstrap (initdb) time, then we don't actually fill in
+ * the index yet. We'll be creating more indices and classes later,
+ * so we delay filling them in until just before we're done with
+ * bootstrapping. Otherwise, we call the routine that constructs the
+ * index. The heap and index relations are closed by index_build().
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ index_register(heapRelationName, indexRelationName, numatts, attNums,
+ parameterCount, parameter, funcInfo, predInfo);
+ }
+ else
+ {
+ heapRelation = heap_openr(heapRelationName);
+ index_build(heapRelation, indexRelation, numatts, attNums,
+ parameterCount, parameter, funcInfo, predInfo);
}
-
- /* ----------------
- * now update the object id's of all the attribute
- * tuple forms in the index relation's tuple descriptor
- * ----------------
- */
- InitializeAttributeOids(indexRelation, numatts, indexoid);
-
- /* ----------------
- * append ATTRIBUTE tuples
- * ----------------
- */
- AppendAttributeTuples(indexRelation, numatts);
-
- /* ----------------
- * update pg_index
- * (append INDEX tuple)
- *
- * Note that this stows away a representation of "predicate".
- * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
- * ----------------
- */
- UpdateIndexRelation(indexoid, heapoid, funcInfo,
- numatts, attNums, classObjectId, predicate,
- attributeList, islossy, unique);
-
- predInfo = (PredInfo*)palloc(sizeof(PredInfo));
- predInfo->pred = predicate;
- predInfo->oldPred = NULL;
-
- /* ----------------
- * initialize the index strategy
- * ----------------
- */
- InitIndexStrategy(numatts, indexRelation, accessMethodObjectId);
-
- /*
- * If this is bootstrap (initdb) time, then we don't actually
- * fill in the index yet. We'll be creating more indices and classes
- * later, so we delay filling them in until just before we're done
- * with bootstrapping. Otherwise, we call the routine that constructs
- * the index. The heap and index relations are closed by index_build().
- */
- if (IsBootstrapProcessingMode()) {
- index_register(heapRelationName, indexRelationName, numatts, attNums,
- parameterCount, parameter, funcInfo, predInfo);
- } else {
- heapRelation = heap_openr(heapRelationName);
- index_build(heapRelation, indexRelation, numatts, attNums,
- parameterCount, parameter, funcInfo, predInfo);
- }
}
/* ----------------------------------------------------------------
- * index_destroy
+ * index_destroy
*
- * XXX break into modules like index_create
+ * XXX break into modules like index_create
* ----------------------------------------------------------------
*/
void
index_destroy(Oid indexId)
{
- Relation indexRelation;
- Relation catalogRelation;
- HeapTuple tuple;
- HeapScanDesc scan;
- ScanKeyData entry;
-
- Assert(OidIsValid(indexId));
-
- indexRelation = index_open(indexId);
-
- /* ----------------
- * fix RELATION relation
- * ----------------
- */
- catalogRelation = heap_openr(RelationRelationName);
-
- ScanKeyEntryInitialize(&entry, 0x0, ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(indexId));;
-
- scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
- tuple = heap_getnext(scan, 0, (Buffer *)NULL);
-
- AssertState(HeapTupleIsValid(tuple));
-
- heap_delete(catalogRelation, &tuple->t_ctid);
- heap_endscan(scan);
- heap_close(catalogRelation);
-
- /* ----------------
- * fix ATTRIBUTE relation
- * ----------------
- */
- catalogRelation = heap_openr(AttributeRelationName);
-
- entry.sk_attno = Anum_pg_attribute_attrelid;
-
- scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
-
- while (tuple = heap_getnext(scan, 0, (Buffer *)NULL),
- HeapTupleIsValid(tuple)) {
-
+ Relation indexRelation;
+ Relation catalogRelation;
+ HeapTuple tuple;
+ HeapScanDesc scan;
+ ScanKeyData entry;
+
+ Assert(OidIsValid(indexId));
+
+ indexRelation = index_open(indexId);
+
+ /* ----------------
+ * fix RELATION relation
+ * ----------------
+ */
+ catalogRelation = heap_openr(RelationRelationName);
+
+ ScanKeyEntryInitialize(&entry, 0x0, ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(indexId));;
+
+ scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
+ tuple = heap_getnext(scan, 0, (Buffer *) NULL);
+
+ AssertState(HeapTupleIsValid(tuple));
+
+ heap_delete(catalogRelation, &tuple->t_ctid);
+ heap_endscan(scan);
+ heap_close(catalogRelation);
+
+ /* ----------------
+ * fix ATTRIBUTE relation
+ * ----------------
+ */
+ catalogRelation = heap_openr(AttributeRelationName);
+
+ entry.sk_attno = Anum_pg_attribute_attrelid;
+
+ scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
+
+ while (tuple = heap_getnext(scan, 0, (Buffer *) NULL),
+ HeapTupleIsValid(tuple))
+ {
+
+ heap_delete(catalogRelation, &tuple->t_ctid);
+ }
+ heap_endscan(scan);
+ heap_close(catalogRelation);
+
+ /* ----------------
+ * fix INDEX relation
+ * ----------------
+ */
+ catalogRelation = heap_openr(IndexRelationName);
+
+ entry.sk_attno = Anum_pg_index_indexrelid;
+
+ scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
+ tuple = heap_getnext(scan, 0, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(NOTICE, "IndexRelationDestroy: %s's INDEX tuple missing",
+ RelationGetRelationName(indexRelation));
+ }
heap_delete(catalogRelation, &tuple->t_ctid);
- }
- heap_endscan(scan);
- heap_close(catalogRelation);
-
- /* ----------------
- * fix INDEX relation
- * ----------------
- */
- catalogRelation = heap_openr(IndexRelationName);
-
- entry.sk_attno = Anum_pg_index_indexrelid;
-
- scan = heap_beginscan(catalogRelation, 0, NowTimeQual, 1, &entry);
- tuple = heap_getnext(scan, 0, (Buffer *)NULL);
- if (! HeapTupleIsValid(tuple)) {
- elog(NOTICE, "IndexRelationDestroy: %s's INDEX tuple missing",
- RelationGetRelationName(indexRelation));
- }
- heap_delete(catalogRelation, &tuple->t_ctid);
- heap_endscan(scan);
- heap_close(catalogRelation);
-
- /*
- * physically remove the file
- */
- if (FileNameUnlink(relpath(indexRelation->rd_rel->relname.data)) < 0)
- elog(WARN, "amdestroyr: unlink: %m");
-
- index_close(indexRelation);
+ heap_endscan(scan);
+ heap_close(catalogRelation);
+
+ /*
+ * physically remove the file
+ */
+ if (FileNameUnlink(relpath(indexRelation->rd_rel->relname.data)) < 0)
+ elog(WARN, "amdestroyr: unlink: %m");
+
+ index_close(indexRelation);
}
/* ----------------------------------------------------------------
- * index_build support
+ * index_build support
* ----------------------------------------------------------------
*/
/* ----------------
- * FormIndexDatum
+ * FormIndexDatum
* ----------------
*/
void
FormIndexDatum(int numberOfAttributes,
- AttrNumber attributeNumber[],
- HeapTuple heapTuple,
- TupleDesc heapDescriptor,
- Buffer buffer,
- Datum *datum,
- char *nullv,
- FuncIndexInfoPtr fInfo)
+ AttrNumber attributeNumber[],
+ HeapTuple heapTuple,
+ TupleDesc heapDescriptor,
+ Buffer buffer,
+ Datum * datum,
+ char *nullv,
+ FuncIndexInfoPtr fInfo)
{
- AttrNumber i;
- int offset;
- bool isNull;
-
- /* ----------------
- * for each attribute we need from the heap tuple,
- * get the attribute and stick it into the datum and
- * null arrays.
- * ----------------
- */
-
- for (i = 1; i <= numberOfAttributes; i += 1) {
- offset = AttrNumberGetAttrOffset(i);
-
- datum[ offset ] =
- PointerGetDatum( GetIndexValue(heapTuple,
- heapDescriptor,
- offset,
- attributeNumber,
- fInfo,
- &isNull,
- buffer) );
-
- nullv[ offset ] = (isNull) ? 'n' : ' ';
- }
+ AttrNumber i;
+ int offset;
+ bool isNull;
+
+ /* ----------------
+ * for each attribute we need from the heap tuple,
+ * get the attribute and stick it into the datum and
+ * null arrays.
+ * ----------------
+ */
+
+ for (i = 1; i <= numberOfAttributes; i += 1)
+ {
+ offset = AttrNumberGetAttrOffset(i);
+
+ datum[offset] =
+ PointerGetDatum(GetIndexValue(heapTuple,
+ heapDescriptor,
+ offset,
+ attributeNumber,
+ fInfo,
+ &isNull,
+ buffer));
+
+ nullv[offset] = (isNull) ? 'n' : ' ';
+ }
}
/* ----------------
- * UpdateStats
+ * UpdateStats
* ----------------
*/
void
UpdateStats(Oid relid, long reltuples, bool hasindex)
{
- Relation whichRel;
- Relation pg_class;
- HeapScanDesc pg_class_scan;
- HeapTuple htup;
- HeapTuple newtup;
- long relpages;
- Buffer buffer;
- int i;
- Form_pg_class rd_rel;
- Relation idescs[Num_pg_class_indices];
-
- static ScanKeyData key[1] = {
- { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure }
- };
- Datum values[Natts_pg_class];
- char nulls[Natts_pg_class];
- char replace[Natts_pg_class];
-
- fmgr_info(ObjectIdEqualRegProcedure, (func_ptr *) &key[0].sk_func,
- &key[0].sk_nargs);
-
- /* ----------------
- * This routine handles updates for both the heap and index relation
- * statistics. In order to guarantee that we're able to *see* the index
- * relation tuple, we bump the command counter id here. The index
- * relation tuple was created in the current transaction.
- * ----------------
- */
- CommandCounterIncrement();
-
- /* ----------------
- * CommandCounterIncrement() flushes invalid cache entries, including
- * those for the heap and index relations for which we're updating
- * statistics. Now that the cache is flushed, it's safe to open the
- * relation again. We need the relation open in order to figure out
- * how many blocks it contains.
- * ----------------
- */
-
- whichRel = RelationIdGetRelation(relid);
-
- if (!RelationIsValid(whichRel))
- elog(WARN, "UpdateStats: cannot open relation id %d", relid);
-
- /* ----------------
- * Find the RELATION relation tuple for the given relation.
- * ----------------
- */
- pg_class = heap_openr(RelationRelationName);
- if (! RelationIsValid(pg_class)) {
- elog(WARN, "UpdateStats: could not open RELATION relation");
- }
- key[0].sk_argument = ObjectIdGetDatum(relid);
-
- pg_class_scan =
- heap_beginscan(pg_class, 0, NowTimeQual, 1, key);
-
- if (! HeapScanIsValid(pg_class_scan)) {
- heap_close(pg_class);
- elog(WARN, "UpdateStats: cannot scan RELATION relation");
- }
-
- /* if the heap_open above succeeded, then so will this heap_getnext() */
- htup = heap_getnext(pg_class_scan, 0, &buffer);
- heap_endscan(pg_class_scan);
-
- /* ----------------
- * update statistics
- * ----------------
- */
- relpages = RelationGetNumberOfBlocks(whichRel);
-
- /*
- * We shouldn't have to do this, but we do... Modify the reldesc
- * in place with the new values so that the cache contains the
- * latest copy.
- */
-
- whichRel->rd_rel->relhasindex = hasindex;
- whichRel->rd_rel->relpages = relpages;
- whichRel->rd_rel->reltuples = reltuples;
-
- for (i = 0; i < Natts_pg_class; i++) {
- nulls[i] = heap_attisnull(htup, i+1) ? 'n' : ' ';
- replace[i] = ' ';
- values[i] = (Datum) NULL;
- }
-
- /*
- * If reltuples wasn't supplied take an educated guess.
- */
- if (reltuples == 0)
- reltuples = relpages*NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
-
- if (IsBootstrapProcessingMode()) {
-
+ Relation whichRel;
+ Relation pg_class;
+ HeapScanDesc pg_class_scan;
+ HeapTuple htup;
+ HeapTuple newtup;
+ long relpages;
+ Buffer buffer;
+ int i;
+ Form_pg_class rd_rel;
+ Relation idescs[Num_pg_class_indices];
+
+ static ScanKeyData key[1] = {
+ {0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure}
+ };
+ Datum values[Natts_pg_class];
+ char nulls[Natts_pg_class];
+ char replace[Natts_pg_class];
+
+ fmgr_info(ObjectIdEqualRegProcedure, (func_ptr *) & key[0].sk_func,
+ &key[0].sk_nargs);
+
+ /* ----------------
+ * This routine handles updates for both the heap and index relation
+ * statistics. In order to guarantee that we're able to *see* the index
+ * relation tuple, we bump the command counter id here. The index
+ * relation tuple was created in the current transaction.
+ * ----------------
+ */
+ CommandCounterIncrement();
+
+ /* ----------------
+ * CommandCounterIncrement() flushes invalid cache entries, including
+ * those for the heap and index relations for which we're updating
+ * statistics. Now that the cache is flushed, it's safe to open the
+ * relation again. We need the relation open in order to figure out
+ * how many blocks it contains.
+ * ----------------
+ */
+
+ whichRel = RelationIdGetRelation(relid);
+
+ if (!RelationIsValid(whichRel))
+ elog(WARN, "UpdateStats: cannot open relation id %d", relid);
+
+ /* ----------------
+ * Find the RELATION relation tuple for the given relation.
+ * ----------------
+ */
+ pg_class = heap_openr(RelationRelationName);
+ if (!RelationIsValid(pg_class))
+ {
+ elog(WARN, "UpdateStats: could not open RELATION relation");
+ }
+ key[0].sk_argument = ObjectIdGetDatum(relid);
+
+ pg_class_scan =
+ heap_beginscan(pg_class, 0, NowTimeQual, 1, key);
+
+ if (!HeapScanIsValid(pg_class_scan))
+ {
+ heap_close(pg_class);
+ elog(WARN, "UpdateStats: cannot scan RELATION relation");
+ }
+
+ /* if the heap_open above succeeded, then so will this heap_getnext() */
+ htup = heap_getnext(pg_class_scan, 0, &buffer);
+ heap_endscan(pg_class_scan);
+
+ /* ----------------
+ * update statistics
+ * ----------------
+ */
+ relpages = RelationGetNumberOfBlocks(whichRel);
+
+ /*
+ * We shouldn't have to do this, but we do... Modify the reldesc in
+ * place with the new values so that the cache contains the latest
+ * copy.
+ */
+
+ whichRel->rd_rel->relhasindex = hasindex;
+ whichRel->rd_rel->relpages = relpages;
+ whichRel->rd_rel->reltuples = reltuples;
+
+ for (i = 0; i < Natts_pg_class; i++)
+ {
+ nulls[i] = heap_attisnull(htup, i + 1) ? 'n' : ' ';
+ replace[i] = ' ';
+ values[i] = (Datum) NULL;
+ }
+
/*
- * At bootstrap time, we don't need to worry about concurrency
- * or visibility of changes, so we cheat.
- */
-
- rd_rel = (Form_pg_class) GETSTRUCT(htup);
- rd_rel->relpages = relpages;
- rd_rel->reltuples = reltuples;
- rd_rel->relhasindex = hasindex;
- } else {
- /* during normal processing, work harder */
- replace[Anum_pg_class_relpages - 1] = 'r';
- values[Anum_pg_class_relpages - 1] = (Datum)relpages;
- replace[Anum_pg_class_reltuples - 1] = 'r';
- values[Anum_pg_class_reltuples - 1] = (Datum)reltuples;
- replace[Anum_pg_class_relhasindex - 1] = 'r';
- values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex);
-
- newtup = heap_modifytuple(htup, buffer, pg_class, values,
- nulls, replace);
- heap_replace(pg_class, &(newtup->t_ctid), newtup);
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
- }
-
- heap_close(pg_class);
- heap_close(whichRel);
+ * If reltuples wasn't supplied take an educated guess.
+ */
+ if (reltuples == 0)
+ reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
+
+ if (IsBootstrapProcessingMode())
+ {
+
+ /*
+ * At bootstrap time, we don't need to worry about concurrency or
+ * visibility of changes, so we cheat.
+ */
+
+ rd_rel = (Form_pg_class) GETSTRUCT(htup);
+ rd_rel->relpages = relpages;
+ rd_rel->reltuples = reltuples;
+ rd_rel->relhasindex = hasindex;
+ }
+ else
+ {
+ /* during normal processing, work harder */
+ replace[Anum_pg_class_relpages - 1] = 'r';
+ values[Anum_pg_class_relpages - 1] = (Datum) relpages;
+ replace[Anum_pg_class_reltuples - 1] = 'r';
+ values[Anum_pg_class_reltuples - 1] = (Datum) reltuples;
+ replace[Anum_pg_class_relhasindex - 1] = 'r';
+ values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex);
+
+ newtup = heap_modifytuple(htup, buffer, pg_class, values,
+ nulls, replace);
+ heap_replace(pg_class, &(newtup->t_ctid), newtup);
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+ }
+
+ heap_close(pg_class);
+ heap_close(whichRel);
}
/* -------------------------
- * FillDummyExprContext
- * Sets up dummy ExprContext and TupleTableSlot objects for use
- * with ExecQual.
+ * FillDummyExprContext
+ * Sets up dummy ExprContext and TupleTableSlot objects for use
+ * with ExecQual.
* -------------------------
*/
void
-FillDummyExprContext(ExprContext *econtext,
- TupleTableSlot *slot,
- TupleDesc tupdesc,
- Buffer buffer)
+FillDummyExprContext(ExprContext * econtext,
+ TupleTableSlot * slot,
+ TupleDesc tupdesc,
+ Buffer buffer)
{
- econtext->ecxt_scantuple = slot;
- econtext->ecxt_innertuple = NULL;
- econtext->ecxt_outertuple = NULL;
- econtext->ecxt_param_list_info = NULL;
- econtext->ecxt_range_table = NULL;
-
- slot->ttc_tupleDescriptor = tupdesc;
- slot->ttc_buffer = buffer;
- slot->ttc_shouldFree = false;
+ econtext->ecxt_scantuple = slot;
+ econtext->ecxt_innertuple = NULL;
+ econtext->ecxt_outertuple = NULL;
+ econtext->ecxt_param_list_info = NULL;
+ econtext->ecxt_range_table = NULL;
+
+ slot->ttc_tupleDescriptor = tupdesc;
+ slot->ttc_buffer = buffer;
+ slot->ttc_shouldFree = false;
}
/* ----------------
- * DefaultBuild
+ * DefaultBuild
* ----------------
*/
static void
DefaultBuild(Relation heapRelation,
- Relation indexRelation,
- int numberOfAttributes,
- AttrNumber attributeNumber[],
- IndexStrategy indexStrategy, /* not used */
- uint16 parameterCount, /* not used */
- Datum parameter[], /* not used */
- FuncIndexInfoPtr funcInfo,
- PredInfo *predInfo)
+ Relation indexRelation,
+ int numberOfAttributes,
+ AttrNumber attributeNumber[],
+ IndexStrategy indexStrategy, /* not used */
+ uint16 parameterCount, /* not used */
+ Datum parameter[], /* not used */
+ FuncIndexInfoPtr funcInfo,
+ PredInfo * predInfo)
{
- HeapScanDesc scan;
- HeapTuple heapTuple;
- Buffer buffer;
-
- IndexTuple indexTuple;
- TupleDesc heapDescriptor;
- TupleDesc indexDescriptor;
- Datum *datum;
- char *nullv;
- long reltuples, indtuples;
+ HeapScanDesc scan;
+ HeapTuple heapTuple;
+ Buffer buffer;
+
+ IndexTuple indexTuple;
+ TupleDesc heapDescriptor;
+ TupleDesc indexDescriptor;
+ Datum *datum;
+ char *nullv;
+ long reltuples,
+ indtuples;
+
#ifndef OMIT_PARTIAL_INDEX
- ExprContext *econtext;
- TupleTable tupleTable;
- TupleTableSlot *slot;
+ ExprContext *econtext;
+ TupleTable tupleTable;
+ TupleTableSlot *slot;
+
#endif
- Node *predicate;
- Node *oldPred;
-
- InsertIndexResult insertResult;
-
- /* ----------------
- * more & better checking is needed
- * ----------------
- */
- Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
-
- /* ----------------
- * get the tuple descriptors from the relations so we know
- * how to form the index tuples..
- * ----------------
- */
- heapDescriptor = RelationGetTupleDescriptor(heapRelation);
- indexDescriptor = RelationGetTupleDescriptor(indexRelation);
-
- /* ----------------
- * datum and null are arrays in which we collect the index attributes
- * when forming a new index tuple.
- * ----------------
- */
- datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
- nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
-
- /*
- * If this is a predicate (partial) index, we will need to evaluate the
- * predicate using ExecQual, which requires the current tuple to be in a
- * slot of a TupleTable. In addition, ExecQual must have an ExprContext
- * referring to that slot. Here, we initialize dummy TupleTable and
- * ExprContext objects for this purpose. --Nels, Feb '92
- */
-
- predicate = predInfo->pred;
- oldPred = predInfo->oldPred;
+ Node *predicate;
+ Node *oldPred;
+
+ InsertIndexResult insertResult;
+
+ /* ----------------
+ * more & better checking is needed
+ * ----------------
+ */
+ Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
+
+ /* ----------------
+ * get the tuple descriptors from the relations so we know
+ * how to form the index tuples..
+ * ----------------
+ */
+ heapDescriptor = RelationGetTupleDescriptor(heapRelation);
+ indexDescriptor = RelationGetTupleDescriptor(indexRelation);
+
+ /* ----------------
+ * datum and null are arrays in which we collect the index attributes
+ * when forming a new index tuple.
+ * ----------------
+ */
+ datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
+ nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
+
+ /*
+ * If this is a predicate (partial) index, we will need to evaluate
+ * the predicate using ExecQual, which requires the current tuple to
+ * be in a slot of a TupleTable. In addition, ExecQual must have an
+ * ExprContext referring to that slot. Here, we initialize dummy
+ * TupleTable and ExprContext objects for this purpose. --Nels, Feb
+ * '92
+ */
+
+ predicate = predInfo->pred;
+ oldPred = predInfo->oldPred;
#ifndef OMIT_PARTIAL_INDEX
- if (predicate != NULL || oldPred != NULL) {
- tupleTable = ExecCreateTupleTable(1);
- slot = ExecAllocTableSlot(tupleTable);
- econtext = makeNode(ExprContext);
- FillDummyExprContext(econtext, slot, heapDescriptor, buffer);
- }
+ if (predicate != NULL || oldPred != NULL)
+ {
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ econtext = makeNode(ExprContext);
+ FillDummyExprContext(econtext, slot, heapDescriptor, buffer);
+ }
else
{
econtext = NULL;
tupleTable = 0;
slot = NULL;
}
-#endif /* OMIT_PARTIAL_INDEX */
-
- /* ----------------
- * Ok, begin our scan of the base relation.
- * ----------------
- */
- scan = heap_beginscan(heapRelation, /* relation */
- 0, /* start at end */
- NowTimeQual, /* time range */
- 0, /* number of keys */
- (ScanKey) NULL); /* scan key */
-
- reltuples = indtuples = 0;
-
- /* ----------------
- * for each tuple in the base relation, we create an index
- * tuple and add it to the index relation. We keep a running
- * count of the number of tuples so that we can update pg_class
- * with correct statistics when we're done building the index.
- * ----------------
- */
- while (heapTuple = heap_getnext(scan, 0, &buffer),
- HeapTupleIsValid(heapTuple)) {
-
- reltuples++;
-
- /*
- * If oldPred != NULL, this is an EXTEND INDEX command, so skip
- * this tuple if it was already in the existing partial index
+#endif /* OMIT_PARTIAL_INDEX */
+
+ /* ----------------
+ * Ok, begin our scan of the base relation.
+ * ----------------
*/
- if (oldPred != NULL) {
+ scan = heap_beginscan(heapRelation, /* relation */
+ 0, /* start at end */
+ NowTimeQual, /* time range */
+ 0, /* number of keys */
+ (ScanKey) NULL); /* scan key */
+
+ reltuples = indtuples = 0;
+
+ /* ----------------
+ * for each tuple in the base relation, we create an index
+ * tuple and add it to the index relation. We keep a running
+ * count of the number of tuples so that we can update pg_class
+ * with correct statistics when we're done building the index.
+ * ----------------
+ */
+ while (heapTuple = heap_getnext(scan, 0, &buffer),
+ HeapTupleIsValid(heapTuple))
+ {
+
+ reltuples++;
+
+ /*
+ * If oldPred != NULL, this is an EXTEND INDEX command, so skip
+ * this tuple if it was already in the existing partial index
+ */
+ if (oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, heapTuple); */
- slot->val = heapTuple;
- if (ExecQual((List*)oldPred, econtext) == true) {
+ /* SetSlotContents(slot, heapTuple); */
+ slot->val = heapTuple;
+ if (ExecQual((List *) oldPred, econtext) == true)
+ {
+ indtuples++;
+ continue;
+ }
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
+ /*
+ * Skip this tuple if it doesn't satisfy the partial-index
+ * predicate
+ */
+ if (predicate != NULL)
+ {
+#ifndef OMIT_PARTIAL_INDEX
+ /* SetSlotContents(slot, heapTuple); */
+ slot->val = heapTuple;
+ if (ExecQual((List *) predicate, econtext) == false)
+ continue;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+
indtuples++;
- continue;
- }
-#endif /* OMIT_PARTIAL_INDEX */
+
+ /* ----------------
+ * FormIndexDatum fills in its datum and null parameters
+ * with attribute information taken from the given heap tuple.
+ * ----------------
+ */
+ FormIndexDatum(numberOfAttributes, /* num attributes */
+ attributeNumber, /* array of att nums to extract */
+ heapTuple, /* tuple from base relation */
+ heapDescriptor, /* heap tuple's descriptor */
+ buffer, /* buffer used in the scan */
+ datum, /* return: array of attributes */
+ nullv, /* return: array of char's */
+ funcInfo);
+
+ indexTuple = index_formtuple(indexDescriptor,
+ datum,
+ nullv);
+
+ indexTuple->t_tid = heapTuple->t_ctid;
+
+ insertResult = index_insert(indexRelation, datum, nullv,
+ &(heapTuple->t_ctid), heapRelation);
+
+ if (insertResult)
+ pfree(insertResult);
+ pfree(indexTuple);
}
-
- /* Skip this tuple if it doesn't satisfy the partial-index predicate */
- if (predicate != NULL) {
+
+ heap_endscan(scan);
+
+ if (predicate != NULL || oldPred != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*SetSlotContents(slot, heapTuple); */
- slot->val = heapTuple;
- if (ExecQual((List*)predicate, econtext) == false)
- continue;
-#endif /* OMIT_PARTIAL_INDEX */
+ ExecDestroyTupleTable(tupleTable, false);
+#endif /* OMIT_PARTIAL_INDEX */
}
-
- indtuples++;
-
- /* ----------------
- * FormIndexDatum fills in its datum and null parameters
- * with attribute information taken from the given heap tuple.
- * ----------------
+
+ pfree(nullv);
+ pfree(datum);
+
+ /*
+ * Okay, now update the reltuples and relpages statistics for both the
+ * heap relation and the index. These statistics are used by the
+ * planner to choose a scan type. They are maintained generally by
+ * the vacuum daemon, but we update them here to make the index useful
+ * as soon as possible.
*/
- FormIndexDatum(numberOfAttributes, /* num attributes */
- attributeNumber, /* array of att nums to extract */
- heapTuple, /* tuple from base relation */
- heapDescriptor, /* heap tuple's descriptor */
- buffer, /* buffer used in the scan */
- datum, /* return: array of attributes */
- nullv, /* return: array of char's */
- funcInfo);
-
- indexTuple = index_formtuple(indexDescriptor,
- datum,
- nullv);
-
- indexTuple->t_tid = heapTuple->t_ctid;
-
- insertResult = index_insert(indexRelation, datum, nullv,
- &(heapTuple->t_ctid), heapRelation);
-
- if (insertResult) pfree(insertResult);
- pfree(indexTuple);
- }
-
- heap_endscan(scan);
-
- if (predicate != NULL || oldPred != NULL) {
-#ifndef OMIT_PARTIAL_INDEX
- ExecDestroyTupleTable(tupleTable, false);
-#endif /* OMIT_PARTIAL_INDEX */
- }
-
- pfree(nullv);
- pfree(datum);
-
- /*
- * Okay, now update the reltuples and relpages statistics for both
- * the heap relation and the index. These statistics are used by
- * the planner to choose a scan type. They are maintained generally
- * by the vacuum daemon, but we update them here to make the index
- * useful as soon as possible.
- */
- UpdateStats(heapRelation->rd_id, reltuples, true);
- UpdateStats(indexRelation->rd_id, indtuples, false);
- if (oldPred != NULL) {
- if (indtuples == reltuples) predicate = NULL;
- UpdateIndexPredicate(indexRelation->rd_id, oldPred, predicate);
- }
+ UpdateStats(heapRelation->rd_id, reltuples, true);
+ UpdateStats(indexRelation->rd_id, indtuples, false);
+ if (oldPred != NULL)
+ {
+ if (indtuples == reltuples)
+ predicate = NULL;
+ UpdateIndexPredicate(indexRelation->rd_id, oldPred, predicate);
+ }
}
/* ----------------
- * index_build
+ * index_build
* ----------------
*/
void
index_build(Relation heapRelation,
- Relation indexRelation,
- int numberOfAttributes,
- AttrNumber attributeNumber[],
- uint16 parameterCount,
- Datum *parameter,
- FuncIndexInfo *funcInfo,
- PredInfo *predInfo)
+ Relation indexRelation,
+ int numberOfAttributes,
+ AttrNumber attributeNumber[],
+ uint16 parameterCount,
+ Datum * parameter,
+ FuncIndexInfo * funcInfo,
+ PredInfo * predInfo)
{
- RegProcedure procedure;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(indexRelation));
- Assert(PointerIsValid(indexRelation->rd_am));
-
- procedure = indexRelation->rd_am->ambuild;
-
- /* ----------------
- * use the access method build procedure if supplied..
- * ----------------
- */
- if (RegProcedureIsValid(procedure))
- fmgr(procedure,
- heapRelation,
- indexRelation,
- numberOfAttributes,
- attributeNumber,
- RelationGetIndexStrategy(indexRelation),
- parameterCount,
- parameter,
- funcInfo,
- predInfo);
- else
- DefaultBuild(heapRelation,
- indexRelation,
- numberOfAttributes,
- attributeNumber,
- RelationGetIndexStrategy(indexRelation),
- parameterCount,
- parameter,
- funcInfo,
- predInfo);
+ RegProcedure procedure;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(indexRelation));
+ Assert(PointerIsValid(indexRelation->rd_am));
+
+ procedure = indexRelation->rd_am->ambuild;
+
+ /* ----------------
+ * use the access method build procedure if supplied..
+ * ----------------
+ */
+ if (RegProcedureIsValid(procedure))
+ fmgr(procedure,
+ heapRelation,
+ indexRelation,
+ numberOfAttributes,
+ attributeNumber,
+ RelationGetIndexStrategy(indexRelation),
+ parameterCount,
+ parameter,
+ funcInfo,
+ predInfo);
+ else
+ DefaultBuild(heapRelation,
+ indexRelation,
+ numberOfAttributes,
+ attributeNumber,
+ RelationGetIndexStrategy(indexRelation),
+ parameterCount,
+ parameter,
+ funcInfo,
+ predInfo);
}
/*
@@ -1712,20 +1781,21 @@ index_build(Relation heapRelation,
bool
IndexIsUnique(Oid indexId)
{
- HeapTuple tuple;
- IndexTupleForm index;
-
- tuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(indexId),
- 0,0,0);
- if(!HeapTupleIsValid(tuple)) {
- elog(WARN, "IndexIsUnique: can't find index id %d",
- indexId);
- }
- index = (IndexTupleForm)GETSTRUCT(tuple);
- Assert(index->indexrelid == indexId);
-
- return index->indisunique;
+ HeapTuple tuple;
+ IndexTupleForm index;
+
+ tuple = SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(indexId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "IndexIsUnique: can't find index id %d",
+ indexId);
+ }
+ index = (IndexTupleForm) GETSTRUCT(tuple);
+ Assert(index->indexrelid == indexId);
+
+ return index->indisunique;
}
/*
@@ -1743,32 +1813,33 @@ IndexIsUnique(Oid indexId)
bool
IndexIsUniqueNoCache(Oid indexId)
{
- Relation pg_index;
- ScanKeyData skey[1];
- HeapScanDesc scandesc;
- HeapTuple tuple;
- IndexTupleForm index;
- bool isunique;
-
- pg_index = heap_openr(IndexRelationName);
-
- ScanKeyEntryInitialize(&skey[0], (bits16)0x0,
- Anum_pg_index_indexrelid,
- (RegProcedure)ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(indexId));
-
- scandesc = heap_beginscan(pg_index, 0, SelfTimeQual, 1, skey);
-
- tuple = heap_getnext(scandesc, 0, NULL);
- if(!HeapTupleIsValid(tuple)) {
- elog(WARN, "IndexIsUniqueNoCache: can't find index id %d",
- indexId);
- }
- index = (IndexTupleForm)GETSTRUCT(tuple);
- Assert(index->indexrelid == indexId);
- isunique = index->indisunique;
-
- heap_endscan (scandesc);
- heap_close (pg_index);
- return isunique;
+ Relation pg_index;
+ ScanKeyData skey[1];
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+ IndexTupleForm index;
+ bool isunique;
+
+ pg_index = heap_openr(IndexRelationName);
+
+ ScanKeyEntryInitialize(&skey[0], (bits16) 0x0,
+ Anum_pg_index_indexrelid,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(indexId));
+
+ scandesc = heap_beginscan(pg_index, 0, SelfTimeQual, 1, skey);
+
+ tuple = heap_getnext(scandesc, 0, NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "IndexIsUniqueNoCache: can't find index id %d",
+ indexId);
+ }
+ index = (IndexTupleForm) GETSTRUCT(tuple);
+ Assert(index->indexrelid == indexId);
+ isunique = index->indisunique;
+
+ heap_endscan(scandesc);
+ heap_close(pg_index);
+ return isunique;
}
diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c
index 2d769d58615..6a89258d972 100644
--- a/src/backend/catalog/indexing.c
+++ b/src/backend/catalog/indexing.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* indexing.c--
- * This file contains routines to support indices defined on system
- * catalogs.
+ * This file contains routines to support indices defined on system
+ * catalogs.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.11 1997/08/31 09:56:18 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.12 1997/09/07 04:40:21 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,36 +34,37 @@
/*
* Names of indices on the following system catalogs:
*
- * pg_attribute
- * pg_proc
- * pg_type
- * pg_naming
- * pg_class
- * pg_attrdef
- * pg_relcheck
- * pg_trigger
+ * pg_attribute
+ * pg_proc
+ * pg_type
+ * pg_naming
+ * pg_class
+ * pg_attrdef
+ * pg_relcheck
+ * pg_trigger
*/
-char *Name_pg_attr_indices[Num_pg_attr_indices] = {AttributeNameIndex,
- AttributeNumIndex,
- AttributeRelidIndex};
-char *Name_pg_proc_indices[Num_pg_proc_indices] = { ProcedureNameIndex,
- ProcedureOidIndex,
- ProcedureSrcIndex};
-char *Name_pg_type_indices[Num_pg_type_indices] = { TypeNameIndex,
- TypeOidIndex};
-char *Name_pg_class_indices[Num_pg_class_indices]= { ClassNameIndex,
- ClassOidIndex};
-char *Name_pg_attrdef_indices[Num_pg_attrdef_indices]= { AttrDefaultIndex };
+char *Name_pg_attr_indices[Num_pg_attr_indices] = {AttributeNameIndex,
+ AttributeNumIndex,
+AttributeRelidIndex};
+char *Name_pg_proc_indices[Num_pg_proc_indices] = {ProcedureNameIndex,
+ ProcedureOidIndex,
+ProcedureSrcIndex};
+char *Name_pg_type_indices[Num_pg_type_indices] = {TypeNameIndex,
+TypeOidIndex};
+char *Name_pg_class_indices[Num_pg_class_indices] = {ClassNameIndex,
+ClassOidIndex};
+char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] = {AttrDefaultIndex};
-char *Name_pg_relcheck_indices[Num_pg_relcheck_indices]= { RelCheckIndex };
+char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] = {RelCheckIndex};
-char *Name_pg_trigger_indices[Num_pg_trigger_indices]= { TriggerRelidIndex };
+char *Name_pg_trigger_indices[Num_pg_trigger_indices] = {TriggerRelidIndex};
-static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
- Relation idesc,
- ScanKey skey);
+static HeapTuple
+CatalogIndexFetchTuple(Relation heapRelation,
+ Relation idesc,
+ ScanKey skey);
/*
@@ -75,11 +76,11 @@ static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
void
CatalogOpenIndices(int nIndices, char *names[], Relation idescs[])
{
- int i;
-
- for (i=0; i<nIndices; i++)
+ int i;
+
+ for (i = 0; i < nIndices; i++)
{
- idescs[i] = index_openr(names[i]);
+ idescs[i] = index_openr(names[i]);
}
}
@@ -87,83 +88,84 @@ CatalogOpenIndices(int nIndices, char *names[], Relation idescs[])
* This is the inverse routine to CatalogOpenIndices()
*/
void
-CatalogCloseIndices(int nIndices, Relation *idescs)
+CatalogCloseIndices(int nIndices, Relation * idescs)
{
- int i;
-
- for (i=0; i<nIndices; i++)
- index_close(idescs[i]);
+ int i;
+
+ for (i = 0; i < nIndices; i++)
+ index_close(idescs[i]);
}
/*
* For the same reasons outlined above CatalogOpenIndices() we need a routine
- * that takes a new catalog tuple and inserts an associated index tuple into
+ * that takes a new catalog tuple and inserts an associated index tuple into
* each catalog index.
*/
void
-CatalogIndexInsert(Relation *idescs,
- int nIndices,
- Relation heapRelation,
- HeapTuple heapTuple)
+CatalogIndexInsert(Relation * idescs,
+ int nIndices,
+ Relation heapRelation,
+ HeapTuple heapTuple)
{
- HeapTuple pgIndexTup;
- TupleDesc heapDescriptor;
- IndexTupleForm pgIndexP;
- Datum datum;
- int natts;
- AttrNumber *attnumP;
- FuncIndexInfo finfo, *finfoP;
- char nulls[INDEX_MAX_KEYS];
- int i;
-
- heapDescriptor = RelationGetTupleDescriptor(heapRelation);
-
- for (i=0; i<nIndices; i++)
+ HeapTuple pgIndexTup;
+ TupleDesc heapDescriptor;
+ IndexTupleForm pgIndexP;
+ Datum datum;
+ int natts;
+ AttrNumber *attnumP;
+ FuncIndexInfo finfo,
+ *finfoP;
+ char nulls[INDEX_MAX_KEYS];
+ int i;
+
+ heapDescriptor = RelationGetTupleDescriptor(heapRelation);
+
+ for (i = 0; i < nIndices; i++)
{
- TupleDesc indexDescriptor;
- InsertIndexResult indexRes;
-
- indexDescriptor = RelationGetTupleDescriptor(idescs[i]);
- pgIndexTup = SearchSysCacheTuple(INDEXRELID,
- Int32GetDatum(idescs[i]->rd_id),
- 0,0,0);
- Assert(pgIndexTup);
- pgIndexP = (IndexTupleForm)GETSTRUCT(pgIndexTup);
-
- /*
- * Compute the number of attributes we are indexing upon.
- * very important - can't assume one if this is a functional
- * index.
- */
- for (attnumP=(&pgIndexP->indkey[0]), natts=0;
- *attnumP != InvalidAttrNumber;
- attnumP++, natts++)
- ;
-
- if (pgIndexP->indproc != InvalidOid)
+ TupleDesc indexDescriptor;
+ InsertIndexResult indexRes;
+
+ indexDescriptor = RelationGetTupleDescriptor(idescs[i]);
+ pgIndexTup = SearchSysCacheTuple(INDEXRELID,
+ Int32GetDatum(idescs[i]->rd_id),
+ 0, 0, 0);
+ Assert(pgIndexTup);
+ pgIndexP = (IndexTupleForm) GETSTRUCT(pgIndexTup);
+
+ /*
+ * Compute the number of attributes we are indexing upon. very
+ * important - can't assume one if this is a functional index.
+ */
+ for (attnumP = (&pgIndexP->indkey[0]), natts = 0;
+ *attnumP != InvalidAttrNumber;
+ attnumP++, natts++)
+ ;
+
+ if (pgIndexP->indproc != InvalidOid)
{
- FIgetnArgs(&finfo) = natts;
- natts = 1;
- FIgetProcOid(&finfo) = pgIndexP->indproc;
- *(FIgetname(&finfo)) = '\0';
- finfoP = &finfo;
+ FIgetnArgs(&finfo) = natts;
+ natts = 1;
+ FIgetProcOid(&finfo) = pgIndexP->indproc;
+ *(FIgetname(&finfo)) = '\0';
+ finfoP = &finfo;
}
- else
- finfoP = (FuncIndexInfo *)NULL;
-
- FormIndexDatum(natts,
- (AttrNumber *)&pgIndexP->indkey[0],
- heapTuple,
- heapDescriptor,
- InvalidBuffer,
- &datum,
- nulls,
- finfoP);
-
- indexRes = index_insert(idescs[i], &datum, nulls,
- &(heapTuple->t_ctid), heapRelation);
- if (indexRes) pfree(indexRes);
+ else
+ finfoP = (FuncIndexInfo *) NULL;
+
+ FormIndexDatum(natts,
+ (AttrNumber *) & pgIndexP->indkey[0],
+ heapTuple,
+ heapDescriptor,
+ InvalidBuffer,
+ &datum,
+ nulls,
+ finfoP);
+
+ indexRes = index_insert(idescs[i], &datum, nulls,
+ &(heapTuple->t_ctid), heapRelation);
+ if (indexRes)
+ pfree(indexRes);
}
}
@@ -174,81 +176,88 @@ CatalogIndexInsert(Relation *idescs,
bool
CatalogHasIndex(char *catName, Oid catId)
{
- Relation pg_class;
- HeapTuple htup;
- Form_pg_class pgRelP;
- int i;
-
- Assert(IsSystemRelationName(catName));
-
- /*
- * If we're bootstraping we don't have pg_class (or any indices).
- */
- if (IsBootstrapProcessingMode())
- return false;
-
- if (IsInitProcessingMode()) {
- for (i = 0; IndexedCatalogNames[i] != NULL; i++) {
- if ( strcmp(IndexedCatalogNames[i], catName) == 0)
- return (true);
+ Relation pg_class;
+ HeapTuple htup;
+ Form_pg_class pgRelP;
+ int i;
+
+ Assert(IsSystemRelationName(catName));
+
+ /*
+ * If we're bootstraping we don't have pg_class (or any indices).
+ */
+ if (IsBootstrapProcessingMode())
+ return false;
+
+ if (IsInitProcessingMode())
+ {
+ for (i = 0; IndexedCatalogNames[i] != NULL; i++)
+ {
+ if (strcmp(IndexedCatalogNames[i], catName) == 0)
+ return (true);
+ }
+ return (false);
}
- return (false);
- }
-
- pg_class = heap_openr(RelationRelationName);
- htup = ClassOidIndexScan(pg_class, catId);
- heap_close(pg_class);
-
- if (! HeapTupleIsValid(htup)) {
- elog(NOTICE, "CatalogHasIndex: no relation with oid %d", catId);
- return false;
- }
-
- pgRelP = (Form_pg_class)GETSTRUCT(htup);
- return (pgRelP->relhasindex);
+
+ pg_class = heap_openr(RelationRelationName);
+ htup = ClassOidIndexScan(pg_class, catId);
+ heap_close(pg_class);
+
+ if (!HeapTupleIsValid(htup))
+ {
+ elog(NOTICE, "CatalogHasIndex: no relation with oid %d", catId);
+ return false;
+ }
+
+ pgRelP = (Form_pg_class) GETSTRUCT(htup);
+ return (pgRelP->relhasindex);
}
/*
- * CatalogIndexFetchTuple() -- Get a tuple that satisfies a scan key
- * from a catalog relation.
+ * CatalogIndexFetchTuple() -- Get a tuple that satisfies a scan key
+ * from a catalog relation.
*
- * Since the index may contain pointers to dead tuples, we need to
- * iterate until we find a tuple that's valid and satisfies the scan
- * key.
+ * Since the index may contain pointers to dead tuples, we need to
+ * iterate until we find a tuple that's valid and satisfies the scan
+ * key.
*/
-static HeapTuple
+static HeapTuple
CatalogIndexFetchTuple(Relation heapRelation,
- Relation idesc,
- ScanKey skey)
+ Relation idesc,
+ ScanKey skey)
{
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- HeapTuple tuple;
- Buffer buffer;
-
- sd = index_beginscan(idesc, false, 1, skey);
- tuple = (HeapTuple)NULL;
-
- do {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (indexRes) {
- ItemPointer iptr;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
- pfree(indexRes);
- } else
- break;
- } while (!HeapTupleIsValid(tuple));
-
- if (HeapTupleIsValid(tuple)) {
- tuple = heap_copytuple(tuple);
- ReleaseBuffer(buffer);
- }
-
- index_endscan(sd);
- pfree(sd);
- return (tuple);
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ HeapTuple tuple;
+ Buffer buffer;
+
+ sd = index_beginscan(idesc, false, 1, skey);
+ tuple = (HeapTuple) NULL;
+
+ do
+ {
+ indexRes = index_getnext(sd, ForwardScanDirection);
+ if (indexRes)
+ {
+ ItemPointer iptr;
+
+ iptr = &indexRes->heap_iptr;
+ tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
+ pfree(indexRes);
+ }
+ else
+ break;
+ } while (!HeapTupleIsValid(tuple));
+
+ if (HeapTupleIsValid(tuple))
+ {
+ tuple = heap_copytuple(tuple);
+ ReleaseBuffer(buffer);
+ }
+
+ index_endscan(sd);
+ pfree(sd);
+ return (tuple);
}
/*
@@ -259,276 +268,295 @@ CatalogIndexFetchTuple(Relation heapRelation,
*/
HeapTuple
AttributeNameIndexScan(Relation heapRelation,
- Oid relid,
- char *attname)
+ Oid relid,
+ char *attname)
{
- Relation idesc;
- ScanKeyData skey;
- OidName keyarg;
- HeapTuple tuple;
-
- keyarg = mkoidname(relid, attname);
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)OidNameEqRegProcedure,
- (Datum)keyarg);
-
- idesc = index_openr(AttributeNameIndex);
- tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
-
- index_close(idesc);
- pfree(keyarg);
-
- return tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ OidName keyarg;
+ HeapTuple tuple;
+
+ keyarg = mkoidname(relid, attname);
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) OidNameEqRegProcedure,
+ (Datum) keyarg);
+
+ idesc = index_openr(AttributeNameIndex);
+ tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
+
+ index_close(idesc);
+ pfree(keyarg);
+
+ return tuple;
}
HeapTuple
AttributeNumIndexScan(Relation heapRelation,
- Oid relid,
- AttrNumber attnum)
+ Oid relid,
+ AttrNumber attnum)
{
- Relation idesc;
- ScanKeyData skey;
- OidInt2 keyarg;
- HeapTuple tuple;
-
- keyarg = mkoidint2(relid, (uint16)attnum);
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)OidInt2EqRegProcedure,
- (Datum)keyarg);
-
- idesc = index_openr(AttributeNumIndex);
- tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
-
- index_close(idesc);
- pfree(keyarg);
-
- return tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ OidInt2 keyarg;
+ HeapTuple tuple;
+
+ keyarg = mkoidint2(relid, (uint16) attnum);
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) OidInt2EqRegProcedure,
+ (Datum) keyarg);
+
+ idesc = index_openr(AttributeNumIndex);
+ tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
+
+ index_close(idesc);
+ pfree(keyarg);
+
+ return tuple;
}
HeapTuple
ProcedureOidIndexScan(Relation heapRelation, Oid procId)
{
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)ObjectIdEqualRegProcedure,
- (Datum)procId);
-
- idesc = index_openr(ProcedureOidIndex);
- tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
-
- index_close(idesc);
-
- return tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ (Datum) procId);
+
+ idesc = index_openr(ProcedureOidIndex);
+ tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
+
+ index_close(idesc);
+
+ return tuple;
}
HeapTuple
ProcedureNameIndexScan(Relation heapRelation,
- char *procName,
- int nargs,
- Oid *argTypes)
+ char *procName,
+ int nargs,
+ Oid * argTypes)
{
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple; /* tuple being tested */
- HeapTuple return_tuple; /* The tuple pointer we eventually return */
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- Buffer buffer;
- Form_pg_proc pgProcP;
- bool ScanComplete;
- /* The index scan is complete, i.e. we've scanned everything there
- is to scan.
- */
- bool FoundMatch;
- /* In scanning pg_proc, we have found a row that meets our search
- criteria.
- */
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)NameEqualRegProcedure,
- (Datum)procName);
-
- idesc = index_openr(ProcedureNameIndex);
-
- sd = index_beginscan(idesc, false, 1, &skey);
-
- /*
- * for now, we do the work usually done by CatalogIndexFetchTuple
- * by hand, so that we can check that the other keys match. when
- * multi-key indices are added, they will be used here.
- */
- tuple = (HeapTuple) NULL; /* initial value */
- ScanComplete = false; /* Scan hasn't begun yet */
- FoundMatch = false; /* No match yet; haven't even looked. */
- while (!FoundMatch && !ScanComplete) {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (indexRes) {
- ItemPointer iptr;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
- pfree(indexRes);
- if (HeapTupleIsValid(tuple)) {
- /* Here's a row for a procedure that has the sought procedure
- name. To be a match, though, we need it to have the
- right number and type of arguments too, so we check that
- now.
- */
- pgProcP = (Form_pg_proc)GETSTRUCT(tuple);
- if (pgProcP->pronargs == nargs &&
- oid8eq(&(pgProcP->proargtypes[0]), argTypes))
- FoundMatch = true;
- else ReleaseBuffer(buffer);
- }
- } else ScanComplete = true;
- }
-
- if (FoundMatch) {
- Assert(HeapTupleIsValid(tuple));
- return_tuple = heap_copytuple(tuple);
- ReleaseBuffer(buffer);
- } else return_tuple = (HeapTuple)NULL;
-
- index_endscan(sd);
- index_close(idesc);
-
- return return_tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ HeapTuple tuple; /* tuple being tested */
+ HeapTuple return_tuple; /* The tuple pointer we eventually
+ * return */
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ Buffer buffer;
+ Form_pg_proc pgProcP;
+ bool ScanComplete;
+
+ /*
+ * The index scan is complete, i.e. we've scanned everything there is
+ * to scan.
+ */
+ bool FoundMatch;
+
+ /*
+ * In scanning pg_proc, we have found a row that meets our search
+ * criteria.
+ */
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) NameEqualRegProcedure,
+ (Datum) procName);
+
+ idesc = index_openr(ProcedureNameIndex);
+
+ sd = index_beginscan(idesc, false, 1, &skey);
+
+ /*
+ * for now, we do the work usually done by CatalogIndexFetchTuple by
+ * hand, so that we can check that the other keys match. when
+ * multi-key indices are added, they will be used here.
+ */
+ tuple = (HeapTuple) NULL; /* initial value */
+ ScanComplete = false; /* Scan hasn't begun yet */
+ FoundMatch = false; /* No match yet; haven't even looked. */
+ while (!FoundMatch && !ScanComplete)
+ {
+ indexRes = index_getnext(sd, ForwardScanDirection);
+ if (indexRes)
+ {
+ ItemPointer iptr;
+
+ iptr = &indexRes->heap_iptr;
+ tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
+ pfree(indexRes);
+ if (HeapTupleIsValid(tuple))
+ {
+
+ /*
+ * Here's a row for a procedure that has the sought
+ * procedure name. To be a match, though, we need it to
+ * have the right number and type of arguments too, so we
+ * check that now.
+ */
+ pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
+ if (pgProcP->pronargs == nargs &&
+ oid8eq(&(pgProcP->proargtypes[0]), argTypes))
+ FoundMatch = true;
+ else
+ ReleaseBuffer(buffer);
+ }
+ }
+ else
+ ScanComplete = true;
+ }
+
+ if (FoundMatch)
+ {
+ Assert(HeapTupleIsValid(tuple));
+ return_tuple = heap_copytuple(tuple);
+ ReleaseBuffer(buffer);
+ }
+ else
+ return_tuple = (HeapTuple) NULL;
+
+ index_endscan(sd);
+ index_close(idesc);
+
+ return return_tuple;
}
HeapTuple
-ProcedureSrcIndexScan(Relation heapRelation, text *procSrc)
+ProcedureSrcIndexScan(Relation heapRelation, text * procSrc)
{
- Relation idesc;
- IndexScanDesc sd;
- ScanKeyData skey;
- RetrieveIndexResult indexRes;
- HeapTuple tuple;
- Buffer buffer;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)Anum_pg_proc_prosrc,
- (RegProcedure)TextEqualRegProcedure,
- (Datum)procSrc);
-
- idesc = index_openr(ProcedureSrcIndex);
- sd = index_beginscan(idesc, false, 1, &skey);
-
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (indexRes) {
- ItemPointer iptr;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
- pfree(indexRes);
- } else
- tuple = (HeapTuple)NULL;
-
- if (HeapTupleIsValid(tuple)) {
- tuple = heap_copytuple(tuple);
- ReleaseBuffer(buffer);
- }
-
- index_endscan(sd);
-
- return tuple;
+ Relation idesc;
+ IndexScanDesc sd;
+ ScanKeyData skey;
+ RetrieveIndexResult indexRes;
+ HeapTuple tuple;
+ Buffer buffer;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) Anum_pg_proc_prosrc,
+ (RegProcedure) TextEqualRegProcedure,
+ (Datum) procSrc);
+
+ idesc = index_openr(ProcedureSrcIndex);
+ sd = index_beginscan(idesc, false, 1, &skey);
+
+ indexRes = index_getnext(sd, ForwardScanDirection);
+ if (indexRes)
+ {
+ ItemPointer iptr;
+
+ iptr = &indexRes->heap_iptr;
+ tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
+ pfree(indexRes);
+ }
+ else
+ tuple = (HeapTuple) NULL;
+
+ if (HeapTupleIsValid(tuple))
+ {
+ tuple = heap_copytuple(tuple);
+ ReleaseBuffer(buffer);
+ }
+
+ index_endscan(sd);
+
+ return tuple;
}
HeapTuple
TypeOidIndexScan(Relation heapRelation, Oid typeId)
{
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)ObjectIdEqualRegProcedure,
- (Datum)typeId);
-
- idesc = index_openr(TypeOidIndex);
- tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
-
- index_close(idesc);
-
- return tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ (Datum) typeId);
+
+ idesc = index_openr(TypeOidIndex);
+ tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
+
+ index_close(idesc);
+
+ return tuple;
}
HeapTuple
TypeNameIndexScan(Relation heapRelation, char *typeName)
{
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)NameEqualRegProcedure,
- (Datum)typeName);
-
- idesc = index_openr(TypeNameIndex);
- tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
-
- index_close(idesc);
-
- return tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) NameEqualRegProcedure,
+ (Datum) typeName);
+
+ idesc = index_openr(TypeNameIndex);
+ tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
+
+ index_close(idesc);
+
+ return tuple;
}
HeapTuple
ClassNameIndexScan(Relation heapRelation, char *relName)
{
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)NameEqualRegProcedure,
- (Datum)relName);
-
- idesc = index_openr(ClassNameIndex);
-
- tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
-
- index_close(idesc);
- return tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) NameEqualRegProcedure,
+ (Datum) relName);
+
+ idesc = index_openr(ClassNameIndex);
+
+ tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
+
+ index_close(idesc);
+ return tuple;
}
HeapTuple
ClassOidIndexScan(Relation heapRelation, Oid relId)
{
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)ObjectIdEqualRegProcedure,
- (Datum)relId);
-
- idesc = index_openr(ClassOidIndex);
- tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
-
- index_close(idesc);
-
- return tuple;
+ Relation idesc;
+ ScanKeyData skey;
+ HeapTuple tuple;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ (Datum) relId);
+
+ idesc = index_openr(ClassOidIndex);
+ tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
+
+ index_close(idesc);
+
+ return tuple;
}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 13a3c48e9f4..540350bac9b 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* pg_aggregate.c--
- * routines to support manipulation of the pg_aggregate relation
+ * routines to support manipulation of the pg_aggregate relation
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.5 1997/07/24 20:11:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.6 1997/09/07 04:40:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,9 +24,9 @@
#include <catalog/pg_aggregate.h>
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/* ----------------
@@ -34,288 +34,303 @@
*
* aggregates overloading has been added. Instead of the full
* overload support we have for functions, aggregate overloading only
- * applies to exact basetype matches. That is, we don't check the
+ * applies to exact basetype matches. That is, we don't check the
* the inheritance hierarchy
*
* OLD COMMENTS:
- * Currently, redefining aggregates using the same name is not
- * supported. In such a case, a warning is printed that the
- * aggregate already exists. If such is not the case, a new tuple
- * is created and inserted in the aggregate relation. The fields
- * of this tuple are aggregate name, owner id, 2 transition functions
- * (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
- * type of data on which aggtransfn1 operates (aggbasetype), return
- * types of the two transition functions (aggtranstype1 and
- * aggtranstype2), final return type (aggfinaltype), and initial values
- * for the two state transition functions (agginitval1 and agginitval2).
- * All types and functions must have been defined
- * prior to defining the aggregate.
- *
+ * Currently, redefining aggregates using the same name is not
+ * supported. In such a case, a warning is printed that the
+ * aggregate already exists. If such is not the case, a new tuple
+ * is created and inserted in the aggregate relation. The fields
+ * of this tuple are aggregate name, owner id, 2 transition functions
+ * (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
+ * type of data on which aggtransfn1 operates (aggbasetype), return
+ * types of the two transition functions (aggtranstype1 and
+ * aggtranstype2), final return type (aggfinaltype), and initial values
+ * for the two state transition functions (agginitval1 and agginitval2).
+ * All types and functions must have been defined
+ * prior to defining the aggregate.
+ *
* ---------------
*/
void
AggregateCreate(char *aggName,
- char *aggtransfn1Name,
- char *aggtransfn2Name,
- char *aggfinalfnName,
- char *aggbasetypeName,
- char *aggtransfn1typeName,
- char *aggtransfn2typeName,
- char *agginitval1,
- char *agginitval2)
+ char *aggtransfn1Name,
+ char *aggtransfn2Name,
+ char *aggfinalfnName,
+ char *aggbasetypeName,
+ char *aggtransfn1typeName,
+ char *aggtransfn2typeName,
+ char *agginitval1,
+ char *agginitval2)
{
- register i;
- Relation aggdesc;
- HeapTuple tup;
- char nulls[Natts_pg_aggregate];
- Datum values[Natts_pg_aggregate];
- Form_pg_proc proc;
- Oid xfn1 = InvalidOid;
- Oid xfn2 = InvalidOid;
- Oid ffn = InvalidOid;
- Oid xbase = InvalidOid;
- Oid xret1 = InvalidOid;
- Oid xret2 = InvalidOid;
- Oid fret = InvalidOid;
- Oid fnArgs[8];
- TupleDesc tupDesc;
-
- memset(fnArgs, 0, 8 * sizeof(Oid));
-
- /* sanity checks */
- if (!aggName)
- elog(WARN, "AggregateCreate: no aggregate name supplied");
-
- if (!aggtransfn1Name && !aggtransfn2Name)
- elog(WARN, "AggregateCreate: aggregate must have at least one transition function");
-
- tup = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(aggbasetypeName),
- 0,0,0);
- if(!HeapTupleIsValid(tup))
- elog(WARN, "AggregateCreate: Type '%s' undefined",aggbasetypeName);
- xbase = tup->t_oid;
+ register i;
+ Relation aggdesc;
+ HeapTuple tup;
+ char nulls[Natts_pg_aggregate];
+ Datum values[Natts_pg_aggregate];
+ Form_pg_proc proc;
+ Oid xfn1 = InvalidOid;
+ Oid xfn2 = InvalidOid;
+ Oid ffn = InvalidOid;
+ Oid xbase = InvalidOid;
+ Oid xret1 = InvalidOid;
+ Oid xret2 = InvalidOid;
+ Oid fret = InvalidOid;
+ Oid fnArgs[8];
+ TupleDesc tupDesc;
+
+ memset(fnArgs, 0, 8 * sizeof(Oid));
+
+ /* sanity checks */
+ if (!aggName)
+ elog(WARN, "AggregateCreate: no aggregate name supplied");
+
+ if (!aggtransfn1Name && !aggtransfn2Name)
+ elog(WARN, "AggregateCreate: aggregate must have at least one transition function");
+
+ tup = SearchSysCacheTuple(TYPNAME,
+ PointerGetDatum(aggbasetypeName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
+ xbase = tup->t_oid;
+
+ if (aggtransfn1Name)
+ {
+ tup = SearchSysCacheTuple(TYPNAME,
+ PointerGetDatum(aggtransfn1typeName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "AggregateCreate: Type '%s' undefined",
+ aggtransfn1typeName);
+ xret1 = tup->t_oid;
+
+ fnArgs[0] = xret1;
+ fnArgs[1] = xbase;
+ tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(aggtransfn1Name),
+ Int32GetDatum(2),
+ PointerGetDatum(fnArgs),
+ 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "AggregateCreate: '%s('%s', '%s') does not exist",
+ aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
+ if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
+ elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
+ aggtransfn1Name,
+ aggtransfn1typeName);
+ xfn1 = tup->t_oid;
+ if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
+ !OidIsValid(xbase))
+ elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
+ }
+
+ if (aggtransfn2Name)
+ {
+ tup = SearchSysCacheTuple(TYPNAME,
+ PointerGetDatum(aggtransfn2typeName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "AggregateCreate: Type '%s' undefined",
+ aggtransfn2typeName);
+ xret2 = tup->t_oid;
+
+ fnArgs[0] = xret2;
+ fnArgs[1] = 0;
+ tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(aggtransfn2Name),
+ Int32GetDatum(1),
+ PointerGetDatum(fnArgs),
+ 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "AggregateCreate: '%s'('%s') does not exist",
+ aggtransfn2Name, aggtransfn2typeName);
+ if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
+ elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
+ aggtransfn2Name, aggtransfn2typeName);
+ xfn2 = tup->t_oid;
+ if (!OidIsValid(xfn2) || !OidIsValid(xret2))
+ elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
+ }
+
+ tup = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggName),
+ ObjectIdGetDatum(xbase),
+ 0, 0);
+ if (HeapTupleIsValid(tup))
+ elog(WARN,
+ "AggregateCreate: aggregate '%s' with base type '%s' already exists",
+ aggName, aggbasetypeName);
+
+ /* more sanity checks */
+ if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
+ elog(WARN, "AggregateCreate: Aggregate must have final function with both transition functions");
- if (aggtransfn1Name) {
- tup = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(aggtransfn1typeName),
- 0,0,0);
- if(!HeapTupleIsValid(tup))
- elog(WARN, "AggregateCreate: Type '%s' undefined",
- aggtransfn1typeName);
- xret1 = tup->t_oid;
-
- fnArgs[0] = xret1;
- fnArgs[1] = xbase;
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(aggtransfn1Name),
- Int32GetDatum(2),
- PointerGetDatum(fnArgs),
- 0);
- if(!HeapTupleIsValid(tup))
- elog(WARN, "AggregateCreate: '%s('%s', '%s') does not exist",
- aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
- if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
- elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
- aggtransfn1Name,
- aggtransfn1typeName);
- xfn1 = tup->t_oid;
- if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
- !OidIsValid(xbase))
- elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
- }
-
- if (aggtransfn2Name) {
- tup = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(aggtransfn2typeName),
- 0,0,0);
- if(!HeapTupleIsValid(tup))
- elog(WARN, "AggregateCreate: Type '%s' undefined",
- aggtransfn2typeName);
- xret2 = tup->t_oid;
-
- fnArgs[0] = xret2;
- fnArgs[1] = 0;
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(aggtransfn2Name),
- Int32GetDatum(1),
- PointerGetDatum(fnArgs),
- 0);
- if(!HeapTupleIsValid(tup))
- elog(WARN, "AggregateCreate: '%s'('%s') does not exist",
- aggtransfn2Name, aggtransfn2typeName);
- if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
- elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
- aggtransfn2Name, aggtransfn2typeName);
- xfn2 = tup->t_oid;
- if (!OidIsValid(xfn2) || !OidIsValid(xret2))
- elog(WARN, "AggregateCreate: bogus function '%s'",aggfinalfnName);
- }
-
- tup = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggName),
- ObjectIdGetDatum(xbase),
- 0,0);
- if (HeapTupleIsValid(tup))
- elog(WARN,
- "AggregateCreate: aggregate '%s' with base type '%s' already exists",
- aggName, aggbasetypeName);
+ if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
+ elog(WARN, "AggregateCreate: Aggregate cannot have final function without both transition functions");
- /* more sanity checks */
- if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
- elog(WARN, "AggregateCreate: Aggregate must have final function with both transition functions");
-
- if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
- elog(WARN, "AggregateCreate: Aggregate cannot have final function without both transition functions");
-
- if (aggfinalfnName) {
- fnArgs[0] = xret1;
- fnArgs[1] = xret2;
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(aggfinalfnName),
- Int32GetDatum(2),
- PointerGetDatum(fnArgs),
- 0);
- if(!HeapTupleIsValid(tup))
- elog(WARN, "AggregateCreate: '%s'('%s','%s') does not exist",
- aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
- ffn = tup->t_oid;
- proc = (Form_pg_proc) GETSTRUCT(tup);
- fret = proc->prorettype;
- if (!OidIsValid(ffn) || !OidIsValid(fret))
- elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
- }
-
- /*
- * If transition function 2 is defined, it must have an initial value,
- * whereas transition function 1 does not, which allows man and min
- * aggregates to return NULL if they are evaluated on empty sets.
- */
- if (OidIsValid(xfn2) && !agginitval2)
- elog(WARN, "AggregateCreate: transition function 2 MUST have an initial value");
-
- /* initialize nulls and values */
- for(i=0; i < Natts_pg_aggregate; i++) {
- nulls[i] = ' ';
- values[i] = (Datum)NULL;
- }
- values[Anum_pg_aggregate_aggname-1] = PointerGetDatum(aggName);
- values[Anum_pg_aggregate_aggowner-1] =
- Int32GetDatum(GetUserId());
- values[Anum_pg_aggregate_aggtransfn1-1] =
- ObjectIdGetDatum(xfn1);
- values[Anum_pg_aggregate_aggtransfn2-1] =
- ObjectIdGetDatum(xfn2);
- values[Anum_pg_aggregate_aggfinalfn-1] =
- ObjectIdGetDatum(ffn);
-
- values[Anum_pg_aggregate_aggbasetype-1] =
- ObjectIdGetDatum(xbase);
- if (!OidIsValid(xfn1)) {
- values[Anum_pg_aggregate_aggtranstype1-1] =
- ObjectIdGetDatum(InvalidOid);
- values[Anum_pg_aggregate_aggtranstype2-1] =
- ObjectIdGetDatum(xret2);
- values[Anum_pg_aggregate_aggfinaltype-1] =
- ObjectIdGetDatum(xret2);
- }
- else if (!OidIsValid(xfn2)) {
- values[Anum_pg_aggregate_aggtranstype1-1] =
- ObjectIdGetDatum(xret1);
- values[Anum_pg_aggregate_aggtranstype2-1] =
- ObjectIdGetDatum(InvalidOid);
- values[Anum_pg_aggregate_aggfinaltype-1] =
- ObjectIdGetDatum(xret1);
- }
- else {
- values[Anum_pg_aggregate_aggtranstype1-1] =
- ObjectIdGetDatum(xret1);
- values[Anum_pg_aggregate_aggtranstype2-1] =
- ObjectIdGetDatum(xret2);
- values[Anum_pg_aggregate_aggfinaltype-1] =
- ObjectIdGetDatum(fret);
- }
-
- if (agginitval1)
- values[Anum_pg_aggregate_agginitval1-1] = PointerGetDatum(textin(agginitval1));
- else
- nulls[Anum_pg_aggregate_agginitval1-1] = 'n';
-
- if (agginitval2)
- values[Anum_pg_aggregate_agginitval2-1] = PointerGetDatum(textin(agginitval2));
- else
- nulls[Anum_pg_aggregate_agginitval2-1] = 'n';
-
- if (!RelationIsValid(aggdesc = heap_openr(AggregateRelationName)))
- elog(WARN, "AggregateCreate: could not open '%s'",
- AggregateRelationName);
+ if (aggfinalfnName)
+ {
+ fnArgs[0] = xret1;
+ fnArgs[1] = xret2;
+ tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(aggfinalfnName),
+ Int32GetDatum(2),
+ PointerGetDatum(fnArgs),
+ 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "AggregateCreate: '%s'('%s','%s') does not exist",
+ aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
+ ffn = tup->t_oid;
+ proc = (Form_pg_proc) GETSTRUCT(tup);
+ fret = proc->prorettype;
+ if (!OidIsValid(ffn) || !OidIsValid(fret))
+ elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
+ }
- tupDesc = aggdesc->rd_att;
- if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
- values,
- nulls)))
- elog(WARN, "AggregateCreate: heap_formtuple failed");
- if (!OidIsValid(heap_insert(aggdesc, tup)))
- elog(WARN, "AggregateCreate: heap_insert failed");
- heap_close(aggdesc);
+ /*
+ * If transition function 2 is defined, it must have an initial value,
+ * whereas transition function 1 does not, which allows man and min
+ * aggregates to return NULL if they are evaluated on empty sets.
+ */
+ if (OidIsValid(xfn2) && !agginitval2)
+ elog(WARN, "AggregateCreate: transition function 2 MUST have an initial value");
+
+ /* initialize nulls and values */
+ for (i = 0; i < Natts_pg_aggregate; i++)
+ {
+ nulls[i] = ' ';
+ values[i] = (Datum) NULL;
+ }
+ values[Anum_pg_aggregate_aggname - 1] = PointerGetDatum(aggName);
+ values[Anum_pg_aggregate_aggowner - 1] =
+ Int32GetDatum(GetUserId());
+ values[Anum_pg_aggregate_aggtransfn1 - 1] =
+ ObjectIdGetDatum(xfn1);
+ values[Anum_pg_aggregate_aggtransfn2 - 1] =
+ ObjectIdGetDatum(xfn2);
+ values[Anum_pg_aggregate_aggfinalfn - 1] =
+ ObjectIdGetDatum(ffn);
+
+ values[Anum_pg_aggregate_aggbasetype - 1] =
+ ObjectIdGetDatum(xbase);
+ if (!OidIsValid(xfn1))
+ {
+ values[Anum_pg_aggregate_aggtranstype1 - 1] =
+ ObjectIdGetDatum(InvalidOid);
+ values[Anum_pg_aggregate_aggtranstype2 - 1] =
+ ObjectIdGetDatum(xret2);
+ values[Anum_pg_aggregate_aggfinaltype - 1] =
+ ObjectIdGetDatum(xret2);
+ }
+ else if (!OidIsValid(xfn2))
+ {
+ values[Anum_pg_aggregate_aggtranstype1 - 1] =
+ ObjectIdGetDatum(xret1);
+ values[Anum_pg_aggregate_aggtranstype2 - 1] =
+ ObjectIdGetDatum(InvalidOid);
+ values[Anum_pg_aggregate_aggfinaltype - 1] =
+ ObjectIdGetDatum(xret1);
+ }
+ else
+ {
+ values[Anum_pg_aggregate_aggtranstype1 - 1] =
+ ObjectIdGetDatum(xret1);
+ values[Anum_pg_aggregate_aggtranstype2 - 1] =
+ ObjectIdGetDatum(xret2);
+ values[Anum_pg_aggregate_aggfinaltype - 1] =
+ ObjectIdGetDatum(fret);
+ }
+
+ if (agginitval1)
+ values[Anum_pg_aggregate_agginitval1 - 1] = PointerGetDatum(textin(agginitval1));
+ else
+ nulls[Anum_pg_aggregate_agginitval1 - 1] = 'n';
+
+ if (agginitval2)
+ values[Anum_pg_aggregate_agginitval2 - 1] = PointerGetDatum(textin(agginitval2));
+ else
+ nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
+
+ if (!RelationIsValid(aggdesc = heap_openr(AggregateRelationName)))
+ elog(WARN, "AggregateCreate: could not open '%s'",
+ AggregateRelationName);
+
+ tupDesc = aggdesc->rd_att;
+ if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
+ values,
+ nulls)))
+ elog(WARN, "AggregateCreate: heap_formtuple failed");
+ if (!OidIsValid(heap_insert(aggdesc, tup)))
+ elog(WARN, "AggregateCreate: heap_insert failed");
+ heap_close(aggdesc);
}
-char *
-AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
+char *
+AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool * isNull)
{
- HeapTuple tup;
- Relation aggRel;
- int initValAttno;
- Oid transtype;
- text *textInitVal;
- char *strInitVal, *initVal;
-
- Assert(PointerIsValid(aggName));
- Assert(PointerIsValid(isNull));
- Assert(xfuncno == 1 || xfuncno == 2);
+ HeapTuple tup;
+ Relation aggRel;
+ int initValAttno;
+ Oid transtype;
+ text *textInitVal;
+ char *strInitVal,
+ *initVal;
+
+ Assert(PointerIsValid(aggName));
+ Assert(PointerIsValid(isNull));
+ Assert(xfuncno == 1 || xfuncno == 2);
+
+ tup = SearchSysCacheTuple(AGGNAME,
+ PointerGetDatum(aggName),
+ PointerGetDatum(basetype),
+ 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
+ aggName);
+ if (xfuncno == 1)
+ {
+ transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
+ initValAttno = Anum_pg_aggregate_agginitval1;
+ }
+ else
+ /* can only be 1 or 2 */
+ {
+ transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
+ initValAttno = Anum_pg_aggregate_agginitval2;
+ }
- tup = SearchSysCacheTuple(AGGNAME,
- PointerGetDatum(aggName),
- PointerGetDatum(basetype),
- 0,0);
- if (!HeapTupleIsValid(tup))
- elog(WARN, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
- aggName);
- if (xfuncno == 1) {
- transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
- initValAttno = Anum_pg_aggregate_agginitval1;
- }
- else /* can only be 1 or 2 */ {
- transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
- initValAttno = Anum_pg_aggregate_agginitval2;
- }
-
- aggRel = heap_openr(AggregateRelationName);
- if (!RelationIsValid(aggRel))
- elog(WARN, "AggNameGetInitVal: could not open \"%-.*s\"",
- AggregateRelationName);
- /*
- * must use fastgetattr in case one or other of the init values is NULL
- */
- textInitVal = (text *) fastgetattr(tup, initValAttno,
- RelationGetTupleDescriptor(aggRel),
- isNull);
- if (!PointerIsValid(textInitVal))
- *isNull = true;
- if (*isNull) {
+ aggRel = heap_openr(AggregateRelationName);
+ if (!RelationIsValid(aggRel))
+ elog(WARN, "AggNameGetInitVal: could not open \"%-.*s\"",
+ AggregateRelationName);
+
+ /*
+ * must use fastgetattr in case one or other of the init values is
+ * NULL
+ */
+ textInitVal = (text *) fastgetattr(tup, initValAttno,
+ RelationGetTupleDescriptor(aggRel),
+ isNull);
+ if (!PointerIsValid(textInitVal))
+ *isNull = true;
+ if (*isNull)
+ {
+ heap_close(aggRel);
+ return ((char *) NULL);
+ }
+ strInitVal = textout(textInitVal);
heap_close(aggRel);
- return((char *) NULL);
- }
- strInitVal = textout(textInitVal);
- heap_close(aggRel);
-
- tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(transtype),
- 0,0,0);
- if (!HeapTupleIsValid(tup)) {
+
+ tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(transtype),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ {
+ pfree(strInitVal);
+ elog(WARN, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type");
+ }
+ initVal = fmgr(((TypeTupleForm) GETSTRUCT(tup))->typinput, strInitVal, -1);
pfree(strInitVal);
- elog(WARN, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type");
- }
- initVal = fmgr(((TypeTupleForm) GETSTRUCT(tup))->typinput, strInitVal, -1);
- pfree(strInitVal);
- return(initVal);
+ return (initVal);
}
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 1151f9f2e69..67a3a2f1495 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* pg_operator.c--
- * routines to support manipulation of the pg_operator relation
+ * routines to support manipulation of the pg_operator relation
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.11 1997/08/18 20:52:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.12 1997/09/07 04:40:27 momjian Exp $
*
* NOTES
- * these routines moved here from commands/define.c and somewhat cleaned up.
- *
+ * these routines moved here from commands/define.c and somewhat cleaned up.
+ *
*-------------------------------------------------------------------------
*/
#include <postgres.h>
@@ -26,28 +26,33 @@
#include <fmgr.h>
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static Oid OperatorGetWithOpenRelation(Relation pg_operator_desc,
- const char *operatorName,
- Oid leftObjectId,
- Oid rightObjectId );
-static Oid OperatorGet(char *operatorName,
- char *leftTypeName,
- char *rightTypeName );
-
-static Oid OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
- char *operatorName,
- Oid leftObjectId,
- Oid rightObjectId );
-static Oid OperatorShellMake(char *operatorName,
- char *leftTypeName,
- char *rightTypeName );
-
-static void OperatorDef(char *operatorName,
+static Oid
+OperatorGetWithOpenRelation(Relation pg_operator_desc,
+ const char *operatorName,
+ Oid leftObjectId,
+ Oid rightObjectId);
+static Oid
+OperatorGet(char *operatorName,
+ char *leftTypeName,
+ char *rightTypeName);
+
+static Oid
+OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
+ char *operatorName,
+ Oid leftObjectId,
+ Oid rightObjectId);
+static Oid
+OperatorShellMake(char *operatorName,
+ char *leftTypeName,
+ char *rightTypeName);
+
+static void
+OperatorDef(char *operatorName,
int definedOK,
char *leftTypeName,
char *rightTypeName,
@@ -60,289 +65,292 @@ static void OperatorDef(char *operatorName,
char *oinName,
bool canHash,
char *leftSortName,
- char *rightSortName );
-static void OperatorUpd(Oid baseId , Oid commId , Oid negId );
-
+ char *rightSortName);
+static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
+
/* ----------------------------------------------------------------
- * OperatorGetWithOpenRelation
+ * OperatorGetWithOpenRelation
*
- * preforms a scan on pg_operator for an operator tuple
- * with given name and left/right type oids.
+ * preforms a scan on pg_operator for an operator tuple
+ * with given name and left/right type oids.
* ----------------------------------------------------------------
- * pg_operator_desc -- reldesc for pg_operator
- * operatorName -- name of operator to fetch
- * leftObjectId -- left oid of operator to fetch
- * rightObjectId -- right oid of operator to fetch
+ * pg_operator_desc -- reldesc for pg_operator
+ * operatorName -- name of operator to fetch
+ * leftObjectId -- left oid of operator to fetch
+ * rightObjectId -- right oid of operator to fetch
*/
-static Oid
+static Oid
OperatorGetWithOpenRelation(Relation pg_operator_desc,
- const char *operatorName,
- Oid leftObjectId,
- Oid rightObjectId)
+ const char *operatorName,
+ Oid leftObjectId,
+ Oid rightObjectId)
{
- HeapScanDesc pg_operator_scan;
- Oid operatorObjectId;
- HeapTuple tup;
-
- static ScanKeyData opKey[3] = {
- { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
- { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure },
- { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure },
- };
-
- fmgr_info(NameEqualRegProcedure,
- &opKey[0].sk_func, &opKey[0].sk_nargs);
- fmgr_info(ObjectIdEqualRegProcedure,
- &opKey[1].sk_func, &opKey[1].sk_nargs);
- fmgr_info(ObjectIdEqualRegProcedure,
- &opKey[2].sk_func, &opKey[2].sk_nargs);
-
- /* ----------------
- * form scan key
- * ----------------
- */
- opKey[0].sk_argument = PointerGetDatum(operatorName);
- opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
- opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
-
- /* ----------------
- * begin the scan
- * ----------------
- */
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- SelfTimeQual,
- 3,
- opKey);
-
- /* ----------------
- * fetch the operator tuple, if it exists, and determine
- * the proper return oid value.
- * ----------------
- */
- tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
- operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
-
- /* ----------------
- * close the scan and return the oid.
- * ----------------
- */
- heap_endscan(pg_operator_scan);
-
- return
- operatorObjectId;
+ HeapScanDesc pg_operator_scan;
+ Oid operatorObjectId;
+ HeapTuple tup;
+
+ static ScanKeyData opKey[3] = {
+ {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
+ {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
+ {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
+ };
+
+ fmgr_info(NameEqualRegProcedure,
+ &opKey[0].sk_func, &opKey[0].sk_nargs);
+ fmgr_info(ObjectIdEqualRegProcedure,
+ &opKey[1].sk_func, &opKey[1].sk_nargs);
+ fmgr_info(ObjectIdEqualRegProcedure,
+ &opKey[2].sk_func, &opKey[2].sk_nargs);
+
+ /* ----------------
+ * form scan key
+ * ----------------
+ */
+ opKey[0].sk_argument = PointerGetDatum(operatorName);
+ opKey[1].sk_argument = ObjectIdGetDatum(leftObjectId);
+ opKey[2].sk_argument = ObjectIdGetDatum(rightObjectId);
+
+ /* ----------------
+ * begin the scan
+ * ----------------
+ */
+ pg_operator_scan = heap_beginscan(pg_operator_desc,
+ 0,
+ SelfTimeQual,
+ 3,
+ opKey);
+
+ /* ----------------
+ * fetch the operator tuple, if it exists, and determine
+ * the proper return oid value.
+ * ----------------
+ */
+ tup = heap_getnext(pg_operator_scan, 0, (Buffer *) 0);
+ operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidOid;
+
+ /* ----------------
+ * close the scan and return the oid.
+ * ----------------
+ */
+ heap_endscan(pg_operator_scan);
+
+ return
+ operatorObjectId;
}
/* ----------------------------------------------------------------
- * OperatorGet
+ * OperatorGet
*
- * finds the operator associated with the specified name
- * and left and right type names.
+ * finds the operator associated with the specified name
+ * and left and right type names.
* ----------------------------------------------------------------
*/
-static Oid
+static Oid
OperatorGet(char *operatorName,
- char *leftTypeName,
- char *rightTypeName)
+ char *leftTypeName,
+ char *rightTypeName)
{
- Relation pg_operator_desc;
-
- Oid operatorObjectId;
- Oid leftObjectId = InvalidOid;
- Oid rightObjectId = InvalidOid;
- bool leftDefined = false;
- bool rightDefined = false;
-
- /* ----------------
- * look up the operator types.
- *
- * Note: types must be defined before operators
- * ----------------
- */
- if (leftTypeName) {
- leftObjectId = TypeGet(leftTypeName, &leftDefined);
-
- if (!OidIsValid(leftObjectId) || !leftDefined)
- elog(WARN, "OperatorGet: left type '%s' nonexistent",leftTypeName);
- }
-
- if (rightTypeName) {
- rightObjectId = TypeGet(rightTypeName, &rightDefined);
-
- if (!OidIsValid(rightObjectId) || !rightDefined)
- elog(WARN, "OperatorGet: right type '%s' nonexistent",
- rightTypeName);
- }
-
- if (!((OidIsValid(leftObjectId) && leftDefined) ||
- (OidIsValid(rightObjectId) && rightDefined)))
- elog(WARN, "OperatorGet: no argument types??");
-
- /* ----------------
- * open the pg_operator relation
- * ----------------
- */
- pg_operator_desc = heap_openr(OperatorRelationName);
-
- /* ----------------
- * get the oid for the operator with the appropriate name
- * and left/right types.
- * ----------------
- */
- operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
- operatorName,
- leftObjectId,
- rightObjectId);
-
- /* ----------------
- * close the relation and return the operator oid.
- * ----------------
- */
- heap_close(pg_operator_desc);
-
- return
- operatorObjectId;
+ Relation pg_operator_desc;
+
+ Oid operatorObjectId;
+ Oid leftObjectId = InvalidOid;
+ Oid rightObjectId = InvalidOid;
+ bool leftDefined = false;
+ bool rightDefined = false;
+
+ /* ----------------
+ * look up the operator types.
+ *
+ * Note: types must be defined before operators
+ * ----------------
+ */
+ if (leftTypeName)
+ {
+ leftObjectId = TypeGet(leftTypeName, &leftDefined);
+
+ if (!OidIsValid(leftObjectId) || !leftDefined)
+ elog(WARN, "OperatorGet: left type '%s' nonexistent", leftTypeName);
+ }
+
+ if (rightTypeName)
+ {
+ rightObjectId = TypeGet(rightTypeName, &rightDefined);
+
+ if (!OidIsValid(rightObjectId) || !rightDefined)
+ elog(WARN, "OperatorGet: right type '%s' nonexistent",
+ rightTypeName);
+ }
+
+ if (!((OidIsValid(leftObjectId) && leftDefined) ||
+ (OidIsValid(rightObjectId) && rightDefined)))
+ elog(WARN, "OperatorGet: no argument types??");
+
+ /* ----------------
+ * open the pg_operator relation
+ * ----------------
+ */
+ pg_operator_desc = heap_openr(OperatorRelationName);
+
+ /* ----------------
+ * get the oid for the operator with the appropriate name
+ * and left/right types.
+ * ----------------
+ */
+ operatorObjectId = OperatorGetWithOpenRelation(pg_operator_desc,
+ operatorName,
+ leftObjectId,
+ rightObjectId);
+
+ /* ----------------
+ * close the relation and return the operator oid.
+ * ----------------
+ */
+ heap_close(pg_operator_desc);
+
+ return
+ operatorObjectId;
}
/* ----------------------------------------------------------------
- * OperatorShellMakeWithOpenRelation
+ * OperatorShellMakeWithOpenRelation
*
* ----------------------------------------------------------------
*/
-static Oid
+static Oid
OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
- char *operatorName,
- Oid leftObjectId,
- Oid rightObjectId)
+ char *operatorName,
+ Oid leftObjectId,
+ Oid rightObjectId)
{
- register int i;
- HeapTuple tup;
- Datum values[ Natts_pg_operator ];
- char nulls[ Natts_pg_operator ];
- Oid operatorObjectId;
- TupleDesc tupDesc;
-
- /* ----------------
- * initialize our nulls[] and values[] arrays
- * ----------------
- */
- for (i = 0; i < Natts_pg_operator; ++i) {
- nulls[i] = ' ';
- values[i] = (Datum)NULL; /* redundant, but safe */
- }
-
- /* ----------------
- * initialize values[] with the type name and
- * ----------------
- */
- i = 0;
- values[i++] = PointerGetDatum(operatorName);
- values[i++] = Int32GetDatum(GetUserId());
- values[i++] = (Datum) (uint16) 0;
-
- values[i++] = (Datum)'b'; /* fill oprkind with a bogus value */
-
- values[i++] = (Datum) (bool) 0;
- values[i++] = (Datum) (bool) 0;
- values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
- values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
- values[i++] = ObjectIdGetDatum(InvalidOid);
- values[i++] = ObjectIdGetDatum(InvalidOid);
- values[i++] = ObjectIdGetDatum(InvalidOid);
- values[i++] = ObjectIdGetDatum(InvalidOid);
- values[i++] = ObjectIdGetDatum(InvalidOid);
- values[i++] = ObjectIdGetDatum(InvalidOid);
- values[i++] = ObjectIdGetDatum(InvalidOid);
- values[i++] = ObjectIdGetDatum(InvalidOid);
-
- /* ----------------
- * create a new operator tuple
- * ----------------
- */
- tupDesc = pg_operator_desc->rd_att;
-
- tup = heap_formtuple(tupDesc,
- values,
- nulls);
-
- /* ----------------
- * insert our "shell" operator tuple and
- * close the relation
- * ----------------
- */
- heap_insert(pg_operator_desc, tup);
- operatorObjectId = tup->t_oid;
-
- /* ----------------
- * free the tuple and return the operator oid
- * ----------------
- */
- pfree(tup);
-
- return
- operatorObjectId;
+ register int i;
+ HeapTuple tup;
+ Datum values[Natts_pg_operator];
+ char nulls[Natts_pg_operator];
+ Oid operatorObjectId;
+ TupleDesc tupDesc;
+
+ /* ----------------
+ * initialize our nulls[] and values[] arrays
+ * ----------------
+ */
+ for (i = 0; i < Natts_pg_operator; ++i)
+ {
+ nulls[i] = ' ';
+ values[i] = (Datum) NULL; /* redundant, but safe */
+ }
+
+ /* ----------------
+ * initialize values[] with the type name and
+ * ----------------
+ */
+ i = 0;
+ values[i++] = PointerGetDatum(operatorName);
+ values[i++] = Int32GetDatum(GetUserId());
+ values[i++] = (Datum) (uint16) 0;
+
+ values[i++] = (Datum) 'b'; /* fill oprkind with a bogus value */
+
+ values[i++] = (Datum) (bool) 0;
+ values[i++] = (Datum) (bool) 0;
+ values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
+ values[i++] = ObjectIdGetDatum(rightObjectId); /* <-- right oid */
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+
+ /* ----------------
+ * create a new operator tuple
+ * ----------------
+ */
+ tupDesc = pg_operator_desc->rd_att;
+
+ tup = heap_formtuple(tupDesc,
+ values,
+ nulls);
+
+ /* ----------------
+ * insert our "shell" operator tuple and
+ * close the relation
+ * ----------------
+ */
+ heap_insert(pg_operator_desc, tup);
+ operatorObjectId = tup->t_oid;
+
+ /* ----------------
+ * free the tuple and return the operator oid
+ * ----------------
+ */
+ pfree(tup);
+
+ return
+ operatorObjectId;
}
/* ----------------------------------------------------------------
- * OperatorShellMake
+ * OperatorShellMake
*
- * Specify operator name and left and right type names,
- * fill an operator struct with this info and NULL's,
- * call heap_insert and return the Oid
- * to the caller.
+ * Specify operator name and left and right type names,
+ * fill an operator struct with this info and NULL's,
+ * call heap_insert and return the Oid
+ * to the caller.
* ----------------------------------------------------------------
*/
-static Oid
+static Oid
OperatorShellMake(char *operatorName,
- char *leftTypeName,
- char *rightTypeName)
-{
- Relation pg_operator_desc;
- Oid operatorObjectId;
-
- Oid leftObjectId = InvalidOid;
- Oid rightObjectId = InvalidOid;
- bool leftDefined = false;
- bool rightDefined = false;
-
- /* ----------------
- * get the left and right type oid's for this operator
- * ----------------
- */
- if (leftTypeName)
- leftObjectId = TypeGet(leftTypeName, &leftDefined);
-
- if (rightTypeName)
- rightObjectId = TypeGet(rightTypeName, &rightDefined);
-
- if (!((OidIsValid(leftObjectId) && leftDefined) ||
- (OidIsValid(rightObjectId) && rightDefined)))
- elog(WARN, "OperatorShellMake: no valid argument types??");
-
- /* ----------------
- * open pg_operator
- * ----------------
- */
- pg_operator_desc = heap_openr(OperatorRelationName);
-
- /* ----------------
- * add a "shell" operator tuple to the operator relation
- * and recover the shell tuple's oid.
- * ----------------
- */
- operatorObjectId =
- OperatorShellMakeWithOpenRelation(pg_operator_desc,
- operatorName,
- leftObjectId,
- rightObjectId);
- /* ----------------
- * close the operator relation and return the oid.
- * ----------------
- */
- heap_close(pg_operator_desc);
-
- return
- operatorObjectId;
+ char *leftTypeName,
+ char *rightTypeName)
+{
+ Relation pg_operator_desc;
+ Oid operatorObjectId;
+
+ Oid leftObjectId = InvalidOid;
+ Oid rightObjectId = InvalidOid;
+ bool leftDefined = false;
+ bool rightDefined = false;
+
+ /* ----------------
+ * get the left and right type oid's for this operator
+ * ----------------
+ */
+ if (leftTypeName)
+ leftObjectId = TypeGet(leftTypeName, &leftDefined);
+
+ if (rightTypeName)
+ rightObjectId = TypeGet(rightTypeName, &rightDefined);
+
+ if (!((OidIsValid(leftObjectId) && leftDefined) ||
+ (OidIsValid(rightObjectId) && rightDefined)))
+ elog(WARN, "OperatorShellMake: no valid argument types??");
+
+ /* ----------------
+ * open pg_operator
+ * ----------------
+ */
+ pg_operator_desc = heap_openr(OperatorRelationName);
+
+ /* ----------------
+ * add a "shell" operator tuple to the operator relation
+ * and recover the shell tuple's oid.
+ * ----------------
+ */
+ operatorObjectId =
+ OperatorShellMakeWithOpenRelation(pg_operator_desc,
+ operatorName,
+ leftObjectId,
+ rightObjectId);
+ /* ----------------
+ * close the operator relation and return the oid.
+ * ----------------
+ */
+ heap_close(pg_operator_desc);
+
+ return
+ operatorObjectId;
}
/* --------------------------------
@@ -352,7 +360,7 @@ OperatorShellMake(char *operatorName,
* specify operators that do not exist. For example, if operator
* "op" is being defined, the negator operator "negop" and the
* commutator "commop" can also be defined without specifying
- * any information other than their names. Since in order to
+ * any information other than their names. Since in order to
* add "op" to the PG_OPERATOR catalog, all the Oid's for these
* operators must be placed in the fields of "op", a forward
* declaration is done on the commutator and negator operators.
@@ -363,518 +371,552 @@ OperatorShellMake(char *operatorName,
* not available to the user as it is for type definition.
*
* Algorithm:
- *
- * check if operator already defined
- * if so issue error if not definedOk, this is a duplicate
- * but if definedOk, save the Oid -- filling in a shell
+ *
+ * check if operator already defined
+ * if so issue error if not definedOk, this is a duplicate
+ * but if definedOk, save the Oid -- filling in a shell
* get the attribute types from relation descriptor for pg_operator
* assign values to the fields of the operator:
- * operatorName
- * owner id (simply the user id of the caller)
- * precedence
- * operator "kind" either "b" for binary or "l" for left unary
- * isLeftAssociative boolean
- * canHash boolean
- * leftTypeObjectId -- type must already be defined
- * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
- * resultType -- defer this, since it must be determined from
- * the pg_procedure catalog
- * commutatorObjectId -- if this is NULL, enter ObjectId=0
- * else if this already exists, enter it's ObjectId
- * else if this does not yet exist, and is not
- * the same as the main operatorName, then create
- * a shell and enter the new ObjectId
- * else if this does not exist but IS the same
- * name as the main operator, set the ObjectId=0.
- * Later OperatorCreate will make another call
- * to OperatorDef which will cause this field
- * to be filled in (because even though the names
- * will be switched, they are the same name and
- * at this point this ObjectId will then be defined)
- * negatorObjectId -- same as for commutatorObjectId
- * leftSortObjectId -- same as for commutatorObjectId
- * rightSortObjectId -- same as for commutatorObjectId
- * operatorProcedure -- must access the pg_procedure catalog to get the
- * ObjectId of the procedure that actually does the operator
- * actions this is required. Do an amgetattr to find out the
- * return type of the procedure
- * restrictionProcedure -- must access the pg_procedure catalog to get
- * the ObjectId but this is optional
- * joinProcedure -- same as restrictionProcedure
+ * operatorName
+ * owner id (simply the user id of the caller)
+ * precedence
+ * operator "kind" either "b" for binary or "l" for left unary
+ * isLeftAssociative boolean
+ * canHash boolean
+ * leftTypeObjectId -- type must already be defined
+ * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
+ * resultType -- defer this, since it must be determined from
+ * the pg_procedure catalog
+ * commutatorObjectId -- if this is NULL, enter ObjectId=0
+ * else if this already exists, enter it's ObjectId
+ * else if this does not yet exist, and is not
+ * the same as the main operatorName, then create
+ * a shell and enter the new ObjectId
+ * else if this does not exist but IS the same
+ * name as the main operator, set the ObjectId=0.
+ * Later OperatorCreate will make another call
+ * to OperatorDef which will cause this field
+ * to be filled in (because even though the names
+ * will be switched, they are the same name and
+ * at this point this ObjectId will then be defined)
+ * negatorObjectId -- same as for commutatorObjectId
+ * leftSortObjectId -- same as for commutatorObjectId
+ * rightSortObjectId -- same as for commutatorObjectId
+ * operatorProcedure -- must access the pg_procedure catalog to get the
+ * ObjectId of the procedure that actually does the operator
+ * actions this is required. Do an amgetattr to find out the
+ * return type of the procedure
+ * restrictionProcedure -- must access the pg_procedure catalog to get
+ * the ObjectId but this is optional
+ * joinProcedure -- same as restrictionProcedure
* now either insert or replace the operator into the pg_operator catalog
* if the operator shell is being filled in
- * access the catalog in order to get a valid buffer
- * create a tuple using ModifyHeapTuple
- * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
+ * access the catalog in order to get a valid buffer
+ * create a tuple using ModifyHeapTuple
+ * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple
* else if a new operator is being created
- * create a tuple using heap_formtuple
- * call heap_insert
+ * create a tuple using heap_formtuple
+ * call heap_insert
* --------------------------------
- * "X" indicates an optional argument (i.e. one that can be NULL)
- * operatorName; -- operator name
- * definedOK; -- operator can already have an oid?
- * leftTypeName; -- X left type name
- * rightTypeName; -- X right type name
- * procedureName; -- procedure oid for operator code
- * precedence; -- operator precedence
- * isLeftAssociative; -- operator is left associative?
- * commutatorName; -- X commutator operator name
- * negatorName; -- X negator operator name
- * restrictionName; -- X restriction sel. procedure name
- * joinName; -- X join sel. procedure name
- * canHash; -- possible hash operator?
- * leftSortName; -- X left sort operator
- * rightSortName; -- X right sort operator
+ * "X" indicates an optional argument (i.e. one that can be NULL)
+ * operatorName; -- operator name
+ * definedOK; -- operator can already have an oid?
+ * leftTypeName; -- X left type name
+ * rightTypeName; -- X right type name
+ * procedureName; -- procedure oid for operator code
+ * precedence; -- operator precedence
+ * isLeftAssociative; -- operator is left associative?
+ * commutatorName; -- X commutator operator name
+ * negatorName; -- X negator operator name
+ * restrictionName; -- X restriction sel. procedure name
+ * joinName; -- X join sel. procedure name
+ * canHash; -- possible hash operator?
+ * leftSortName; -- X left sort operator
+ * rightSortName; -- X right sort operator
*/
static void
OperatorDef(char *operatorName,
- int definedOK,
- char *leftTypeName,
- char *rightTypeName,
- char *procedureName,
- uint16 precedence,
- bool isLeftAssociative,
- char *commutatorName,
- char *negatorName,
- char *restrictionName,
- char *joinName,
- bool canHash,
- char *leftSortName,
- char *rightSortName)
+ int definedOK,
+ char *leftTypeName,
+ char *rightTypeName,
+ char *procedureName,
+ uint16 precedence,
+ bool isLeftAssociative,
+ char *commutatorName,
+ char *negatorName,
+ char *restrictionName,
+ char *joinName,
+ bool canHash,
+ char *leftSortName,
+ char *rightSortName)
{
- register i, j;
- Relation pg_operator_desc;
-
- HeapScanDesc pg_operator_scan;
- HeapTuple tup;
- Buffer buffer;
- ItemPointerData itemPointerData;
- char nulls[ Natts_pg_operator ];
- char replaces[ Natts_pg_operator ];
- Datum values[ Natts_pg_operator ];
- Oid other_oid = 0;
- Oid operatorObjectId;
- Oid leftTypeId = InvalidOid;
- Oid rightTypeId = InvalidOid;
- Oid commutatorId = InvalidOid;
- Oid negatorId = InvalidOid;
- bool leftDefined = false;
- bool rightDefined = false;
- char *name[4];
- Oid typeId[8];
- int nargs;
- TupleDesc tupDesc;
-
- static ScanKeyData opKey[3] = {
- { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
- { 0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure },
- { 0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure },
- };
-
- fmgr_info(NameEqualRegProcedure,
- &opKey[0].sk_func, &opKey[0].sk_nargs);
- fmgr_info(ObjectIdEqualRegProcedure,
- &opKey[1].sk_func, &opKey[1].sk_nargs);
- fmgr_info(ObjectIdEqualRegProcedure,
- &opKey[2].sk_func, &opKey[2].sk_nargs);
-
- operatorObjectId = OperatorGet(operatorName,
- leftTypeName,
- rightTypeName);
-
- if (OidIsValid(operatorObjectId) && !definedOK)
- elog(WARN, "OperatorDef: operator \"%s\" already defined",
- operatorName);
-
- if (leftTypeName)
- leftTypeId = TypeGet(leftTypeName, &leftDefined);
-
- if (rightTypeName)
- rightTypeId = TypeGet(rightTypeName, &rightDefined);
-
- if (!((OidIsValid(leftTypeId && leftDefined)) ||
- (OidIsValid(rightTypeId && rightDefined))))
- elog(WARN, "OperatorGet: no argument types??");
-
- for (i = 0; i < Natts_pg_operator; ++i) {
- values[i] = (Datum)NULL;
- replaces[i] = 'r';
- nulls[i] = ' ';
- }
-
- /* ----------------
- * Look up registered procedures -- find the return type
- * of procedureName to place in "result" field.
- * Do this before shells are created so we don't
- * have to worry about deleting them later.
- * ----------------
- */
- memset(typeId, 0, 8 * sizeof(Oid));
- if (!leftTypeName) {
- typeId[0] = rightTypeId;
- nargs = 1;
- }
- else if (!rightTypeName) {
- typeId[0] = leftTypeId;
- nargs = 1;
- }
- else {
- typeId[0] = leftTypeId;
- typeId[1] = rightTypeId;
- nargs = 2;
- }
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(procedureName),
- Int32GetDatum(nargs),
- PointerGetDatum(typeId),
- 0);
-
- if (!PointerIsValid(tup))
- func_error("OperatorDef", procedureName, nargs, typeId);
-
- values[ Anum_pg_operator_oprcode-1 ] = ObjectIdGetDatum(tup->t_oid);
- values[ Anum_pg_operator_oprresult-1 ] =
- ObjectIdGetDatum(((Form_pg_proc)
- GETSTRUCT(tup))->prorettype);
-
- /* ----------------
- * find restriction
- * ----------------
- */
- if (restrictionName) { /* optional */
- memset(typeId, 0, 8 * sizeof(Oid));
- typeId[0] = OIDOID; /* operator OID */
- typeId[1] = OIDOID; /* relation OID */
- typeId[2] = INT2OID; /* attribute number */
- typeId[3] = 0; /* value - can be any type */
- typeId[4] = INT4OID; /* flags - left or right selectivity */
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(restrictionName),
- Int32GetDatum(5),
- PointerGetDatum(typeId),
- 0);
- if (!HeapTupleIsValid(tup))
- func_error("OperatorDef", restrictionName, 5, typeId);
-
- values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(tup->t_oid);
- } else
- values[ Anum_pg_operator_oprrest-1 ] = ObjectIdGetDatum(InvalidOid);
-
- /* ----------------
- * find join - only valid for binary operators
- * ----------------
- */
- if (joinName) { /* optional */
+ register i,
+ j;
+ Relation pg_operator_desc;
+
+ HeapScanDesc pg_operator_scan;
+ HeapTuple tup;
+ Buffer buffer;
+ ItemPointerData itemPointerData;
+ char nulls[Natts_pg_operator];
+ char replaces[Natts_pg_operator];
+ Datum values[Natts_pg_operator];
+ Oid other_oid = 0;
+ Oid operatorObjectId;
+ Oid leftTypeId = InvalidOid;
+ Oid rightTypeId = InvalidOid;
+ Oid commutatorId = InvalidOid;
+ Oid negatorId = InvalidOid;
+ bool leftDefined = false;
+ bool rightDefined = false;
+ char *name[4];
+ Oid typeId[8];
+ int nargs;
+ TupleDesc tupDesc;
+
+ static ScanKeyData opKey[3] = {
+ {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
+ {0, Anum_pg_operator_oprleft, ObjectIdEqualRegProcedure},
+ {0, Anum_pg_operator_oprright, ObjectIdEqualRegProcedure},
+ };
+
+ fmgr_info(NameEqualRegProcedure,
+ &opKey[0].sk_func, &opKey[0].sk_nargs);
+ fmgr_info(ObjectIdEqualRegProcedure,
+ &opKey[1].sk_func, &opKey[1].sk_nargs);
+ fmgr_info(ObjectIdEqualRegProcedure,
+ &opKey[2].sk_func, &opKey[2].sk_nargs);
+
+ operatorObjectId = OperatorGet(operatorName,
+ leftTypeName,
+ rightTypeName);
+
+ if (OidIsValid(operatorObjectId) && !definedOK)
+ elog(WARN, "OperatorDef: operator \"%s\" already defined",
+ operatorName);
+
+ if (leftTypeName)
+ leftTypeId = TypeGet(leftTypeName, &leftDefined);
+
+ if (rightTypeName)
+ rightTypeId = TypeGet(rightTypeName, &rightDefined);
+
+ if (!((OidIsValid(leftTypeId && leftDefined)) ||
+ (OidIsValid(rightTypeId && rightDefined))))
+ elog(WARN, "OperatorGet: no argument types??");
+
+ for (i = 0; i < Natts_pg_operator; ++i)
+ {
+ values[i] = (Datum) NULL;
+ replaces[i] = 'r';
+ nulls[i] = ' ';
+ }
+
+ /* ----------------
+ * Look up registered procedures -- find the return type
+ * of procedureName to place in "result" field.
+ * Do this before shells are created so we don't
+ * have to worry about deleting them later.
+ * ----------------
+ */
memset(typeId, 0, 8 * sizeof(Oid));
- typeId[0] = OIDOID; /* operator OID */
- typeId[1] = OIDOID; /* relation OID 1 */
- typeId[2] = INT2OID; /* attribute number 1 */
- typeId[3] = OIDOID; /* relation OID 2 */
- typeId[4] = INT2OID; /* attribute number 2 */
-
+ if (!leftTypeName)
+ {
+ typeId[0] = rightTypeId;
+ nargs = 1;
+ }
+ else if (!rightTypeName)
+ {
+ typeId[0] = leftTypeId;
+ nargs = 1;
+ }
+ else
+ {
+ typeId[0] = leftTypeId;
+ typeId[1] = rightTypeId;
+ nargs = 2;
+ }
tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(joinName),
- Int32GetDatum(5),
- PointerGetDatum(typeId),
- 0);
- if (!HeapTupleIsValid(tup))
- func_error("OperatorDef", joinName, 5, typeId);
-
- values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(tup->t_oid);
- } else
- values[Anum_pg_operator_oprjoin-1] = ObjectIdGetDatum(InvalidOid);
-
- /* ----------------
- * set up values in the operator tuple
- * ----------------
- */
- i = 0;
- values[i++] = PointerGetDatum(operatorName);
- values[i++] = Int32GetDatum(GetUserId());
- values[i++] = UInt16GetDatum(precedence);
- values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
- values[i++] = Int8GetDatum(isLeftAssociative);
- values[i++] = Int8GetDatum(canHash);
- values[i++] = ObjectIdGetDatum(leftTypeId);
- values[i++] = ObjectIdGetDatum(rightTypeId);
-
- ++i; /* Skip "prorettype", this was done above */
-
- /*
- * Set up the other operators. If they do not currently exist,
- * set up shells in order to get ObjectId's and call OperatorDef
- * again later to fill in the shells.
- */
- name[0] = commutatorName;
- name[1] = negatorName;
- name[2] = leftSortName;
- name[3] = rightSortName;
-
- for (j = 0; j < 4; ++j) {
- if (name[j]) {
-
- /* for the commutator, switch order of arguments */
- if (j == 0) {
- other_oid = OperatorGet(name[j], rightTypeName,leftTypeName);
- commutatorId = other_oid;
- } else {
- other_oid = OperatorGet(name[j], leftTypeName,rightTypeName);
- if (j == 1)
- negatorId = other_oid;
- }
-
- if (OidIsValid(other_oid)) /* already in catalogs */
- values[i++] = ObjectIdGetDatum(other_oid);
- else if (strcmp(operatorName, name[j]) != 0) {
- /* not in catalogs, different from operator */
-
- /* for the commutator, switch order of arguments */
- if (j == 0) {
- other_oid = OperatorShellMake(name[j],
- rightTypeName,
- leftTypeName);
- } else {
- other_oid = OperatorShellMake(name[j],
- leftTypeName,
- rightTypeName);
+ PointerGetDatum(procedureName),
+ Int32GetDatum(nargs),
+ PointerGetDatum(typeId),
+ 0);
+
+ if (!PointerIsValid(tup))
+ func_error("OperatorDef", procedureName, nargs, typeId);
+
+ values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(tup->t_oid);
+ values[Anum_pg_operator_oprresult - 1] =
+ ObjectIdGetDatum(((Form_pg_proc)
+ GETSTRUCT(tup))->prorettype);
+
+ /* ----------------
+ * find restriction
+ * ----------------
+ */
+ if (restrictionName)
+ { /* optional */
+ memset(typeId, 0, 8 * sizeof(Oid));
+ typeId[0] = OIDOID; /* operator OID */
+ typeId[1] = OIDOID; /* relation OID */
+ typeId[2] = INT2OID; /* attribute number */
+ typeId[3] = 0; /* value - can be any type */
+ typeId[4] = INT4OID; /* flags - left or right selectivity */
+ tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(restrictionName),
+ Int32GetDatum(5),
+ PointerGetDatum(typeId),
+ 0);
+ if (!HeapTupleIsValid(tup))
+ func_error("OperatorDef", restrictionName, 5, typeId);
+
+ values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(tup->t_oid);
+ }
+ else
+ values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
+
+ /* ----------------
+ * find join - only valid for binary operators
+ * ----------------
+ */
+ if (joinName)
+ { /* optional */
+ memset(typeId, 0, 8 * sizeof(Oid));
+ typeId[0] = OIDOID; /* operator OID */
+ typeId[1] = OIDOID; /* relation OID 1 */
+ typeId[2] = INT2OID; /* attribute number 1 */
+ typeId[3] = OIDOID; /* relation OID 2 */
+ typeId[4] = INT2OID; /* attribute number 2 */
+
+ tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(joinName),
+ Int32GetDatum(5),
+ PointerGetDatum(typeId),
+ 0);
+ if (!HeapTupleIsValid(tup))
+ func_error("OperatorDef", joinName, 5, typeId);
+
+ values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(tup->t_oid);
+ }
+ else
+ values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
+
+ /* ----------------
+ * set up values in the operator tuple
+ * ----------------
+ */
+ i = 0;
+ values[i++] = PointerGetDatum(operatorName);
+ values[i++] = Int32GetDatum(GetUserId());
+ values[i++] = UInt16GetDatum(precedence);
+ values[i++] = leftTypeName ? (rightTypeName ? 'b' : 'r') : 'l';
+ values[i++] = Int8GetDatum(isLeftAssociative);
+ values[i++] = Int8GetDatum(canHash);
+ values[i++] = ObjectIdGetDatum(leftTypeId);
+ values[i++] = ObjectIdGetDatum(rightTypeId);
+
+ ++i; /* Skip "prorettype", this was done above */
+
+ /*
+ * Set up the other operators. If they do not currently exist, set up
+ * shells in order to get ObjectId's and call OperatorDef again later
+ * to fill in the shells.
+ */
+ name[0] = commutatorName;
+ name[1] = negatorName;
+ name[2] = leftSortName;
+ name[3] = rightSortName;
+
+ for (j = 0; j < 4; ++j)
+ {
+ if (name[j])
+ {
+
+ /* for the commutator, switch order of arguments */
+ if (j == 0)
+ {
+ other_oid = OperatorGet(name[j], rightTypeName, leftTypeName);
+ commutatorId = other_oid;
+ }
+ else
+ {
+ other_oid = OperatorGet(name[j], leftTypeName, rightTypeName);
+ if (j == 1)
+ negatorId = other_oid;
+ }
+
+ if (OidIsValid(other_oid)) /* already in catalogs */
+ values[i++] = ObjectIdGetDatum(other_oid);
+ else if (strcmp(operatorName, name[j]) != 0)
+ {
+ /* not in catalogs, different from operator */
+
+ /* for the commutator, switch order of arguments */
+ if (j == 0)
+ {
+ other_oid = OperatorShellMake(name[j],
+ rightTypeName,
+ leftTypeName);
+ }
+ else
+ {
+ other_oid = OperatorShellMake(name[j],
+ leftTypeName,
+ rightTypeName);
+ }
+
+ if (!OidIsValid(other_oid))
+ elog(WARN,
+ "OperatorDef: can't create operator '%s'",
+ name[j]);
+ values[i++] = ObjectIdGetDatum(other_oid);
+
+ }
+ else
+/* not in catalogs, same as operator ??? */
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+
}
-
- if (!OidIsValid(other_oid))
- elog(WARN,
- "OperatorDef: can't create operator '%s'",
- name[j]);
- values[i++] = ObjectIdGetDatum(other_oid);
-
- } else /* not in catalogs, same as operator ??? */
- values[i++] = ObjectIdGetDatum(InvalidOid);
-
- } else /* new operator is optional */
- values[i++] = ObjectIdGetDatum(InvalidOid);
- }
-
- /* last three fields were filled in first */
-
- /*
- * If we are adding to an operator shell, get its t_ctid and a
- * buffer.
- */
- pg_operator_desc = heap_openr(OperatorRelationName);
-
- if (operatorObjectId) {
- opKey[0].sk_argument = PointerGetDatum(operatorName);
- opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
- opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
-
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- SelfTimeQual,
- 3,
- opKey);
-
- tup = heap_getnext(pg_operator_scan, 0, &buffer);
- if (HeapTupleIsValid(tup)) {
- tup = heap_modifytuple(tup,
- buffer,
- pg_operator_desc,
- values,
- nulls,
- replaces);
-
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- setheapoverride(true);
- heap_replace(pg_operator_desc, &itemPointerData, tup);
- setheapoverride(false);
- } else
- elog(WARN, "OperatorDef: no operator %d", other_oid);
-
- heap_endscan(pg_operator_scan);
-
- } else {
- tupDesc = pg_operator_desc->rd_att;
- tup = heap_formtuple(tupDesc, values, nulls);
-
- heap_insert(pg_operator_desc, tup);
- operatorObjectId = tup->t_oid;
- }
-
- heap_close(pg_operator_desc);
-
- /*
- * It's possible that we're creating a skeleton operator here for
- * the commute or negate attributes of a real operator. If we are,
- * then we're done. If not, we may need to update the negator and
- * commutator for this attribute. The reason for this is that the
- * user may want to create two operators (say < and >=). When he
- * defines <, if he uses >= as the negator or commutator, he won't
- * be able to insert it later, since (for some reason) define operator
- * defines it for him. So what he does is to define > without a
- * negator or commutator. Then he defines >= with < as the negator
- * and commutator. As a side effect, this will update the > tuple
- * if it has no commutator or negator defined.
- *
- * Alstublieft, Tom Vijlbrief.
- */
- if (!definedOK)
- OperatorUpd(operatorObjectId, commutatorId, negatorId);
+ else
+/* new operator is optional */
+ values[i++] = ObjectIdGetDatum(InvalidOid);
+ }
+
+ /* last three fields were filled in first */
+
+ /*
+ * If we are adding to an operator shell, get its t_ctid and a buffer.
+ */
+ pg_operator_desc = heap_openr(OperatorRelationName);
+
+ if (operatorObjectId)
+ {
+ opKey[0].sk_argument = PointerGetDatum(operatorName);
+ opKey[1].sk_argument = ObjectIdGetDatum(leftTypeId);
+ opKey[2].sk_argument = ObjectIdGetDatum(rightTypeId);
+
+ pg_operator_scan = heap_beginscan(pg_operator_desc,
+ 0,
+ SelfTimeQual,
+ 3,
+ opKey);
+
+ tup = heap_getnext(pg_operator_scan, 0, &buffer);
+ if (HeapTupleIsValid(tup))
+ {
+ tup = heap_modifytuple(tup,
+ buffer,
+ pg_operator_desc,
+ values,
+ nulls,
+ replaces);
+
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ setheapoverride(true);
+ heap_replace(pg_operator_desc, &itemPointerData, tup);
+ setheapoverride(false);
+ }
+ else
+ elog(WARN, "OperatorDef: no operator %d", other_oid);
+
+ heap_endscan(pg_operator_scan);
+
+ }
+ else
+ {
+ tupDesc = pg_operator_desc->rd_att;
+ tup = heap_formtuple(tupDesc, values, nulls);
+
+ heap_insert(pg_operator_desc, tup);
+ operatorObjectId = tup->t_oid;
+ }
+
+ heap_close(pg_operator_desc);
+
+ /*
+ * It's possible that we're creating a skeleton operator here for the
+ * commute or negate attributes of a real operator. If we are, then
+ * we're done. If not, we may need to update the negator and
+ * commutator for this attribute. The reason for this is that the
+ * user may want to create two operators (say < and >=). When he
+ * defines <, if he uses >= as the negator or commutator, he won't be
+ * able to insert it later, since (for some reason) define operator
+ * defines it for him. So what he does is to define > without a
+ * negator or commutator. Then he defines >= with < as the negator
+ * and commutator. As a side effect, this will update the > tuple if
+ * it has no commutator or negator defined.
+ *
+ * Alstublieft, Tom Vijlbrief.
+ */
+ if (!definedOK)
+ OperatorUpd(operatorObjectId, commutatorId, negatorId);
}
/* ----------------------------------------------------------------
* OperatorUpd
*
- * For a given operator, look up its negator and commutator operators.
- * If they are defined, but their negator and commutator operators
- * (respectively) are not, then use the new operator for neg and comm.
- * This solves a problem for users who need to insert two new operators
- * which are the negator or commutator of each other.
- * ----------------------------------------------------------------
+ * For a given operator, look up its negator and commutator operators.
+ * If they are defined, but their negator and commutator operators
+ * (respectively) are not, then use the new operator for neg and comm.
+ * This solves a problem for users who need to insert two new operators
+ * which are the negator or commutator of each other.
+ * ----------------------------------------------------------------
*/
static void
OperatorUpd(Oid baseId, Oid commId, Oid negId)
{
- register i;
- Relation pg_operator_desc;
- HeapScanDesc pg_operator_scan;
- HeapTuple tup;
- Buffer buffer;
- ItemPointerData itemPointerData;
- char nulls[ Natts_pg_operator ];
- char replaces[ Natts_pg_operator ];
- Datum values[ Natts_pg_operator ];
-
- static ScanKeyData opKey[1] = {
- { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure },
- };
-
- fmgr_info(ObjectIdEqualRegProcedure,
- &opKey[0].sk_func, &opKey[0].sk_nargs);
-
- for (i = 0; i < Natts_pg_operator; ++i) {
- values[i] = (Datum)NULL;
- replaces[i] = ' ';
- nulls[i] = ' ';
- }
-
- pg_operator_desc = heap_openr(OperatorRelationName);
-
- /* check and update the commutator, if necessary */
- opKey[0].sk_argument = ObjectIdGetDatum(commId);
-
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- SelfTimeQual,
- 1,
- opKey);
-
- tup = heap_getnext(pg_operator_scan, 0, &buffer);
-
- /* if the commutator and negator are the same operator, do one update */
- if (commId == negId) {
- if (HeapTupleIsValid(tup)) {
- OperatorTupleForm t;
-
- t = (OperatorTupleForm) GETSTRUCT(tup);
- if (!OidIsValid(t->oprcom)
- || !OidIsValid(t->oprnegate)) {
-
- if (!OidIsValid(t->oprnegate)) {
- values[Anum_pg_operator_oprnegate - 1] =
- ObjectIdGetDatum(baseId);
- replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r';
- }
-
- if (!OidIsValid(t->oprcom)) {
- values[Anum_pg_operator_oprcom - 1] =
- ObjectIdGetDatum(baseId);
- replaces[ Anum_pg_operator_oprcom - 1 ] = 'r';
+ register i;
+ Relation pg_operator_desc;
+ HeapScanDesc pg_operator_scan;
+ HeapTuple tup;
+ Buffer buffer;
+ ItemPointerData itemPointerData;
+ char nulls[Natts_pg_operator];
+ char replaces[Natts_pg_operator];
+ Datum values[Natts_pg_operator];
+
+ static ScanKeyData opKey[1] = {
+ {0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure},
+ };
+
+ fmgr_info(ObjectIdEqualRegProcedure,
+ &opKey[0].sk_func, &opKey[0].sk_nargs);
+
+ for (i = 0; i < Natts_pg_operator; ++i)
+ {
+ values[i] = (Datum) NULL;
+ replaces[i] = ' ';
+ nulls[i] = ' ';
+ }
+
+ pg_operator_desc = heap_openr(OperatorRelationName);
+
+ /* check and update the commutator, if necessary */
+ opKey[0].sk_argument = ObjectIdGetDatum(commId);
+
+ pg_operator_scan = heap_beginscan(pg_operator_desc,
+ 0,
+ SelfTimeQual,
+ 1,
+ opKey);
+
+ tup = heap_getnext(pg_operator_scan, 0, &buffer);
+
+ /* if the commutator and negator are the same operator, do one update */
+ if (commId == negId)
+ {
+ if (HeapTupleIsValid(tup))
+ {
+ OperatorTupleForm t;
+
+ t = (OperatorTupleForm) GETSTRUCT(tup);
+ if (!OidIsValid(t->oprcom)
+ || !OidIsValid(t->oprnegate))
+ {
+
+ if (!OidIsValid(t->oprnegate))
+ {
+ values[Anum_pg_operator_oprnegate - 1] =
+ ObjectIdGetDatum(baseId);
+ replaces[Anum_pg_operator_oprnegate - 1] = 'r';
+ }
+
+ if (!OidIsValid(t->oprcom))
+ {
+ values[Anum_pg_operator_oprcom - 1] =
+ ObjectIdGetDatum(baseId);
+ replaces[Anum_pg_operator_oprcom - 1] = 'r';
+ }
+
+ tup = heap_modifytuple(tup,
+ buffer,
+ pg_operator_desc,
+ values,
+ nulls,
+ replaces);
+
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+
+ setheapoverride(true);
+ heap_replace(pg_operator_desc, &itemPointerData, tup);
+ setheapoverride(false);
+
+ }
}
-
+ heap_endscan(pg_operator_scan);
+
+ heap_close(pg_operator_desc);
+
+ /* release the buffer properly */
+ if (BufferIsValid(buffer))
+ ReleaseBuffer(buffer);
+
+ return;
+ }
+
+ /* if commutator and negator are different, do two updates */
+ if (HeapTupleIsValid(tup) &&
+ !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom)))
+ {
+ values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
+ replaces[Anum_pg_operator_oprcom - 1] = 'r';
tup = heap_modifytuple(tup,
- buffer,
- pg_operator_desc,
- values,
- nulls,
- replaces);
-
+ buffer,
+ pg_operator_desc,
+ values,
+ nulls,
+ replaces);
+
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
-
setheapoverride(true);
heap_replace(pg_operator_desc, &itemPointerData, tup);
setheapoverride(false);
- }
+ values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
+ replaces[Anum_pg_operator_oprcom - 1] = ' ';
+
+ /* release the buffer properly */
+ if (BufferIsValid(buffer))
+ ReleaseBuffer(buffer);
+
+ }
+
+ /* check and update the negator, if necessary */
+ opKey[0].sk_argument = ObjectIdGetDatum(negId);
+
+ pg_operator_scan = heap_beginscan(pg_operator_desc,
+ 0,
+ SelfTimeQual,
+ 1,
+ opKey);
+
+ tup = heap_getnext(pg_operator_scan, 0, &buffer);
+ if (HeapTupleIsValid(tup) &&
+ !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate)))
+ {
+ values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
+ replaces[Anum_pg_operator_oprnegate - 1] = 'r';
+ tup = heap_modifytuple(tup,
+ buffer,
+ pg_operator_desc,
+ values,
+ nulls,
+ replaces);
+
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+
+ setheapoverride(true);
+ heap_replace(pg_operator_desc, &itemPointerData, tup);
+ setheapoverride(false);
}
- heap_endscan(pg_operator_scan);
-
- heap_close(pg_operator_desc);
-
- /* release the buffer properly */
- if (BufferIsValid(buffer))
- ReleaseBuffer(buffer);
-
- return;
- }
-
- /* if commutator and negator are different, do two updates */
- if (HeapTupleIsValid(tup) &&
- !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprcom))) {
- values[ Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
- replaces[ Anum_pg_operator_oprcom - 1] = 'r';
- tup = heap_modifytuple(tup,
- buffer,
- pg_operator_desc,
- values,
- nulls,
- replaces);
-
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- setheapoverride(true);
- heap_replace(pg_operator_desc, &itemPointerData, tup);
- setheapoverride(false);
-
- values[ Anum_pg_operator_oprcom - 1 ] = (Datum)NULL;
- replaces[ Anum_pg_operator_oprcom - 1 ] = ' ';
/* release the buffer properly */
if (BufferIsValid(buffer))
- ReleaseBuffer(buffer);
-
- }
-
- /* check and update the negator, if necessary */
- opKey[0].sk_argument = ObjectIdGetDatum(negId);
-
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- SelfTimeQual,
- 1,
- opKey);
-
- tup = heap_getnext(pg_operator_scan, 0, &buffer);
- if (HeapTupleIsValid(tup) &&
- !(OidIsValid(((OperatorTupleForm) GETSTRUCT(tup))->oprnegate))) {
- values[Anum_pg_operator_oprnegate-1] = ObjectIdGetDatum(baseId);
- replaces[ Anum_pg_operator_oprnegate - 1 ] = 'r';
- tup = heap_modifytuple(tup,
- buffer,
- pg_operator_desc,
- values,
- nulls,
- replaces);
-
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
-
- setheapoverride(true);
- heap_replace(pg_operator_desc, &itemPointerData, tup);
- setheapoverride(false);
- }
-
- /* release the buffer properly */
- if (BufferIsValid(buffer))
- ReleaseBuffer(buffer);
-
- heap_endscan(pg_operator_scan);
-
- heap_close(pg_operator_desc);
+ ReleaseBuffer(buffer);
+
+ heap_endscan(pg_operator_scan);
+
+ heap_close(pg_operator_desc);
}
@@ -883,196 +925,202 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
*
* Algorithm:
*
- * Since the commutator, negator, leftsortoperator, and rightsortoperator
- * can be defined implicitly through OperatorCreate, must check before
- * the main operator is added to see if they already exist. If they
- * do not already exist, OperatorDef makes a "shell" for each undefined
- * one, and then OperatorCreate must call OperatorDef again to fill in
- * each shell. All this is necessary in order to get the right ObjectId's
- * filled into the right fields.
+ * Since the commutator, negator, leftsortoperator, and rightsortoperator
+ * can be defined implicitly through OperatorCreate, must check before
+ * the main operator is added to see if they already exist. If they
+ * do not already exist, OperatorDef makes a "shell" for each undefined
+ * one, and then OperatorCreate must call OperatorDef again to fill in
+ * each shell. All this is necessary in order to get the right ObjectId's
+ * filled into the right fields.
+ *
+ * The "definedOk" flag indicates that OperatorDef can be called on
+ * the operator even though it already has an entry in the PG_OPERATOR
+ * relation. This allows shells to be filled in. The user cannot
+ * forward declare operators, this is strictly an internal capability.
*
- * The "definedOk" flag indicates that OperatorDef can be called on
- * the operator even though it already has an entry in the PG_OPERATOR
- * relation. This allows shells to be filled in. The user cannot
- * forward declare operators, this is strictly an internal capability.
+ * When the shells are filled in by subsequent calls to OperatorDef,
+ * all the fields are the same as the definition of the original operator
+ * except that the target operator name and the original operatorName
+ * are switched. In the case of commutator and negator, special flags
+ * are set to indicate their status, telling the executor(?) that
+ * the operands are to be switched, or the outcome of the procedure
+ * negated.
*
- * When the shells are filled in by subsequent calls to OperatorDef,
- * all the fields are the same as the definition of the original operator
- * except that the target operator name and the original operatorName
- * are switched. In the case of commutator and negator, special flags
- * are set to indicate their status, telling the executor(?) that
- * the operands are to be switched, or the outcome of the procedure
- * negated.
- *
* ************************* NOTE NOTE NOTE ******************************
- *
- * If the execution of this utility is interrupted, the pg_operator
- * catalog may be left in an inconsistent state. Similarly, if
- * something is removed from the pg_operator, pg_type, or pg_procedure
- * catalog while this is executing, the results may be inconsistent.
+ *
+ * If the execution of this utility is interrupted, the pg_operator
+ * catalog may be left in an inconsistent state. Similarly, if
+ * something is removed from the pg_operator, pg_type, or pg_procedure
+ * catalog while this is executing, the results may be inconsistent.
* ----------------------------------------------------------------
*
- * "X" indicates an optional argument (i.e. one that can be NULL)
- * operatorName; -- operator name
- * leftTypeName; -- X left type name
- * rightTypeName; -- X right type name
- * procedureName; -- procedure for operator
- * precedence; -- operator precedence
- * isLeftAssociative; -- operator is left associative
- * commutatorName; -- X commutator operator name
- * negatorName; -- X negator operator name
- * restrictionName; -- X restriction sel. procedure
- * joinName; -- X join sel. procedure name
- * canHash; -- operator hashes
- * leftSortName; -- X left sort operator
- * rightSortName; -- X right sort operator
- *
+ * "X" indicates an optional argument (i.e. one that can be NULL)
+ * operatorName; -- operator name
+ * leftTypeName; -- X left type name
+ * rightTypeName; -- X right type name
+ * procedureName; -- procedure for operator
+ * precedence; -- operator precedence
+ * isLeftAssociative; -- operator is left associative
+ * commutatorName; -- X commutator operator name
+ * negatorName; -- X negator operator name
+ * restrictionName; -- X restriction sel. procedure
+ * joinName; -- X join sel. procedure name
+ * canHash; -- operator hashes
+ * leftSortName; -- X left sort operator
+ * rightSortName; -- X right sort operator
+ *
*/
void
OperatorCreate(char *operatorName,
- char *leftTypeName,
- char *rightTypeName,
- char *procedureName,
- uint16 precedence,
- bool isLeftAssociative,
- char *commutatorName,
- char *negatorName,
- char *restrictionName,
- char *joinName,
- bool canHash,
- char *leftSortName,
- char *rightSortName)
+ char *leftTypeName,
+ char *rightTypeName,
+ char *procedureName,
+ uint16 precedence,
+ bool isLeftAssociative,
+ char *commutatorName,
+ char *negatorName,
+ char *restrictionName,
+ char *joinName,
+ bool canHash,
+ char *leftSortName,
+ char *rightSortName)
{
- Oid commObjectId, negObjectId;
- Oid leftSortObjectId, rightSortObjectId;
- int definedOK;
-
- if (!leftTypeName && !rightTypeName)
- elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined");
-
- /* ----------------
- * get the oid's of the operator's associated operators, if possible.
- * ----------------
- */
- if (commutatorName)
- commObjectId = OperatorGet(commutatorName, /* commute type order */
- rightTypeName,
- leftTypeName);
- else commObjectId = 0;
-
- if (negatorName)
- negObjectId = OperatorGet(negatorName,
- leftTypeName,
- rightTypeName);
- else negObjectId = 0;
-
- if (leftSortName)
- leftSortObjectId = OperatorGet(leftSortName,
- leftTypeName,
- rightTypeName);
- else leftSortObjectId = 0;
-
- if (rightSortName)
- rightSortObjectId = OperatorGet(rightSortName,
+ Oid commObjectId,
+ negObjectId;
+ Oid leftSortObjectId,
+ rightSortObjectId;
+ int definedOK;
+
+ if (!leftTypeName && !rightTypeName)
+ elog(WARN, "OperatorCreate : at least one of leftarg or rightarg must be defined");
+
+ /* ----------------
+ * get the oid's of the operator's associated operators, if possible.
+ * ----------------
+ */
+ if (commutatorName)
+ commObjectId = OperatorGet(commutatorName, /* commute type order */
+ rightTypeName,
+ leftTypeName);
+ else
+ commObjectId = 0;
+
+ if (negatorName)
+ negObjectId = OperatorGet(negatorName,
+ leftTypeName,
+ rightTypeName);
+ else
+ negObjectId = 0;
+
+ if (leftSortName)
+ leftSortObjectId = OperatorGet(leftSortName,
+ leftTypeName,
+ rightTypeName);
+ else
+ leftSortObjectId = 0;
+
+ if (rightSortName)
+ rightSortObjectId = OperatorGet(rightSortName,
+ rightTypeName,
+ leftTypeName);
+ else
+ rightSortObjectId = 0;
+
+ /* ----------------
+ * Use OperatorDef() to define the specified operator and
+ * also create shells for the operator's associated operators
+ * if they don't already exist.
+ *
+ * This operator should not be defined yet.
+ * ----------------
+ */
+ definedOK = 0;
+
+ OperatorDef(operatorName,
+ definedOK,
+ leftTypeName,
+ rightTypeName,
+ procedureName,
+ precedence,
+ isLeftAssociative,
+ commutatorName,
+ negatorName,
+ restrictionName,
+ joinName,
+ canHash,
+ leftSortName,
+ rightSortName);
+
+ /* ----------------
+ * Now fill in information in the operator's associated
+ * operators.
+ *
+ * These operators should be defined or have shells defined.
+ * ----------------
+ */
+ definedOK = 1;
+
+ if (!OidIsValid(commObjectId) && commutatorName)
+ OperatorDef(commutatorName,
+ definedOK,
+ leftTypeName, /* should eventually */
+ rightTypeName, /* commute order */
+ procedureName,
+ precedence,
+ isLeftAssociative,
+ operatorName, /* commutator */
+ negatorName,
+ restrictionName,
+ joinName,
+ canHash,
+ rightSortName,
+ leftSortName);
+
+ if (negatorName && !OidIsValid(negObjectId))
+ OperatorDef(negatorName,
+ definedOK,
+ leftTypeName,
+ rightTypeName,
+ procedureName,
+ precedence,
+ isLeftAssociative,
+ commutatorName,
+ operatorName, /* negator */
+ restrictionName,
+ joinName,
+ canHash,
+ leftSortName,
+ rightSortName);
+
+ if (leftSortName && !OidIsValid(leftSortObjectId))
+ OperatorDef(leftSortName,
+ definedOK,
+ leftTypeName,
+ rightTypeName,
+ procedureName,
+ precedence,
+ isLeftAssociative,
+ commutatorName,
+ negatorName,
+ restrictionName,
+ joinName,
+ canHash,
+ operatorName, /* left sort */
+ rightSortName);
+
+ if (rightSortName && !OidIsValid(rightSortObjectId))
+ OperatorDef(rightSortName,
+ definedOK,
+ leftTypeName,
rightTypeName,
- leftTypeName);
- else rightSortObjectId = 0;
-
- /* ----------------
- * Use OperatorDef() to define the specified operator and
- * also create shells for the operator's associated operators
- * if they don't already exist.
- *
- * This operator should not be defined yet.
- * ----------------
- */
- definedOK = 0;
-
- OperatorDef(operatorName,
- definedOK,
- leftTypeName,
- rightTypeName,
- procedureName,
- precedence,
- isLeftAssociative,
- commutatorName,
- negatorName,
- restrictionName,
- joinName,
- canHash,
- leftSortName,
- rightSortName);
-
- /* ----------------
- * Now fill in information in the operator's associated
- * operators.
- *
- * These operators should be defined or have shells defined.
- * ----------------
- */
- definedOK = 1;
-
- if (!OidIsValid(commObjectId) && commutatorName)
- OperatorDef(commutatorName,
- definedOK,
- leftTypeName, /* should eventually */
- rightTypeName, /* commute order */
- procedureName,
- precedence,
- isLeftAssociative,
- operatorName, /* commutator */
- negatorName,
- restrictionName,
- joinName,
- canHash,
- rightSortName,
- leftSortName);
-
- if (negatorName && !OidIsValid(negObjectId))
- OperatorDef(negatorName,
- definedOK,
- leftTypeName,
- rightTypeName,
- procedureName,
- precedence,
- isLeftAssociative,
- commutatorName,
- operatorName, /* negator */
- restrictionName,
- joinName,
- canHash,
- leftSortName,
- rightSortName);
-
- if (leftSortName && !OidIsValid(leftSortObjectId))
- OperatorDef(leftSortName,
- definedOK,
- leftTypeName,
- rightTypeName,
- procedureName,
- precedence,
- isLeftAssociative,
- commutatorName,
- negatorName,
- restrictionName,
- joinName,
- canHash,
- operatorName, /* left sort */
- rightSortName);
-
- if (rightSortName && !OidIsValid(rightSortObjectId))
- OperatorDef(rightSortName,
- definedOK,
- leftTypeName,
- rightTypeName,
- procedureName,
- precedence,
- isLeftAssociative,
- commutatorName,
- negatorName,
- restrictionName,
- joinName,
- canHash,
- leftSortName,
- operatorName); /* right sort */
+ procedureName,
+ precedence,
+ isLeftAssociative,
+ commutatorName,
+ negatorName,
+ restrictionName,
+ joinName,
+ canHash,
+ leftSortName,
+ operatorName); /* right sort */
}
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 947bdc6051b..1dd1b0867c3 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* pg_proc.c--
- * routines to support manipulation of the pg_proc relation
+ * routines to support manipulation of the pg_proc relation
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.5 1996/11/08 00:44:34 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.6 1997/09/07 04:40:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,231 +30,252 @@
#include <utils/lsyscache.h>
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/* ----------------------------------------------------------------
- * ProcedureDefine
+ * ProcedureDefine
* ----------------------------------------------------------------
*/
Oid
ProcedureCreate(char *procedureName,
- bool returnsSet,
- char *returnTypeName,
- char *languageName,
- char *prosrc,
- char *probin,
- bool canCache,
- bool trusted,
- int32 byte_pct,
- int32 perbyte_cpu,
- int32 percall_cpu,
- int32 outin_ratio,
- List *argList,
- CommandDest dest)
+ bool returnsSet,
+ char *returnTypeName,
+ char *languageName,
+ char *prosrc,
+ char *probin,
+ bool canCache,
+ bool trusted,
+ int32 byte_pct,
+ int32 perbyte_cpu,
+ int32 percall_cpu,
+ int32 outin_ratio,
+ List * argList,
+ CommandDest dest)
{
- register i;
- Relation rdesc;
- HeapTuple tup;
- bool defined;
- uint16 parameterCount;
- char nulls[ Natts_pg_proc ];
- Datum values[ Natts_pg_proc ];
- Oid languageObjectId;
- Oid typeObjectId;
- List *x;
- QueryTreeList *querytree_list;
- List *plan_list;
- Oid typev[8];
- Oid relid;
- Oid toid;
- text *prosrctext;
- TupleDesc tupDesc;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(PointerIsValid(prosrc));
- Assert(PointerIsValid(probin));
-
- parameterCount = 0;
- memset(typev, 0, 8 * sizeof(Oid));
- foreach (x, argList) {
- Value *t = lfirst(x);
-
- if (parameterCount == 8)
- elog(WARN, "Procedures cannot take more than 8 arguments");
-
- if (strcmp(strVal(t), "opaque") == 0) {
- if (strcmp(languageName, "sql") == 0) {
- elog(WARN, "ProcedureDefine: sql functions cannot take type \"opaque\"");
- }
- toid = 0;
- } else {
- toid = TypeGet(strVal(t), &defined);
-
- if (!OidIsValid(toid)) {
- elog(WARN, "ProcedureCreate: arg type '%s' is not defined",
- strVal(t));
- }
-
- if (!defined) {
- elog(NOTICE, "ProcedureCreate: arg type '%s' is only a shell",
- strVal(t));
- }
- }
-
- typev[parameterCount++] = toid;
- }
-
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(procedureName),
- UInt16GetDatum(parameterCount),
- PointerGetDatum(typev),
- 0);
-
- if (HeapTupleIsValid(tup))
- elog(WARN, "ProcedureCreate: procedure %s already exists with same arguments",
- procedureName);
-
- if (!strcmp(languageName, "sql")) {
- /* If this call is defining a set, check if the set is already
- * defined by looking to see whether this call's function text
- * matches a function already in pg_proc. If so just return the
- * OID of the existing set.
+ register i;
+ Relation rdesc;
+ HeapTuple tup;
+ bool defined;
+ uint16 parameterCount;
+ char nulls[Natts_pg_proc];
+ Datum values[Natts_pg_proc];
+ Oid languageObjectId;
+ Oid typeObjectId;
+ List *x;
+ QueryTreeList *querytree_list;
+ List *plan_list;
+ Oid typev[8];
+ Oid relid;
+ Oid toid;
+ text *prosrctext;
+ TupleDesc tupDesc;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
*/
- if (!strcmp(procedureName, GENERICSETNAME)) {
- prosrctext = textin(prosrc);
- tup = SearchSysCacheTuple(PROSRC,
- PointerGetDatum(prosrctext),
- 0,0,0);
- if (HeapTupleIsValid(tup))
- return tup->t_oid;
+ Assert(PointerIsValid(prosrc));
+ Assert(PointerIsValid(probin));
+
+ parameterCount = 0;
+ memset(typev, 0, 8 * sizeof(Oid));
+ foreach(x, argList)
+ {
+ Value *t = lfirst(x);
+
+ if (parameterCount == 8)
+ elog(WARN, "Procedures cannot take more than 8 arguments");
+
+ if (strcmp(strVal(t), "opaque") == 0)
+ {
+ if (strcmp(languageName, "sql") == 0)
+ {
+ elog(WARN, "ProcedureDefine: sql functions cannot take type \"opaque\"");
+ }
+ toid = 0;
+ }
+ else
+ {
+ toid = TypeGet(strVal(t), &defined);
+
+ if (!OidIsValid(toid))
+ {
+ elog(WARN, "ProcedureCreate: arg type '%s' is not defined",
+ strVal(t));
+ }
+
+ if (!defined)
+ {
+ elog(NOTICE, "ProcedureCreate: arg type '%s' is only a shell",
+ strVal(t));
+ }
+ }
+
+ typev[parameterCount++] = toid;
+ }
+
+ tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(procedureName),
+ UInt16GetDatum(parameterCount),
+ PointerGetDatum(typev),
+ 0);
+
+ if (HeapTupleIsValid(tup))
+ elog(WARN, "ProcedureCreate: procedure %s already exists with same arguments",
+ procedureName);
+
+ if (!strcmp(languageName, "sql"))
+ {
+
+ /*
+ * If this call is defining a set, check if the set is already
+ * defined by looking to see whether this call's function text
+ * matches a function already in pg_proc. If so just return the
+ * OID of the existing set.
+ */
+ if (!strcmp(procedureName, GENERICSETNAME))
+ {
+ prosrctext = textin(prosrc);
+ tup = SearchSysCacheTuple(PROSRC,
+ PointerGetDatum(prosrctext),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tup))
+ return tup->t_oid;
+ }
}
- }
-
- tup = SearchSysCacheTuple(LANNAME,
- PointerGetDatum(languageName),
- 0,0,0);
-
- if (!HeapTupleIsValid(tup))
- elog(WARN, "ProcedureCreate: no such language %s",
- languageName);
-
- languageObjectId = tup->t_oid;
-
- if (strcmp(returnTypeName, "opaque") == 0) {
- if (strcmp(languageName, "sql") == 0) {
- elog(WARN, "ProcedureCreate: sql functions cannot return type \"opaque\"");
+
+ tup = SearchSysCacheTuple(LANNAME,
+ PointerGetDatum(languageName),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "ProcedureCreate: no such language %s",
+ languageName);
+
+ languageObjectId = tup->t_oid;
+
+ if (strcmp(returnTypeName, "opaque") == 0)
+ {
+ if (strcmp(languageName, "sql") == 0)
+ {
+ elog(WARN, "ProcedureCreate: sql functions cannot return type \"opaque\"");
+ }
+ typeObjectId = 0;
}
- typeObjectId = 0;
- }
-
- else {
- typeObjectId = TypeGet(returnTypeName, &defined);
-
- if (!OidIsValid(typeObjectId)) {
- elog(NOTICE, "ProcedureCreate: type '%s' is not yet defined",
- returnTypeName);
+
+ else
+ {
+ typeObjectId = TypeGet(returnTypeName, &defined);
+
+ if (!OidIsValid(typeObjectId))
+ {
+ elog(NOTICE, "ProcedureCreate: type '%s' is not yet defined",
+ returnTypeName);
#if 0
- elog(NOTICE, "ProcedureCreate: creating a shell for type '%s'",
- returnTypeName);
-#endif
- typeObjectId = TypeShellMake(returnTypeName);
- if (!OidIsValid(typeObjectId)) {
- elog(WARN, "ProcedureCreate: could not create type '%s'",
- returnTypeName);
- }
+ elog(NOTICE, "ProcedureCreate: creating a shell for type '%s'",
+ returnTypeName);
+#endif
+ typeObjectId = TypeShellMake(returnTypeName);
+ if (!OidIsValid(typeObjectId))
+ {
+ elog(WARN, "ProcedureCreate: could not create type '%s'",
+ returnTypeName);
+ }
+ }
+
+ else if (!defined)
+ {
+ elog(NOTICE, "ProcedureCreate: return type '%s' is only a shell",
+ returnTypeName);
+ }
}
-
- else if (!defined) {
- elog(NOTICE, "ProcedureCreate: return type '%s' is only a shell",
- returnTypeName);
+
+ /*
+ * don't allow functions of complex types that have the same name as
+ * existing attributes of the type
+ */
+ if (parameterCount == 1 &&
+ (toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
+ defined &&
+ (relid = typeid_get_relid(toid)) != 0 &&
+ get_attnum(relid, procedureName) != InvalidAttrNumber)
+ elog(WARN, "method %s already an attribute of type %s",
+ procedureName, strVal(lfirst(argList)));
+
+
+ /*
+ * If this is a postquel procedure, we parse it here in order to be
+ * sure that it contains no syntax errors. We should store the plan
+ * in an Inversion file for use later, but for now, we just store the
+ * procedure's text in the prosrc attribute.
+ */
+
+ if (strcmp(languageName, "sql") == 0)
+ {
+ plan_list = pg_plan(prosrc, typev, parameterCount,
+ &querytree_list, dest);
+
+ /* typecheck return value */
+ pg_checkretval(typeObjectId, querytree_list);
}
- }
-
- /* don't allow functions of complex types that have the same name as
- existing attributes of the type */
- if (parameterCount == 1 &&
- (toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
- defined &&
- (relid = typeid_get_relid(toid)) != 0 &&
- get_attnum(relid, procedureName) != InvalidAttrNumber)
- elog(WARN, "method %s already an attribute of type %s",
- procedureName, strVal(lfirst(argList)));
-
-
- /*
- * If this is a postquel procedure, we parse it here in order to
- * be sure that it contains no syntax errors. We should store
- * the plan in an Inversion file for use later, but for now, we
- * just store the procedure's text in the prosrc attribute.
- */
-
- if (strcmp(languageName, "sql") == 0) {
- plan_list = pg_plan(prosrc, typev, parameterCount,
- &querytree_list, dest);
-
- /* typecheck return value */
- pg_checkretval(typeObjectId, querytree_list);
- }
-
- for (i = 0; i < Natts_pg_proc; ++i) {
- nulls[i] = ' ';
- values[i] = (Datum)NULL;
- }
-
- i = 0;
- values[i++] = PointerGetDatum(procedureName);
- values[i++] = Int32GetDatum(GetUserId());
- values[i++] = ObjectIdGetDatum(languageObjectId);
-
- /* XXX isinherited is always false for now */
-
- values[i++] = Int8GetDatum((bool) 0);
-
- /* XXX istrusted is always false for now */
-
- values[i++] = Int8GetDatum(trusted);
- values[i++] = Int8GetDatum(canCache);
- values[i++] = UInt16GetDatum(parameterCount);
- values[i++] = Int8GetDatum(returnsSet);
- values[i++] = ObjectIdGetDatum(typeObjectId);
-
- values[i++] = (Datum) typev;
- /*
- * The following assignments of constants are made. The real values
- * will have to be extracted from the arglist someday soon.
- */
- values[i++] = Int32GetDatum(byte_pct); /* probyte_pct */
- values[i++] = Int32GetDatum(perbyte_cpu); /* properbyte_cpu */
- values[i++] = Int32GetDatum(percall_cpu); /* propercall_cpu */
- values[i++] = Int32GetDatum(outin_ratio); /* prooutin_ratio */
-
- values[i++] = (Datum)fmgr(TextInRegProcedure, prosrc); /* prosrc */
- values[i++] = (Datum)fmgr(TextInRegProcedure, probin); /* probin */
-
- rdesc = heap_openr(ProcedureRelationName);
-
- tupDesc = rdesc->rd_att;
- tup = heap_formtuple(tupDesc,
- values,
- nulls);
-
- heap_insert(rdesc, tup);
-
- if (RelationGetRelationTupleForm(rdesc)->relhasindex)
+
+ for (i = 0; i < Natts_pg_proc; ++i)
{
- Relation idescs[Num_pg_proc_indices];
-
- CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_proc_indices, rdesc, tup);
- CatalogCloseIndices(Num_pg_proc_indices, idescs);
+ nulls[i] = ' ';
+ values[i] = (Datum) NULL;
}
- heap_close(rdesc);
- return tup->t_oid;
-}
+ i = 0;
+ values[i++] = PointerGetDatum(procedureName);
+ values[i++] = Int32GetDatum(GetUserId());
+ values[i++] = ObjectIdGetDatum(languageObjectId);
+
+ /* XXX isinherited is always false for now */
+
+ values[i++] = Int8GetDatum((bool) 0);
+
+ /* XXX istrusted is always false for now */
+
+ values[i++] = Int8GetDatum(trusted);
+ values[i++] = Int8GetDatum(canCache);
+ values[i++] = UInt16GetDatum(parameterCount);
+ values[i++] = Int8GetDatum(returnsSet);
+ values[i++] = ObjectIdGetDatum(typeObjectId);
+
+ values[i++] = (Datum) typev;
+
+ /*
+ * The following assignments of constants are made. The real values
+ * will have to be extracted from the arglist someday soon.
+ */
+ values[i++] = Int32GetDatum(byte_pct); /* probyte_pct */
+ values[i++] = Int32GetDatum(perbyte_cpu); /* properbyte_cpu */
+ values[i++] = Int32GetDatum(percall_cpu); /* propercall_cpu */
+ values[i++] = Int32GetDatum(outin_ratio); /* prooutin_ratio */
+
+ values[i++] = (Datum) fmgr(TextInRegProcedure, prosrc); /* prosrc */
+ values[i++] = (Datum) fmgr(TextInRegProcedure, probin); /* probin */
+
+ rdesc = heap_openr(ProcedureRelationName);
+
+ tupDesc = rdesc->rd_att;
+ tup = heap_formtuple(tupDesc,
+ values,
+ nulls);
+
+ heap_insert(rdesc, tup);
+
+ if (RelationGetRelationTupleForm(rdesc)->relhasindex)
+ {
+ Relation idescs[Num_pg_proc_indices];
+
+ CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_proc_indices, rdesc, tup);
+ CatalogCloseIndices(Num_pg_proc_indices, idescs);
+ }
+ heap_close(rdesc);
+ return tup->t_oid;
+}
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index caf53b03ea6..9a31030421c 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* pg_type.c--
- * routines to support manipulation of the pg_type relation
+ * routines to support manipulation of the pg_type relation
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.7 1997/08/19 21:30:38 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.8 1997/09/07 04:40:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,572 +25,595 @@
#include <storage/lmgr.h>
#include <miscadmin.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static Oid TypeShellMakeWithOpenRelation(Relation pg_type_desc,
- char *typeName);
+static Oid
+TypeShellMakeWithOpenRelation(Relation pg_type_desc,
+ char *typeName);
/* ----------------------------------------------------------------
- * TypeGetWithOpenRelation
+ * TypeGetWithOpenRelation
*
- * preforms a scan on pg_type for a type tuple with the
- * given type name.
+ * preforms a scan on pg_type for a type tuple with the
+ * given type name.
* ----------------------------------------------------------------
- * pg_type_desc -- reldesc for pg_type
- * typeName -- name of type to be fetched
- * defined -- has the type been defined?
+ * pg_type_desc -- reldesc for pg_type
+ * typeName -- name of type to be fetched
+ * defined -- has the type been defined?
*/
-static Oid
+static Oid
TypeGetWithOpenRelation(Relation pg_type_desc,
- char* typeName,
- bool *defined)
+ char *typeName,
+ bool * defined)
{
- HeapScanDesc scan;
- HeapTuple tup;
-
- static ScanKeyData typeKey[1] = {
- { 0, Anum_pg_type_typname, NameEqualRegProcedure }
- };
-
- /* ----------------
- * initialize the scan key and begin a scan of pg_type
- * ----------------
- */
- fmgr_info(NameEqualRegProcedure,
- &typeKey[0].sk_func, &typeKey[0].sk_nargs);
- typeKey[0].sk_argument = PointerGetDatum(typeName);
-
- scan = heap_beginscan(pg_type_desc,
- 0,
- SelfTimeQual,
- 1,
- typeKey);
-
- /* ----------------
- * get the type tuple, if it exists.
- * ----------------
- */
- tup = heap_getnext(scan, 0, (Buffer *) 0);
-
- /* ----------------
- * if no type tuple exists for the given type name, then
- * end the scan and return appropriate information.
- * ----------------
- */
- if (! HeapTupleIsValid(tup)) {
+ HeapScanDesc scan;
+ HeapTuple tup;
+
+ static ScanKeyData typeKey[1] = {
+ {0, Anum_pg_type_typname, NameEqualRegProcedure}
+ };
+
+ /* ----------------
+ * initialize the scan key and begin a scan of pg_type
+ * ----------------
+ */
+ fmgr_info(NameEqualRegProcedure,
+ &typeKey[0].sk_func, &typeKey[0].sk_nargs);
+ typeKey[0].sk_argument = PointerGetDatum(typeName);
+
+ scan = heap_beginscan(pg_type_desc,
+ 0,
+ SelfTimeQual,
+ 1,
+ typeKey);
+
+ /* ----------------
+ * get the type tuple, if it exists.
+ * ----------------
+ */
+ tup = heap_getnext(scan, 0, (Buffer *) 0);
+
+ /* ----------------
+ * if no type tuple exists for the given type name, then
+ * end the scan and return appropriate information.
+ * ----------------
+ */
+ if (!HeapTupleIsValid(tup))
+ {
+ heap_endscan(scan);
+ *defined = false;
+ return InvalidOid;
+ }
+
+ /* ----------------
+ * here, the type tuple does exist so we pull information from
+ * the typisdefined field of the tuple and return the tuple's
+ * oid, which is the oid of the type.
+ * ----------------
+ */
heap_endscan(scan);
- *defined = false;
- return InvalidOid;
- }
-
- /* ----------------
- * here, the type tuple does exist so we pull information from
- * the typisdefined field of the tuple and return the tuple's
- * oid, which is the oid of the type.
- * ----------------
- */
- heap_endscan(scan);
- *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
-
- return
- tup->t_oid;
+ *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
+
+ return
+ tup->t_oid;
}
/* ----------------------------------------------------------------
- * TypeGet
+ * TypeGet
*
- * Finds the ObjectId of a type, even if uncommitted; "defined"
- * is only set if the type has actually been defined, i.e., if
- * the type tuple is not a shell.
+ * Finds the ObjectId of a type, even if uncommitted; "defined"
+ * is only set if the type has actually been defined, i.e., if
+ * the type tuple is not a shell.
*
- * Note: the meat of this function is now in the function
- * TypeGetWithOpenRelation(). -cim 6/15/90
+ * Note: the meat of this function is now in the function
+ * TypeGetWithOpenRelation(). -cim 6/15/90
*
- * Also called from util/remove.c
+ * Also called from util/remove.c
* ----------------------------------------------------------------
*/
Oid
-TypeGet(char* typeName, /* name of type to be fetched */
- bool *defined) /* has the type been defined? */
+TypeGet(char *typeName, /* name of type to be fetched */
+ bool * defined) /* has the type been defined? */
{
- Relation pg_type_desc;
- Oid typeoid;
-
- /* ----------------
- * open the pg_type relation
- * ----------------
- */
- pg_type_desc = heap_openr(TypeRelationName);
-
- /* ----------------
- * scan the type relation for the information we want
- * ----------------
- */
- typeoid = TypeGetWithOpenRelation(pg_type_desc,
- typeName,
- defined);
-
- /* ----------------
- * close the type relation and return the type oid.
- * ----------------
- */
- heap_close(pg_type_desc);
-
- return
- typeoid;
+ Relation pg_type_desc;
+ Oid typeoid;
+
+ /* ----------------
+ * open the pg_type relation
+ * ----------------
+ */
+ pg_type_desc = heap_openr(TypeRelationName);
+
+ /* ----------------
+ * scan the type relation for the information we want
+ * ----------------
+ */
+ typeoid = TypeGetWithOpenRelation(pg_type_desc,
+ typeName,
+ defined);
+
+ /* ----------------
+ * close the type relation and return the type oid.
+ * ----------------
+ */
+ heap_close(pg_type_desc);
+
+ return
+ typeoid;
}
/* ----------------------------------------------------------------
- * TypeShellMakeWithOpenRelation
+ * TypeShellMakeWithOpenRelation
*
* ----------------------------------------------------------------
*/
-static Oid
+static Oid
TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
{
- register int i;
- HeapTuple tup;
- Datum values[ Natts_pg_type ];
- char nulls[ Natts_pg_type ];
- Oid typoid;
- TupleDesc tupDesc;
-
- /* ----------------
- * initialize our nulls[] and values[] arrays
- * ----------------
- */
- for (i = 0; i < Natts_pg_type; ++i) {
- nulls[i] = ' ';
- values[i] = (Datum)NULL; /* redundant, but safe */
- }
-
- /* ----------------
- * initialize values[] with the type name and
- * ----------------
- */
- i = 0;
- values[i++] = (Datum) typeName; /* 1 */
- values[i++] = (Datum) InvalidOid; /* 2 */
- values[i++] = (Datum) (int16) 0; /* 3 */
- values[i++] = (Datum) (int16) 0; /* 4 */
- values[i++] = (Datum) (bool) 0; /* 5 */
- values[i++] = (Datum) (bool) 0; /* 6 */
- values[i++] = (Datum) (bool) 0; /* 7 */
- values[i++] = (Datum) (bool) 0; /* 8 */
- values[i++] = (Datum) InvalidOid; /* 9 */
- values[i++] = (Datum) InvalidOid; /* 10 */
- values[i++] = (Datum) InvalidOid; /* 11 */
- values[i++] = (Datum) InvalidOid; /* 12 */
- values[i++] = (Datum) InvalidOid; /* 13 */
- values[i++] = (Datum) InvalidOid; /* 14 */
- values[i++] = (Datum) 'i'; /* 15 */
-
- /*
- * ... and fill typdefault with a bogus value
- */
- values[i++] =
- (Datum)fmgr(TextInRegProcedure, typeName); /* 15 */
-
- /* ----------------
- * create a new type tuple with FormHeapTuple
- * ----------------
- */
- tupDesc = pg_type_desc->rd_att;
-
- tup = heap_formtuple(tupDesc, values, nulls);
-
- /* ----------------
- * insert the tuple in the relation and get the tuple's oid.
- * ----------------
- */
- heap_insert(pg_type_desc, tup);
- typoid = tup->t_oid;
-
- if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
+ register int i;
+ HeapTuple tup;
+ Datum values[Natts_pg_type];
+ char nulls[Natts_pg_type];
+ Oid typoid;
+ TupleDesc tupDesc;
+
+ /* ----------------
+ * initialize our nulls[] and values[] arrays
+ * ----------------
+ */
+ for (i = 0; i < Natts_pg_type; ++i)
+ {
+ nulls[i] = ' ';
+ values[i] = (Datum) NULL; /* redundant, but safe */
+ }
+
+ /* ----------------
+ * initialize values[] with the type name and
+ * ----------------
+ */
+ i = 0;
+ values[i++] = (Datum) typeName; /* 1 */
+ values[i++] = (Datum) InvalidOid; /* 2 */
+ values[i++] = (Datum) (int16) 0; /* 3 */
+ values[i++] = (Datum) (int16) 0; /* 4 */
+ values[i++] = (Datum) (bool) 0; /* 5 */
+ values[i++] = (Datum) (bool) 0; /* 6 */
+ values[i++] = (Datum) (bool) 0; /* 7 */
+ values[i++] = (Datum) (bool) 0; /* 8 */
+ values[i++] = (Datum) InvalidOid; /* 9 */
+ values[i++] = (Datum) InvalidOid; /* 10 */
+ values[i++] = (Datum) InvalidOid; /* 11 */
+ values[i++] = (Datum) InvalidOid; /* 12 */
+ values[i++] = (Datum) InvalidOid; /* 13 */
+ values[i++] = (Datum) InvalidOid; /* 14 */
+ values[i++] = (Datum) 'i'; /* 15 */
+
+ /*
+ * ... and fill typdefault with a bogus value
+ */
+ values[i++] =
+ (Datum) fmgr(TextInRegProcedure, typeName); /* 15 */
+
+ /* ----------------
+ * create a new type tuple with FormHeapTuple
+ * ----------------
+ */
+ tupDesc = pg_type_desc->rd_att;
+
+ tup = heap_formtuple(tupDesc, values, nulls);
+
+ /* ----------------
+ * insert the tuple in the relation and get the tuple's oid.
+ * ----------------
+ */
+ heap_insert(pg_type_desc, tup);
+ typoid = tup->t_oid;
+
+ if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
{
- Relation idescs[Num_pg_type_indices];
-
- CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
- CatalogCloseIndices(Num_pg_type_indices, idescs);
+ Relation idescs[Num_pg_type_indices];
+
+ CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
+ CatalogCloseIndices(Num_pg_type_indices, idescs);
}
- /* ----------------
- * free the tuple and return the type-oid
- * ----------------
- */
- pfree(tup);
-
- return
- typoid;
+ /* ----------------
+ * free the tuple and return the type-oid
+ * ----------------
+ */
+ pfree(tup);
+
+ return
+ typoid;
}
/* ----------------------------------------------------------------
- * TypeShellMake
+ * TypeShellMake
*
- * This procedure inserts a "shell" tuple into the type
- * relation. The type tuple inserted has invalid values
- * and in particular, the "typisdefined" field is false.
+ * This procedure inserts a "shell" tuple into the type
+ * relation. The type tuple inserted has invalid values
+ * and in particular, the "typisdefined" field is false.
*
- * This is used so that a tuple exists in the catalogs.
- * The invalid fields should be fixed up sometime after
- * this routine is called, and then the "typeisdefined"
- * field is set to true. -cim 6/15/90
+ * This is used so that a tuple exists in the catalogs.
+ * The invalid fields should be fixed up sometime after
+ * this routine is called, and then the "typeisdefined"
+ * field is set to true. -cim 6/15/90
* ----------------------------------------------------------------
*/
Oid
TypeShellMake(char *typeName)
{
- Relation pg_type_desc;
- Oid typoid;
-
- Assert(PointerIsValid(typeName));
-
- /* ----------------
- * open pg_type
- * ----------------
- */
- pg_type_desc = heap_openr(TypeRelationName);
-
- /* ----------------
- * insert the shell tuple
- * ----------------
- */
- typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
-
- /* ----------------
- * close pg_type and return the tuple's oid.
- * ----------------
- */
- heap_close(pg_type_desc);
-
- return
- typoid;
+ Relation pg_type_desc;
+ Oid typoid;
+
+ Assert(PointerIsValid(typeName));
+
+ /* ----------------
+ * open pg_type
+ * ----------------
+ */
+ pg_type_desc = heap_openr(TypeRelationName);
+
+ /* ----------------
+ * insert the shell tuple
+ * ----------------
+ */
+ typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
+
+ /* ----------------
+ * close pg_type and return the tuple's oid.
+ * ----------------
+ */
+ heap_close(pg_type_desc);
+
+ return
+ typoid;
}
/* ----------------------------------------------------------------
- * TypeCreate
+ * TypeCreate
*
- * This does all the necessary work needed to define a new type.
+ * This does all the necessary work needed to define a new type.
* ----------------------------------------------------------------
*/
Oid
TypeCreate(char *typeName,
- Oid relationOid, /* only for 'c'atalog typeTypes */
- int16 internalSize,
- int16 externalSize,
- char typeType,
- char typDelim,
- char *inputProcedure,
- char *outputProcedure,
- char *sendProcedure,
- char *receiveProcedure,
- char *elementTypeName,
- char *defaultTypeValue, /* internal rep */
- bool passedByValue,
- char alignment)
+ Oid relationOid, /* only for 'c'atalog typeTypes */
+ int16 internalSize,
+ int16 externalSize,
+ char typeType,
+ char typDelim,
+ char *inputProcedure,
+ char *outputProcedure,
+ char *sendProcedure,
+ char *receiveProcedure,
+ char *elementTypeName,
+ char *defaultTypeValue, /* internal rep */
+ bool passedByValue,
+ char alignment)
{
- register i, j;
- Relation pg_type_desc;
- HeapScanDesc pg_type_scan;
-
- Oid typeObjectId;
- Oid elementObjectId = InvalidOid;
-
- HeapTuple tup;
- char nulls[Natts_pg_type];
- char replaces[Natts_pg_type];
- Datum values[Natts_pg_type];
-
- Buffer buffer;
- char *procname;
- char *procs[4];
- bool defined;
- ItemPointerData itemPointerData;
- TupleDesc tupDesc;
-
- Oid argList[8];
-
-
- static ScanKeyData typeKey[1] = {
- { 0, Anum_pg_type_typname, NameEqualRegProcedure }
- };
-
- fmgr_info(NameEqualRegProcedure,
- &typeKey[0].sk_func, &typeKey[0].sk_nargs);
-
- /* ----------------
- * check that the type is not already defined.
- * ----------------
- */
- typeObjectId = TypeGet(typeName, &defined);
- if (OidIsValid(typeObjectId) && defined) {
- elog(WARN, "TypeCreate: type %s already defined", typeName);
- }
-
- /* ----------------
- * if this type has an associated elementType, then we check that
- * it is defined.
- * ----------------
- */
- if (elementTypeName) {
- elementObjectId = TypeGet(elementTypeName, &defined);
- if (!defined) {
- elog(WARN, "TypeCreate: type %s is not defined", elementTypeName);
+ register i,
+ j;
+ Relation pg_type_desc;
+ HeapScanDesc pg_type_scan;
+
+ Oid typeObjectId;
+ Oid elementObjectId = InvalidOid;
+
+ HeapTuple tup;
+ char nulls[Natts_pg_type];
+ char replaces[Natts_pg_type];
+ Datum values[Natts_pg_type];
+
+ Buffer buffer;
+ char *procname;
+ char *procs[4];
+ bool defined;
+ ItemPointerData itemPointerData;
+ TupleDesc tupDesc;
+
+ Oid argList[8];
+
+
+ static ScanKeyData typeKey[1] = {
+ {0, Anum_pg_type_typname, NameEqualRegProcedure}
+ };
+
+ fmgr_info(NameEqualRegProcedure,
+ &typeKey[0].sk_func, &typeKey[0].sk_nargs);
+
+ /* ----------------
+ * check that the type is not already defined.
+ * ----------------
+ */
+ typeObjectId = TypeGet(typeName, &defined);
+ if (OidIsValid(typeObjectId) && defined)
+ {
+ elog(WARN, "TypeCreate: type %s already defined", typeName);
+ }
+
+ /* ----------------
+ * if this type has an associated elementType, then we check that
+ * it is defined.
+ * ----------------
+ */
+ if (elementTypeName)
+ {
+ elementObjectId = TypeGet(elementTypeName, &defined);
+ if (!defined)
+ {
+ elog(WARN, "TypeCreate: type %s is not defined", elementTypeName);
+ }
+ }
+
+ /* ----------------
+ * XXX comment me
+ * ----------------
+ */
+ if (externalSize == 0)
+ {
+ externalSize = -1; /* variable length */
+ }
+
+ /* ----------------
+ * initialize arrays needed by FormHeapTuple
+ * ----------------
+ */
+ for (i = 0; i < Natts_pg_type; ++i)
+ {
+ nulls[i] = ' ';
+ replaces[i] = 'r';
+ values[i] = (Datum) NULL; /* redundant, but nice */
}
- }
-
- /* ----------------
- * XXX comment me
- * ----------------
- */
- if (externalSize == 0) {
- externalSize = -1; /* variable length */
- }
-
- /* ----------------
- * initialize arrays needed by FormHeapTuple
- * ----------------
- */
- for (i = 0; i < Natts_pg_type; ++i) {
- nulls[i] = ' ';
- replaces[i] = 'r';
- values[i] = (Datum)NULL; /* redundant, but nice */
- }
-
- /*
- * XXX
- *
- * Do this so that user-defined types have size -1 instead of zero if
- * they are variable-length - this is so that everything else in the
- * backend works.
- */
-
- if (internalSize == 0)
- internalSize = -1;
-
- /* ----------------
- * initialize the values[] information
- * ----------------
- */
- i = 0;
- values[i++] = PointerGetDatum(typeName); /* 1 */
- values[i++] = (Datum) GetUserId(); /* 2 */
- values[i++] = (Datum) internalSize; /* 3 */
- values[i++] = (Datum) externalSize; /* 4 */
- values[i++] = (Datum) passedByValue; /* 5 */
- values[i++] = (Datum) typeType; /* 6 */
- values[i++] = (Datum) (bool) 1; /* 7 */
- values[i++] = (Datum) typDelim; /* 8 */
- values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
- values[i++] = (Datum) elementObjectId; /* 10 */
-
- /*
- * arguments to type input and output functions must be 0
- */
- memset(argList, 0, 8 * sizeof(Oid));
-
- procs[0] = inputProcedure;
- procs[1] = outputProcedure;
- procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
- procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
-
- for (j = 0; j < 4; ++j) {
- procname = procs[j];
-
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(procname),
- Int32GetDatum(1),
- PointerGetDatum(argList),
- 0);
-
- if (!HeapTupleIsValid(tup)) {
- /*
- * it is possible for the input/output procedure
- * to take two arguments, where the second argument
- * is the element type (eg array_in/array_out)
- */
- if (OidIsValid(elementObjectId)) {
+
+ /*
+ * XXX
+ *
+ * Do this so that user-defined types have size -1 instead of zero if
+ * they are variable-length - this is so that everything else in the
+ * backend works.
+ */
+
+ if (internalSize == 0)
+ internalSize = -1;
+
+ /* ----------------
+ * initialize the values[] information
+ * ----------------
+ */
+ i = 0;
+ values[i++] = PointerGetDatum(typeName); /* 1 */
+ values[i++] = (Datum) GetUserId(); /* 2 */
+ values[i++] = (Datum) internalSize; /* 3 */
+ values[i++] = (Datum) externalSize; /* 4 */
+ values[i++] = (Datum) passedByValue; /* 5 */
+ values[i++] = (Datum) typeType; /* 6 */
+ values[i++] = (Datum) (bool) 1; /* 7 */
+ values[i++] = (Datum) typDelim; /* 8 */
+ values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
+ values[i++] = (Datum) elementObjectId; /* 10 */
+
+ /*
+ * arguments to type input and output functions must be 0
+ */
+ memset(argList, 0, 8 * sizeof(Oid));
+
+ procs[0] = inputProcedure;
+ procs[1] = outputProcedure;
+ procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
+ procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
+
+ for (j = 0; j < 4; ++j)
+ {
+ procname = procs[j];
+
tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(procname),
- Int32GetDatum(2),
- PointerGetDatum(argList),
- 0);
- }
- if (!HeapTupleIsValid(tup)) {
- func_error("TypeCreate", procname, 1, argList);
- }
+ PointerGetDatum(procname),
+ Int32GetDatum(1),
+ PointerGetDatum(argList),
+ 0);
+
+ if (!HeapTupleIsValid(tup))
+ {
+
+ /*
+ * it is possible for the input/output procedure to take two
+ * arguments, where the second argument is the element type
+ * (eg array_in/array_out)
+ */
+ if (OidIsValid(elementObjectId))
+ {
+ tup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(procname),
+ Int32GetDatum(2),
+ PointerGetDatum(argList),
+ 0);
+ }
+ if (!HeapTupleIsValid(tup))
+ {
+ func_error("TypeCreate", procname, 1, argList);
+ }
+ }
+
+ values[i++] = (Datum) tup->t_oid; /* 11 - 14 */
}
-
- values[i++] = (Datum)tup->t_oid; /* 11 - 14 */
- }
-
- /* ----------------
- * set default alignment
- * ----------------
- */
- values[i++] = (Datum)alignment; /* 15 */
-
- /* ----------------
- * initialize the default value for this type.
- * ----------------
- */
- values[i] = (Datum)fmgr(TextInRegProcedure, /* 16 */
- PointerIsValid(defaultTypeValue)
- ? defaultTypeValue : "-"); /* XXX default typdefault */
-
- /* ----------------
- * open pg_type and begin a scan for the type name.
- * ----------------
- */
- pg_type_desc = heap_openr(TypeRelationName);
-
- /* -----------------
- * Set a write lock initially so as not upgrade a read to a write
- * when the heap_insert() or heap_replace() is called.
- * -----------------
- */
- RelationSetLockForWrite(pg_type_desc);
-
- typeKey[0].sk_argument = PointerGetDatum(typeName);
- pg_type_scan = heap_beginscan(pg_type_desc,
- 0,
- SelfTimeQual,
- 1,
- typeKey);
-
- /* ----------------
- * define the type either by adding a tuple to the type
- * relation, or by updating the fields of the "shell" tuple
- * already there.
- * ----------------
- */
- tup = heap_getnext(pg_type_scan, 0, &buffer);
- if (HeapTupleIsValid(tup)) {
- tup = heap_modifytuple(tup,
- buffer,
- pg_type_desc,
- values,
- nulls,
- replaces);
-
- /* XXX may not be necessary */
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
-
- setheapoverride(true);
- heap_replace(pg_type_desc, &itemPointerData, tup);
- setheapoverride(false);
-
- typeObjectId = tup->t_oid;
- } else {
- tupDesc = pg_type_desc->rd_att;
- tup = heap_formtuple(tupDesc,
- values,
- nulls);
-
- heap_insert(pg_type_desc, tup);
-
- typeObjectId = tup->t_oid;
- }
-
- /* ----------------
- * finish up
- * ----------------
- */
- heap_endscan(pg_type_scan);
-
- if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
+ /* ----------------
+ * set default alignment
+ * ----------------
+ */
+ values[i++] = (Datum) alignment; /* 15 */
+
+ /* ----------------
+ * initialize the default value for this type.
+ * ----------------
+ */
+ values[i] = (Datum) fmgr(TextInRegProcedure, /* 16 */
+ PointerIsValid(defaultTypeValue)
+ ? defaultTypeValue : "-"); /* XXX default
+ * typdefault */
+
+ /* ----------------
+ * open pg_type and begin a scan for the type name.
+ * ----------------
+ */
+ pg_type_desc = heap_openr(TypeRelationName);
+
+ /* -----------------
+ * Set a write lock initially so as not upgrade a read to a write
+ * when the heap_insert() or heap_replace() is called.
+ * -----------------
+ */
+ RelationSetLockForWrite(pg_type_desc);
+
+ typeKey[0].sk_argument = PointerGetDatum(typeName);
+ pg_type_scan = heap_beginscan(pg_type_desc,
+ 0,
+ SelfTimeQual,
+ 1,
+ typeKey);
+
+ /* ----------------
+ * define the type either by adding a tuple to the type
+ * relation, or by updating the fields of the "shell" tuple
+ * already there.
+ * ----------------
+ */
+ tup = heap_getnext(pg_type_scan, 0, &buffer);
+ if (HeapTupleIsValid(tup))
+ {
+ tup = heap_modifytuple(tup,
+ buffer,
+ pg_type_desc,
+ values,
+ nulls,
+ replaces);
+
+ /* XXX may not be necessary */
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+
+ setheapoverride(true);
+ heap_replace(pg_type_desc, &itemPointerData, tup);
+ setheapoverride(false);
+
+ typeObjectId = tup->t_oid;
+ }
+ else
+ {
+ tupDesc = pg_type_desc->rd_att;
+
+ tup = heap_formtuple(tupDesc,
+ values,
+ nulls);
+
+ heap_insert(pg_type_desc, tup);
+
+ typeObjectId = tup->t_oid;
+ }
+
+ /* ----------------
+ * finish up
+ * ----------------
+ */
+ heap_endscan(pg_type_scan);
+
+ if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
{
- Relation idescs[Num_pg_type_indices];
-
- CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
- CatalogCloseIndices(Num_pg_type_indices, idescs);
+ Relation idescs[Num_pg_type_indices];
+
+ CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
+ CatalogCloseIndices(Num_pg_type_indices, idescs);
}
- RelationUnsetLockForWrite(pg_type_desc);
- heap_close(pg_type_desc);
-
-
- return
- typeObjectId;
+ RelationUnsetLockForWrite(pg_type_desc);
+ heap_close(pg_type_desc);
+
+
+ return
+ typeObjectId;
}
/* ----------------------------------------------------------------
- * TypeRename
+ * TypeRename
*
- * This renames a type
+ * This renames a type
* ----------------------------------------------------------------
*/
void
TypeRename(char *oldTypeName, char *newTypeName)
{
- Relation pg_type_desc;
- Relation idescs[Num_pg_type_indices];
- Oid type_oid;
- HeapTuple tup;
- bool defined;
- ItemPointerData itemPointerData;
-
- /* check that that the new type is not already defined */
- type_oid = TypeGet(newTypeName, &defined);
- if (OidIsValid(type_oid) && defined) {
- elog(WARN, "TypeRename: type %s already defined", newTypeName);
- }
-
- /* get the type tuple from the catalog index scan manager */
- pg_type_desc = heap_openr(TypeRelationName);
- tup = TypeNameIndexScan(pg_type_desc, oldTypeName);
-
- /* ----------------
- * change the name of the type
- * ----------------
- */
- if (HeapTupleIsValid(tup)) {
-
- namestrcpy(& (((TypeTupleForm) GETSTRUCT(tup))->typname),newTypeName);
-
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
-
- setheapoverride(true);
- heap_replace(pg_type_desc, &itemPointerData, tup);
- setheapoverride(false);
-
- /* update the system catalog indices */
- CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
- CatalogCloseIndices(Num_pg_type_indices, idescs);
-
- /* all done */
- pfree(tup);
-
- } else {
- elog(WARN, "TypeRename: type %s not defined", oldTypeName);
- }
-
- /* finish up */
- heap_close(pg_type_desc);
+ Relation pg_type_desc;
+ Relation idescs[Num_pg_type_indices];
+ Oid type_oid;
+ HeapTuple tup;
+ bool defined;
+ ItemPointerData itemPointerData;
+
+ /* check that that the new type is not already defined */
+ type_oid = TypeGet(newTypeName, &defined);
+ if (OidIsValid(type_oid) && defined)
+ {
+ elog(WARN, "TypeRename: type %s already defined", newTypeName);
+ }
+
+ /* get the type tuple from the catalog index scan manager */
+ pg_type_desc = heap_openr(TypeRelationName);
+ tup = TypeNameIndexScan(pg_type_desc, oldTypeName);
+
+ /* ----------------
+ * change the name of the type
+ * ----------------
+ */
+ if (HeapTupleIsValid(tup))
+ {
+
+ namestrcpy(&(((TypeTupleForm) GETSTRUCT(tup))->typname), newTypeName);
+
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+
+ setheapoverride(true);
+ heap_replace(pg_type_desc, &itemPointerData, tup);
+ setheapoverride(false);
+
+ /* update the system catalog indices */
+ CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
+ CatalogCloseIndices(Num_pg_type_indices, idescs);
+
+ /* all done */
+ pfree(tup);
+
+ }
+ else
+ {
+ elog(WARN, "TypeRename: type %s not defined", oldTypeName);
+ }
+
+ /* finish up */
+ heap_close(pg_type_desc);
}
/*
* makeArrayTypeName(typeName);
- * - given a base type name, make an array of type name out of it
+ * - given a base type name, make an array of type name out of it
*
- * the CALLER is responsible for pfreeing the
+ * the CALLER is responsible for pfreeing the
*/
-char*
-makeArrayTypeName(char* typeName)
+char *
+makeArrayTypeName(char *typeName)
{
- char *arr;
+ char *arr;
+
+ if (!typeName)
+ return NULL;
+ arr = palloc(strlen(typeName) + 2);
+ arr[0] = '_';
+ strcpy(arr + 1, typeName);
- if (!typeName) return NULL;
- arr = palloc (strlen(typeName) + 2);
- arr[0] = '_';
- strcpy(arr+1, typeName);
+ return arr;
- return arr;
-
}
diff --git a/src/backend/commands/_deadcode/version.c b/src/backend/commands/_deadcode/version.c
index bac35cd4f87..c3eb6f47797 100644
--- a/src/backend/commands/_deadcode/version.c
+++ b/src/backend/commands/_deadcode/version.c
@@ -1,23 +1,23 @@
/*-------------------------------------------------------------------------
*
* version.c--
- * This file contains all the rules that govern all version semantics.
+ * This file contains all the rules that govern all version semantics.
*
* Copyright (c) 1994, Regents of the University of California
*
- * The version stuff has not been tested under postgres95 and probably doesn't
- * work! - jolly 8/19/95
- *
+ * The version stuff has not been tested under postgres95 and probably doesn't
+ * work! - jolly 8/19/95
+ *
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.5 1997/08/19 21:30:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.6 1997/09/07 04:41:04 momjian Exp $
*
* NOTES
- * At the point the version is defined, 2 physical relations are created
- * <vname>_added and <vname>_deleted.
+ * At the point the version is defined, 2 physical relations are created
+ * <vname>_added and <vname>_deleted.
*
- * In addition, 4 rules are defined which govern the semantics of versions
- * w.r.t retrieves, appends, replaces and deletes.
+ * In addition, 4 rules are defined which govern the semantics of versions
+ * w.r.t retrieves, appends, replaces and deletes.
*
*-------------------------------------------------------------------------
*/
@@ -34,29 +34,31 @@
#define MAX_QUERY_LEN 1024
-char rule_buf[MAX_QUERY_LEN];
+char rule_buf[MAX_QUERY_LEN];
+
#ifdef NOT_USED
-static char attr_list[MAX_QUERY_LEN];
+static char attr_list[MAX_QUERY_LEN];
+
#endif
/*
* problem: the version system assumes that the rules it declares will
- * be fired in the order of declaration, it also assumes
- * goh's silly instead semantics. Unfortunately, it is a pain
- * to make the version system work with the new semantics.
- * However the whole problem can be solved, and some nice
- * functionality can be achieved if we get multiple action rules
- * to work. So thats what I did -- glass
+ * be fired in the order of declaration, it also assumes
+ * goh's silly instead semantics. Unfortunately, it is a pain
+ * to make the version system work with the new semantics.
+ * However the whole problem can be solved, and some nice
+ * functionality can be achieved if we get multiple action rules
+ * to work. So thats what I did -- glass
*
* Well, at least they've been working for about 20 minutes.
- *
+ *
* So any comments in this code about 1 rule per transction are false...:)
*
*/
/*
- * This is needed because the rule system only allows
- * *1* rule to be defined per transaction.
+ * This is needed because the rule system only allows
+ * *1* rule to be defined per transaction.
*
* NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
* OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
@@ -80,267 +82,282 @@ static char attr_list[MAX_QUERY_LEN];
* a strange memory bug instead of watching the "Get Smart" marathon
* in NICK !
* DO NOT COMMIT THE XACT, just increase the Cid counter!
- * _sp.
+ * _sp.
*/
#ifdef NOT_USED
static void
eval_as_new_xact(char *query)
{
- /* WARNING! do not uncomment the following lines WARNING!
- * CommitTransactionCommand();
- * StartTransactionCommand();
- */
- CommandCounterIncrement();
- pg_eval(query, (char **) NULL, (Oid *) NULL, 0);
+
+ /*
+ * WARNING! do not uncomment the following lines WARNING!
+ * CommitTransactionCommand(); StartTransactionCommand();
+ */
+ CommandCounterIncrement();
+ pg_eval(query, (char **) NULL, (Oid *) NULL, 0);
}
+
#endif
/*
- * Define a version.
+ * Define a version.
*/
#ifdef NOT_USED
void
DefineVersion(char *name, char *fromRelname, char *date)
{
- char *bname;
- static char saved_basename[512];
- static char saved_snapshot[512];
-
- if (date == NULL) {
- /* no time ranges */
- bname = fromRelname;
- strcpy(saved_basename, (char *) bname);
- *saved_snapshot = (char)NULL;
- } else {
- /* version is a snapshot */
- bname = fromRelname;
- strcpy(saved_basename, (char *) bname);
- sprintf(saved_snapshot, "['%s']", date);
- }
-
-
- /*
- * Calls the routine ``GetAttrList'' get the list of attributes
- * from the base relation.
- * Code is put here so that we only need to look up the attribute once for
- * both appends and replaces.
- */
- setAttrList(bname);
-
- VersionCreate (name, saved_basename);
- VersionAppend (name, saved_basename);
- VersionDelete (name, saved_basename,saved_snapshot);
- VersionReplace (name, saved_basename,saved_snapshot);
- VersionRetrieve (name, saved_basename, saved_snapshot);
+ char *bname;
+ static char saved_basename[512];
+ static char saved_snapshot[512];
+
+ if (date == NULL)
+ {
+ /* no time ranges */
+ bname = fromRelname;
+ strcpy(saved_basename, (char *) bname);
+ *saved_snapshot = (char) NULL;
+ }
+ else
+ {
+ /* version is a snapshot */
+ bname = fromRelname;
+ strcpy(saved_basename, (char *) bname);
+ sprintf(saved_snapshot, "['%s']", date);
+ }
+
+
+ /*
+ * Calls the routine ``GetAttrList'' get the list of attributes from
+ * the base relation. Code is put here so that we only need to look up
+ * the attribute once for both appends and replaces.
+ */
+ setAttrList(bname);
+
+ VersionCreate(name, saved_basename);
+ VersionAppend(name, saved_basename);
+ VersionDelete(name, saved_basename, saved_snapshot);
+ VersionReplace(name, saved_basename, saved_snapshot);
+ VersionRetrieve(name, saved_basename, saved_snapshot);
}
+
#endif
/*
- * Creates the deltas.
+ * Creates the deltas.
*/
#ifdef NOT_USED
void
VersionCreate(char *vname, char *bname)
{
- static char query_buf [MAX_QUERY_LEN];
-
- /*
- * Creating the dummy version relation for triggering rules.
- */
- sprintf(query_buf, "SELECT * INTO TABLE %s from %s where 1 =2",
- vname, bname);
-
- pg_eval (query_buf, (char **) NULL, (Oid *) NULL, 0);
-
- /*
- * Creating the ``v_added'' relation
- */
- sprintf (query_buf, "SELECT * INTO TABLE %s_added from %s where 1 = 2",
- vname, bname);
- eval_as_new_xact (query_buf);
-
- /*
- * Creating the ``v_deleted'' relation.
- */
- sprintf (query_buf, "CREATE TABLE %s_del (DOID oid)", vname);
- eval_as_new_xact (query_buf);
+ static char query_buf[MAX_QUERY_LEN];
+
+ /*
+ * Creating the dummy version relation for triggering rules.
+ */
+ sprintf(query_buf, "SELECT * INTO TABLE %s from %s where 1 =2",
+ vname, bname);
+
+ pg_eval(query_buf, (char **) NULL, (Oid *) NULL, 0);
+
+ /*
+ * Creating the ``v_added'' relation
+ */
+ sprintf(query_buf, "SELECT * INTO TABLE %s_added from %s where 1 = 2",
+ vname, bname);
+ eval_as_new_xact(query_buf);
+
+ /*
+ * Creating the ``v_deleted'' relation.
+ */
+ sprintf(query_buf, "CREATE TABLE %s_del (DOID oid)", vname);
+ eval_as_new_xact(query_buf);
}
+
#endif
/*
* Given the relation name, does a catalog lookup for that relation and
* sets the global variable 'attr_list' with the list of attributes (names)
- * for that relation.
+ * for that relation.
*/
#ifdef NOT_USED
static void
setAttrList(char *bname)
{
- Relation rdesc;
- int i = 0;
- int maxattrs = 0;
- char *attrname;
- char temp_buf[512];
- int notfirst = 0;
-
- rdesc = heap_openr(bname);
- if (rdesc == NULL ) {
- elog(WARN,"Unable to expand all -- amopenr failed ");
- return;
- }
- maxattrs = RelationGetNumberOfAttributes(rdesc);
-
- attr_list[0] = '\0';
-
- for ( i = maxattrs-1 ; i > -1 ; --i ) {
- attrname = (rdesc->rd_att->attrs[i]->attname).data;
-
- if (notfirst == 1) {
- sprintf(temp_buf, ", %s = new.%s", attrname, attrname);
- } else {
- sprintf(temp_buf, "%s = new.%s", attrname, attrname);
- notfirst = 1;
+ Relation rdesc;
+ int i = 0;
+ int maxattrs = 0;
+ char *attrname;
+ char temp_buf[512];
+ int notfirst = 0;
+
+ rdesc = heap_openr(bname);
+ if (rdesc == NULL)
+ {
+ elog(WARN, "Unable to expand all -- amopenr failed ");
+ return;
+ }
+ maxattrs = RelationGetNumberOfAttributes(rdesc);
+
+ attr_list[0] = '\0';
+
+ for (i = maxattrs - 1; i > -1; --i)
+ {
+ attrname = (rdesc->rd_att->attrs[i]->attname).data;
+
+ if (notfirst == 1)
+ {
+ sprintf(temp_buf, ", %s = new.%s", attrname, attrname);
+ }
+ else
+ {
+ sprintf(temp_buf, "%s = new.%s", attrname, attrname);
+ notfirst = 1;
+ }
+ strcat(attr_list, temp_buf);
}
- strcat(attr_list, temp_buf);
- }
-
- heap_close(rdesc);
-
- return;
+
+ heap_close(rdesc);
+
+ return;
}
+
#endif
/*
* This routine defines the rule governing the append semantics of
- * versions. All tuples appended to a version gets appended to the
+ * versions. All tuples appended to a version gets appended to the
* <vname>_added relation.
*/
#ifdef NOT_USED
static void
VersionAppend(char *vname, char *bname)
{
- sprintf(rule_buf,
- "define rewrite rule %s_append is on INSERT to %s do instead append %s_added(%s)",
- vname, vname, vname, attr_list);
-
- eval_as_new_xact(rule_buf);
+ sprintf(rule_buf,
+ "define rewrite rule %s_append is on INSERT to %s do instead append %s_added(%s)",
+ vname, vname, vname, attr_list);
+
+ eval_as_new_xact(rule_buf);
}
+
#endif
/*
* This routine defines the rule governing the retrieval semantics of
* versions. To retrieve tuples from a version , we need to:
*
- * 1. Retrieve all tuples in the <vname>_added relation.
- * 2. Retrieve all tuples in the base relation which are not in
- * the <vname>_del relation.
+ * 1. Retrieve all tuples in the <vname>_added relation.
+ * 2. Retrieve all tuples in the base relation which are not in
+ * the <vname>_del relation.
*/
#ifdef NOT_USED
void
VersionRetrieve(char *vname, char *bname, char *snapshot)
{
-
- sprintf(rule_buf,
- "define rewrite rule %s_retrieve is on SELECT to %s do instead\n\
+
+ sprintf(rule_buf,
+ "define rewrite rule %s_retrieve is on SELECT to %s do instead\n\
SELECT %s_1.oid, %s_1.* from _%s in %s%s, %s_1 in (%s_added | _%s) \
where _%s.oid !!= '%s_del.DOID'",
- vname, vname, vname, vname, bname,
- bname, snapshot,
- vname, vname, bname, bname, vname);
-
- eval_as_new_xact(rule_buf);
-
- /* printf("%s\n",rule_buf); */
-
+ vname, vname, vname, vname, bname,
+ bname, snapshot,
+ vname, vname, bname, bname, vname);
+
+ eval_as_new_xact(rule_buf);
+
+ /* printf("%s\n",rule_buf); */
+
}
+
#endif
/*
- * This routine defines the rules that govern the delete semantics of
+ * This routine defines the rules that govern the delete semantics of
* versions. Two things happens when we delete a tuple from a version:
*
- * 1. If the tuple to be deleted was added to the version *after*
- * the version was created, then we simply delete the tuple
- * from the <vname>_added relation.
- * 2. If the tuple to be deleted is actually in the base relation,
- * then we have to mark that tuple as being deleted by adding
- * it to the <vname>_del relation.
+ * 1. If the tuple to be deleted was added to the version *after*
+ * the version was created, then we simply delete the tuple
+ * from the <vname>_added relation.
+ * 2. If the tuple to be deleted is actually in the base relation,
+ * then we have to mark that tuple as being deleted by adding
+ * it to the <vname>_del relation.
*/
#ifdef NOT_USED
void
VersionDelete(char *vname, char *bname, char *snapshot)
{
-
- sprintf(rule_buf,
- "define rewrite rule %s_delete1 is on delete to %s do instead\n \
+
+ sprintf(rule_buf,
+ "define rewrite rule %s_delete1 is on delete to %s do instead\n \
[delete %s_added where current.oid = %s_added.oid\n \
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid] \n",
- vname,vname,vname,vname,vname,
-bname,bname,snapshot,bname);
+ vname, vname, vname, vname, vname,
+ bname, bname, snapshot, bname);
- eval_as_new_xact(rule_buf);
+ eval_as_new_xact(rule_buf);
#ifdef OLD_REWRITE
- sprintf(rule_buf,
- "define rewrite rule %s_delete2 is on delete to %s do instead \n \
+ sprintf(rule_buf,
+ "define rewrite rule %s_delete2 is on delete to %s do instead \n \
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid \n",
- vname,vname,vname,bname,bname,snapshot,bname);
+ vname, vname, vname, bname, bname, snapshot, bname);
- eval_as_new_xact(rule_buf);
-#endif /* OLD_REWRITE */
+ eval_as_new_xact(rule_buf);
+#endif /* OLD_REWRITE */
}
+
#endif
/*
- * This routine defines the rules that govern the update semantics
- * of versions. To update a tuple in a version:
+ * This routine defines the rules that govern the update semantics
+ * of versions. To update a tuple in a version:
*
- * 1. If the tuple is in <vname>_added, we simply ``replace''
- * the tuple (as per postgres style).
- * 2. if the tuple is in the base relation, then two things have to
- * happen:
- * 2.1 The tuple is marked ``deleted'' from the base relation by
- * adding the tuple to the <vname>_del relation.
- * 2.2 A copy of the tuple is appended to the <vname>_added relation
+ * 1. If the tuple is in <vname>_added, we simply ``replace''
+ * the tuple (as per postgres style).
+ * 2. if the tuple is in the base relation, then two things have to
+ * happen:
+ * 2.1 The tuple is marked ``deleted'' from the base relation by
+ * adding the tuple to the <vname>_del relation.
+ * 2.2 A copy of the tuple is appended to the <vname>_added relation
*/
#ifdef NOT_USED
void
VersionReplace(char *vname, char *bname, char *snapshot)
{
- sprintf(rule_buf,
- "define rewrite rule %s_replace1 is on replace to %s do instead \n\
+ sprintf(rule_buf,
+ "define rewrite rule %s_replace1 is on replace to %s do instead \n\
[replace %s_added(%s) where current.oid = %s_added.oid \n\
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid\n\
append %s_added(%s) from _%s in %s%s \
where current.oid !!= '%s_added.oid' and current.oid = _%s.oid]\n",
- vname,vname,vname,attr_list,vname,
- vname,bname,bname,snapshot,bname,
-vname,attr_list,bname,bname,snapshot,vname,bname);
+ vname, vname, vname, attr_list, vname,
+ vname, bname, bname, snapshot, bname,
+ vname, attr_list, bname, bname, snapshot, vname, bname);
- eval_as_new_xact(rule_buf);
+ eval_as_new_xact(rule_buf);
-/* printf("%s\n",rule_buf); */
+/* printf("%s\n",rule_buf); */
#ifdef OLD_REWRITE
- sprintf(rule_buf,
- "define rewrite rule %s_replace2 is on replace to %s do \n\
+ sprintf(rule_buf,
+ "define rewrite rule %s_replace2 is on replace to %s do \n\
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid\n",
- vname,vname,vname,bname,bname,snapshot,bname);
+ vname, vname, vname, bname, bname, snapshot, bname);
- eval_as_new_xact(rule_buf);
+ eval_as_new_xact(rule_buf);
- sprintf(rule_buf,
- "define rewrite rule %s_replace3 is on replace to %s do instead\n\
+ sprintf(rule_buf,
+ "define rewrite rule %s_replace3 is on replace to %s do instead\n\
append %s_added(%s) from _%s in %s%s \
where current.oid !!= '%s_added.oid' and current.oid = \
_%s.oid\n",
- vname,vname, vname,attr_list,bname,bname,snapshot,vname,bname);
+ vname, vname, vname, attr_list, bname, bname, snapshot, vname, bname);
- eval_as_new_xact(rule_buf);
-#endif /* OLD_REWRITE */
-/* printf("%s\n",rule_buf); */
+ eval_as_new_xact(rule_buf);
+#endif /* OLD_REWRITE */
+/* printf("%s\n",rule_buf); */
}
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 8a1e6d59b57..42d440a8676 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1,35 +1,35 @@
/*-------------------------------------------------------------------------
*
* async.c--
- * Asynchronous notification
+ * Asynchronous notification
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.17 1997/08/19 21:30:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.18 1997/09/07 04:40:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* New Async Notification Model:
* 1. Multiple backends on same machine. Multiple backends listening on
- * one relation.
+ * one relation.
*
* 2. One of the backend does a 'notify <relname>'. For all backends that
- * are listening to this relation (all notifications take place at the
- * end of commit),
- * 2.a If the process is the same as the backend process that issued
- * notification (we are notifying something that we are listening),
- * signal the corresponding frontend over the comm channel using the
- * out-of-band channel.
- * 2.b For all other listening processes, we send kill(2) to wake up
- * the listening backend.
+ * are listening to this relation (all notifications take place at the
+ * end of commit),
+ * 2.a If the process is the same as the backend process that issued
+ * notification (we are notifying something that we are listening),
+ * signal the corresponding frontend over the comm channel using the
+ * out-of-band channel.
+ * 2.b For all other listening processes, we send kill(2) to wake up
+ * the listening backend.
* 3. Upon receiving a kill(2) signal from another backend process notifying
- * that one of the relation that we are listening is being notified,
- * we can be in either of two following states:
- * 3.a We are sleeping, wake up and signal our frontend.
- * 3.b We are in middle of another transaction, wait until the end of
- * of the current transaction and signal our frontend.
+ * that one of the relation that we are listening is being notified,
+ * we can be in either of two following states:
+ * 3.a We are sleeping, wake up and signal our frontend.
+ * 3.b We are in middle of another transaction, wait until the end of
+ * of the current transaction and signal our frontend.
* 4. Each frontend receives this notification and prcesses accordingly.
*
* -- jw, 12/28/93
@@ -42,16 +42,16 @@
* Model is:
* 1. Multiple backends on same machine.
*
- * 2. Query on one backend sends stuff over an asynchronous portal by
- * appending to a relation, and then doing an async. notification
- * (which takes place after commit) to all listeners on this relation.
+ * 2. Query on one backend sends stuff over an asynchronous portal by
+ * appending to a relation, and then doing an async. notification
+ * (which takes place after commit) to all listeners on this relation.
*
- * 3. Async. notification results in all backends listening on relation
- * to be woken up, by a process signal kill(2), with name of relation
- * passed in shared memory.
+ * 3. Async. notification results in all backends listening on relation
+ * to be woken up, by a process signal kill(2), with name of relation
+ * passed in shared memory.
*
* 4. Each backend notifies its respective frontend over the comm
- * channel using the out-of-band channel.
+ * channel using the out-of-band channel.
*
* 5. Each frontend receives this notification and processes accordingly.
*
@@ -62,7 +62,7 @@
#include <signal.h>
#include <string.h>
#include <errno.h>
-#include <sys/types.h> /* Needed by in.h on Ultrix */
+#include <sys/types.h> /* Needed by in.h on Ultrix */
#include <netinet/in.h>
#include <postgres.h>
@@ -75,546 +75,585 @@
#include <catalog/pg_proc.h>
#include <catalog/catname.h>
#include <catalog/pg_listener.h>
-#include <access/heapam.h>
+#include <access/heapam.h>
#include <storage/bufmgr.h>
#include <nodes/memnodes.h>
#include <utils/mcxt.h>
#include <commands/async.h>
#include <libpq/libpq.h>
-#include <port-protos.h> /* for strdup() */
+#include <port-protos.h> /* for strdup() */
#include <storage/lmgr.h>
-static int notifyFrontEndPending = 0;
-static int notifyIssued = 0;
-static Dllist *pendingNotifies = NULL;
+static int notifyFrontEndPending = 0;
+static int notifyIssued = 0;
+static Dllist *pendingNotifies = NULL;
-static int AsyncExistsPendingNotify(char *);
-static void ClearPendingNotify(void);
-static void Async_NotifyFrontEnd(void);
-static void Async_Unlisten(char *relname, int pid);
-static void Async_UnlistenOnExit(int code, char *relname);
-
+static int AsyncExistsPendingNotify(char *);
+static void ClearPendingNotify(void);
+static void Async_NotifyFrontEnd(void);
+static void Async_Unlisten(char *relname, int pid);
+static void Async_UnlistenOnExit(int code, char *relname);
+
/*
*--------------------------------------------------------------
* Async_NotifyHandler --
*
- * This is the signal handler for SIGUSR2. When the backend
- * is signaled, the backend can be in two states.
- * 1. If the backend is in the middle of another transaction,
- * we set the flag, notifyFrontEndPending, and wait until
- * the end of the transaction to notify the front end.
- * 2. If the backend is not in the middle of another transaction,
- * we notify the front end immediately.
+ * This is the signal handler for SIGUSR2. When the backend
+ * is signaled, the backend can be in two states.
+ * 1. If the backend is in the middle of another transaction,
+ * we set the flag, notifyFrontEndPending, and wait until
+ * the end of the transaction to notify the front end.
+ * 2. If the backend is not in the middle of another transaction,
+ * we notify the front end immediately.
*
- * -- jw, 12/28/93
+ * -- jw, 12/28/93
* Results:
- * none
+ * none
*
* Side effects:
- * none
+ * none
*/
void
Async_NotifyHandler(SIGNAL_ARGS)
{
- extern TransactionState CurrentTransactionState;
-
- if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
- (CurrentTransactionState->blockState == TRANS_DEFAULT)) {
+ extern TransactionState CurrentTransactionState;
+
+ if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
+ (CurrentTransactionState->blockState == TRANS_DEFAULT))
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Waking up sleeping backend process");
+ elog(DEBUG, "Waking up sleeping backend process");
#endif
- Async_NotifyFrontEnd();
+ Async_NotifyFrontEnd();
- }else {
+ }
+ else
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Process is in the middle of another transaction, state = %d, block state = %d",
- CurrentTransactionState->state,
- CurrentTransactionState->blockState);
+ elog(DEBUG, "Process is in the middle of another transaction, state = %d, block state = %d",
+ CurrentTransactionState->state,
+ CurrentTransactionState->blockState);
#endif
- notifyFrontEndPending = 1;
- }
+ notifyFrontEndPending = 1;
+ }
}
/*
*--------------------------------------------------------------
* Async_Notify --
*
- * Adds the relation to the list of pending notifies.
- * All notification happens at end of commit.
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Adds the relation to the list of pending notifies.
+ * All notification happens at end of commit.
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
- * All notification of backend processes happens here,
- * then each backend notifies its corresponding front end at
- * the end of commit.
+ * All notification of backend processes happens here,
+ * then each backend notifies its corresponding front end at
+ * the end of commit.
*
- * This correspond to 'notify <relname>' command
- * -- jw, 12/28/93
+ * This correspond to 'notify <relname>' command
+ * -- jw, 12/28/93
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
- * All tuples for relname in pg_listener are updated.
+ * All tuples for relname in pg_listener are updated.
*
*--------------------------------------------------------------
*/
void
Async_Notify(char *relname)
{
-
- HeapTuple lTuple, rTuple;
- Relation lRel;
- HeapScanDesc sRel;
- TupleDesc tdesc;
- ScanKeyData key;
- Buffer b;
- Datum d, value[3];
- bool isnull;
- char repl[3], nulls[3];
-
- char *notifyName;
-
+
+ HeapTuple lTuple,
+ rTuple;
+ Relation lRel;
+ HeapScanDesc sRel;
+ TupleDesc tdesc;
+ ScanKeyData key;
+ Buffer b;
+ Datum d,
+ value[3];
+ bool isnull;
+ char repl[3],
+ nulls[3];
+
+ char *notifyName;
+
#ifdef ASYNC_DEBUG
- elog(DEBUG,"Async_Notify: %s",relname);
+ elog(DEBUG, "Async_Notify: %s", relname);
#endif
-
- if (!pendingNotifies)
- pendingNotifies = DLNewList();
-
- /*
- * Allocate memory from the global malloc pool because it needs to be
- * referenced also when the transaction is finished. DZ - 26-08-1996
- */
- notifyName = strdup(relname);
- DLAddHead(pendingNotifies, DLNewElem(notifyName));
-
- ScanKeyEntryInitialize(&key, 0,
- Anum_pg_listener_relname,
- NameEqualRegProcedure,
- PointerGetDatum(notifyName));
-
- lRel = heap_openr(ListenerRelationName);
- tdesc = RelationGetTupleDescriptor(lRel);
- RelationSetLockForWrite(lRel);
- sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
-
- nulls[0] = nulls[1] = nulls[2] = ' ';
- repl[0] = repl[1] = repl[2] = ' ';
- repl[Anum_pg_listener_notify - 1] = 'r';
- value[0] = value[1] = value[2] = (Datum) 0;
- value[Anum_pg_listener_notify - 1] = Int32GetDatum(1);
-
- while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_notify,
- tdesc, &isnull);
- if (!DatumGetInt32(d)) {
- rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
- heap_replace(lRel, &lTuple->t_ctid, rTuple);
+
+ if (!pendingNotifies)
+ pendingNotifies = DLNewList();
+
+ /*
+ * Allocate memory from the global malloc pool because it needs to be
+ * referenced also when the transaction is finished. DZ - 26-08-1996
+ */
+ notifyName = strdup(relname);
+ DLAddHead(pendingNotifies, DLNewElem(notifyName));
+
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_listener_relname,
+ NameEqualRegProcedure,
+ PointerGetDatum(notifyName));
+
+ lRel = heap_openr(ListenerRelationName);
+ tdesc = RelationGetTupleDescriptor(lRel);
+ RelationSetLockForWrite(lRel);
+ sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
+
+ nulls[0] = nulls[1] = nulls[2] = ' ';
+ repl[0] = repl[1] = repl[2] = ' ';
+ repl[Anum_pg_listener_notify - 1] = 'r';
+ value[0] = value[1] = value[2] = (Datum) 0;
+ value[Anum_pg_listener_notify - 1] = Int32GetDatum(1);
+
+ while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_notify,
+ tdesc, &isnull);
+ if (!DatumGetInt32(d))
+ {
+ rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
+ heap_replace(lRel, &lTuple->t_ctid, rTuple);
+ }
+ ReleaseBuffer(b);
}
- ReleaseBuffer(b);
- }
- heap_endscan(sRel);
- RelationUnsetLockForWrite(lRel);
- heap_close(lRel);
- notifyIssued = 1;
+ heap_endscan(sRel);
+ RelationUnsetLockForWrite(lRel);
+ heap_close(lRel);
+ notifyIssued = 1;
}
/*
*--------------------------------------------------------------
* Async_NotifyAtCommit --
*
- * Signal our corresponding frontend process on relations that
- * were notified. Signal all other backend process that
- * are listening also.
+ * Signal our corresponding frontend process on relations that
+ * were notified. Signal all other backend process that
+ * are listening also.
*
- * -- jw, 12/28/93
+ * -- jw, 12/28/93
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
- * Tuples in pg_listener that has our listenerpid are updated so
- * that the notification is 0. We do not want to notify frontend
- * more than once.
+ * Tuples in pg_listener that has our listenerpid are updated so
+ * that the notification is 0. We do not want to notify frontend
+ * more than once.
*
- * -- jw, 12/28/93
+ * -- jw, 12/28/93
*
*--------------------------------------------------------------
*/
void
Async_NotifyAtCommit()
{
- HeapTuple lTuple;
- Relation lRel;
- HeapScanDesc sRel;
- TupleDesc tdesc;
- ScanKeyData key;
- Datum d;
- int ourpid;
- bool isnull;
- Buffer b;
- extern TransactionState CurrentTransactionState;
-
- if (!pendingNotifies)
- pendingNotifies = DLNewList();
-
- if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
- (CurrentTransactionState->blockState == TRANS_DEFAULT)) {
-
- if (notifyIssued) { /* 'notify <relname>' issued by us */
- notifyIssued = 0;
- StartTransactionCommand();
+ HeapTuple lTuple;
+ Relation lRel;
+ HeapScanDesc sRel;
+ TupleDesc tdesc;
+ ScanKeyData key;
+ Datum d;
+ int ourpid;
+ bool isnull;
+ Buffer b;
+ extern TransactionState CurrentTransactionState;
+
+ if (!pendingNotifies)
+ pendingNotifies = DLNewList();
+
+ if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
+ (CurrentTransactionState->blockState == TRANS_DEFAULT))
+ {
+
+ if (notifyIssued)
+ { /* 'notify <relname>' issued by us */
+ notifyIssued = 0;
+ StartTransactionCommand();
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Async_NotifyAtCommit.");
+ elog(DEBUG, "Async_NotifyAtCommit.");
#endif
- ScanKeyEntryInitialize(&key, 0,
- Anum_pg_listener_notify,
- Integer32EqualRegProcedure,
- Int32GetDatum(1));
- lRel = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lRel);
- sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
- tdesc = RelationGetTupleDescriptor(lRel);
- ourpid = getpid();
-
- while (HeapTupleIsValid(lTuple = heap_getnext(sRel,0, &b))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
- tdesc, &isnull);
-
- if (AsyncExistsPendingNotify((char *) DatumGetPointer(d))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_pid,
- tdesc, &isnull);
-
- if (ourpid == DatumGetInt32(d)) {
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_listener_notify,
+ Integer32EqualRegProcedure,
+ Int32GetDatum(1));
+ lRel = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lRel);
+ sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
+ tdesc = RelationGetTupleDescriptor(lRel);
+ ourpid = getpid();
+
+ while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
+ tdesc, &isnull);
+
+ if (AsyncExistsPendingNotify((char *) DatumGetPointer(d)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_pid,
+ tdesc, &isnull);
+
+ if (ourpid == DatumGetInt32(d))
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Notifying self, setting notifyFronEndPending to 1");
+ elog(DEBUG, "Notifying self, setting notifyFronEndPending to 1");
#endif
- notifyFrontEndPending = 1;
- } else {
+ notifyFrontEndPending = 1;
+ }
+ else
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Notifying others");
+ elog(DEBUG, "Notifying others");
#endif
#ifdef HAVE_KILL
- if (kill(DatumGetInt32(d), SIGUSR2) < 0) {
- if (errno == ESRCH) {
- heap_delete(lRel, &lTuple->t_ctid);
- }
+ if (kill(DatumGetInt32(d), SIGUSR2) < 0)
+ {
+ if (errno == ESRCH)
+ {
+ heap_delete(lRel, &lTuple->t_ctid);
+ }
+ }
+#endif
+ }
+ }
+ ReleaseBuffer(b);
}
-#endif
- }
+ heap_endscan(sRel);
+ RelationUnsetLockForWrite(lRel);
+ heap_close(lRel);
+
+ CommitTransactionCommand();
+ ClearPendingNotify();
}
- ReleaseBuffer(b);
- }
- heap_endscan(sRel);
- RelationUnsetLockForWrite(lRel);
- heap_close(lRel);
- CommitTransactionCommand();
- ClearPendingNotify();
- }
-
- if (notifyFrontEndPending) { /* we need to notify the frontend of
- all pending notifies. */
- notifyFrontEndPending = 1;
- Async_NotifyFrontEnd();
+ if (notifyFrontEndPending)
+ { /* we need to notify the frontend of all
+ * pending notifies. */
+ notifyFrontEndPending = 1;
+ Async_NotifyFrontEnd();
+ }
}
- }
}
/*
*--------------------------------------------------------------
* Async_NotifyAtAbort --
*
- * Gets rid of pending notifies. List elements are automatically
- * freed through memory context.
- *
+ * Gets rid of pending notifies. List elements are automatically
+ * freed through memory context.
+ *
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
- * XXX
+ * XXX
*
*--------------------------------------------------------------
*/
void
Async_NotifyAtAbort()
{
- extern TransactionState CurrentTransactionState;
-
- if (notifyIssued) {
- ClearPendingNotify();
- }
- notifyIssued = 0;
- if (pendingNotifies)
- DLFreeList(pendingNotifies);
- pendingNotifies = DLNewList();
-
- if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
- (CurrentTransactionState->blockState == TRANS_DEFAULT)) {
- if (notifyFrontEndPending) { /* don't forget to notify front end */
- Async_NotifyFrontEnd();
+ extern TransactionState CurrentTransactionState;
+
+ if (notifyIssued)
+ {
+ ClearPendingNotify();
+ }
+ notifyIssued = 0;
+ if (pendingNotifies)
+ DLFreeList(pendingNotifies);
+ pendingNotifies = DLNewList();
+
+ if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
+ (CurrentTransactionState->blockState == TRANS_DEFAULT))
+ {
+ if (notifyFrontEndPending)
+ { /* don't forget to notify front end */
+ Async_NotifyFrontEnd();
+ }
}
- }
}
/*
*--------------------------------------------------------------
* Async_Listen --
*
- * Register a backend (identified by its Unix PID) as listening
- * on the specified relation.
+ * Register a backend (identified by its Unix PID) as listening
+ * on the specified relation.
*
- * This corresponds to the 'listen <relation>' command in SQL
+ * This corresponds to the 'listen <relation>' command in SQL
*
- * One listener per relation, pg_listener relation is keyed
- * on (relname,pid) to provide multiple listeners in future.
+ * One listener per relation, pg_listener relation is keyed
+ * on (relname,pid) to provide multiple listeners in future.
*
* Results:
- * pg_listeners is updated.
+ * pg_listeners is updated.
*
* Side effects:
- * XXX
+ * XXX
*
*--------------------------------------------------------------
*/
void
Async_Listen(char *relname, int pid)
{
- Datum values[Natts_pg_listener];
- char nulls[Natts_pg_listener];
- TupleDesc tdesc;
- HeapScanDesc s;
- HeapTuple htup,tup;
- Relation lDesc;
- Buffer b;
- Datum d;
- int i;
- bool isnull;
- int alreadyListener = 0;
- int ourPid = getpid();
- char *relnamei;
- TupleDesc tupDesc;
-
+ Datum values[Natts_pg_listener];
+ char nulls[Natts_pg_listener];
+ TupleDesc tdesc;
+ HeapScanDesc s;
+ HeapTuple htup,
+ tup;
+ Relation lDesc;
+ Buffer b;
+ Datum d;
+ int i;
+ bool isnull;
+ int alreadyListener = 0;
+ int ourPid = getpid();
+ char *relnamei;
+ TupleDesc tupDesc;
+
#ifdef ASYNC_DEBUG
- elog(DEBUG,"Async_Listen: %s",relname);
+ elog(DEBUG, "Async_Listen: %s", relname);
#endif
- for (i = 0 ; i < Natts_pg_listener; i++) {
- nulls[i] = ' ';
- values[i] = PointerGetDatum(NULL);
- }
-
- i = 0;
- values[i++] = (Datum) relname;
- values[i++] = (Datum) pid;
- values[i++] = (Datum) 0; /* no notifies pending */
-
- lDesc = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lDesc);
-
- /* is someone already listening. One listener per relation */
- tdesc = RelationGetTupleDescriptor(lDesc);
- s = heap_beginscan(lDesc,0,NowTimeQual,0,(ScanKey)NULL);
- while (HeapTupleIsValid(htup = heap_getnext(s,0,&b))) {
- d = (Datum) heap_getattr(htup,b,Anum_pg_listener_relname,tdesc,
- &isnull);
- relnamei = DatumGetPointer(d);
- if (!strncmp(relnamei,relname, NAMEDATALEN)) {
- d = (Datum) heap_getattr(htup,b,Anum_pg_listener_pid,tdesc,&isnull);
- pid = DatumGetInt32(d);
- if (pid == ourPid) {
- alreadyListener = 1;
- }
+ for (i = 0; i < Natts_pg_listener; i++)
+ {
+ nulls[i] = ' ';
+ values[i] = PointerGetDatum(NULL);
}
- ReleaseBuffer(b);
- }
- heap_endscan(s);
-
- if (alreadyListener) {
- elog(NOTICE, "Async_Listen: We are already listening on %s",
- relname);
- return;
- }
-
- tupDesc = lDesc->rd_att;
- tup = heap_formtuple(tupDesc,
- values,
- nulls);
- heap_insert(lDesc, tup);
-
- pfree(tup);
- /* if (alreadyListener) {
- elog(NOTICE,"Async_Listen: already one listener on %s (possibly dead)",relname);
- }*/
-
- RelationUnsetLockForWrite(lDesc);
- heap_close(lDesc);
-
- /*
- * now that we are listening, we should make a note to ourselves
- * to unlisten prior to dying.
- */
- relnamei = malloc(NAMEDATALEN); /* persists to process exit */
- strNcpy(relnamei, relname, NAMEDATALEN-1);
- on_exitpg(Async_UnlistenOnExit, (caddr_t) relnamei);
+
+ i = 0;
+ values[i++] = (Datum) relname;
+ values[i++] = (Datum) pid;
+ values[i++] = (Datum) 0; /* no notifies pending */
+
+ lDesc = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lDesc);
+
+ /* is someone already listening. One listener per relation */
+ tdesc = RelationGetTupleDescriptor(lDesc);
+ s = heap_beginscan(lDesc, 0, NowTimeQual, 0, (ScanKey) NULL);
+ while (HeapTupleIsValid(htup = heap_getnext(s, 0, &b)))
+ {
+ d = (Datum) heap_getattr(htup, b, Anum_pg_listener_relname, tdesc,
+ &isnull);
+ relnamei = DatumGetPointer(d);
+ if (!strncmp(relnamei, relname, NAMEDATALEN))
+ {
+ d = (Datum) heap_getattr(htup, b, Anum_pg_listener_pid, tdesc, &isnull);
+ pid = DatumGetInt32(d);
+ if (pid == ourPid)
+ {
+ alreadyListener = 1;
+ }
+ }
+ ReleaseBuffer(b);
+ }
+ heap_endscan(s);
+
+ if (alreadyListener)
+ {
+ elog(NOTICE, "Async_Listen: We are already listening on %s",
+ relname);
+ return;
+ }
+
+ tupDesc = lDesc->rd_att;
+ tup = heap_formtuple(tupDesc,
+ values,
+ nulls);
+ heap_insert(lDesc, tup);
+
+ pfree(tup);
+
+ /*
+ * if (alreadyListener) { elog(NOTICE,"Async_Listen: already one
+ * listener on %s (possibly dead)",relname); }
+ */
+
+ RelationUnsetLockForWrite(lDesc);
+ heap_close(lDesc);
+
+ /*
+ * now that we are listening, we should make a note to ourselves to
+ * unlisten prior to dying.
+ */
+ relnamei = malloc(NAMEDATALEN); /* persists to process exit */
+ strNcpy(relnamei, relname, NAMEDATALEN - 1);
+ on_exitpg(Async_UnlistenOnExit, (caddr_t) relnamei);
}
/*
*--------------------------------------------------------------
* Async_Unlisten --
*
- * Remove the backend from the list of listening backends
- * for the specified relation.
- *
- * This would correspond to the 'unlisten <relation>'
- * command, but there isn't one yet.
+ * Remove the backend from the list of listening backends
+ * for the specified relation.
+ *
+ * This would correspond to the 'unlisten <relation>'
+ * command, but there isn't one yet.
*
* Results:
- * pg_listeners is updated.
+ * pg_listeners is updated.
*
* Side effects:
- * XXX
+ * XXX
*
*--------------------------------------------------------------
*/
static void
Async_Unlisten(char *relname, int pid)
{
- Relation lDesc;
- HeapTuple lTuple;
-
- lTuple = SearchSysCacheTuple(LISTENREL, PointerGetDatum(relname),
- Int32GetDatum(pid),
- 0,0);
- lDesc = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lDesc);
-
- if (lTuple != NULL) {
- heap_delete(lDesc,&lTuple->t_ctid);
- }
-
- RelationUnsetLockForWrite(lDesc);
- heap_close(lDesc);
+ Relation lDesc;
+ HeapTuple lTuple;
+
+ lTuple = SearchSysCacheTuple(LISTENREL, PointerGetDatum(relname),
+ Int32GetDatum(pid),
+ 0, 0);
+ lDesc = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lDesc);
+
+ if (lTuple != NULL)
+ {
+ heap_delete(lDesc, &lTuple->t_ctid);
+ }
+
+ RelationUnsetLockForWrite(lDesc);
+ heap_close(lDesc);
}
static void
Async_UnlistenOnExit(int code, /* from exitpg */
- char *relname)
+ char *relname)
{
- Async_Unlisten((char *) relname, getpid());
+ Async_Unlisten((char *) relname, getpid());
}
/*
* --------------------------------------------------------------
* Async_NotifyFrontEnd --
*
- * Perform an asynchronous notification to front end over
- * portal comm channel. The name of the relation which contains the
- * data is sent to the front end.
+ * Perform an asynchronous notification to front end over
+ * portal comm channel. The name of the relation which contains the
+ * data is sent to the front end.
*
- * We remove the notification flag from the pg_listener tuple
- * associated with our process.
+ * We remove the notification flag from the pg_listener tuple
+ * associated with our process.
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
*
- * We make use of the out-of-band channel to transmit the
- * notification to the front end. The actual data transfer takes
- * place at the front end's request.
+ * We make use of the out-of-band channel to transmit the
+ * notification to the front end. The actual data transfer takes
+ * place at the front end's request.
*
* --------------------------------------------------------------
*/
-GlobalMemory notifyContext = NULL;
+GlobalMemory notifyContext = NULL;
static void
Async_NotifyFrontEnd()
{
- extern CommandDest whereToSendOutput;
- HeapTuple lTuple, rTuple;
- Relation lRel;
- HeapScanDesc sRel;
- TupleDesc tdesc;
- ScanKeyData key[2];
- Datum d, value[3];
- char repl[3], nulls[3];
- Buffer b;
- int ourpid;
- bool isnull;
-
- notifyFrontEndPending = 0;
-
+ extern CommandDest whereToSendOutput;
+ HeapTuple lTuple,
+ rTuple;
+ Relation lRel;
+ HeapScanDesc sRel;
+ TupleDesc tdesc;
+ ScanKeyData key[2];
+ Datum d,
+ value[3];
+ char repl[3],
+ nulls[3];
+ Buffer b;
+ int ourpid;
+ bool isnull;
+
+ notifyFrontEndPending = 0;
+
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Async_NotifyFrontEnd: notifying front end.");
+ elog(DEBUG, "Async_NotifyFrontEnd: notifying front end.");
#endif
-
- StartTransactionCommand();
- ourpid = getpid();
- ScanKeyEntryInitialize(&key[0], 0,
- Anum_pg_listener_notify,
- Integer32EqualRegProcedure,
- Int32GetDatum(1));
- ScanKeyEntryInitialize(&key[1], 0,
- Anum_pg_listener_pid,
- Integer32EqualRegProcedure,
- Int32GetDatum(ourpid));
- lRel = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lRel);
- tdesc = RelationGetTupleDescriptor(lRel);
- sRel = heap_beginscan(lRel, 0, NowTimeQual, 2, key);
-
- nulls[0] = nulls[1] = nulls[2] = ' ';
- repl[0] = repl[1] = repl[2] = ' ';
- repl[Anum_pg_listener_notify - 1] = 'r';
- value[0] = value[1] = value[2] = (Datum) 0;
- value[Anum_pg_listener_notify - 1] = Int32GetDatum(0);
-
- while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0,&b))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
- tdesc, &isnull);
- rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
- heap_replace(lRel, &lTuple->t_ctid, rTuple);
-
- /* notifying the front end */
-
- if (whereToSendOutput == Remote) {
- pq_putnchar("A", 1);
- pq_putint(ourpid, 4);
- pq_putstr(DatumGetName(d)->data);
- pq_flush();
- } else {
- elog(NOTICE, "Async_NotifyFrontEnd: no asynchronous notification to frontend on interactive sessions");
+
+ StartTransactionCommand();
+ ourpid = getpid();
+ ScanKeyEntryInitialize(&key[0], 0,
+ Anum_pg_listener_notify,
+ Integer32EqualRegProcedure,
+ Int32GetDatum(1));
+ ScanKeyEntryInitialize(&key[1], 0,
+ Anum_pg_listener_pid,
+ Integer32EqualRegProcedure,
+ Int32GetDatum(ourpid));
+ lRel = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lRel);
+ tdesc = RelationGetTupleDescriptor(lRel);
+ sRel = heap_beginscan(lRel, 0, NowTimeQual, 2, key);
+
+ nulls[0] = nulls[1] = nulls[2] = ' ';
+ repl[0] = repl[1] = repl[2] = ' ';
+ repl[Anum_pg_listener_notify - 1] = 'r';
+ value[0] = value[1] = value[2] = (Datum) 0;
+ value[Anum_pg_listener_notify - 1] = Int32GetDatum(0);
+
+ while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
+ tdesc, &isnull);
+ rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
+ heap_replace(lRel, &lTuple->t_ctid, rTuple);
+
+ /* notifying the front end */
+
+ if (whereToSendOutput == Remote)
+ {
+ pq_putnchar("A", 1);
+ pq_putint(ourpid, 4);
+ pq_putstr(DatumGetName(d)->data);
+ pq_flush();
+ }
+ else
+ {
+ elog(NOTICE, "Async_NotifyFrontEnd: no asynchronous notification to frontend on interactive sessions");
+ }
+ ReleaseBuffer(b);
}
- ReleaseBuffer(b);
- }
- CommitTransactionCommand();
+ CommitTransactionCommand();
}
static int
AsyncExistsPendingNotify(char *relname)
{
- Dlelem* p;
- for (p = DLGetHead(pendingNotifies);
- p != NULL;
- p = DLGetSucc(p)) {
- /* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */
- if (!strncmp(DLE_VAL(p), relname, NAMEDATALEN))
- return 1;
- }
-
- return 0;
+ Dlelem *p;
+
+ for (p = DLGetHead(pendingNotifies);
+ p != NULL;
+ p = DLGetSucc(p))
+ {
+ /* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */
+ if (!strncmp(DLE_VAL(p), relname, NAMEDATALEN))
+ return 1;
+ }
+
+ return 0;
}
static void
ClearPendingNotify()
{
- Dlelem* p;
- while ( (p = DLRemHead(pendingNotifies)) != NULL)
- free(DLE_VAL(p));
-}
+ Dlelem *p;
+ while ((p = DLRemHead(pendingNotifies)) != NULL)
+ free(DLE_VAL(p));
+}
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 65a9c041643..2b18cb46df0 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1,20 +1,20 @@
/*-------------------------------------------------------------------------
*
* cluster.c--
- * Paul Brown's implementation of cluster index.
+ * Paul Brown's implementation of cluster index.
*
- * I am going to use the rename function as a model for this in the
- * parser and executor, and the vacuum code as an example in this
- * file. As I go - in contrast to the rest of postgres - there will
- * be BUCKETS of comments. This is to allow reviewers to understand
- * my (probably bogus) assumptions about the way this works.
- * [pbrown '94]
+ * I am going to use the rename function as a model for this in the
+ * parser and executor, and the vacuum code as an example in this
+ * file. As I go - in contrast to the rest of postgres - there will
+ * be BUCKETS of comments. This is to allow reviewers to understand
+ * my (probably bogus) assumptions about the way this works.
+ * [pbrown '94]
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.13 1997/08/19 21:30:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.14 1997/09/07 04:40:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,307 +47,323 @@
#include <optimizer/internal.h>
#ifndef NO_SECURITY
#include <utils/acl.h>
-#endif /* !NO_SECURITY */
+#endif /* !NO_SECURITY */
static Relation copy_heap(Oid OIDOldHeap);
-static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap);
-static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
+static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap);
+static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
/*
* cluster
*
- * Check that the relation is a relation in the appropriate user
- * ACL. I will use the same security that limits users on the
- * renamerel() function.
+ * Check that the relation is a relation in the appropriate user
+ * ACL. I will use the same security that limits users on the
+ * renamerel() function.
*
- * Check that the index specified is appropriate for the task
- * ( ie it's an index over this relation ). This is trickier.
+ * Check that the index specified is appropriate for the task
+ * ( ie it's an index over this relation ). This is trickier.
*
- * Create a list of all the other indicies on this relation. Because
- * the cluster will wreck all the tids, I'll need to destroy bogus
- * indicies. The user will have to re-create them. Not nice, but
- * I'm not a nice guy. The alternative is to try some kind of post
- * destroy re-build. This may be possible. I'll check out what the
- * index create functiond want in the way of paramaters. On the other
- * hand, re-creating n indicies may blow out the space.
+ * Create a list of all the other indicies on this relation. Because
+ * the cluster will wreck all the tids, I'll need to destroy bogus
+ * indicies. The user will have to re-create them. Not nice, but
+ * I'm not a nice guy. The alternative is to try some kind of post
+ * destroy re-build. This may be possible. I'll check out what the
+ * index create functiond want in the way of paramaters. On the other
+ * hand, re-creating n indicies may blow out the space.
*
- * Create new (temporary) relations for the base heap and the new
- * index.
- *
- * Exclusively lock the relations.
- *
- * Create new clustered index and base heap relation.
+ * Create new (temporary) relations for the base heap and the new
+ * index.
+ *
+ * Exclusively lock the relations.
+ *
+ * Create new clustered index and base heap relation.
*
*/
void
cluster(char oldrelname[], char oldindexname[])
{
- Oid OIDOldHeap, OIDOldIndex, OIDNewHeap;
-
- Relation OldHeap, OldIndex;
- Relation NewHeap;
-
- char NewIndexName[NAMEDATALEN];
- char NewHeapName[NAMEDATALEN];
- char saveoldrelname[NAMEDATALEN];
- char saveoldindexname[NAMEDATALEN];
-
-
- /* Save the old names because they will get lost when the old relations
- * are destroyed.
- */
- strcpy(saveoldrelname, oldrelname);
- strcpy(saveoldindexname, oldindexname);
-
- /*
- *
- * I'm going to force all checking back into the commands.c function.
- *
- * Get the list if indicies for this relation. If the index we want
- * is among them, do not add it to the 'kill' list, as it will be
- * handled by the 'clean up' code which commits this transaction.
- *
- * I'm not using the SysCache, because this will happen but
- * once, and the slow way is the sure way in this case.
- *
- */
- /*
- * Like vacuum, cluster spans transactions, so I'm going to handle it in
- * the same way.
- */
-
- /* matches the StartTransaction in PostgresMain() */
-
- OldHeap = heap_openr(oldrelname);
- if (!RelationIsValid(OldHeap)) {
- elog(WARN, "cluster: unknown relation: \"%s\"",
- oldrelname);
- }
- OIDOldHeap = OldHeap->rd_id; /* Get OID for the index scan */
-
- OldIndex=index_openr(oldindexname);/* Open old index relation */
- if (!RelationIsValid(OldIndex)) {
- elog(WARN, "cluster: unknown index: \"%s\"",
- oldindexname);
- }
- OIDOldIndex = OldIndex->rd_id; /* OID for the index scan */
-
- heap_close(OldHeap);
- index_close(OldIndex);
-
- /*
- * I need to build the copies of the heap and the index. The Commit()
- * between here is *very* bogus. If someone is appending stuff, they will
- * get the lock after being blocked and add rows which won't be present in
- * the new table. Bleagh! I'd be best to try and ensure that no-one's
- * in the tables for the entire duration of this process with a pg_vlock.
- */
- NewHeap = copy_heap(OIDOldHeap);
- OIDNewHeap = NewHeap->rd_id;
- strcpy(NewHeapName,NewHeap->rd_rel->relname.data);
-
-
- /* To make the new heap visible (which is until now empty). */
- CommandCounterIncrement();
-
- rebuildheap(OIDNewHeap, OIDOldHeap, OIDOldIndex);
-
- /* To flush the filled new heap (and the statistics about it). */
- CommandCounterIncrement();
-
- /* Create new index over the tuples of the new heap. */
- copy_index(OIDOldIndex, OIDNewHeap);
- sprintf(NewIndexName, "temp_%x", OIDOldIndex);
-
- /*
- * make this really happen. Flush all the buffers.
- * (Believe me, it is necessary ... ended up in a mess without it.)
- */
- CommitTransactionCommand();
- StartTransactionCommand();
-
-
- /* Destroy old heap (along with its index) and rename new. */
- heap_destroy(oldrelname);
-
- renamerel(NewHeapName, saveoldrelname);
- TypeRename(NewHeapName, saveoldrelname);
-
- renamerel(NewIndexName, saveoldindexname);
-
- /*
- * Again flush all the buffers.
- */
- CommitTransactionCommand();
- StartTransactionCommand();
+ Oid OIDOldHeap,
+ OIDOldIndex,
+ OIDNewHeap;
+
+ Relation OldHeap,
+ OldIndex;
+ Relation NewHeap;
+
+ char NewIndexName[NAMEDATALEN];
+ char NewHeapName[NAMEDATALEN];
+ char saveoldrelname[NAMEDATALEN];
+ char saveoldindexname[NAMEDATALEN];
+
+
+ /*
+ * Save the old names because they will get lost when the old
+ * relations are destroyed.
+ */
+ strcpy(saveoldrelname, oldrelname);
+ strcpy(saveoldindexname, oldindexname);
+
+ /*
+ * I'm going to force all checking back into the commands.c function.
+ *
+ * Get the list if indicies for this relation. If the index we want is
+ * among them, do not add it to the 'kill' list, as it will be handled
+ * by the 'clean up' code which commits this transaction.
+ *
+ * I'm not using the SysCache, because this will happen but once, and the
+ * slow way is the sure way in this case.
+ *
+ */
+
+ /*
+ * Like vacuum, cluster spans transactions, so I'm going to handle it
+ * in the same way.
+ */
+
+ /* matches the StartTransaction in PostgresMain() */
+
+ OldHeap = heap_openr(oldrelname);
+ if (!RelationIsValid(OldHeap))
+ {
+ elog(WARN, "cluster: unknown relation: \"%s\"",
+ oldrelname);
+ }
+ OIDOldHeap = OldHeap->rd_id;/* Get OID for the index scan */
+
+ OldIndex = index_openr(oldindexname); /* Open old index relation */
+ if (!RelationIsValid(OldIndex))
+ {
+ elog(WARN, "cluster: unknown index: \"%s\"",
+ oldindexname);
+ }
+ OIDOldIndex = OldIndex->rd_id; /* OID for the index scan */
+
+ heap_close(OldHeap);
+ index_close(OldIndex);
+
+ /*
+ * I need to build the copies of the heap and the index. The Commit()
+ * between here is *very* bogus. If someone is appending stuff, they
+ * will get the lock after being blocked and add rows which won't be
+ * present in the new table. Bleagh! I'd be best to try and ensure
+ * that no-one's in the tables for the entire duration of this process
+ * with a pg_vlock.
+ */
+ NewHeap = copy_heap(OIDOldHeap);
+ OIDNewHeap = NewHeap->rd_id;
+ strcpy(NewHeapName, NewHeap->rd_rel->relname.data);
+
+
+ /* To make the new heap visible (which is until now empty). */
+ CommandCounterIncrement();
+
+ rebuildheap(OIDNewHeap, OIDOldHeap, OIDOldIndex);
+
+ /* To flush the filled new heap (and the statistics about it). */
+ CommandCounterIncrement();
+
+ /* Create new index over the tuples of the new heap. */
+ copy_index(OIDOldIndex, OIDNewHeap);
+ sprintf(NewIndexName, "temp_%x", OIDOldIndex);
+
+ /*
+ * make this really happen. Flush all the buffers. (Believe me, it is
+ * necessary ... ended up in a mess without it.)
+ */
+ CommitTransactionCommand();
+ StartTransactionCommand();
+
+
+ /* Destroy old heap (along with its index) and rename new. */
+ heap_destroy(oldrelname);
+
+ renamerel(NewHeapName, saveoldrelname);
+ TypeRename(NewHeapName, saveoldrelname);
+
+ renamerel(NewIndexName, saveoldindexname);
+
+ /*
+ * Again flush all the buffers.
+ */
+ CommitTransactionCommand();
+ StartTransactionCommand();
}
-static Relation
+static Relation
copy_heap(Oid OIDOldHeap)
{
- char NewName[NAMEDATALEN];
- TupleDesc OldHeapDesc, tupdesc;
- Oid OIDNewHeap;
- Relation NewHeap, OldHeap;
-
- /*
- * Create a new heap relation with a temporary name, which has the
- * same tuple description as the old one.
- */
- sprintf(NewName,"temp_%x", OIDOldHeap);
-
- OldHeap= heap_open(OIDOldHeap);
- OldHeapDesc= RelationGetTupleDescriptor(OldHeap);
-
- /*
- * Need to make a copy of the tuple descriptor, heap_create modifies
- * it.
- */
-
- tupdesc = CreateTupleDescCopy(OldHeapDesc);
-
- OIDNewHeap=heap_create(NewName,
- NULL,
- OldHeap->rd_rel->relarch,
- OldHeap->rd_rel->relsmgr,
- tupdesc);
-
- if (!OidIsValid(OIDNewHeap))
- elog(WARN,"clusterheap: cannot create temporary heap relation\n");
-
- NewHeap=heap_open(OIDNewHeap);
-
- heap_close(NewHeap);
- heap_close(OldHeap);
-
- return NewHeap;
+ char NewName[NAMEDATALEN];
+ TupleDesc OldHeapDesc,
+ tupdesc;
+ Oid OIDNewHeap;
+ Relation NewHeap,
+ OldHeap;
+
+ /*
+ * Create a new heap relation with a temporary name, which has the
+ * same tuple description as the old one.
+ */
+ sprintf(NewName, "temp_%x", OIDOldHeap);
+
+ OldHeap = heap_open(OIDOldHeap);
+ OldHeapDesc = RelationGetTupleDescriptor(OldHeap);
+
+ /*
+ * Need to make a copy of the tuple descriptor, heap_create modifies
+ * it.
+ */
+
+ tupdesc = CreateTupleDescCopy(OldHeapDesc);
+
+ OIDNewHeap = heap_create(NewName,
+ NULL,
+ OldHeap->rd_rel->relarch,
+ OldHeap->rd_rel->relsmgr,
+ tupdesc);
+
+ if (!OidIsValid(OIDNewHeap))
+ elog(WARN, "clusterheap: cannot create temporary heap relation\n");
+
+ NewHeap = heap_open(OIDNewHeap);
+
+ heap_close(NewHeap);
+ heap_close(OldHeap);
+
+ return NewHeap;
}
static void
copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
{
- Relation OldIndex, NewHeap;
- HeapTuple Old_pg_index_Tuple, Old_pg_index_relation_Tuple, pg_proc_Tuple;
- IndexTupleForm Old_pg_index_Form;
- Form_pg_class Old_pg_index_relation_Form;
- Form_pg_proc pg_proc_Form;
- char *NewIndexName;
- AttrNumber *attnumP;
- int natts;
- FuncIndexInfo * finfo;
-
- NewHeap = heap_open(OIDNewHeap);
- OldIndex = index_open(OIDOldIndex);
-
- /*
- * OK. Create a new (temporary) index for the one that's already
- * here. To do this I get the info from pg_index, re-build the
- * FunctInfo if I have to, and add a new index with a temporary
- * name.
- */
- Old_pg_index_Tuple =
- SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(OldIndex->rd_id),
- 0,0,0);
-
- Assert(Old_pg_index_Tuple);
- Old_pg_index_Form = (IndexTupleForm)GETSTRUCT(Old_pg_index_Tuple);
-
- Old_pg_index_relation_Tuple =
- SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(OldIndex->rd_id),
- 0,0,0);
-
- Assert(Old_pg_index_relation_Tuple);
- Old_pg_index_relation_Form =
- (Form_pg_class)GETSTRUCT(Old_pg_index_relation_Tuple);
-
- NewIndexName = palloc(NAMEDATALEN); /* XXX */
- sprintf(NewIndexName, "temp_%x", OIDOldIndex); /* Set the name. */
-
- /*
- * Ugly as it is, the only way I have of working out the number of
- * attribues is to count them. Mostly there'll be just one but
- * I've got to be sure.
- */
- for (attnumP = &(Old_pg_index_Form->indkey[0]), natts = 0;
- *attnumP != InvalidAttrNumber;
- attnumP++, natts++);
-
- /*
- * If this is a functional index, I need to rebuild the functional
- * component to pass it to the defining procedure.
- */
- if (Old_pg_index_Form->indproc != InvalidOid) {
- finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
- FIgetnArgs(finfo) = natts;
- FIgetProcOid(finfo) = Old_pg_index_Form->indproc;
-
- pg_proc_Tuple =
- SearchSysCacheTuple(PROOID,
- ObjectIdGetDatum(Old_pg_index_Form->indproc),
- 0,0,0);
-
- Assert(pg_proc_Tuple);
- pg_proc_Form = (Form_pg_proc)GETSTRUCT(pg_proc_Tuple);
- namecpy(&(finfo->funcName), &(pg_proc_Form->proname));
- } else {
- finfo = (FuncIndexInfo *) NULL;
- natts = 1;
- }
-
- index_create((NewHeap->rd_rel->relname).data,
- NewIndexName,
- finfo,
- NULL, /* type info is in the old index */
- Old_pg_index_relation_Form->relam,
- natts,
- Old_pg_index_Form->indkey,
- Old_pg_index_Form->indclass,
- (uint16)0, (Datum) NULL, NULL,
- Old_pg_index_Form->indislossy,
- Old_pg_index_Form->indisunique);
-
- heap_close(OldIndex);
- heap_close(NewHeap);
+ Relation OldIndex,
+ NewHeap;
+ HeapTuple Old_pg_index_Tuple,
+ Old_pg_index_relation_Tuple,
+ pg_proc_Tuple;
+ IndexTupleForm Old_pg_index_Form;
+ Form_pg_class Old_pg_index_relation_Form;
+ Form_pg_proc pg_proc_Form;
+ char *NewIndexName;
+ AttrNumber *attnumP;
+ int natts;
+ FuncIndexInfo *finfo;
+
+ NewHeap = heap_open(OIDNewHeap);
+ OldIndex = index_open(OIDOldIndex);
+
+ /*
+ * OK. Create a new (temporary) index for the one that's already here.
+ * To do this I get the info from pg_index, re-build the FunctInfo if
+ * I have to, and add a new index with a temporary name.
+ */
+ Old_pg_index_Tuple =
+ SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(OldIndex->rd_id),
+ 0, 0, 0);
+
+ Assert(Old_pg_index_Tuple);
+ Old_pg_index_Form = (IndexTupleForm) GETSTRUCT(Old_pg_index_Tuple);
+
+ Old_pg_index_relation_Tuple =
+ SearchSysCacheTuple(RELOID,
+ ObjectIdGetDatum(OldIndex->rd_id),
+ 0, 0, 0);
+
+ Assert(Old_pg_index_relation_Tuple);
+ Old_pg_index_relation_Form =
+ (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
+
+ NewIndexName = palloc(NAMEDATALEN); /* XXX */
+ sprintf(NewIndexName, "temp_%x", OIDOldIndex); /* Set the name. */
+
+ /*
+ * Ugly as it is, the only way I have of working out the number of
+ * attribues is to count them. Mostly there'll be just one but I've
+ * got to be sure.
+ */
+ for (attnumP = &(Old_pg_index_Form->indkey[0]), natts = 0;
+ *attnumP != InvalidAttrNumber;
+ attnumP++, natts++);
+
+ /*
+ * If this is a functional index, I need to rebuild the functional
+ * component to pass it to the defining procedure.
+ */
+ if (Old_pg_index_Form->indproc != InvalidOid)
+ {
+ finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
+ FIgetnArgs(finfo) = natts;
+ FIgetProcOid(finfo) = Old_pg_index_Form->indproc;
+
+ pg_proc_Tuple =
+ SearchSysCacheTuple(PROOID,
+ ObjectIdGetDatum(Old_pg_index_Form->indproc),
+ 0, 0, 0);
+
+ Assert(pg_proc_Tuple);
+ pg_proc_Form = (Form_pg_proc) GETSTRUCT(pg_proc_Tuple);
+ namecpy(&(finfo->funcName), &(pg_proc_Form->proname));
+ }
+ else
+ {
+ finfo = (FuncIndexInfo *) NULL;
+ natts = 1;
+ }
+
+ index_create((NewHeap->rd_rel->relname).data,
+ NewIndexName,
+ finfo,
+ NULL, /* type info is in the old index */
+ Old_pg_index_relation_Form->relam,
+ natts,
+ Old_pg_index_Form->indkey,
+ Old_pg_index_Form->indclass,
+ (uint16) 0, (Datum) NULL, NULL,
+ Old_pg_index_Form->indislossy,
+ Old_pg_index_Form->indisunique);
+
+ heap_close(OldIndex);
+ heap_close(NewHeap);
}
static void
rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
{
- Relation LocalNewHeap, LocalOldHeap, LocalOldIndex;
- IndexScanDesc ScanDesc;
- RetrieveIndexResult ScanResult;
- ItemPointer HeapTid;
- HeapTuple LocalHeapTuple;
- Buffer LocalBuffer;
- Oid OIDNewHeapInsert;
-
- /*
- * Open the relations I need. Scan through the OldHeap on the OldIndex and
- * insert each tuple into the NewHeap.
- */
- LocalNewHeap=(Relation)heap_open(OIDNewHeap);
- LocalOldHeap=(Relation)heap_open(OIDOldHeap);
- LocalOldIndex=(Relation)index_open(OIDOldIndex);
-
- ScanDesc=index_beginscan(LocalOldIndex, false, 0, (ScanKey) NULL);
-
- while ((ScanResult =
- index_getnext(ScanDesc, ForwardScanDirection)) != NULL) {
-
- HeapTid = &ScanResult->heap_iptr;
- LocalHeapTuple = heap_fetch(LocalOldHeap, 0, HeapTid, &LocalBuffer);
- OIDNewHeapInsert =
- heap_insert(LocalNewHeap, LocalHeapTuple);
- pfree(ScanResult);
- ReleaseBuffer(LocalBuffer);
- }
- index_endscan(ScanDesc);
-
- index_close(LocalOldIndex);
- heap_close(LocalOldHeap);
- heap_close(LocalNewHeap);
+ Relation LocalNewHeap,
+ LocalOldHeap,
+ LocalOldIndex;
+ IndexScanDesc ScanDesc;
+ RetrieveIndexResult ScanResult;
+ ItemPointer HeapTid;
+ HeapTuple LocalHeapTuple;
+ Buffer LocalBuffer;
+ Oid OIDNewHeapInsert;
+
+ /*
+ * Open the relations I need. Scan through the OldHeap on the OldIndex
+ * and insert each tuple into the NewHeap.
+ */
+ LocalNewHeap = (Relation) heap_open(OIDNewHeap);
+ LocalOldHeap = (Relation) heap_open(OIDOldHeap);
+ LocalOldIndex = (Relation) index_open(OIDOldIndex);
+
+ ScanDesc = index_beginscan(LocalOldIndex, false, 0, (ScanKey) NULL);
+
+ while ((ScanResult =
+ index_getnext(ScanDesc, ForwardScanDirection)) != NULL)
+ {
+
+ HeapTid = &ScanResult->heap_iptr;
+ LocalHeapTuple = heap_fetch(LocalOldHeap, 0, HeapTid, &LocalBuffer);
+ OIDNewHeapInsert =
+ heap_insert(LocalNewHeap, LocalHeapTuple);
+ pfree(ScanResult);
+ ReleaseBuffer(LocalBuffer);
+ }
+ index_endscan(ScanDesc);
+
+ index_close(LocalOldIndex);
+ heap_close(LocalOldHeap);
+ heap_close(LocalNewHeap);
}
-
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 376bd3ae5fa..7af9b37c072 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -1,29 +1,29 @@
/*-------------------------------------------------------------------------
*
* command.c--
- * random postgres portal and utility support code
+ * random postgres portal and utility support code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.13 1997/08/22 14:22:07 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.14 1997/09/07 04:40:38 momjian Exp $
*
* NOTES
- * The PortalExecutorHeapMemory crap needs to be eliminated
- * by designing a better executor / portal processing memory
- * interface.
- *
- * The PerformAddAttribute() code, like most of the relation
- * manipulating code in the commands/ directory, should go
- * someplace closer to the lib/catalog code.
- *
+ * The PortalExecutorHeapMemory crap needs to be eliminated
+ * by designing a better executor / portal processing memory
+ * interface.
+ *
+ * The PerformAddAttribute() code, like most of the relation
+ * manipulating code in the commands/ directory, should go
+ * someplace closer to the lib/catalog code.
+ *
*-------------------------------------------------------------------------
*/
#include <postgres.h>
#include <access/relscan.h>
-#include <utils/portal.h>
+#include <utils/portal.h>
#include <commands/command.h>
#include <utils/mcxt.h>
#include <executor/executor.h>
@@ -31,7 +31,7 @@
#include <catalog/indexing.h>
#include <utils/syscache.h>
#include <catalog/catalog.h>
-#include <access/heapam.h>
+#include <access/heapam.h>
#include <utils/array.h>
#include <utils/acl.h>
#include <optimizer/prep.h>
@@ -41,443 +41,468 @@
#include <utils/builtins.h>
/* ----------------
- * PortalExecutorHeapMemory stuff
+ * PortalExecutorHeapMemory stuff
*
- * This is where the XXXSuperDuperHacky code was. -cim 3/15/90
+ * This is where the XXXSuperDuperHacky code was. -cim 3/15/90
* ----------------
*/
-MemoryContext PortalExecutorHeapMemory = NULL;
+MemoryContext PortalExecutorHeapMemory = NULL;
/* --------------------------------
- * PortalCleanup
+ * PortalCleanup
* --------------------------------
*/
void
PortalCleanup(Portal portal)
{
- MemoryContext context;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertArg(PortalIsValid(portal));
- AssertArg(portal->cleanup == PortalCleanup);
-
- /* ----------------
- * set proper portal-executor context before calling ExecMain.
- * ----------------
- */
- context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
- PortalExecutorHeapMemory = (MemoryContext)
- PortalGetHeapMemory(portal);
-
- /* ----------------
- * tell the executor to shutdown the query
- * ----------------
- */
- ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
-
- /* ----------------
- * switch back to previous context
- * ----------------
- */
- MemoryContextSwitchTo(context);
- PortalExecutorHeapMemory = (MemoryContext) NULL;
+ MemoryContext context;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ AssertArg(PortalIsValid(portal));
+ AssertArg(portal->cleanup == PortalCleanup);
+
+ /* ----------------
+ * set proper portal-executor context before calling ExecMain.
+ * ----------------
+ */
+ context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
+ PortalExecutorHeapMemory = (MemoryContext)
+ PortalGetHeapMemory(portal);
+
+ /* ----------------
+ * tell the executor to shutdown the query
+ * ----------------
+ */
+ ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
+
+ /* ----------------
+ * switch back to previous context
+ * ----------------
+ */
+ MemoryContextSwitchTo(context);
+ PortalExecutorHeapMemory = (MemoryContext) NULL;
}
/* --------------------------------
- * PerformPortalFetch
+ * PerformPortalFetch
* --------------------------------
*/
void
PerformPortalFetch(char *name,
- bool forward,
- int count,
- char *tag,
- CommandDest dest)
+ bool forward,
+ int count,
+ char *tag,
+ CommandDest dest)
{
- Portal portal;
- int feature;
- QueryDesc *queryDesc;
- MemoryContext context;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- if (name == NULL) {
- elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
- return;
- }
-
- /* ----------------
- * get the portal from the portal name
- * ----------------
- */
- portal = GetPortalByName(name);
- if (! PortalIsValid(portal)) {
- elog(NOTICE, "PerformPortalFetch: portal \"%s\" not found",
- name);
- return;
- }
-
- /* ----------------
- * switch into the portal context
- * ----------------
- */
- context= MemoryContextSwitchTo((MemoryContext)PortalGetHeapMemory(portal));
-
- AssertState(context ==
- (MemoryContext)PortalGetHeapMemory(GetPortalByName(NULL)));
-
- /* ----------------
- * setup "feature" to tell the executor what direction and
- * how many tuples to fetch.
- * ----------------
- */
- if (forward)
- feature = EXEC_FOR;
- else
- feature = EXEC_BACK;
-
- /* ----------------
- * tell the destination to prepare to recieve some tuples
- * ----------------
- */
- queryDesc = PortalGetQueryDesc(portal);
- BeginCommand(name,
- queryDesc->operation,
- portal->attinfo,/* QueryDescGetTypeInfo(queryDesc), */
- false, /* portal fetches don't end up in relations */
- false, /* this is a portal fetch, not a "retrieve portal" */
- tag,
- dest);
-
- /* ----------------
- * execute the portal fetch operation
- * ----------------
- */
- PortalExecutorHeapMemory = (MemoryContext)
- PortalGetHeapMemory(portal);
-
- ExecutorRun(queryDesc, PortalGetState(portal), feature, count);
-
- /* ----------------
- * Note: the "end-of-command" tag is returned by higher-level
- * utility code
- *
- * Return blank portal for now.
- * Otherwise, this named portal will be cleaned.
- * Note: portals will only be supported within a BEGIN...END
- * block in the near future. Later, someone will fix it to
- * do what is possible across transaction boundries.
- * ----------------
- */
- MemoryContextSwitchTo(
- (MemoryContext)PortalGetHeapMemory(GetPortalByName(NULL)));
+ Portal portal;
+ int feature;
+ QueryDesc *queryDesc;
+ MemoryContext context;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ if (name == NULL)
+ {
+ elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
+ return;
+ }
+
+ /* ----------------
+ * get the portal from the portal name
+ * ----------------
+ */
+ portal = GetPortalByName(name);
+ if (!PortalIsValid(portal))
+ {
+ elog(NOTICE, "PerformPortalFetch: portal \"%s\" not found",
+ name);
+ return;
+ }
+
+ /* ----------------
+ * switch into the portal context
+ * ----------------
+ */
+ context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
+
+ AssertState(context ==
+ (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
+
+ /* ----------------
+ * setup "feature" to tell the executor what direction and
+ * how many tuples to fetch.
+ * ----------------
+ */
+ if (forward)
+ feature = EXEC_FOR;
+ else
+ feature = EXEC_BACK;
+
+ /* ----------------
+ * tell the destination to prepare to recieve some tuples
+ * ----------------
+ */
+ queryDesc = PortalGetQueryDesc(portal);
+ BeginCommand(name,
+ queryDesc->operation,
+ portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
+ * */
+ false, /* portal fetches don't end up in
+ * relations */
+ false, /* this is a portal fetch, not a "retrieve
+ * portal" */
+ tag,
+ dest);
+
+ /* ----------------
+ * execute the portal fetch operation
+ * ----------------
+ */
+ PortalExecutorHeapMemory = (MemoryContext)
+ PortalGetHeapMemory(portal);
+
+ ExecutorRun(queryDesc, PortalGetState(portal), feature, count);
+
+ /* ----------------
+ * Note: the "end-of-command" tag is returned by higher-level
+ * utility code
+ *
+ * Return blank portal for now.
+ * Otherwise, this named portal will be cleaned.
+ * Note: portals will only be supported within a BEGIN...END
+ * block in the near future. Later, someone will fix it to
+ * do what is possible across transaction boundries.
+ * ----------------
+ */
+ MemoryContextSwitchTo(
+ (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
}
/* --------------------------------
- * PerformPortalClose
+ * PerformPortalClose
* --------------------------------
*/
void
PerformPortalClose(char *name, CommandDest dest)
{
- Portal portal;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- if (name == NULL) {
- elog(NOTICE, "PerformPortalClose: blank portal unsupported");
- return;
- }
-
- /* ----------------
- * get the portal from the portal name
- * ----------------
- */
- portal = GetPortalByName(name);
- if (! PortalIsValid(portal)) {
- elog(NOTICE, "PerformPortalClose: portal \"%s\" not found",
- name);
- return;
- }
-
- /* ----------------
- * Note: PortalCleanup is called as a side-effect
- * ----------------
- */
- PortalDestroy(&portal);
+ Portal portal;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ if (name == NULL)
+ {
+ elog(NOTICE, "PerformPortalClose: blank portal unsupported");
+ return;
+ }
+
+ /* ----------------
+ * get the portal from the portal name
+ * ----------------
+ */
+ portal = GetPortalByName(name);
+ if (!PortalIsValid(portal))
+ {
+ elog(NOTICE, "PerformPortalClose: portal \"%s\" not found",
+ name);
+ return;
+ }
+
+ /* ----------------
+ * Note: PortalCleanup is called as a side-effect
+ * ----------------
+ */
+ PortalDestroy(&portal);
}
/* ----------------
- * PerformAddAttribute
+ * PerformAddAttribute
*
- * adds an additional attribute to a relation
+ * adds an additional attribute to a relation
*
- * Adds attribute field(s) to a relation. Each new attribute
- * is given attnums in sequential order and is added to the
- * ATTRIBUTE relation. If the AMI fails, defunct tuples will
- * remain in the ATTRIBUTE relation for later vacuuming.
- * Later, there may be some reserved attribute names???
+ * Adds attribute field(s) to a relation. Each new attribute
+ * is given attnums in sequential order and is added to the
+ * ATTRIBUTE relation. If the AMI fails, defunct tuples will
+ * remain in the ATTRIBUTE relation for later vacuuming.
+ * Later, there may be some reserved attribute names???
*
- * (If needed, can instead use elog to handle exceptions.)
+ * (If needed, can instead use elog to handle exceptions.)
*
- * Note:
- * Initial idea of ordering the tuple attributes so that all
- * the variable length domains occured last was scratched. Doing
- * so would not speed access too much (in general) and would create
- * many complications in formtuple, amgetattr, and addattribute.
+ * Note:
+ * Initial idea of ordering the tuple attributes so that all
+ * the variable length domains occured last was scratched. Doing
+ * so would not speed access too much (in general) and would create
+ * many complications in formtuple, amgetattr, and addattribute.
*
- * scan attribute catalog for name conflict (within rel)
- * scan type catalog for absence of data type (if not arg)
- * create attnum magically???
- * create attribute tuple
- * insert attribute in attribute catalog
- * modify reldesc
- * create new relation tuple
- * insert new relation in relation catalog
- * delete original relation from relation catalog
+ * scan attribute catalog for name conflict (within rel)
+ * scan type catalog for absence of data type (if not arg)
+ * create attnum magically???
+ * create attribute tuple
+ * insert attribute in attribute catalog
+ * modify reldesc
+ * create new relation tuple
+ * insert new relation in relation catalog
+ * delete original relation from relation catalog
* ----------------
*/
void
PerformAddAttribute(char *relationName,
- char *userName,
- bool inherits,
- ColumnDef *colDef)
-{
- Relation relrdesc, attrdesc;
- HeapScanDesc attsdesc;
- HeapTuple reltup;
- HeapTuple attributeTuple;
- AttributeTupleForm attribute;
- FormData_pg_attribute attributeD;
- int i;
- int minattnum, maxatts;
- HeapTuple tup;
- ScanKeyData key[2];
- ItemPointerData oldTID;
- Relation idescs[Num_pg_attr_indices];
- Relation ridescs[Num_pg_class_indices];
- bool hasindex;
-
- /*
- * permissions checking. this would normally be done in utility.c,
- * but this particular routine is recursive.
- *
- * normally, only the owner of a class can change its schema.
- */
- if (IsSystemRelationName(relationName))
- elog(WARN, "PerformAddAttribute: class \"%s\" is a system catalog",
- relationName);
+ char *userName,
+ bool inherits,
+ ColumnDef * colDef)
+{
+ Relation relrdesc,
+ attrdesc;
+ HeapScanDesc attsdesc;
+ HeapTuple reltup;
+ HeapTuple attributeTuple;
+ AttributeTupleForm attribute;
+ FormData_pg_attribute attributeD;
+ int i;
+ int minattnum,
+ maxatts;
+ HeapTuple tup;
+ ScanKeyData key[2];
+ ItemPointerData oldTID;
+ Relation idescs[Num_pg_attr_indices];
+ Relation ridescs[Num_pg_class_indices];
+ bool hasindex;
+
+ /*
+ * permissions checking. this would normally be done in utility.c,
+ * but this particular routine is recursive.
+ *
+ * normally, only the owner of a class can change its schema.
+ */
+ if (IsSystemRelationName(relationName))
+ elog(WARN, "PerformAddAttribute: class \"%s\" is a system catalog",
+ relationName);
#ifndef NO_SECURITY
- if (!pg_ownercheck(userName, relationName, RELNAME))
- elog(WARN, "PerformAddAttribute: you do not own class \"%s\"",
- relationName);
+ if (!pg_ownercheck(userName, relationName, RELNAME))
+ elog(WARN, "PerformAddAttribute: you do not own class \"%s\"",
+ relationName);
#endif
- /*
- * we can't add a not null attribute
- */
- if (colDef->is_not_null)
- elog(WARN,"Can't add a not null attribute to a existent relation");
- if (colDef->defval)
- elog(WARN,"ADD ATTRIBUTE: DEFAULT is not implemented, yet");
- /*
- * if the first element in the 'schema' list is a "*" then we are
- * supposed to add this attribute to all classes that inherit from
- * 'relationName' (as well as to 'relationName').
- *
- * any permissions or problems with duplicate attributes will cause
- * the whole transaction to abort, which is what we want -- all or
- * nothing.
- */
- if (colDef != NULL) {
- if (inherits) {
- Oid myrelid, childrelid;
- List *child, *children;
-
- relrdesc = heap_openr(relationName);
- if (!RelationIsValid(relrdesc)) {
- elog(WARN, "PerformAddAttribute: unknown relation: \"%s\"",
- relationName);
- }
- myrelid = relrdesc->rd_id;
- heap_close(relrdesc);
-
- /* this routine is actually in the planner */
- children = find_all_inheritors(lconsi(myrelid,NIL), NIL);
-
- /*
- * find_all_inheritors does the recursive search of the
- * inheritance hierarchy, so all we have to do is process
- * all of the relids in the list that it returns.
- */
- foreach (child, children) {
- childrelid = lfirsti(child);
- if (childrelid == myrelid)
- continue;
- relrdesc = heap_open(childrelid);
- if (!RelationIsValid(relrdesc)) {
- elog(WARN, "PerformAddAttribute: can't find catalog entry for inheriting class with oid %d",
- childrelid);
+
+ /*
+ * we can't add a not null attribute
+ */
+ if (colDef->is_not_null)
+ elog(WARN, "Can't add a not null attribute to a existent relation");
+ if (colDef->defval)
+ elog(WARN, "ADD ATTRIBUTE: DEFAULT is not implemented, yet");
+
+ /*
+ * if the first element in the 'schema' list is a "*" then we are
+ * supposed to add this attribute to all classes that inherit from
+ * 'relationName' (as well as to 'relationName').
+ *
+ * any permissions or problems with duplicate attributes will cause the
+ * whole transaction to abort, which is what we want -- all or
+ * nothing.
+ */
+ if (colDef != NULL)
+ {
+ if (inherits)
+ {
+ Oid myrelid,
+ childrelid;
+ List *child,
+ *children;
+
+ relrdesc = heap_openr(relationName);
+ if (!RelationIsValid(relrdesc))
+ {
+ elog(WARN, "PerformAddAttribute: unknown relation: \"%s\"",
+ relationName);
+ }
+ myrelid = relrdesc->rd_id;
+ heap_close(relrdesc);
+
+ /* this routine is actually in the planner */
+ children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
+
+ /*
+ * find_all_inheritors does the recursive search of the
+ * inheritance hierarchy, so all we have to do is process all
+ * of the relids in the list that it returns.
+ */
+ foreach(child, children)
+ {
+ childrelid = lfirsti(child);
+ if (childrelid == myrelid)
+ continue;
+ relrdesc = heap_open(childrelid);
+ if (!RelationIsValid(relrdesc))
+ {
+ elog(WARN, "PerformAddAttribute: can't find catalog entry for inheriting class with oid %d",
+ childrelid);
+ }
+ PerformAddAttribute((relrdesc->rd_rel->relname).data,
+ userName, false, colDef);
+ heap_close(relrdesc);
+ }
}
- PerformAddAttribute((relrdesc->rd_rel->relname).data,
- userName, false, colDef);
+ }
+
+ relrdesc = heap_openr(RelationRelationName);
+ reltup = ClassNameIndexScan(relrdesc, relationName);
+
+ if (!PointerIsValid(reltup))
+ {
heap_close(relrdesc);
- }
+ elog(WARN, "PerformAddAttribute: relation \"%s\" not found",
+ relationName);
}
- }
-
- relrdesc = heap_openr(RelationRelationName);
- reltup = ClassNameIndexScan(relrdesc, relationName);
-
- if (!PointerIsValid(reltup)) {
- heap_close(relrdesc);
- elog(WARN, "PerformAddAttribute: relation \"%s\" not found",
- relationName);
- }
- /*
- * XXX is the following check sufficient?
- */
- if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX) {
- elog(WARN, "PerformAddAttribute: index relation \"%s\" not changed",
- relationName);
- return;
- }
-
- minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
- maxatts = minattnum + 1;
- if (maxatts > MaxHeapAttributeNumber) {
- pfree(reltup); /* XXX temp */
- heap_close(relrdesc); /* XXX temp */
- elog(WARN, "PerformAddAttribute: relations limited to %d attributes",
- MaxHeapAttributeNumber);
- return;
- }
-
- attrdesc = heap_openr(AttributeRelationName);
-
- Assert(attrdesc);
- Assert(RelationGetRelationTupleForm(attrdesc));
-
- /*
- * Open all (if any) pg_attribute indices
- */
- hasindex = RelationGetRelationTupleForm(attrdesc)->relhasindex;
- if (hasindex)
- CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
-
- ScanKeyEntryInitialize(&key[0],
- (bits16) NULL,
- (AttrNumber) Anum_pg_attribute_attrelid,
- (RegProcedure)ObjectIdEqualRegProcedure,
- (Datum) reltup->t_oid);
-
- ScanKeyEntryInitialize(&key[1],
- (bits16) NULL,
- (AttrNumber) Anum_pg_attribute_attname,
- (RegProcedure)NameEqualRegProcedure,
- (Datum) NULL);
-
- attributeD.attrelid = reltup->t_oid;
- attributeD.attdisbursion = 0; /* XXX temporary */
- attributeD.attcacheoff = -1;
-
- attributeTuple = heap_addheader(Natts_pg_attribute,
- sizeof attributeD,
- (char *)&attributeD);
-
- attribute = (AttributeTupleForm)GETSTRUCT(attributeTuple);
-
- i = 1 + minattnum;
-
- {
- HeapTuple typeTuple;
- TypeTupleForm form;
- char *p;
- int attnelems;
-
+
/*
- * XXX use syscache here as an optimization
+ * XXX is the following check sufficient?
*/
- key[1].sk_argument = (Datum)colDef->colname;
- attsdesc = heap_beginscan(attrdesc, 0, NowTimeQual, 2, key);
-
-
- tup = heap_getnext(attsdesc, 0, (Buffer *) NULL);
- if (HeapTupleIsValid(tup)) {
- pfree(reltup); /* XXX temp */
- heap_endscan(attsdesc); /* XXX temp */
- heap_close(attrdesc); /* XXX temp */
- heap_close(relrdesc); /* XXX temp */
- elog(WARN, "PerformAddAttribute: attribute \"%s\" already exists in class \"%s\"",
- key[1].sk_argument,
- relationName);
- return;
+ if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX)
+ {
+ elog(WARN, "PerformAddAttribute: index relation \"%s\" not changed",
+ relationName);
+ return;
+ }
+
+ minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
+ maxatts = minattnum + 1;
+ if (maxatts > MaxHeapAttributeNumber)
+ {
+ pfree(reltup); /* XXX temp */
+ heap_close(relrdesc); /* XXX temp */
+ elog(WARN, "PerformAddAttribute: relations limited to %d attributes",
+ MaxHeapAttributeNumber);
+ return;
}
- heap_endscan(attsdesc);
-
+
+ attrdesc = heap_openr(AttributeRelationName);
+
+ Assert(attrdesc);
+ Assert(RelationGetRelationTupleForm(attrdesc));
+
/*
- * check to see if it is an array attribute.
+ * Open all (if any) pg_attribute indices
*/
-
- p = colDef->typename->name;
-
- if (colDef->typename->arrayBounds)
- {
- attnelems = length(colDef->typename->arrayBounds);
- p = makeArrayTypeName(colDef->typename->name);
- }
- else
- attnelems = 0;
-
- typeTuple = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(p),
- 0,0,0);
- form = (TypeTupleForm)GETSTRUCT(typeTuple);
-
- if (!HeapTupleIsValid(typeTuple)) {
- elog(WARN, "Add: type \"%s\" nonexistent", p);
+ hasindex = RelationGetRelationTupleForm(attrdesc)->relhasindex;
+ if (hasindex)
+ CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
+
+ ScanKeyEntryInitialize(&key[0],
+ (bits16) NULL,
+ (AttrNumber) Anum_pg_attribute_attrelid,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ (Datum) reltup->t_oid);
+
+ ScanKeyEntryInitialize(&key[1],
+ (bits16) NULL,
+ (AttrNumber) Anum_pg_attribute_attname,
+ (RegProcedure) NameEqualRegProcedure,
+ (Datum) NULL);
+
+ attributeD.attrelid = reltup->t_oid;
+ attributeD.attdisbursion = 0; /* XXX temporary */
+ attributeD.attcacheoff = -1;
+
+ attributeTuple = heap_addheader(Natts_pg_attribute,
+ sizeof attributeD,
+ (char *) &attributeD);
+
+ attribute = (AttributeTupleForm) GETSTRUCT(attributeTuple);
+
+ i = 1 + minattnum;
+
+ {
+ HeapTuple typeTuple;
+ TypeTupleForm form;
+ char *p;
+ int attnelems;
+
+ /*
+ * XXX use syscache here as an optimization
+ */
+ key[1].sk_argument = (Datum) colDef->colname;
+ attsdesc = heap_beginscan(attrdesc, 0, NowTimeQual, 2, key);
+
+
+ tup = heap_getnext(attsdesc, 0, (Buffer *) NULL);
+ if (HeapTupleIsValid(tup))
+ {
+ pfree(reltup); /* XXX temp */
+ heap_endscan(attsdesc); /* XXX temp */
+ heap_close(attrdesc); /* XXX temp */
+ heap_close(relrdesc); /* XXX temp */
+ elog(WARN, "PerformAddAttribute: attribute \"%s\" already exists in class \"%s\"",
+ key[1].sk_argument,
+ relationName);
+ return;
+ }
+ heap_endscan(attsdesc);
+
+ /*
+ * check to see if it is an array attribute.
+ */
+
+ p = colDef->typename->name;
+
+ if (colDef->typename->arrayBounds)
+ {
+ attnelems = length(colDef->typename->arrayBounds);
+ p = makeArrayTypeName(colDef->typename->name);
+ }
+ else
+ attnelems = 0;
+
+ typeTuple = SearchSysCacheTuple(TYPNAME,
+ PointerGetDatum(p),
+ 0, 0, 0);
+ form = (TypeTupleForm) GETSTRUCT(typeTuple);
+
+ if (!HeapTupleIsValid(typeTuple))
+ {
+ elog(WARN, "Add: type \"%s\" nonexistent", p);
+ }
+ namestrcpy(&(attribute->attname), (char *) key[1].sk_argument);
+ attribute->atttypid = typeTuple->t_oid;
+ if (colDef->typename->typlen > 0)
+ attribute->attlen = colDef->typename->typlen;
+ else
+/* bpchar, varchar, text */
+ attribute->attlen = form->typlen;
+ attribute->attnum = i;
+ attribute->attbyval = form->typbyval;
+ attribute->attnelems = attnelems;
+ attribute->attcacheoff = -1;
+ attribute->attisset = (bool) (form->typtype == 'c');
+ attribute->attalign = form->typalign;
+ attribute->attnotnull = false;
+
+ heap_insert(attrdesc, attributeTuple);
+ if (hasindex)
+ CatalogIndexInsert(idescs,
+ Num_pg_attr_indices,
+ attrdesc,
+ attributeTuple);
}
- namestrcpy(&(attribute->attname), (char*) key[1].sk_argument);
- attribute->atttypid = typeTuple->t_oid;
- if (colDef->typename->typlen > 0)
- attribute->attlen = colDef->typename->typlen;
- else /* bpchar, varchar, text */
- attribute->attlen = form->typlen;
- attribute->attnum = i;
- attribute->attbyval = form->typbyval;
- attribute->attnelems = attnelems;
- attribute->attcacheoff = -1;
- attribute->attisset = (bool) (form->typtype == 'c');
- attribute->attalign = form->typalign;
- attribute->attnotnull = false;
-
- heap_insert(attrdesc, attributeTuple);
+
if (hasindex)
- CatalogIndexInsert(idescs,
- Num_pg_attr_indices,
- attrdesc,
- attributeTuple);
- }
-
- if (hasindex)
- CatalogCloseIndices(Num_pg_attr_indices, idescs);
- heap_close(attrdesc);
-
- ((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
- oldTID = reltup->t_ctid;
- heap_replace(relrdesc, &oldTID, reltup);
-
- /* keep catalog indices current */
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
- CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, reltup);
- CatalogCloseIndices(Num_pg_class_indices, ridescs);
-
- pfree(reltup);
- heap_close(relrdesc);
+ CatalogCloseIndices(Num_pg_attr_indices, idescs);
+ heap_close(attrdesc);
+
+ ((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
+ oldTID = reltup->t_ctid;
+ heap_replace(relrdesc, &oldTID, reltup);
+
+ /* keep catalog indices current */
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
+ CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, reltup);
+ CatalogCloseIndices(Num_pg_class_indices, ridescs);
+
+ pfree(reltup);
+ heap_close(relrdesc);
}
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 687cd1eb12e..795e9f5584f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.29 1997/09/04 13:18:59 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.30 1997/09/07 04:40:40 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,736 +42,857 @@
/* non-export function prototypes */
-static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
-static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
-static Oid GetOutputFunction(Oid type);
-static Oid GetTypeElement(Oid type);
-static Oid GetInputFunction(Oid type);
-static Oid IsTypeByVal(Oid type);
-static void GetIndexRelations(Oid main_relation_oid,
- int *n_indices,
- Relation **index_rels);
+static void CopyTo(Relation rel, bool binary, bool oids, FILE * fp, char *delim);
+static void CopyFrom(Relation rel, bool binary, bool oids, FILE * fp, char *delim);
+static Oid GetOutputFunction(Oid type);
+static Oid GetTypeElement(Oid type);
+static Oid GetInputFunction(Oid type);
+static Oid IsTypeByVal(Oid type);
+static void
+GetIndexRelations(Oid main_relation_oid,
+ int *n_indices,
+ Relation ** index_rels);
+
#ifdef COPY_PATCH
-static void CopyReadNewline(FILE *fp, int *newline);
-static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline);
+static void CopyReadNewline(FILE * fp, int *newline);
+static char *CopyReadAttribute(FILE * fp, bool * isnull, char *delim, int *newline);
+
#else
-static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim);
+static char *CopyReadAttribute(FILE * fp, bool * isnull, char *delim);
+
#endif
-static void CopyAttributeOut(FILE *fp, char *string, char *delim);
-static int CountTuples(Relation relation);
+static void CopyAttributeOut(FILE * fp, char *string, char *delim);
+static int CountTuples(Relation relation);
-extern FILE *Pfout, *Pfin;
+extern FILE *Pfout,
+ *Pfin;
#ifdef COPY_DEBUG
-static int lineno;
+static int lineno;
+
#endif
-
+
/*
- * DoCopy executes a the SQL COPY statement.
+ * DoCopy executes a the SQL COPY statement.
*/
void
-DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
- char *filename, char *delim) {
+DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
+ char *filename, char *delim)
+{
/*----------------------------------------------------------------------------
Either unload or reload contents of class <relname>, depending on <from>.
If <pipe> is false, transfer is between the class and the file named
<filename>. Otherwise, transfer is between the class and our regular
- input/output stream. The latter could be either stdin/stdout or a
+ input/output stream. The latter could be either stdin/stdout or a
socket, depending on whether we're running under Postmaster control.
Iff <binary>, unload or reload in the binary format, as opposed to the
- more wasteful but more robust and portable text format.
+ more wasteful but more robust and portable text format.
- If in the text format, delimit columns with delimiter <delim>.
+ If in the text format, delimit columns with delimiter <delim>.
When loading in the text format from an input stream (as opposed to
- a file), recognize a "." on a line by itself as EOF. Also recognize
+ a file), recognize a "." on a line by itself as EOF. Also recognize
a stream EOF. When unloading in the text format to an output stream,
write a "." on a line by itself at the end of the data.
Iff <oids>, unload or reload the format that includes OID information.
Do not allow a Postgres user without superuser privilege to read from
- or write to a file.
+ or write to a file.
Do not allow the copy if user doesn't have proper permission to access
the class.
----------------------------------------------------------------------------*/
- FILE *fp;
- Relation rel;
- extern char *UserName; /* defined in global.c */
- const AclMode required_access = from ? ACL_WR : ACL_RD;
- int result;
-
- rel = heap_openr(relname);
- if (rel == NULL) elog(WARN, "COPY command failed. Class %s "
- "does not exist.", relname);
-
- result = pg_aclcheck(relname, UserName, required_access);
- if(result != ACLCHECK_OK)
- elog(WARN, "%s: %s", relname, aclcheck_error_strings[result]);
- /* Above should not return */
- else if (!superuser() && !pipe)
- elog(WARN, "You must have Postgres superuser privilege to do a COPY "
- "directly to or from a file. Anyone can COPY to stdout or "
- "from stdin. Psql's \\copy command also works for anyone.");
- /* Above should not return. */
- else {
- if (from) { /* copy from file to database */
- if ( rel->rd_rel->relkind == RELKIND_SEQUENCE )
- elog (WARN, "You can't change sequence relation %s", relname);
- if (pipe) {
- if (IsUnderPostmaster) {
- ReceiveCopyBegin();
- fp = Pfin;
- } else fp = stdin;
- } else {
- fp = AllocateFile(filename, "r");
- if (fp == NULL)
- elog(WARN, "COPY command, running in backend with "
- "effective uid %d, could not open file '%s' for "
- "reading. Errno = %s (%d).",
- geteuid(), filename, strerror(errno), errno);
- /* Above should not return */
- }
- CopyFrom(rel, binary, oids, fp, delim);
- } else { /* copy from database to file */
- if (pipe) {
- if (IsUnderPostmaster) {
- SendCopyBegin();
- fp = Pfout;
- } else fp = stdout;
- } else {
- mode_t oumask; /* Pre-existing umask value */
- oumask = umask((mode_t) 0);
- fp = AllocateFile(filename, "w");
- umask(oumask);
- if (fp == NULL)
- elog(WARN, "COPY command, running in backend with "
- "effective uid %d, could not open file '%s' for "
- "writing. Errno = %s (%d).",
- geteuid(), filename, strerror(errno), errno);
- /* Above should not return */
- }
- CopyTo(rel, binary, oids, fp, delim);
- }
- if (!pipe)
- FreeFile(fp);
- else if (!from && !binary) {
- fputs("\\.\n", fp);
- if (IsUnderPostmaster) fflush(Pfout);
- }
- }
+ FILE *fp;
+ Relation rel;
+ extern char *UserName; /* defined in global.c */
+ const AclMode required_access = from ? ACL_WR : ACL_RD;
+ int result;
+
+ rel = heap_openr(relname);
+ if (rel == NULL)
+ elog(WARN, "COPY command failed. Class %s "
+ "does not exist.", relname);
+
+ result = pg_aclcheck(relname, UserName, required_access);
+ if (result != ACLCHECK_OK)
+ elog(WARN, "%s: %s", relname, aclcheck_error_strings[result]);
+ /* Above should not return */
+ else if (!superuser() && !pipe)
+ elog(WARN, "You must have Postgres superuser privilege to do a COPY "
+ "directly to or from a file. Anyone can COPY to stdout or "
+ "from stdin. Psql's \\copy command also works for anyone.");
+ /* Above should not return. */
+ else
+ {
+ if (from)
+ { /* copy from file to database */
+ if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+ elog(WARN, "You can't change sequence relation %s", relname);
+ if (pipe)
+ {
+ if (IsUnderPostmaster)
+ {
+ ReceiveCopyBegin();
+ fp = Pfin;
+ }
+ else
+ fp = stdin;
+ }
+ else
+ {
+ fp = AllocateFile(filename, "r");
+ if (fp == NULL)
+ elog(WARN, "COPY command, running in backend with "
+ "effective uid %d, could not open file '%s' for "
+ "reading. Errno = %s (%d).",
+ geteuid(), filename, strerror(errno), errno);
+ /* Above should not return */
+ }
+ CopyFrom(rel, binary, oids, fp, delim);
+ }
+ else
+ { /* copy from database to file */
+ if (pipe)
+ {
+ if (IsUnderPostmaster)
+ {
+ SendCopyBegin();
+ fp = Pfout;
+ }
+ else
+ fp = stdout;
+ }
+ else
+ {
+ mode_t oumask; /* Pre-existing umask value */
+
+ oumask = umask((mode_t) 0);
+ fp = AllocateFile(filename, "w");
+ umask(oumask);
+ if (fp == NULL)
+ elog(WARN, "COPY command, running in backend with "
+ "effective uid %d, could not open file '%s' for "
+ "writing. Errno = %s (%d).",
+ geteuid(), filename, strerror(errno), errno);
+ /* Above should not return */
+ }
+ CopyTo(rel, binary, oids, fp, delim);
+ }
+ if (!pipe)
+ FreeFile(fp);
+ else if (!from && !binary)
+ {
+ fputs("\\.\n", fp);
+ if (IsUnderPostmaster)
+ fflush(Pfout);
+ }
+ }
}
static void
-CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
+CopyTo(Relation rel, bool binary, bool oids, FILE * fp, char *delim)
{
- HeapTuple tuple;
- HeapScanDesc scandesc;
-
- int32 attr_count, i;
- AttributeTupleForm *attr;
- func_ptr *out_functions;
- int dummy;
- Oid out_func_oid;
- Oid *elements;
- Datum value;
- bool isnull; /* The attribute we are copying is null */
- char *nulls;
- /* <nulls> is a (dynamically allocated) array with one character
- per attribute in the instance being copied. nulls[I-1] is
- 'n' if Attribute Number I is null, and ' ' otherwise.
-
- <nulls> is meaningful only if we are doing a binary copy.
- */
- char *string;
- int32 ntuples;
- TupleDesc tupDesc;
-
- scandesc = heap_beginscan(rel, 0, NULL, 0, NULL);
-
- attr_count = rel->rd_att->natts;
- attr = rel->rd_att->attrs;
- tupDesc = rel->rd_att;
-
- if (!binary) {
- out_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
- elements = (Oid *) palloc(attr_count * sizeof(Oid));
- for (i = 0; i < attr_count; i++) {
- out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid);
- fmgr_info(out_func_oid, &out_functions[i], &dummy);
- elements[i] = GetTypeElement(attr[i]->atttypid);
- }
- nulls = NULL; /* meaningless, but compiler doesn't know that */
- }else {
- elements = NULL;
- out_functions = NULL;
- nulls = (char *) palloc(attr_count);
- for (i = 0; i < attr_count; i++) nulls[i] = ' ';
-
- /* XXX expensive */
-
- ntuples = CountTuples(rel);
- fwrite(&ntuples, sizeof(int32), 1, fp);
- }
-
- for (tuple = heap_getnext(scandesc, 0, NULL);
- tuple != NULL;
- tuple = heap_getnext(scandesc, 0, NULL)) {
-
- if (oids && !binary) {
- fputs(oidout(tuple->t_oid),fp);
- fputc(delim[0], fp);
- }
-
- for (i = 0; i < attr_count; i++) {
- value = (Datum)
- heap_getattr(tuple, InvalidBuffer, i+1, tupDesc, &isnull);
- if (!binary) {
- if (!isnull) {
- string = (char *) (out_functions[i]) (value, elements[i]);
- CopyAttributeOut(fp, string, delim);
- pfree(string);
- }
- else
- fputs("\\N", fp); /* null indicator */
-
- if (i == attr_count - 1) {
- fputc('\n', fp);
- }else {
- /* when copying out, only use the first char of the delim
- string */
- fputc(delim[0], fp);
- }
- }else {
- /*
- * only interesting thing heap_getattr tells us in this case
- * is if we have a null attribute or not.
- */
- if (isnull) nulls[i] = 'n';
- }
- }
-
- if (binary) {
- int32 null_ct = 0, length;
-
- for (i = 0; i < attr_count; i++) {
- if (nulls[i] == 'n') null_ct++;
- }
-
- length = tuple->t_len - tuple->t_hoff;
- fwrite(&length, sizeof(int32), 1, fp);
- if (oids)
- fwrite((char *) &tuple->t_oid, sizeof(int32), 1, fp);
-
- fwrite(&null_ct, sizeof(int32), 1, fp);
- if (null_ct > 0) {
- for (i = 0; i < attr_count; i++) {
- if (nulls[i] == 'n') {
- fwrite(&i, sizeof(int32), 1, fp);
- nulls[i] = ' ';
- }
- }
- }
- fwrite((char *) tuple + tuple->t_hoff, length, 1, fp);
- }
- }
-
- heap_endscan(scandesc);
- if (binary) {
- pfree(nulls);
- }else {
- pfree(out_functions);
- pfree(elements);
- }
-
- heap_close(rel);
+ HeapTuple tuple;
+ HeapScanDesc scandesc;
+
+ int32 attr_count,
+ i;
+ AttributeTupleForm *attr;
+ func_ptr *out_functions;
+ int dummy;
+ Oid out_func_oid;
+ Oid *elements;
+ Datum value;
+ bool isnull; /* The attribute we are copying is null */
+ char *nulls;
+
+ /*
+ * <nulls> is a (dynamically allocated) array with one character per
+ * attribute in the instance being copied. nulls[I-1] is 'n' if
+ * Attribute Number I is null, and ' ' otherwise.
+ *
+ * <nulls> is meaningful only if we are doing a binary copy.
+ */
+ char *string;
+ int32 ntuples;
+ TupleDesc tupDesc;
+
+ scandesc = heap_beginscan(rel, 0, NULL, 0, NULL);
+
+ attr_count = rel->rd_att->natts;
+ attr = rel->rd_att->attrs;
+ tupDesc = rel->rd_att;
+
+ if (!binary)
+ {
+ out_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
+ elements = (Oid *) palloc(attr_count * sizeof(Oid));
+ for (i = 0; i < attr_count; i++)
+ {
+ out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid);
+ fmgr_info(out_func_oid, &out_functions[i], &dummy);
+ elements[i] = GetTypeElement(attr[i]->atttypid);
+ }
+ nulls = NULL; /* meaningless, but compiler doesn't know
+ * that */
+ }
+ else
+ {
+ elements = NULL;
+ out_functions = NULL;
+ nulls = (char *) palloc(attr_count);
+ for (i = 0; i < attr_count; i++)
+ nulls[i] = ' ';
+
+ /* XXX expensive */
+
+ ntuples = CountTuples(rel);
+ fwrite(&ntuples, sizeof(int32), 1, fp);
+ }
+
+ for (tuple = heap_getnext(scandesc, 0, NULL);
+ tuple != NULL;
+ tuple = heap_getnext(scandesc, 0, NULL))
+ {
+
+ if (oids && !binary)
+ {
+ fputs(oidout(tuple->t_oid), fp);
+ fputc(delim[0], fp);
+ }
+
+ for (i = 0; i < attr_count; i++)
+ {
+ value = (Datum)
+ heap_getattr(tuple, InvalidBuffer, i + 1, tupDesc, &isnull);
+ if (!binary)
+ {
+ if (!isnull)
+ {
+ string = (char *) (out_functions[i]) (value, elements[i]);
+ CopyAttributeOut(fp, string, delim);
+ pfree(string);
+ }
+ else
+ fputs("\\N", fp); /* null indicator */
+
+ if (i == attr_count - 1)
+ {
+ fputc('\n', fp);
+ }
+ else
+ {
+
+ /*
+ * when copying out, only use the first char of the
+ * delim string
+ */
+ fputc(delim[0], fp);
+ }
+ }
+ else
+ {
+
+ /*
+ * only interesting thing heap_getattr tells us in this
+ * case is if we have a null attribute or not.
+ */
+ if (isnull)
+ nulls[i] = 'n';
+ }
+ }
+
+ if (binary)
+ {
+ int32 null_ct = 0,
+ length;
+
+ for (i = 0; i < attr_count; i++)
+ {
+ if (nulls[i] == 'n')
+ null_ct++;
+ }
+
+ length = tuple->t_len - tuple->t_hoff;
+ fwrite(&length, sizeof(int32), 1, fp);
+ if (oids)
+ fwrite((char *) &tuple->t_oid, sizeof(int32), 1, fp);
+
+ fwrite(&null_ct, sizeof(int32), 1, fp);
+ if (null_ct > 0)
+ {
+ for (i = 0; i < attr_count; i++)
+ {
+ if (nulls[i] == 'n')
+ {
+ fwrite(&i, sizeof(int32), 1, fp);
+ nulls[i] = ' ';
+ }
+ }
+ }
+ fwrite((char *) tuple + tuple->t_hoff, length, 1, fp);
+ }
+ }
+
+ heap_endscan(scandesc);
+ if (binary)
+ {
+ pfree(nulls);
+ }
+ else
+ {
+ pfree(out_functions);
+ pfree(elements);
+ }
+
+ heap_close(rel);
}
static void
-CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
+CopyFrom(Relation rel, bool binary, bool oids, FILE * fp, char *delim)
{
- HeapTuple tuple;
- AttrNumber attr_count;
- AttributeTupleForm *attr;
- func_ptr *in_functions;
- int i, dummy;
- Oid in_func_oid;
- Datum *values;
- char *nulls, *index_nulls;
- bool *byval;
- bool isnull;
- bool has_index;
- int done = 0;
- char *string = NULL, *ptr;
- Relation *index_rels;
- int32 len, null_ct, null_id;
- int32 ntuples, tuples_read = 0;
- bool reading_to_eof = true;
- Oid *elements;
- FuncIndexInfo *finfo, **finfoP = NULL;
- TupleDesc *itupdescArr;
- HeapTuple pgIndexTup;
- IndexTupleForm *pgIndexP = NULL;
- int *indexNatts = NULL;
- char *predString;
- Node **indexPred = NULL;
- TupleDesc rtupdesc;
- ExprContext *econtext = NULL;
+ HeapTuple tuple;
+ AttrNumber attr_count;
+ AttributeTupleForm *attr;
+ func_ptr *in_functions;
+ int i,
+ dummy;
+ Oid in_func_oid;
+ Datum *values;
+ char *nulls,
+ *index_nulls;
+ bool *byval;
+ bool isnull;
+ bool has_index;
+ int done = 0;
+ char *string = NULL,
+ *ptr;
+ Relation *index_rels;
+ int32 len,
+ null_ct,
+ null_id;
+ int32 ntuples,
+ tuples_read = 0;
+ bool reading_to_eof = true;
+ Oid *elements;
+ FuncIndexInfo *finfo,
+ **finfoP = NULL;
+ TupleDesc *itupdescArr;
+ HeapTuple pgIndexTup;
+ IndexTupleForm *pgIndexP = NULL;
+ int *indexNatts = NULL;
+ char *predString;
+ Node **indexPred = NULL;
+ TupleDesc rtupdesc;
+ ExprContext *econtext = NULL;
+
#ifndef OMIT_PARTIAL_INDEX
- TupleTable tupleTable;
- TupleTableSlot *slot = NULL;
+ TupleTable tupleTable;
+ TupleTableSlot *slot = NULL;
+
#endif
- int natts;
- AttrNumber *attnumP;
- Datum *idatum;
- int n_indices;
- InsertIndexResult indexRes;
- TupleDesc tupDesc;
- Oid loaded_oid;
- bool skip_tuple = false;
-
- tupDesc = RelationGetTupleDescriptor(rel);
- attr = tupDesc->attrs;
- attr_count = tupDesc->natts;
-
- has_index = false;
-
- /*
- * This may be a scalar or a functional index. We initialize all
- * kinds of arrays here to avoid doing extra work at every tuple
- * copy.
- */
-
- if (rel->rd_rel->relhasindex) {
- GetIndexRelations(rel->rd_id, &n_indices, &index_rels);
- if (n_indices > 0) {
- has_index = true;
- itupdescArr =
- (TupleDesc *)palloc(n_indices * sizeof(TupleDesc));
- pgIndexP =
- (IndexTupleForm *)palloc(n_indices * sizeof(IndexTupleForm));
- indexNatts = (int *) palloc(n_indices * sizeof(int));
- finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
- finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
- indexPred = (Node **) palloc(n_indices * sizeof(Node*));
- econtext = NULL;
- for (i = 0; i < n_indices; i++) {
- itupdescArr[i] = RelationGetTupleDescriptor(index_rels[i]);
- pgIndexTup =
- SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(index_rels[i]->rd_id),
- 0,0,0);
- Assert(pgIndexTup);
- pgIndexP[i] = (IndexTupleForm)GETSTRUCT(pgIndexTup);
- for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
- *attnumP != InvalidAttrNumber;
- attnumP++, natts++);
- if (pgIndexP[i]->indproc != InvalidOid) {
- FIgetnArgs(&finfo[i]) = natts;
- natts = 1;
- FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc;
- *(FIgetname(&finfo[i])) = '\0';
- finfoP[i] = &finfo[i];
- } else
- finfoP[i] = (FuncIndexInfo *) NULL;
- indexNatts[i] = natts;
- if (VARSIZE(&pgIndexP[i]->indpred) != 0) {
- predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred);
- indexPred[i] = stringToNode(predString);
- pfree(predString);
- /* make dummy ExprContext for use by ExecQual */
- if (econtext == NULL) {
+ int natts;
+ AttrNumber *attnumP;
+ Datum *idatum;
+ int n_indices;
+ InsertIndexResult indexRes;
+ TupleDesc tupDesc;
+ Oid loaded_oid;
+ bool skip_tuple = false;
+
+ tupDesc = RelationGetTupleDescriptor(rel);
+ attr = tupDesc->attrs;
+ attr_count = tupDesc->natts;
+
+ has_index = false;
+
+ /*
+ * This may be a scalar or a functional index. We initialize all
+ * kinds of arrays here to avoid doing extra work at every tuple copy.
+ */
+
+ if (rel->rd_rel->relhasindex)
+ {
+ GetIndexRelations(rel->rd_id, &n_indices, &index_rels);
+ if (n_indices > 0)
+ {
+ has_index = true;
+ itupdescArr =
+ (TupleDesc *) palloc(n_indices * sizeof(TupleDesc));
+ pgIndexP =
+ (IndexTupleForm *) palloc(n_indices * sizeof(IndexTupleForm));
+ indexNatts = (int *) palloc(n_indices * sizeof(int));
+ finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
+ finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
+ indexPred = (Node **) palloc(n_indices * sizeof(Node *));
+ econtext = NULL;
+ for (i = 0; i < n_indices; i++)
+ {
+ itupdescArr[i] = RelationGetTupleDescriptor(index_rels[i]);
+ pgIndexTup =
+ SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(index_rels[i]->rd_id),
+ 0, 0, 0);
+ Assert(pgIndexTup);
+ pgIndexP[i] = (IndexTupleForm) GETSTRUCT(pgIndexTup);
+ for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
+ *attnumP != InvalidAttrNumber;
+ attnumP++, natts++);
+ if (pgIndexP[i]->indproc != InvalidOid)
+ {
+ FIgetnArgs(&finfo[i]) = natts;
+ natts = 1;
+ FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc;
+ *(FIgetname(&finfo[i])) = '\0';
+ finfoP[i] = &finfo[i];
+ }
+ else
+ finfoP[i] = (FuncIndexInfo *) NULL;
+ indexNatts[i] = natts;
+ if (VARSIZE(&pgIndexP[i]->indpred) != 0)
+ {
+ predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred);
+ indexPred[i] = stringToNode(predString);
+ pfree(predString);
+ /* make dummy ExprContext for use by ExecQual */
+ if (econtext == NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- tupleTable = ExecCreateTupleTable(1);
- slot = ExecAllocTableSlot(tupleTable);
- econtext = makeNode(ExprContext);
- econtext->ecxt_scantuple = slot;
- rtupdesc = RelationGetTupleDescriptor(rel);
- slot->ttc_tupleDescriptor = rtupdesc;
- /*
- * There's no buffer associated with heap tuples here,
- * so I set the slot's buffer to NULL. Currently, it
- * appears that the only way a buffer could be needed
- * would be if the partial index predicate referred to
- * the "lock" system attribute. If it did, then
- * heap_getattr would call HeapTupleGetRuleLock, which
- * uses the buffer's descriptor to get the relation id.
- * Rather than try to fix this, I'll just disallow
- * partial indexes on "lock", which wouldn't be useful
- * anyway. --Nels, Nov '92
- */
- /* SetSlotBuffer(slot, (Buffer) NULL); */
- /* SetSlotShouldFree(slot, false); */
- slot->ttc_buffer = (Buffer)NULL;
- slot->ttc_shouldFree = false;
-#endif /* OMIT_PARTIAL_INDEX */
- }
- } else {
- indexPred[i] = NULL;
- }
- }
- }
- }
-
- if (!binary)
- {
- in_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
- elements = (Oid *) palloc(attr_count * sizeof(Oid));
- for (i = 0; i < attr_count; i++)
- {
- in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
- fmgr_info(in_func_oid, &in_functions[i], &dummy);
- elements[i] = GetTypeElement(attr[i]->atttypid);
- }
- }
- else
- {
- in_functions = NULL;
- elements = NULL;
- fread(&ntuples, sizeof(int32), 1, fp);
- if (ntuples != 0) reading_to_eof = false;
- }
-
- values = (Datum *) palloc(sizeof(Datum) * attr_count);
- nulls = (char *) palloc(attr_count);
- index_nulls = (char *) palloc(attr_count);
- idatum = (Datum *) palloc(sizeof(Datum) * attr_count);
- byval = (bool *) palloc(attr_count * sizeof(bool));
-
- for (i = 0; i < attr_count; i++) {
- nulls[i] = ' ';
- index_nulls[i] = ' ';
- byval[i] = (bool) IsTypeByVal(attr[i]->atttypid);
- }
-
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ econtext = makeNode(ExprContext);
+ econtext->ecxt_scantuple = slot;
+ rtupdesc = RelationGetTupleDescriptor(rel);
+ slot->ttc_tupleDescriptor = rtupdesc;
+
+ /*
+ * There's no buffer associated with heap tuples
+ * here, so I set the slot's buffer to NULL.
+ * Currently, it appears that the only way a
+ * buffer could be needed would be if the partial
+ * index predicate referred to the "lock" system
+ * attribute. If it did, then heap_getattr would
+ * call HeapTupleGetRuleLock, which uses the
+ * buffer's descriptor to get the relation id.
+ * Rather than try to fix this, I'll just disallow
+ * partial indexes on "lock", which wouldn't be
+ * useful anyway. --Nels, Nov '92
+ */
+ /* SetSlotBuffer(slot, (Buffer) NULL); */
+ /* SetSlotShouldFree(slot, false); */
+ slot->ttc_buffer = (Buffer) NULL;
+ slot->ttc_shouldFree = false;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+ }
+ else
+ {
+ indexPred[i] = NULL;
+ }
+ }
+ }
+ }
+
+ if (!binary)
+ {
+ in_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
+ elements = (Oid *) palloc(attr_count * sizeof(Oid));
+ for (i = 0; i < attr_count; i++)
+ {
+ in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
+ fmgr_info(in_func_oid, &in_functions[i], &dummy);
+ elements[i] = GetTypeElement(attr[i]->atttypid);
+ }
+ }
+ else
+ {
+ in_functions = NULL;
+ elements = NULL;
+ fread(&ntuples, sizeof(int32), 1, fp);
+ if (ntuples != 0)
+ reading_to_eof = false;
+ }
+
+ values = (Datum *) palloc(sizeof(Datum) * attr_count);
+ nulls = (char *) palloc(attr_count);
+ index_nulls = (char *) palloc(attr_count);
+ idatum = (Datum *) palloc(sizeof(Datum) * attr_count);
+ byval = (bool *) palloc(attr_count * sizeof(bool));
+
+ for (i = 0; i < attr_count; i++)
+ {
+ nulls[i] = ' ';
+ index_nulls[i] = ' ';
+ byval[i] = (bool) IsTypeByVal(attr[i]->atttypid);
+ }
+
#ifdef COPY_DEBUG
- lineno = 0;
+ lineno = 0;
#endif
- while (!done) {
- if (!binary) {
+ while (!done)
+ {
+ if (!binary)
+ {
#ifdef COPY_PATCH
- int newline = 0;
+ int newline = 0;
+
#endif
#ifdef COPY_DEBUG
- lineno++;
- elog(DEBUG, "line %d", lineno);
+ lineno++;
+ elog(DEBUG, "line %d", lineno);
#endif
- if (oids) {
+ if (oids)
+ {
#ifdef COPY_PATCH
- string = CopyReadAttribute(fp, &isnull, delim, &newline);
+ string = CopyReadAttribute(fp, &isnull, delim, &newline);
#else
- string = CopyReadAttribute(fp, &isnull, delim);
+ string = CopyReadAttribute(fp, &isnull, delim);
#endif
- if (string == NULL)
- done = 1;
- else {
- loaded_oid = oidin(string);
- if (loaded_oid < BootstrapObjectIdData)
- elog(WARN, "COPY TEXT: Invalid Oid");
- }
- }
- for (i = 0; i < attr_count && !done; i++) {
+ if (string == NULL)
+ done = 1;
+ else
+ {
+ loaded_oid = oidin(string);
+ if (loaded_oid < BootstrapObjectIdData)
+ elog(WARN, "COPY TEXT: Invalid Oid");
+ }
+ }
+ for (i = 0; i < attr_count && !done; i++)
+ {
#ifdef COPY_PATCH
- string = CopyReadAttribute(fp, &isnull, delim, &newline);
+ string = CopyReadAttribute(fp, &isnull, delim, &newline);
#else
- string = CopyReadAttribute(fp, &isnull, delim);
+ string = CopyReadAttribute(fp, &isnull, delim);
#endif
- if (isnull) {
- values[i] = PointerGetDatum(NULL);
- nulls[i] = 'n';
- }else if (string == NULL) {
- done = 1;
- }else {
- values[i] =
- (Datum)(in_functions[i])(string,
- elements[i],
- attr[i]->attlen);
- /*
- * Sanity check - by reference attributes cannot return
- * NULL
- */
- if (!PointerIsValid(values[i]) &&
- !(rel->rd_att->attrs[i]->attbyval)) {
+ if (isnull)
+ {
+ values[i] = PointerGetDatum(NULL);
+ nulls[i] = 'n';
+ }
+ else if (string == NULL)
+ {
+ done = 1;
+ }
+ else
+ {
+ values[i] =
+ (Datum) (in_functions[i]) (string,
+ elements[i],
+ attr[i]->attlen);
+
+ /*
+ * Sanity check - by reference attributes cannot
+ * return NULL
+ */
+ if (!PointerIsValid(values[i]) &&
+ !(rel->rd_att->attrs[i]->attbyval))
+ {
#ifdef COPY_DEBUG
- elog(WARN,
- "copy from: line %d - Bad file format", lineno);
+ elog(WARN,
+ "copy from: line %d - Bad file format", lineno);
#else
- elog(WARN, "copy from: Bad file format");
+ elog(WARN, "copy from: Bad file format");
#endif
- }
- }
- }
+ }
+ }
+ }
#ifdef COPY_PATCH
- if (!done) {
- CopyReadNewline(fp, &newline);
- }
+ if (!done)
+ {
+ CopyReadNewline(fp, &newline);
+ }
#endif
- }else { /* binary */
- fread(&len, sizeof(int32), 1, fp);
- if (feof(fp)) {
- done = 1;
- }else {
- if (oids) {
- fread(&loaded_oid, sizeof(int32), 1, fp);
- if (loaded_oid < BootstrapObjectIdData)
- elog(WARN, "COPY BINARY: Invalid Oid");
- }
- fread(&null_ct, sizeof(int32), 1, fp);
- if (null_ct > 0) {
- for (i = 0; i < null_ct; i++) {
- fread(&null_id, sizeof(int32), 1, fp);
- nulls[null_id] = 'n';
- }
- }
-
- string = (char *) palloc(len);
- fread(string, len, 1, fp);
-
- ptr = string;
-
- for (i = 0; i < attr_count; i++) {
- if (byval[i] && nulls[i] != 'n') {
-
- switch(attr[i]->attlen) {
- case sizeof(char):
- values[i] = (Datum) *(unsigned char *) ptr;
- ptr += sizeof(char);
- break;
- case sizeof(short):
- ptr = (char *) SHORTALIGN(ptr);
- values[i] = (Datum) *(unsigned short *) ptr;
- ptr += sizeof(short);
- break;
- case sizeof(int32):
- ptr = (char *) INTALIGN(ptr);
- values[i] = (Datum) *(uint32 *) ptr;
- ptr += sizeof(int32);
- break;
- default:
- elog(WARN, "COPY BINARY: impossible size!");
- break;
- }
- }else if (nulls[i] != 'n') {
- switch (attr[i]->attlen) {
- case -1:
- if (attr[i]->attalign == 'd')
- ptr = (char *)DOUBLEALIGN(ptr);
- else
- ptr = (char *)INTALIGN(ptr);
- values[i] = (Datum) ptr;
- ptr += * (uint32 *) ptr;
- break;
- case sizeof(char):
- values[i] = (Datum)ptr;
- ptr += attr[i]->attlen;
- break;
- case sizeof(short):
- ptr = (char*)SHORTALIGN(ptr);
- values[i] = (Datum)ptr;
- ptr += attr[i]->attlen;
- break;
- case sizeof(int32):
- ptr = (char*)INTALIGN(ptr);
- values[i] = (Datum)ptr;
- ptr += attr[i]->attlen;
- break;
- default:
- if (attr[i]->attalign == 'd')
- ptr = (char *)DOUBLEALIGN(ptr);
- else
- ptr = (char *)LONGALIGN(ptr);
- values[i] = (Datum) ptr;
- ptr += attr[i]->attlen;
- }
- }
- }
- }
- }
- if (done) continue;
+ }
+ else
+ { /* binary */
+ fread(&len, sizeof(int32), 1, fp);
+ if (feof(fp))
+ {
+ done = 1;
+ }
+ else
+ {
+ if (oids)
+ {
+ fread(&loaded_oid, sizeof(int32), 1, fp);
+ if (loaded_oid < BootstrapObjectIdData)
+ elog(WARN, "COPY BINARY: Invalid Oid");
+ }
+ fread(&null_ct, sizeof(int32), 1, fp);
+ if (null_ct > 0)
+ {
+ for (i = 0; i < null_ct; i++)
+ {
+ fread(&null_id, sizeof(int32), 1, fp);
+ nulls[null_id] = 'n';
+ }
+ }
- /*
- * Does it have any sence ? - vadim 12/14/96
- *
- tupDesc = CreateTupleDesc(attr_count, attr);
- */
- tuple = heap_formtuple(tupDesc, values, nulls);
- if (oids)
- tuple->t_oid = loaded_oid;
-
- skip_tuple = false;
- /* BEFORE ROW INSERT Triggers */
- if ( rel->trigdesc &&
- rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0 )
- {
- HeapTuple newtuple;
-
- newtuple = ExecBRInsertTriggers (rel, tuple);
-
- if ( newtuple == NULL ) /* "do nothing" */
- skip_tuple = true;
- else if ( newtuple != tuple ) /* modified by Trigger(s) */
- {
- pfree (tuple);
- tuple = newtuple;
- }
- }
-
- if ( !skip_tuple )
- {
- /* ----------------
- * Check the constraints of a tuple
- * ----------------
- */
-
- if ( rel->rd_att->constr )
- {
- HeapTuple newtuple;
-
- newtuple = ExecConstraints ("CopyFrom", rel, tuple);
-
- if ( newtuple != tuple )
- {
- pfree (tuple);
- tuple = newtuple;
- }
- }
-
- heap_insert(rel, tuple);
-
- if (has_index)
- {
- for (i = 0; i < n_indices; i++)
- {
- if (indexPred[i] != NULL)
- {
+ string = (char *) palloc(len);
+ fread(string, len, 1, fp);
+
+ ptr = string;
+
+ for (i = 0; i < attr_count; i++)
+ {
+ if (byval[i] && nulls[i] != 'n')
+ {
+
+ switch (attr[i]->attlen)
+ {
+ case sizeof(char):
+ values[i] = (Datum) * (unsigned char *) ptr;
+ ptr += sizeof(char);
+ break;
+ case sizeof(short):
+ ptr = (char *) SHORTALIGN(ptr);
+ values[i] = (Datum) * (unsigned short *) ptr;
+ ptr += sizeof(short);
+ break;
+ case sizeof(int32):
+ ptr = (char *) INTALIGN(ptr);
+ values[i] = (Datum) * (uint32 *) ptr;
+ ptr += sizeof(int32);
+ break;
+ default:
+ elog(WARN, "COPY BINARY: impossible size!");
+ break;
+ }
+ }
+ else if (nulls[i] != 'n')
+ {
+ switch (attr[i]->attlen)
+ {
+ case -1:
+ if (attr[i]->attalign == 'd')
+ ptr = (char *) DOUBLEALIGN(ptr);
+ else
+ ptr = (char *) INTALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += *(uint32 *) ptr;
+ break;
+ case sizeof(char):
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ break;
+ case sizeof(short):
+ ptr = (char *) SHORTALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ break;
+ case sizeof(int32):
+ ptr = (char *) INTALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ break;
+ default:
+ if (attr[i]->attalign == 'd')
+ ptr = (char *) DOUBLEALIGN(ptr);
+ else
+ ptr = (char *) LONGALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ }
+ }
+ }
+ }
+ }
+ if (done)
+ continue;
+
+ /*
+ * Does it have any sence ? - vadim 12/14/96
+ *
+ * tupDesc = CreateTupleDesc(attr_count, attr);
+ */
+ tuple = heap_formtuple(tupDesc, values, nulls);
+ if (oids)
+ tuple->t_oid = loaded_oid;
+
+ skip_tuple = false;
+ /* BEFORE ROW INSERT Triggers */
+ if (rel->trigdesc &&
+ rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecBRInsertTriggers(rel, tuple);
+
+ if (newtuple == NULL) /* "do nothing" */
+ skip_tuple = true;
+ else if (newtuple != tuple) /* modified by Trigger(s) */
+ {
+ pfree(tuple);
+ tuple = newtuple;
+ }
+ }
+
+ if (!skip_tuple)
+ {
+ /* ----------------
+ * Check the constraints of a tuple
+ * ----------------
+ */
+
+ if (rel->rd_att->constr)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecConstraints("CopyFrom", rel, tuple);
+
+ if (newtuple != tuple)
+ {
+ pfree(tuple);
+ tuple = newtuple;
+ }
+ }
+
+ heap_insert(rel, tuple);
+
+ if (has_index)
+ {
+ for (i = 0; i < n_indices; i++)
+ {
+ if (indexPred[i] != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*
- * if tuple doesn't satisfy predicate,
- * don't update index
- */
- slot->val = tuple;
- /*SetSlotContents(slot, tuple); */
- if (ExecQual((List*)indexPred[i], econtext) == false)
- continue;
-#endif /* OMIT_PARTIAL_INDEX */
- }
- FormIndexDatum(indexNatts[i],
- (AttrNumber *)&(pgIndexP[i]->indkey[0]),
- tuple,
- tupDesc,
- InvalidBuffer,
- idatum,
- index_nulls,
- finfoP[i]);
- indexRes = index_insert(index_rels[i], idatum, index_nulls,
- &(tuple->t_ctid), rel);
- if (indexRes) pfree(indexRes);
- }
- }
- /* AFTER ROW INSERT Triggers */
- if ( rel->trigdesc &&
- rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 )
- ExecARInsertTriggers (rel, tuple);
- }
-
- if (binary) pfree(string);
-
- for (i = 0; i < attr_count; i++) {
- if (!byval[i] && nulls[i] != 'n') {
- if (!binary) pfree((void*)values[i]);
- }else if (nulls[i] == 'n') {
- nulls[i] = ' ';
- }
- }
-
- pfree(tuple);
- tuples_read++;
-
- if (!reading_to_eof && ntuples == tuples_read) done = true;
- }
- pfree(values);
- if (!binary) pfree(in_functions);
- pfree(nulls);
- pfree(byval);
- heap_close(rel);
+
+ /*
+ * if tuple doesn't satisfy predicate, don't
+ * update index
+ */
+ slot->val = tuple;
+ /* SetSlotContents(slot, tuple); */
+ if (ExecQual((List *) indexPred[i], econtext) == false)
+ continue;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+ FormIndexDatum(indexNatts[i],
+ (AttrNumber *) & (pgIndexP[i]->indkey[0]),
+ tuple,
+ tupDesc,
+ InvalidBuffer,
+ idatum,
+ index_nulls,
+ finfoP[i]);
+ indexRes = index_insert(index_rels[i], idatum, index_nulls,
+ &(tuple->t_ctid), rel);
+ if (indexRes)
+ pfree(indexRes);
+ }
+ }
+ /* AFTER ROW INSERT Triggers */
+ if (rel->trigdesc &&
+ rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
+ ExecARInsertTriggers(rel, tuple);
+ }
+
+ if (binary)
+ pfree(string);
+
+ for (i = 0; i < attr_count; i++)
+ {
+ if (!byval[i] && nulls[i] != 'n')
+ {
+ if (!binary)
+ pfree((void *) values[i]);
+ }
+ else if (nulls[i] == 'n')
+ {
+ nulls[i] = ' ';
+ }
+ }
+
+ pfree(tuple);
+ tuples_read++;
+
+ if (!reading_to_eof && ntuples == tuples_read)
+ done = true;
+ }
+ pfree(values);
+ if (!binary)
+ pfree(in_functions);
+ pfree(nulls);
+ pfree(byval);
+ heap_close(rel);
}
-static Oid
+static Oid
GetOutputFunction(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput);
-
- elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput);
+
+ elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
-static Oid
+static Oid
GetTypeElement(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem);
-
- elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem);
+
+ elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
-static Oid
+static Oid
GetInputFunction(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typinput);
-
- elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typinput);
+
+ elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
-static Oid
+static Oid
IsTypeByVal(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typbyval);
-
- elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
-
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typbyval);
+
+ elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
+
+ return (InvalidOid);
}
-/*
+/*
* Given the OID of a relation, return an array of index relation descriptors
* and the number of index relations. These relation descriptors are open
* using heap_open().
@@ -779,71 +900,77 @@ IsTypeByVal(Oid type)
* Space for the array itself is palloc'ed.
*/
-typedef struct rel_list {
- Oid index_rel_oid;
- struct rel_list *next;
-} RelationList;
+typedef struct rel_list
+{
+ Oid index_rel_oid;
+ struct rel_list *next;
+} RelationList;
static void
GetIndexRelations(Oid main_relation_oid,
- int *n_indices,
- Relation **index_rels)
+ int *n_indices,
+ Relation ** index_rels)
{
- RelationList *head, *scan;
- Relation pg_index_rel;
- HeapScanDesc scandesc;
- Oid index_relation_oid;
- HeapTuple tuple;
- TupleDesc tupDesc;
- int i;
- bool isnull;
-
- pg_index_rel = heap_openr(IndexRelationName);
- scandesc = heap_beginscan(pg_index_rel, 0, NULL, 0, NULL);
- tupDesc = RelationGetTupleDescriptor(pg_index_rel);
-
- *n_indices = 0;
-
- head = (RelationList *) palloc(sizeof(RelationList));
- scan = head;
- head->next = NULL;
-
- for (tuple = heap_getnext(scandesc, 0, NULL);
- tuple != NULL;
- tuple = heap_getnext(scandesc, 0, NULL)) {
-
- index_relation_oid =
- (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, 2,
- tupDesc, &isnull));
- if (index_relation_oid == main_relation_oid) {
- scan->index_rel_oid =
- (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer,
- Anum_pg_index_indexrelid,
- tupDesc, &isnull));
- (*n_indices)++;
- scan->next = (RelationList *) palloc(sizeof(RelationList));
- scan = scan->next;
- }
- }
-
- heap_endscan(scandesc);
- heap_close(pg_index_rel);
-
- /* We cannot trust to relhasindex of the main_relation now, so... */
- if ( *n_indices == 0 )
- return;
-
- *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
-
- for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next) {
- (*index_rels)[i] = index_open(scan->index_rel_oid);
- }
-
- for (i = 0, scan = head; i < *n_indices + 1; i++) {
- scan = head->next;
- pfree(head);
- head = scan;
- }
+ RelationList *head,
+ *scan;
+ Relation pg_index_rel;
+ HeapScanDesc scandesc;
+ Oid index_relation_oid;
+ HeapTuple tuple;
+ TupleDesc tupDesc;
+ int i;
+ bool isnull;
+
+ pg_index_rel = heap_openr(IndexRelationName);
+ scandesc = heap_beginscan(pg_index_rel, 0, NULL, 0, NULL);
+ tupDesc = RelationGetTupleDescriptor(pg_index_rel);
+
+ *n_indices = 0;
+
+ head = (RelationList *) palloc(sizeof(RelationList));
+ scan = head;
+ head->next = NULL;
+
+ for (tuple = heap_getnext(scandesc, 0, NULL);
+ tuple != NULL;
+ tuple = heap_getnext(scandesc, 0, NULL))
+ {
+
+ index_relation_oid =
+ (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, 2,
+ tupDesc, &isnull));
+ if (index_relation_oid == main_relation_oid)
+ {
+ scan->index_rel_oid =
+ (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer,
+ Anum_pg_index_indexrelid,
+ tupDesc, &isnull));
+ (*n_indices)++;
+ scan->next = (RelationList *) palloc(sizeof(RelationList));
+ scan = scan->next;
+ }
+ }
+
+ heap_endscan(scandesc);
+ heap_close(pg_index_rel);
+
+ /* We cannot trust to relhasindex of the main_relation now, so... */
+ if (*n_indices == 0)
+ return;
+
+ *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
+
+ for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
+ {
+ (*index_rels)[i] = index_open(scan->index_rel_oid);
+ }
+
+ for (i = 0, scan = head; i < *n_indices + 1; i++)
+ {
+ scan = head->next;
+ pfree(head);
+ head = scan;
+ }
}
#define EXT_ATTLEN 5*8192
@@ -851,20 +978,22 @@ GetIndexRelations(Oid main_relation_oid,
/*
returns 1 is c is in s
*/
-static bool
-inString(char c, char* s)
+static bool
+inString(char c, char *s)
{
- int i;
-
- if (s) {
- i = 0;
- while (s[i] != '\0') {
- if (s[i] == c)
- return 1;
- i++;
- }
- }
- return 0;
+ int i;
+
+ if (s)
+ {
+ i = 0;
+ while (s[i] != '\0')
+ {
+ if (s[i] == c)
+ return 1;
+ i++;
+ }
+ }
+ return 0;
}
#ifdef COPY_PATCH
@@ -873,19 +1002,21 @@ inString(char c, char* s)
*/
void
-CopyReadNewline(FILE *fp, int *newline)
+CopyReadNewline(FILE * fp, int *newline)
{
- if (!*newline) {
+ if (!*newline)
+ {
#ifdef COPY_DEBUG
- elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored",
- lineno);
+ elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored",
+ lineno);
#else
- elog(NOTICE, "CopyReadNewline: line - extra fields ignored");
+ elog(NOTICE, "CopyReadNewline: line - extra fields ignored");
#endif
- while (!feof(fp) && (getc(fp) != '\n'));
- }
- *newline = 0;
+ while (!feof(fp) && (getc(fp) != '\n'));
+ }
+ *newline = 0;
}
+
#endif
/*
@@ -895,148 +1026,167 @@ CopyReadNewline(FILE *fp, int *newline)
* can be used as standard input.
*/
-static char *
+static char *
#ifdef COPY_PATCH
-CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline)
+CopyReadAttribute(FILE * fp, bool * isnull, char *delim, int *newline)
#else
-CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
+CopyReadAttribute(FILE * fp, bool * isnull, char *delim)
#endif
{
- static char attribute[EXT_ATTLEN];
- char c;
- int done = 0;
- int i = 0;
-
+ static char attribute[EXT_ATTLEN];
+ char c;
+ int done = 0;
+ int i = 0;
+
#ifdef COPY_PATCH
- /* if last delimiter was a newline return a NULL attribute */
- if (*newline) {
- *isnull = (bool) true;
- return(NULL);
- }
+ /* if last delimiter was a newline return a NULL attribute */
+ if (*newline)
+ {
+ *isnull = (bool) true;
+ return (NULL);
+ }
#endif
- *isnull = (bool) false; /* set default */
- if (feof(fp))
- return(NULL);
-
- while (!done) {
- c = getc(fp);
-
- if (feof(fp))
- return(NULL);
- else if (c == '\\') {
- c = getc(fp);
- if (feof(fp))
- return(NULL);
- switch (c) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7': {
- int val;
- val = VALUE(c);
- c = getc(fp);
- if (ISOCTAL(c)) {
- val = (val<<3) + VALUE(c);
- c = getc(fp);
- if (ISOCTAL(c)) {
- val = (val<<3) + VALUE(c);
- } else {
- if (feof(fp))
- return(NULL);
- ungetc(c, fp);
- }
- } else {
- if (feof(fp))
- return(NULL);
- ungetc(c, fp);
- }
- c = val & 0377;
- }
- break;
- case 'b':
- c = '\b';
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'v':
- c = '\v';
- break;
- case 'N':
- attribute[0] = '\0'; /* just to be safe */
- *isnull = (bool) true;
- break;
- case '.':
- c = getc(fp);
- if (c != '\n')
- elog(WARN, "CopyReadAttribute - end of record marker corrupted");
- return(NULL);
- break;
- }
- }else if (inString(c,delim) || c == '\n') {
+ *isnull = (bool) false; /* set default */
+ if (feof(fp))
+ return (NULL);
+
+ while (!done)
+ {
+ c = getc(fp);
+
+ if (feof(fp))
+ return (NULL);
+ else if (c == '\\')
+ {
+ c = getc(fp);
+ if (feof(fp))
+ return (NULL);
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int val;
+
+ val = VALUE(c);
+ c = getc(fp);
+ if (ISOCTAL(c))
+ {
+ val = (val << 3) + VALUE(c);
+ c = getc(fp);
+ if (ISOCTAL(c))
+ {
+ val = (val << 3) + VALUE(c);
+ }
+ else
+ {
+ if (feof(fp))
+ return (NULL);
+ ungetc(c, fp);
+ }
+ }
+ else
+ {
+ if (feof(fp))
+ return (NULL);
+ ungetc(c, fp);
+ }
+ c = val & 0377;
+ }
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case 'N':
+ attribute[0] = '\0'; /* just to be safe */
+ *isnull = (bool) true;
+ break;
+ case '.':
+ c = getc(fp);
+ if (c != '\n')
+ elog(WARN, "CopyReadAttribute - end of record marker corrupted");
+ return (NULL);
+ break;
+ }
+ }
+ else if (inString(c, delim) || c == '\n')
+ {
#ifdef COPY_PATCH
- if (c == '\n') {
- *newline = 1;
- }
+ if (c == '\n')
+ {
+ *newline = 1;
+ }
#endif
- done = 1;
- }
- if (!done) attribute[i++] = c;
- if (i == EXT_ATTLEN - 1)
- elog(WARN, "CopyReadAttribute - attribute length too long");
- }
- attribute[i] = '\0';
- return(&attribute[0]);
+ done = 1;
+ }
+ if (!done)
+ attribute[i++] = c;
+ if (i == EXT_ATTLEN - 1)
+ elog(WARN, "CopyReadAttribute - attribute length too long");
+ }
+ attribute[i] = '\0';
+ return (&attribute[0]);
}
static void
-CopyAttributeOut(FILE *fp, char *string, char *delim)
+CopyAttributeOut(FILE * fp, char *string, char *delim)
{
- char c;
- int is_array = false;
- int len = strlen(string);
-
- /* XXX - This is a kludge, we should check the data type */
- if (len && (string[0] == '{') && (string[len-1] == '}'))
- is_array = true;
-
- for ( ; (c = *string) != '\0'; string++) {
- if (c == delim[0] || c == '\n' ||
- (c == '\\' && !is_array))
- fputc('\\', fp);
- else
- if (c == '\\' && is_array)
- if (*(string+1) == '\\') {
- /* translate \\ to \\\\ */
- fputc('\\', fp);
- fputc('\\', fp);
- fputc('\\', fp);
- string++;
- } else if (*(string+1) == '"') {
- /* translate \" to \\\" */
- fputc('\\', fp);
- fputc('\\', fp);
- }
- fputc(*string, fp);
- }
+ char c;
+ int is_array = false;
+ int len = strlen(string);
+
+ /* XXX - This is a kludge, we should check the data type */
+ if (len && (string[0] == '{') && (string[len - 1] == '}'))
+ is_array = true;
+
+ for (; (c = *string) != '\0'; string++)
+ {
+ if (c == delim[0] || c == '\n' ||
+ (c == '\\' && !is_array))
+ fputc('\\', fp);
+ else if (c == '\\' && is_array)
+ if (*(string + 1) == '\\')
+ {
+ /* translate \\ to \\\\ */
+ fputc('\\', fp);
+ fputc('\\', fp);
+ fputc('\\', fp);
+ string++;
+ }
+ else if (*(string + 1) == '"')
+ {
+ /* translate \" to \\\" */
+ fputc('\\', fp);
+ fputc('\\', fp);
+ }
+ fputc(*string, fp);
+ }
}
/*
- * Returns the number of tuples in a relation. Unfortunately, currently
+ * Returns the number of tuples in a relation. Unfortunately, currently
* must do a scan of the entire relation to determine this.
*
* relation is expected to be an open relation descriptor.
@@ -1044,17 +1194,17 @@ CopyAttributeOut(FILE *fp, char *string, char *delim)
static int
CountTuples(Relation relation)
{
- HeapScanDesc scandesc;
- HeapTuple tuple;
-
- int i;
-
- scandesc = heap_beginscan(relation, 0, NULL, 0, NULL);
-
- for (tuple = heap_getnext(scandesc, 0, NULL), i = 0;
- tuple != NULL;
- tuple = heap_getnext(scandesc, 0, NULL), i++)
- ;
- heap_endscan(scandesc);
- return(i);
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+
+ int i;
+
+ scandesc = heap_beginscan(relation, 0, NULL, 0, NULL);
+
+ for (tuple = heap_getnext(scandesc, 0, NULL), i = 0;
+ tuple != NULL;
+ tuple = heap_getnext(scandesc, 0, NULL), i++)
+ ;
+ heap_endscan(scandesc);
+ return (i);
}
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index 248aaa3e768..92641ca70d6 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* creatinh.c--
- * POSTGRES create/destroy relation with inheritance utility code.
+ * POSTGRES create/destroy relation with inheritance utility code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.14 1997/08/22 03:03:56 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.15 1997/09/07 04:40:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,623 +29,661 @@
#include <catalog/pg_ipl.h>
/* ----------------
- * local stuff
+ * local stuff
* ----------------
*/
-static int checkAttrExists(char *attributeName,
- char *attributeType, List *schema);
-static List *MergeAttributes(List *schema, List *supers, List **supconstr);
-static void StoreCatalogInheritance(Oid relationId, List *supers);
+static int
+checkAttrExists(char *attributeName,
+ char *attributeType, List * schema);
+static List *MergeAttributes(List * schema, List * supers, List ** supconstr);
+static void StoreCatalogInheritance(Oid relationId, List * supers);
/* ----------------------------------------------------------------
- * DefineRelation --
- * Creates a new relation.
+ * DefineRelation --
+ * Creates a new relation.
* ----------------------------------------------------------------
*/
void
-DefineRelation(CreateStmt *stmt)
+DefineRelation(CreateStmt * stmt)
{
- char *relname = palloc(NAMEDATALEN);
- List *schema = stmt->tableElts;
- int numberOfAttributes;
- Oid relationId;
- char archChar;
- List *inheritList = NULL;
- char *archiveName = NULL;
- TupleDesc descriptor;
- List *constraints;
- int heaploc, archloc;
-
- char* typename = NULL; /* the typename of this relation. not useod for now */
-
- if ( strlen(stmt->relname) >= NAMEDATALEN)
- elog(WARN, "the relation name %s is >= %d characters long", stmt->relname,
- NAMEDATALEN);
- strNcpy(relname,stmt->relname,NAMEDATALEN-1); /* make full length for copy */
-
- /* ----------------
- * Handle parameters
- * XXX parameter handling missing below.
- * ----------------
- */
- inheritList = stmt->inhRelnames;
-
- /* ----------------
- * determine archive mode
- * XXX use symbolic constants...
- * ----------------
- */
- archChar = 'n';
-
- switch (stmt->archiveType) {
- case ARCH_NONE:
+ char *relname = palloc(NAMEDATALEN);
+ List *schema = stmt->tableElts;
+ int numberOfAttributes;
+ Oid relationId;
+ char archChar;
+ List *inheritList = NULL;
+ char *archiveName = NULL;
+ TupleDesc descriptor;
+ List *constraints;
+ int heaploc,
+ archloc;
+
+ char *typename = NULL; /* the typename of this relation.
+ * not useod for now */
+
+ if (strlen(stmt->relname) >= NAMEDATALEN)
+ elog(WARN, "the relation name %s is >= %d characters long", stmt->relname,
+ NAMEDATALEN);
+ strNcpy(relname, stmt->relname, NAMEDATALEN - 1); /* make full length for
+ * copy */
+
+ /* ----------------
+ * Handle parameters
+ * XXX parameter handling missing below.
+ * ----------------
+ */
+ inheritList = stmt->inhRelnames;
+
+ /* ----------------
+ * determine archive mode
+ * XXX use symbolic constants...
+ * ----------------
+ */
archChar = 'n';
- break;
- case ARCH_LIGHT:
- archChar = 'l';
- break;
- case ARCH_HEAVY:
- archChar = 'h';
- break;
- default:
- elog(WARN, "Botched archive mode %d, ignoring",
- stmt->archiveType);
- break;
- }
-
- if (stmt->location == -1)
- heaploc = 0;
- else
- heaploc = stmt->location;
-
- /*
- * For now, any user-defined relation defaults to the magnetic
- * disk storgage manager. --mao 2 july 91
- */
- if (stmt->archiveLoc == -1) {
- archloc = 0;
- } else {
- if (archChar == 'n') {
- elog(WARN, "Set archive location, but not mode, for %s",
- relname);
+
+ switch (stmt->archiveType)
+ {
+ case ARCH_NONE:
+ archChar = 'n';
+ break;
+ case ARCH_LIGHT:
+ archChar = 'l';
+ break;
+ case ARCH_HEAVY:
+ archChar = 'h';
+ break;
+ default:
+ elog(WARN, "Botched archive mode %d, ignoring",
+ stmt->archiveType);
+ break;
+ }
+
+ if (stmt->location == -1)
+ heaploc = 0;
+ else
+ heaploc = stmt->location;
+
+ /*
+ * For now, any user-defined relation defaults to the magnetic disk
+ * storgage manager. --mao 2 july 91
+ */
+ if (stmt->archiveLoc == -1)
+ {
+ archloc = 0;
+ }
+ else
+ {
+ if (archChar == 'n')
+ {
+ elog(WARN, "Set archive location, but not mode, for %s",
+ relname);
+ }
+ archloc = stmt->archiveLoc;
+ }
+
+ /* ----------------
+ * generate relation schema, including inherited attributes.
+ * ----------------
+ */
+ schema = MergeAttributes(schema, inheritList, &constraints);
+ constraints = nconc(constraints, stmt->constraints);
+
+ numberOfAttributes = length(schema);
+ if (numberOfAttributes <= 0)
+ {
+ elog(WARN, "DefineRelation: %s",
+ "please inherit from a relation or define an attribute");
}
- archloc = stmt->archiveLoc;
- }
-
- /* ----------------
- * generate relation schema, including inherited attributes.
- * ----------------
- */
- schema = MergeAttributes(schema, inheritList, &constraints);
- constraints = nconc (constraints, stmt->constraints);
-
- numberOfAttributes = length(schema);
- if (numberOfAttributes <= 0) {
- elog(WARN, "DefineRelation: %s",
- "please inherit from a relation or define an attribute");
- }
-
- /* ----------------
- * create a relation descriptor from the relation schema
- * and create the relation.
- * ----------------
- */
- descriptor = BuildDescForRelation(schema, relname);
-
- if ( constraints != NIL )
- {
- List *entry;
- int nconstr = length (constraints);
- ConstrCheck *check = (ConstrCheck *) palloc (nconstr * sizeof (ConstrCheck));
- int ncheck = 0;
- int i;
-
- foreach (entry, constraints)
- {
- ConstraintDef *cdef = (ConstraintDef *) lfirst (entry);
-
- if ( cdef->type == CONSTR_CHECK )
- {
- if ( cdef->name != NULL )
- {
- for (i = 0; i < ncheck; i++)
- {
- if ( strcmp (check[i].ccname, cdef->name) == 0 )
- elog (WARN, "DefineRelation: name (%s) of CHECK constraint duplicated", cdef->name);
- }
- check[ncheck].ccname = cdef->name;
- }
- else
- {
- check[ncheck].ccname = (char*) palloc (NAMEDATALEN);
- sprintf (check[ncheck].ccname, "$%d", ncheck + 1);
- }
- check[ncheck].ccbin = NULL;
- check[ncheck].ccsrc = (char*) cdef->def;
- ncheck++;
- }
- }
- if ( ncheck > 0 )
- {
- if ( ncheck < nconstr )
- check = (ConstrCheck *) repalloc (check, ncheck * sizeof (ConstrCheck));
- if ( descriptor->constr == NULL )
- {
- descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
- descriptor->constr->num_defval = 0;
- descriptor->constr->has_not_null = false;
- }
- descriptor->constr->num_check = ncheck;
- descriptor->constr->check = check;
- }
- }
-
- relationId = heap_create(relname,
- typename,
- archChar,
- heaploc,
- descriptor);
-
- StoreCatalogInheritance(relationId, inheritList);
-
- /*
- * create an archive relation if necessary
- */
- if (archChar != 'n')
- {
- TupleDesc tupdesc;
+
+ /* ----------------
+ * create a relation descriptor from the relation schema
+ * and create the relation.
+ * ----------------
+ */
+ descriptor = BuildDescForRelation(schema, relname);
+
+ if (constraints != NIL)
+ {
+ List *entry;
+ int nconstr = length(constraints);
+ ConstrCheck *check = (ConstrCheck *) palloc(nconstr * sizeof(ConstrCheck));
+ int ncheck = 0;
+ int i;
+
+ foreach(entry, constraints)
+ {
+ ConstraintDef *cdef = (ConstraintDef *) lfirst(entry);
+
+ if (cdef->type == CONSTR_CHECK)
+ {
+ if (cdef->name != NULL)
+ {
+ for (i = 0; i < ncheck; i++)
+ {
+ if (strcmp(check[i].ccname, cdef->name) == 0)
+ elog(WARN, "DefineRelation: name (%s) of CHECK constraint duplicated", cdef->name);
+ }
+ check[ncheck].ccname = cdef->name;
+ }
+ else
+ {
+ check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
+ sprintf(check[ncheck].ccname, "$%d", ncheck + 1);
+ }
+ check[ncheck].ccbin = NULL;
+ check[ncheck].ccsrc = (char *) cdef->def;
+ ncheck++;
+ }
+ }
+ if (ncheck > 0)
+ {
+ if (ncheck < nconstr)
+ check = (ConstrCheck *) repalloc(check, ncheck * sizeof(ConstrCheck));
+ if (descriptor->constr == NULL)
+ {
+ descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
+ descriptor->constr->num_defval = 0;
+ descriptor->constr->has_not_null = false;
+ }
+ descriptor->constr->num_check = ncheck;
+ descriptor->constr->check = check;
+ }
+ }
+
+ relationId = heap_create(relname,
+ typename,
+ archChar,
+ heaploc,
+ descriptor);
+
+ StoreCatalogInheritance(relationId, inheritList);
+
/*
- * Need to create an archive relation for this heap relation.
- * We cobble up the command by hand, and increment the command
- * counter ourselves.
+ * create an archive relation if necessary
*/
-
- CommandCounterIncrement();
- archiveName = MakeArchiveName(relationId);
-
- tupdesc = CreateTupleDescCopy (descriptor); /* get rid of constraints */
- (void) heap_create(archiveName,
- typename,
- 'n', /* archive isn't archived */
- archloc,
- tupdesc);
-
- FreeTupleDesc (tupdesc);
- FreeTupleDesc (descriptor);
- pfree(archiveName);
- }
+ if (archChar != 'n')
+ {
+ TupleDesc tupdesc;
+
+ /*
+ * Need to create an archive relation for this heap relation. We
+ * cobble up the command by hand, and increment the command
+ * counter ourselves.
+ */
+
+ CommandCounterIncrement();
+ archiveName = MakeArchiveName(relationId);
+
+ tupdesc = CreateTupleDescCopy(descriptor); /* get rid of
+ * constraints */
+ (void) heap_create(archiveName,
+ typename,
+ 'n', /* archive isn't archived */
+ archloc,
+ tupdesc);
+
+ FreeTupleDesc(tupdesc);
+ FreeTupleDesc(descriptor);
+ pfree(archiveName);
+ }
}
/*
* RemoveRelation --
- * Deletes a new relation.
+ * Deletes a new relation.
*
* Exceptions:
- * BadArg if name is invalid.
+ * BadArg if name is invalid.
*
* Note:
- * If the relation has indices defined on it, then the index relations
+ * If the relation has indices defined on it, then the index relations
* themselves will be destroyed, too.
*/
void
RemoveRelation(char *name)
{
- AssertArg(name);
- heap_destroy(name);
+ AssertArg(name);
+ heap_destroy(name);
}
/*
* MergeAttributes --
- * Returns new schema given initial schema and supers.
+ * Returns new schema given initial schema and supers.
*
*
* 'schema' is the column/attribute definition for the table. (It's a list
- * of ColumnDef's.) It is destructively changed.
+ * of ColumnDef's.) It is destructively changed.
* 'inheritList' is the list of inherited relations (a list of Value(str)'s).
*
* Notes:
- * The order in which the attributes are inherited is very important.
- * Intuitively, the inherited attributes should come first. If a table
- * inherits from multiple parents, the order of those attributes are
- * according to the order of the parents specified in CREATE TABLE.
+ * The order in which the attributes are inherited is very important.
+ * Intuitively, the inherited attributes should come first. If a table
+ * inherits from multiple parents, the order of those attributes are
+ * according to the order of the parents specified in CREATE TABLE.
*
- * Here's an example:
+ * Here's an example:
*
- * create table person (name text, age int4, location point);
- * create table emp (salary int4, manager char16) inherits(person);
- * create table student (gpa float8) inherits (person);
- * create table stud_emp (percent int4) inherits (emp, student);
+ * create table person (name text, age int4, location point);
+ * create table emp (salary int4, manager char16) inherits(person);
+ * create table student (gpa float8) inherits (person);
+ * create table stud_emp (percent int4) inherits (emp, student);
*
- * the order of the attributes of stud_emp is as follow:
+ * the order of the attributes of stud_emp is as follow:
*
*
- * person {1:name, 2:age, 3:location}
- * / \
- * {6:gpa} student emp {4:salary, 5:manager}
- * \ /
- * stud_emp {7:percent}
+ * person {1:name, 2:age, 3:location}
+ * / \
+ * {6:gpa} student emp {4:salary, 5:manager}
+ * \ /
+ * stud_emp {7:percent}
*/
-static List *
-MergeAttributes(List *schema, List *supers, List **supconstr)
+static List *
+MergeAttributes(List * schema, List * supers, List ** supconstr)
{
- List *entry;
- List *inhSchema = NIL;
- List *constraints = NIL;
-
- /*
- * Validates that there are no duplications.
- * Validity checking of types occurs later.
- */
- foreach (entry, schema) {
- List *rest;
- ColumnDef *coldef = lfirst(entry);
-
- foreach (rest, lnext(entry)) {
- /*
- * check for duplicated relation names
- */
- ColumnDef *restdef = lfirst(rest);
-
- if (!strcmp(coldef->colname, restdef->colname)) {
- elog(WARN, "attribute \"%s\" duplicated",
- coldef->colname);
- }
- }
- }
- foreach (entry, supers) {
- List *rest;
-
- foreach (rest, lnext(entry)) {
- if (!strcmp(strVal(lfirst(entry)), strVal(lfirst(rest)))) {
- elog(WARN, "relation \"%s\" duplicated",
- strVal(lfirst(entry)));
- }
- }
- }
-
- /*
- * merge the inherited attributes into the schema
- */
- foreach (entry, supers) {
- char *name = strVal(lfirst(entry));
- Relation relation;
- List *partialResult = NIL;
- AttrNumber attrno;
- TupleDesc tupleDesc;
- TupleConstr *constr;
-
- relation = heap_openr(name);
- if (relation==NULL) {
- elog(WARN,
- "MergeAttr: Can't inherit from non-existent superclass '%s'",
- name);
- }
- if ( relation->rd_rel->relkind == 'S' )
+ List *entry;
+ List *inhSchema = NIL;
+ List *constraints = NIL;
+
+ /*
+ * Validates that there are no duplications. Validity checking of
+ * types occurs later.
+ */
+ foreach(entry, schema)
{
- elog(WARN, "MergeAttr: Can't inherit from sequence superclass '%s'",
- name);
- }
- tupleDesc = RelationGetTupleDescriptor(relation);
- constr = tupleDesc->constr;
-
- for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--) {
- AttributeTupleForm attribute = tupleDesc->attrs[attrno];
- char *attributeName;
- char *attributeType;
- HeapTuple tuple;
- ColumnDef *def;
- TypeName *typename;
-
- /*
- * form name, type and constraints
- */
- attributeName = (attribute->attname).data;
- tuple =
- SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(attribute->atttypid),
- 0,0,0);
- AssertState(HeapTupleIsValid(tuple));
- attributeType =
- (((TypeTupleForm)GETSTRUCT(tuple))->typname).data;
- /*
- * check validity
- *
- */
- if (checkAttrExists(attributeName, attributeType, inhSchema) ||
- checkAttrExists(attributeName, attributeType, schema)) {
- /*
- * this entry already exists
- */
- continue;
- }
-
- /*
- * add an entry to the schema
- */
- def = makeNode(ColumnDef);
- typename = makeNode(TypeName);
- def->colname = pstrdup(attributeName);
- typename->name = pstrdup(attributeType);
- def->typename = typename;
- def->is_not_null = attribute->attnotnull;
- def->defval = NULL;
- if ( attribute->atthasdef )
- {
- AttrDefault *attrdef = constr->defval;
- int i;
-
- Assert ( constr != NULL && constr->num_defval > 0 );
-
- for (i = 0; i < constr->num_defval; i++)
- {
- if ( attrdef[i].adnum != attrno + 1 )
- continue;
- def->defval = pstrdup (attrdef[i].adsrc);
- break;
- }
- Assert ( def->defval != NULL );
- }
- partialResult = lcons(def, partialResult);
+ List *rest;
+ ColumnDef *coldef = lfirst(entry);
+
+ foreach(rest, lnext(entry))
+ {
+
+ /*
+ * check for duplicated relation names
+ */
+ ColumnDef *restdef = lfirst(rest);
+
+ if (!strcmp(coldef->colname, restdef->colname))
+ {
+ elog(WARN, "attribute \"%s\" duplicated",
+ coldef->colname);
+ }
+ }
}
-
- if ( constr && constr->num_check > 0 )
+ foreach(entry, supers)
{
- ConstrCheck *check = constr->check;
- int i;
-
- for (i = 0; i < constr->num_check; i++)
- {
- ConstraintDef *cdef = (ConstraintDef *) palloc (sizeof (ConstraintDef));
-
- cdef->type = CONSTR_CHECK;
- if ( check[i].ccname[0] == '$' )
- cdef->name = NULL;
- else
- cdef->name = pstrdup (check[i].ccname);
- cdef->def = (void*) pstrdup (check[i].ccsrc);
- constraints = lappend (constraints, cdef);
- }
+ List *rest;
+
+ foreach(rest, lnext(entry))
+ {
+ if (!strcmp(strVal(lfirst(entry)), strVal(lfirst(rest))))
+ {
+ elog(WARN, "relation \"%s\" duplicated",
+ strVal(lfirst(entry)));
+ }
+ }
}
-
+
/*
- * iteration cleanup and result collection
+ * merge the inherited attributes into the schema
*/
- heap_close(relation);
+ foreach(entry, supers)
+ {
+ char *name = strVal(lfirst(entry));
+ Relation relation;
+ List *partialResult = NIL;
+ AttrNumber attrno;
+ TupleDesc tupleDesc;
+ TupleConstr *constr;
+
+ relation = heap_openr(name);
+ if (relation == NULL)
+ {
+ elog(WARN,
+ "MergeAttr: Can't inherit from non-existent superclass '%s'",
+ name);
+ }
+ if (relation->rd_rel->relkind == 'S')
+ {
+ elog(WARN, "MergeAttr: Can't inherit from sequence superclass '%s'",
+ name);
+ }
+ tupleDesc = RelationGetTupleDescriptor(relation);
+ constr = tupleDesc->constr;
+
+ for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--)
+ {
+ AttributeTupleForm attribute = tupleDesc->attrs[attrno];
+ char *attributeName;
+ char *attributeType;
+ HeapTuple tuple;
+ ColumnDef *def;
+ TypeName *typename;
+
+ /*
+ * form name, type and constraints
+ */
+ attributeName = (attribute->attname).data;
+ tuple =
+ SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(attribute->atttypid),
+ 0, 0, 0);
+ AssertState(HeapTupleIsValid(tuple));
+ attributeType =
+ (((TypeTupleForm) GETSTRUCT(tuple))->typname).data;
+
+ /*
+ * check validity
+ *
+ */
+ if (checkAttrExists(attributeName, attributeType, inhSchema) ||
+ checkAttrExists(attributeName, attributeType, schema))
+ {
+
+ /*
+ * this entry already exists
+ */
+ continue;
+ }
+
+ /*
+ * add an entry to the schema
+ */
+ def = makeNode(ColumnDef);
+ typename = makeNode(TypeName);
+ def->colname = pstrdup(attributeName);
+ typename->name = pstrdup(attributeType);
+ def->typename = typename;
+ def->is_not_null = attribute->attnotnull;
+ def->defval = NULL;
+ if (attribute->atthasdef)
+ {
+ AttrDefault *attrdef = constr->defval;
+ int i;
+
+ Assert(constr != NULL && constr->num_defval > 0);
+
+ for (i = 0; i < constr->num_defval; i++)
+ {
+ if (attrdef[i].adnum != attrno + 1)
+ continue;
+ def->defval = pstrdup(attrdef[i].adsrc);
+ break;
+ }
+ Assert(def->defval != NULL);
+ }
+ partialResult = lcons(def, partialResult);
+ }
+
+ if (constr && constr->num_check > 0)
+ {
+ ConstrCheck *check = constr->check;
+ int i;
+
+ for (i = 0; i < constr->num_check; i++)
+ {
+ ConstraintDef *cdef = (ConstraintDef *) palloc(sizeof(ConstraintDef));
+
+ cdef->type = CONSTR_CHECK;
+ if (check[i].ccname[0] == '$')
+ cdef->name = NULL;
+ else
+ cdef->name = pstrdup(check[i].ccname);
+ cdef->def = (void *) pstrdup(check[i].ccsrc);
+ constraints = lappend(constraints, cdef);
+ }
+ }
+
+ /*
+ * iteration cleanup and result collection
+ */
+ heap_close(relation);
+
+ /*
+ * wants the inherited schema to appear in the order they are
+ * specified in CREATE TABLE
+ */
+ inhSchema = nconc(inhSchema, partialResult);
+ }
/*
- * wants the inherited schema to appear in the order they are
- * specified in CREATE TABLE
+ * put the inherited schema before our the schema for this table
*/
- inhSchema = nconc(inhSchema, partialResult);
- }
-
- /*
- * put the inherited schema before our the schema for this table
- */
- schema = nconc(inhSchema, schema);
- *supconstr = constraints;
- return (schema);
+ schema = nconc(inhSchema, schema);
+ *supconstr = constraints;
+ return (schema);
}
/*
* StoreCatalogInheritance --
- * Updates the system catalogs with proper inheritance information.
+ * Updates the system catalogs with proper inheritance information.
*/
static void
-StoreCatalogInheritance(Oid relationId, List *supers)
+StoreCatalogInheritance(Oid relationId, List * supers)
{
- Relation relation;
- TupleDesc desc;
- int16 seqNumber;
- List *entry;
- List *idList;
- HeapTuple tuple;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertArg(OidIsValid(relationId));
-
- if (supers==NIL)
- return;
-
- /* ----------------
- * Catalog INHERITS information.
- * ----------------
- */
- relation = heap_openr( InheritsRelationName );
- desc = RelationGetTupleDescriptor(relation);
-
- seqNumber = 1;
- idList = NIL;
- foreach (entry, supers) {
- Datum datum[ Natts_pg_inherits ];
- char nullarr[ Natts_pg_inherits ];
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(strVal(lfirst(entry))),
- 0,0,0);
- AssertArg(HeapTupleIsValid(tuple));
-
- /*
- * build idList for use below
- */
- idList = lappendi(idList, tuple->t_oid);
-
- datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
- datum[1] = ObjectIdGetDatum(tuple->t_oid); /* inhparent */
- datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
-
- nullarr[0] = ' ';
- nullarr[1] = ' ';
- nullarr[2] = ' ';
-
- tuple = heap_formtuple(desc,datum, nullarr);
-
- heap_insert(relation, tuple);
- pfree(tuple);
-
- seqNumber += 1;
- }
-
- heap_close(relation);
-
- /* ----------------
- * Catalog IPL information.
- *
- * Algorithm:
- * 0. list superclasses (by Oid) in order given (see idList).
- * 1. append after each relationId, its superclasses, recursively.
- * 3. remove all but last of duplicates.
- * 4. store result.
- * ----------------
- */
-
- /* ----------------
- * 1.
- * ----------------
- */
- foreach (entry, idList) {
+ Relation relation;
+ TupleDesc desc;
+ int16 seqNumber;
+ List *entry;
+ List *idList;
HeapTuple tuple;
- Oid id;
- int16 number;
- List *next;
- List *current;
-
- id = (Oid)lfirsti(entry);
- current = entry;
- next = lnext(entry);
-
- for (number = 1; ; number += 1) {
- tuple = SearchSysCacheTuple(INHRELID,
- ObjectIdGetDatum(id),
- Int16GetDatum(number),
- 0,0);
-
- if (! HeapTupleIsValid(tuple))
- break;
-
- lnext(current) =
- lconsi(((InheritsTupleForm)
- GETSTRUCT(tuple))->inhparent,
- NIL);
-
- current = lnext(current);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ AssertArg(OidIsValid(relationId));
+
+ if (supers == NIL)
+ return;
+
+ /* ----------------
+ * Catalog INHERITS information.
+ * ----------------
+ */
+ relation = heap_openr(InheritsRelationName);
+ desc = RelationGetTupleDescriptor(relation);
+
+ seqNumber = 1;
+ idList = NIL;
+ foreach(entry, supers)
+ {
+ Datum datum[Natts_pg_inherits];
+ char nullarr[Natts_pg_inherits];
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(strVal(lfirst(entry))),
+ 0, 0, 0);
+ AssertArg(HeapTupleIsValid(tuple));
+
+ /*
+ * build idList for use below
+ */
+ idList = lappendi(idList, tuple->t_oid);
+
+ datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
+ datum[1] = ObjectIdGetDatum(tuple->t_oid); /* inhparent */
+ datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
+
+ nullarr[0] = ' ';
+ nullarr[1] = ' ';
+ nullarr[2] = ' ';
+
+ tuple = heap_formtuple(desc, datum, nullarr);
+
+ heap_insert(relation, tuple);
+ pfree(tuple);
+
+ seqNumber += 1;
}
- lnext(current) = next;
- }
-
- /* ----------------
- * 2.
- * ----------------
- */
- foreach (entry, idList) {
- Oid name;
- List *rest;
- bool found = false;
-
- again:
- name = lfirsti(entry);
- foreach (rest, lnext(entry)) {
- if (name == lfirsti(rest)) {
- found = true;
- break;
- }
+
+ heap_close(relation);
+
+ /* ----------------
+ * Catalog IPL information.
+ *
+ * Algorithm:
+ * 0. list superclasses (by Oid) in order given (see idList).
+ * 1. append after each relationId, its superclasses, recursively.
+ * 3. remove all but last of duplicates.
+ * 4. store result.
+ * ----------------
+ */
+
+ /* ----------------
+ * 1.
+ * ----------------
+ */
+ foreach(entry, idList)
+ {
+ HeapTuple tuple;
+ Oid id;
+ int16 number;
+ List *next;
+ List *current;
+
+ id = (Oid) lfirsti(entry);
+ current = entry;
+ next = lnext(entry);
+
+ for (number = 1;; number += 1)
+ {
+ tuple = SearchSysCacheTuple(INHRELID,
+ ObjectIdGetDatum(id),
+ Int16GetDatum(number),
+ 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ break;
+
+ lnext(current) =
+ lconsi(((InheritsTupleForm)
+ GETSTRUCT(tuple))->inhparent,
+ NIL);
+
+ current = lnext(current);
+ }
+ lnext(current) = next;
}
- if (found) {
- /*
- * entry list must be of length >= 2 or else no match
- *
- * so, remove this entry.
- */
- lfirst(entry) = lfirst(lnext(entry));
- lnext(entry) = lnext(lnext(entry));
-
- found = false;
- goto again;
+
+ /* ----------------
+ * 2.
+ * ----------------
+ */
+ foreach(entry, idList)
+ {
+ Oid name;
+ List *rest;
+ bool found = false;
+
+again:
+ name = lfirsti(entry);
+ foreach(rest, lnext(entry))
+ {
+ if (name == lfirsti(rest))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ {
+
+ /*
+ * entry list must be of length >= 2 or else no match
+ *
+ * so, remove this entry.
+ */
+ lfirst(entry) = lfirst(lnext(entry));
+ lnext(entry) = lnext(lnext(entry));
+
+ found = false;
+ goto again;
+ }
}
- }
-
- /* ----------------
- * 3.
- * ----------------
- */
- relation = heap_openr( InheritancePrecidenceListRelationName );
- desc = RelationGetTupleDescriptor(relation);
-
- seqNumber = 1;
-
- foreach (entry, idList) {
- Datum datum[ Natts_pg_ipl ];
- char nullarr[ Natts_pg_ipl ];
-
- datum[0] = ObjectIdGetDatum(relationId); /* iplrel */
- datum[1] = ObjectIdGetDatum(lfirsti(entry));
- /*iplinherits*/
- datum[2] = Int16GetDatum(seqNumber); /* iplseqno */
-
- nullarr[0] = ' ';
- nullarr[1] = ' ';
- nullarr[2] = ' ';
-
- tuple = heap_formtuple( desc, datum, nullarr);
-
- heap_insert(relation, tuple);
- pfree(tuple);
-
- seqNumber += 1;
- }
-
- heap_close(relation);
+
+ /* ----------------
+ * 3.
+ * ----------------
+ */
+ relation = heap_openr(InheritancePrecidenceListRelationName);
+ desc = RelationGetTupleDescriptor(relation);
+
+ seqNumber = 1;
+
+ foreach(entry, idList)
+ {
+ Datum datum[Natts_pg_ipl];
+ char nullarr[Natts_pg_ipl];
+
+ datum[0] = ObjectIdGetDatum(relationId); /* iplrel */
+ datum[1] = ObjectIdGetDatum(lfirsti(entry));
+ /* iplinherits */
+ datum[2] = Int16GetDatum(seqNumber); /* iplseqno */
+
+ nullarr[0] = ' ';
+ nullarr[1] = ' ';
+ nullarr[2] = ' ';
+
+ tuple = heap_formtuple(desc, datum, nullarr);
+
+ heap_insert(relation, tuple);
+ pfree(tuple);
+
+ seqNumber += 1;
+ }
+
+ heap_close(relation);
}
/*
* returns 1 if attribute already exists in schema, 0 otherwise.
*/
static int
-checkAttrExists(char *attributeName, char *attributeType, List *schema)
+checkAttrExists(char *attributeName, char *attributeType, List * schema)
{
- List *s;
-
- foreach (s, schema) {
- ColumnDef *def = lfirst(s);
-
- if (!strcmp(attributeName, def->colname)) {
- /*
- * attribute exists. Make sure the types are the same.
- */
- if (strcmp(attributeType, def->typename->name) != 0) {
- elog(WARN, "%s and %s conflict for %s",
- attributeType, def->typename->name, attributeName);
- }
- return 1;
+ List *s;
+
+ foreach(s, schema)
+ {
+ ColumnDef *def = lfirst(s);
+
+ if (!strcmp(attributeName, def->colname))
+ {
+
+ /*
+ * attribute exists. Make sure the types are the same.
+ */
+ if (strcmp(attributeType, def->typename->name) != 0)
+ {
+ elog(WARN, "%s and %s conflict for %s",
+ attributeType, def->typename->name, attributeName);
+ }
+ return 1;
+ }
}
- }
- return 0;
+ return 0;
}
/*
* MakeArchiveName
- * make an archive rel name out of a regular rel name
+ * make an archive rel name out of a regular rel name
*
* the CALLER is responsible for freeing the memory allocated
*/
-char*
+char *
MakeArchiveName(Oid relationId)
{
- char *arch;
+ char *arch;
- /*
- * Archive relations are named a,XXXXX where XXXXX == the OID
- * of the relation they archive. Create a string containing
- * this name and find the reldesc for the archive relation.
- */
- arch = palloc(NAMEDATALEN);
- sprintf(arch, "a,%d",relationId);
+ /*
+ * Archive relations are named a,XXXXX where XXXXX == the OID of the
+ * relation they archive. Create a string containing this name and
+ * find the reldesc for the archive relation.
+ */
+ arch = palloc(NAMEDATALEN);
+ sprintf(arch, "a,%d", relationId);
- return arch;
+ return arch;
}
diff --git a/src/backend/commands/defind.c b/src/backend/commands/defind.c
index c6b293fec68..9b8c5a0218a 100644
--- a/src/backend/commands/defind.c
+++ b/src/backend/commands/defind.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* defind.c--
- * POSTGRES define, extend and remove index code.
+ * POSTGRES define, extend and remove index code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.12 1997/03/26 03:05:28 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.13 1997/09/07 04:40:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,7 +30,7 @@
#include <utils/relcache.h>
#include <utils/lsyscache.h>
#include <commands/defrem.h>
-#include <parser/parsetree.h> /* for getrelid() */
+#include <parser/parsetree.h> /* for getrelid() */
#include <optimizer/prep.h>
#include <optimizer/clauses.h>
#include <storage/lmgr.h>
@@ -39,508 +39,543 @@
#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args!=NULL)
/* non-export function prototypes */
-static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
-static void CheckPredExpr(Node *predicate, List *rangeTable,
+static void CheckPredicate(List * predList, List * rangeTable, Oid baseRelOid);
+static void
+CheckPredExpr(Node * predicate, List * rangeTable,
Oid baseRelOid);
static void
-CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
-static void FuncIndexArgs(IndexElem *funcIndex, AttrNumber *attNumP,
- Oid *argTypes, Oid *opOidP, Oid relId);
-static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
- Oid *opOidP, Oid relId);
-static char *GetDefaultOpClass(Oid atttypid);
+ CheckPredClause(Expr * predicate, List * rangeTable, Oid baseRelOid);
+static void
+FuncIndexArgs(IndexElem * funcIndex, AttrNumber * attNumP,
+ Oid * argTypes, Oid * opOidP, Oid relId);
+static void
+NormIndexAttrs(List * attList, AttrNumber * attNumP,
+ Oid * opOidP, Oid relId);
+static char *GetDefaultOpClass(Oid atttypid);
/*
* DefineIndex --
- * Creates a new index.
+ * Creates a new index.
*
* 'attributeList' is a list of IndexElem specifying either a functional
- * index or a list of attributes to index on.
+ * index or a list of attributes to index on.
* 'parameterList' is a list of ParamString specified in the with clause.
* 'predicate' is the qual specified in the where clause.
* 'rangetable' is for the predicate
*
* Exceptions:
- * XXX
+ * XXX
*/
void
DefineIndex(char *heapRelationName,
- char *indexRelationName,
- char *accessMethodName,
- List *attributeList,
- List *parameterList,
- bool unique,
- Expr *predicate,
- List *rangetable)
+ char *indexRelationName,
+ char *accessMethodName,
+ List * attributeList,
+ List * parameterList,
+ bool unique,
+ Expr * predicate,
+ List * rangetable)
{
- Oid *classObjectId;
- Oid accessMethodId;
- Oid relationId;
- int numberOfAttributes;
- AttrNumber *attributeNumberA;
- HeapTuple tuple;
- uint16 parameterCount = 0;
- Datum *parameterA = NULL;
- FuncIndexInfo fInfo;
- List *cnfPred = NULL;
- bool lossy = FALSE;
- List *pl;
-
- /*
- * Handle attributes
- */
- numberOfAttributes = length(attributeList);
- if (numberOfAttributes <= 0) {
- elog(WARN, "DefineIndex: must specify at least one attribute");
- }
-
- /*
- * compute heap relation id
- */
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(heapRelationName),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "DefineIndex: %s relation not found",
- heapRelationName);
- }
- relationId = tuple->t_oid;
-
- if (unique && strcmp(accessMethodName,"btree") != 0)
- elog(WARN, "DefineIndex: unique indices are only available with the btree access method");
-
- if (numberOfAttributes > 1 && strcmp(accessMethodName,"btree") != 0)
- elog(WARN, "DefineIndex: multi-column indices are only available with the btree access method");
-
- /*
- * compute access method id
- */
- tuple = SearchSysCacheTuple(AMNAME, PointerGetDatum(accessMethodName),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "DefineIndex: %s access method not found",
- accessMethodName);
- }
- accessMethodId = tuple->t_oid;
-
-
- /*
- * Handle parameters
- * [param list is now different (NOT USED, really) - ay 10/94]
- *
- * WITH clause reinstated to handle lossy indices.
- * -- JMH, 7/22/96
- */
- foreach(pl, parameterList) {
- ParamString *param = (ParamString*)lfirst(pl);
-
- if (!strcasecmp(param->name, "islossy"))
- lossy = TRUE;
- }
-
-
- /*
- * Convert the partial-index predicate from parsetree form to plan
- * form, so it can be readily evaluated during index creation.
- * Note: "predicate" comes in as a list containing (1) the predicate
- * itself (a where_clause), and (2) a corresponding range table.
- *
- * [(1) is 'predicate' and (2) is 'rangetable' now. - ay 10/94]
- */
- if (predicate != NULL && rangetable != NIL) {
- cnfPred = cnfify((Expr*)copyObject(predicate), true);
- fix_opids(cnfPred);
- CheckPredicate(cnfPred, rangetable, relationId);
- }
-
- if (IsFuncIndex(attributeList)) {
- IndexElem *funcIndex= lfirst(attributeList);
- int nargs;
-
- nargs = length(funcIndex->args);
- if (nargs > INDEX_MAX_KEYS) {
- elog(WARN,
- "Too many args to function, limit of %d",
- INDEX_MAX_KEYS);
+ Oid *classObjectId;
+ Oid accessMethodId;
+ Oid relationId;
+ int numberOfAttributes;
+ AttrNumber *attributeNumberA;
+ HeapTuple tuple;
+ uint16 parameterCount = 0;
+ Datum *parameterA = NULL;
+ FuncIndexInfo fInfo;
+ List *cnfPred = NULL;
+ bool lossy = FALSE;
+ List *pl;
+
+ /*
+ * Handle attributes
+ */
+ numberOfAttributes = length(attributeList);
+ if (numberOfAttributes <= 0)
+ {
+ elog(WARN, "DefineIndex: must specify at least one attribute");
+ }
+
+ /*
+ * compute heap relation id
+ */
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(heapRelationName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "DefineIndex: %s relation not found",
+ heapRelationName);
}
-
- FIsetnArgs(&fInfo,nargs);
+ relationId = tuple->t_oid;
- strcpy(FIgetname(&fInfo), funcIndex->name);
+ if (unique && strcmp(accessMethodName, "btree") != 0)
+ elog(WARN, "DefineIndex: unique indices are only available with the btree access method");
- attributeNumberA =
- (AttrNumber *)palloc(nargs * sizeof attributeNumberA[0]);
-
- classObjectId = (Oid *)palloc(sizeof classObjectId[0]);
-
-
- FuncIndexArgs(funcIndex, attributeNumberA,
- &(FIgetArg(&fInfo, 0)),
- classObjectId, relationId);
-
- index_create(heapRelationName,
- indexRelationName,
- &fInfo, NULL, accessMethodId,
- numberOfAttributes, attributeNumberA,
- classObjectId, parameterCount, parameterA, (Node*)cnfPred,
- lossy, unique);
- }else {
- attributeNumberA =
- (AttrNumber *)palloc(numberOfAttributes *
- sizeof attributeNumberA[0]);
-
- classObjectId =
- (Oid *)palloc(numberOfAttributes * sizeof classObjectId[0]);
-
- NormIndexAttrs(attributeList, attributeNumberA,
- classObjectId, relationId);
-
- index_create(heapRelationName, indexRelationName, NULL,
- attributeList,
- accessMethodId, numberOfAttributes, attributeNumberA,
- classObjectId, parameterCount, parameterA, (Node*)cnfPred,
- lossy, unique);
- }
+ if (numberOfAttributes > 1 && strcmp(accessMethodName, "btree") != 0)
+ elog(WARN, "DefineIndex: multi-column indices are only available with the btree access method");
+
+ /*
+ * compute access method id
+ */
+ tuple = SearchSysCacheTuple(AMNAME, PointerGetDatum(accessMethodName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "DefineIndex: %s access method not found",
+ accessMethodName);
+ }
+ accessMethodId = tuple->t_oid;
+
+
+ /*
+ * Handle parameters [param list is now different (NOT USED, really) -
+ * ay 10/94]
+ *
+ * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
+ */
+ foreach(pl, parameterList)
+ {
+ ParamString *param = (ParamString *) lfirst(pl);
+
+ if (!strcasecmp(param->name, "islossy"))
+ lossy = TRUE;
+ }
+
+
+ /*
+ * Convert the partial-index predicate from parsetree form to plan
+ * form, so it can be readily evaluated during index creation. Note:
+ * "predicate" comes in as a list containing (1) the predicate itself
+ * (a where_clause), and (2) a corresponding range table.
+ *
+ * [(1) is 'predicate' and (2) is 'rangetable' now. - ay 10/94]
+ */
+ if (predicate != NULL && rangetable != NIL)
+ {
+ cnfPred = cnfify((Expr *) copyObject(predicate), true);
+ fix_opids(cnfPred);
+ CheckPredicate(cnfPred, rangetable, relationId);
+ }
+
+ if (IsFuncIndex(attributeList))
+ {
+ IndexElem *funcIndex = lfirst(attributeList);
+ int nargs;
+
+ nargs = length(funcIndex->args);
+ if (nargs > INDEX_MAX_KEYS)
+ {
+ elog(WARN,
+ "Too many args to function, limit of %d",
+ INDEX_MAX_KEYS);
+ }
+
+ FIsetnArgs(&fInfo, nargs);
+
+ strcpy(FIgetname(&fInfo), funcIndex->name);
+
+ attributeNumberA =
+ (AttrNumber *) palloc(nargs * sizeof attributeNumberA[0]);
+
+ classObjectId = (Oid *) palloc(sizeof classObjectId[0]);
+
+
+ FuncIndexArgs(funcIndex, attributeNumberA,
+ &(FIgetArg(&fInfo, 0)),
+ classObjectId, relationId);
+
+ index_create(heapRelationName,
+ indexRelationName,
+ &fInfo, NULL, accessMethodId,
+ numberOfAttributes, attributeNumberA,
+ classObjectId, parameterCount, parameterA, (Node *) cnfPred,
+ lossy, unique);
+ }
+ else
+ {
+ attributeNumberA =
+ (AttrNumber *) palloc(numberOfAttributes *
+ sizeof attributeNumberA[0]);
+
+ classObjectId =
+ (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
+
+ NormIndexAttrs(attributeList, attributeNumberA,
+ classObjectId, relationId);
+
+ index_create(heapRelationName, indexRelationName, NULL,
+ attributeList,
+ accessMethodId, numberOfAttributes, attributeNumberA,
+ classObjectId, parameterCount, parameterA, (Node *) cnfPred,
+ lossy, unique);
+ }
}
/*
* ExtendIndex --
- * Extends a partial index.
+ * Extends a partial index.
*
* Exceptions:
- * XXX
+ * XXX
*/
void
-ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
+ExtendIndex(char *indexRelationName, Expr * predicate, List * rangetable)
{
- Oid *classObjectId;
- Oid accessMethodId;
- Oid indexId, relationId;
- Oid indproc;
- int numberOfAttributes;
- AttrNumber *attributeNumberA;
- HeapTuple tuple;
- FuncIndexInfo fInfo;
- FuncIndexInfo *funcInfo = NULL;
- IndexTupleForm index;
- Node *oldPred = NULL;
- List *cnfPred = NULL;
- PredInfo *predInfo;
- Relation heapRelation;
- Relation indexRelation;
- int i;
-
- /*
- * compute index relation id and access method id
- */
- tuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(indexRelationName),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "ExtendIndex: %s index not found",
- indexRelationName);
- }
- indexId = tuple->t_oid;
- accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
-
- /*
- * find pg_index tuple
- */
- tuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(indexId),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "ExtendIndex: %s is not an index",
- indexRelationName);
- }
-
- /*
- * Extract info from the pg_index tuple
- */
- index = (IndexTupleForm)GETSTRUCT(tuple);
- Assert(index->indexrelid == indexId);
- relationId = index->indrelid;
- indproc = index->indproc;
-
- for (i=0; i<INDEX_MAX_KEYS; i++)
- if (index->indkey[i] == 0) break;
- numberOfAttributes = i;
-
- if (VARSIZE(&index->indpred) != 0) {
- char *predString;
-
- predString = fmgr(F_TEXTOUT, &index->indpred);
- oldPred = stringToNode(predString);
- pfree(predString);
- }
- if (oldPred == NULL)
- elog(WARN, "ExtendIndex: %s is not a partial index",
- indexRelationName);
-
- /*
- * Convert the extension predicate from parsetree form to plan
- * form, so it can be readily evaluated during index creation.
- * Note: "predicate" comes in as a list containing (1) the predicate
- * itself (a where_clause), and (2) a corresponding range table.
- */
- if (rangetable != NIL) {
- cnfPred = cnfify((Expr*)copyObject(predicate), true);
- fix_opids(cnfPred);
- CheckPredicate(cnfPred, rangetable, relationId);
- }
-
- /* make predInfo list to pass to index_build */
- predInfo = (PredInfo*)palloc(sizeof(PredInfo));
- predInfo->pred = (Node*)cnfPred;
- predInfo->oldPred = oldPred;
-
- attributeNumberA =
- (AttrNumber *)palloc(numberOfAttributes*
- sizeof attributeNumberA[0]);
- classObjectId =
- (Oid *)palloc(numberOfAttributes * sizeof classObjectId[0]);
-
-
- for (i=0; i<numberOfAttributes; i++) {
- attributeNumberA[i] = index->indkey[i];
- classObjectId[i] = index->indclass[i];
- }
-
- if (indproc != InvalidOid) {
- funcInfo = &fInfo;
-/* FIgetnArgs(funcInfo) = numberOfAttributes; */
- FIsetnArgs(funcInfo,numberOfAttributes);
-
- tuple = SearchSysCacheTuple(PROOID,
- ObjectIdGetDatum(indproc),
- 0,0,0);
+ Oid *classObjectId;
+ Oid accessMethodId;
+ Oid indexId,
+ relationId;
+ Oid indproc;
+ int numberOfAttributes;
+ AttrNumber *attributeNumberA;
+ HeapTuple tuple;
+ FuncIndexInfo fInfo;
+ FuncIndexInfo *funcInfo = NULL;
+ IndexTupleForm index;
+ Node *oldPred = NULL;
+ List *cnfPred = NULL;
+ PredInfo *predInfo;
+ Relation heapRelation;
+ Relation indexRelation;
+ int i;
+
+ /*
+ * compute index relation id and access method id
+ */
+ tuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(indexRelationName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "ExtendIndex: %s index not found",
+ indexRelationName);
+ }
+ indexId = tuple->t_oid;
+ accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
+
+ /*
+ * find pg_index tuple
+ */
+ tuple = SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(indexId),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(WARN, "ExtendIndex: index procedure not found");
-
- namecpy(&(funcInfo->funcName),
- &(((Form_pg_proc) GETSTRUCT(tuple))->proname));
-
- FIsetProcOid(funcInfo,tuple->t_oid);
- }
-
- heapRelation = heap_open(relationId);
- indexRelation = index_open(indexId);
-
- RelationSetLockForWrite(heapRelation);
-
- InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
-
- index_build(heapRelation, indexRelation, numberOfAttributes,
- attributeNumberA, 0, NULL, funcInfo, predInfo);
+ {
+ elog(WARN, "ExtendIndex: %s is not an index",
+ indexRelationName);
+ }
+
+ /*
+ * Extract info from the pg_index tuple
+ */
+ index = (IndexTupleForm) GETSTRUCT(tuple);
+ Assert(index->indexrelid == indexId);
+ relationId = index->indrelid;
+ indproc = index->indproc;
+
+ for (i = 0; i < INDEX_MAX_KEYS; i++)
+ if (index->indkey[i] == 0)
+ break;
+ numberOfAttributes = i;
+
+ if (VARSIZE(&index->indpred) != 0)
+ {
+ char *predString;
+
+ predString = fmgr(F_TEXTOUT, &index->indpred);
+ oldPred = stringToNode(predString);
+ pfree(predString);
+ }
+ if (oldPred == NULL)
+ elog(WARN, "ExtendIndex: %s is not a partial index",
+ indexRelationName);
+
+ /*
+ * Convert the extension predicate from parsetree form to plan form,
+ * so it can be readily evaluated during index creation. Note:
+ * "predicate" comes in as a list containing (1) the predicate itself
+ * (a where_clause), and (2) a corresponding range table.
+ */
+ if (rangetable != NIL)
+ {
+ cnfPred = cnfify((Expr *) copyObject(predicate), true);
+ fix_opids(cnfPred);
+ CheckPredicate(cnfPred, rangetable, relationId);
+ }
+
+ /* make predInfo list to pass to index_build */
+ predInfo = (PredInfo *) palloc(sizeof(PredInfo));
+ predInfo->pred = (Node *) cnfPred;
+ predInfo->oldPred = oldPred;
+
+ attributeNumberA =
+ (AttrNumber *) palloc(numberOfAttributes *
+ sizeof attributeNumberA[0]);
+ classObjectId =
+ (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
+
+
+ for (i = 0; i < numberOfAttributes; i++)
+ {
+ attributeNumberA[i] = index->indkey[i];
+ classObjectId[i] = index->indclass[i];
+ }
+
+ if (indproc != InvalidOid)
+ {
+ funcInfo = &fInfo;
+/* FIgetnArgs(funcInfo) = numberOfAttributes; */
+ FIsetnArgs(funcInfo, numberOfAttributes);
+
+ tuple = SearchSysCacheTuple(PROOID,
+ ObjectIdGetDatum(indproc),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(WARN, "ExtendIndex: index procedure not found");
+
+ namecpy(&(funcInfo->funcName),
+ &(((Form_pg_proc) GETSTRUCT(tuple))->proname));
+
+ FIsetProcOid(funcInfo, tuple->t_oid);
+ }
+
+ heapRelation = heap_open(relationId);
+ indexRelation = index_open(indexId);
+
+ RelationSetLockForWrite(heapRelation);
+
+ InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
+
+ index_build(heapRelation, indexRelation, numberOfAttributes,
+ attributeNumberA, 0, NULL, funcInfo, predInfo);
}
/*
* CheckPredicate
- * Checks that the given list of partial-index predicates refer
- * (via the given range table) only to the given base relation oid,
- * and that they're in a form the planner can handle, i.e.,
- * boolean combinations of "ATTR OP CONST" (yes, for now, the ATTR
- * has to be on the left).
+ * Checks that the given list of partial-index predicates refer
+ * (via the given range table) only to the given base relation oid,
+ * and that they're in a form the planner can handle, i.e.,
+ * boolean combinations of "ATTR OP CONST" (yes, for now, the ATTR
+ * has to be on the left).
*/
static void
-CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
+CheckPredicate(List * predList, List * rangeTable, Oid baseRelOid)
{
- List *item;
-
- foreach (item, predList) {
- CheckPredExpr(lfirst(item), rangeTable, baseRelOid);
- }
+ List *item;
+
+ foreach(item, predList)
+ {
+ CheckPredExpr(lfirst(item), rangeTable, baseRelOid);
+ }
}
static void
-CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid)
+CheckPredExpr(Node * predicate, List * rangeTable, Oid baseRelOid)
{
- List *clauses = NIL, *clause;
-
- if (is_opclause(predicate)) {
- CheckPredClause((Expr*)predicate, rangeTable, baseRelOid);
- return;
- } else if (or_clause(predicate))
- clauses = ((Expr*)predicate)->args;
- else if (and_clause(predicate))
- clauses = ((Expr*)predicate)->args;
- else
- elog(WARN, "Unsupported partial-index predicate expression type");
-
- foreach (clause, clauses) {
- CheckPredExpr(lfirst(clause), rangeTable, baseRelOid);
- }
+ List *clauses = NIL,
+ *clause;
+
+ if (is_opclause(predicate))
+ {
+ CheckPredClause((Expr *) predicate, rangeTable, baseRelOid);
+ return;
+ }
+ else if (or_clause(predicate))
+ clauses = ((Expr *) predicate)->args;
+ else if (and_clause(predicate))
+ clauses = ((Expr *) predicate)->args;
+ else
+ elog(WARN, "Unsupported partial-index predicate expression type");
+
+ foreach(clause, clauses)
+ {
+ CheckPredExpr(lfirst(clause), rangeTable, baseRelOid);
+ }
}
static void
-CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
+CheckPredClause(Expr * predicate, List * rangeTable, Oid baseRelOid)
{
- Var *pred_var;
- Const *pred_const;
-
- pred_var = (Var *)get_leftop(predicate);
- pred_const = (Const *)get_rightop(predicate);
-
- if (!IsA(predicate->oper,Oper) ||
- !IsA(pred_var,Var) ||
- !IsA(pred_const,Const)) {
- elog(WARN, "Unsupported partial-index predicate clause type");
- }
-
- if (getrelid(pred_var->varno, rangeTable) != baseRelOid)
- elog(WARN,
- "Partial-index predicates may refer only to the base relation");
+ Var *pred_var;
+ Const *pred_const;
+
+ pred_var = (Var *) get_leftop(predicate);
+ pred_const = (Const *) get_rightop(predicate);
+
+ if (!IsA(predicate->oper, Oper) ||
+ !IsA(pred_var, Var) ||
+ !IsA(pred_const, Const))
+ {
+ elog(WARN, "Unsupported partial-index predicate clause type");
+ }
+
+ if (getrelid(pred_var->varno, rangeTable) != baseRelOid)
+ elog(WARN,
+ "Partial-index predicates may refer only to the base relation");
}
-static void
-FuncIndexArgs(IndexElem *funcIndex,
- AttrNumber *attNumP,
- Oid *argTypes,
- Oid *opOidP,
- Oid relId)
+static void
+FuncIndexArgs(IndexElem * funcIndex,
+ AttrNumber * attNumP,
+ Oid * argTypes,
+ Oid * opOidP,
+ Oid relId)
{
- List *rest;
- HeapTuple tuple;
- AttributeTupleForm att;
-
- tuple = SearchSysCacheTuple(CLANAME,
- PointerGetDatum(funcIndex->class),
- 0,0,0);
-
- if (!HeapTupleIsValid(tuple))
+ List *rest;
+ HeapTuple tuple;
+ AttributeTupleForm att;
+
+ tuple = SearchSysCacheTuple(CLANAME,
+ PointerGetDatum(funcIndex->class),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
{
- elog(WARN, "DefineIndex: %s class not found",
- funcIndex->class);
+ elog(WARN, "DefineIndex: %s class not found",
+ funcIndex->class);
}
- *opOidP = tuple->t_oid;
-
- memset(argTypes, 0, 8 * sizeof(Oid));
-
- /*
- * process the function arguments
- */
- for (rest=funcIndex->args; rest != NIL; rest = lnext(rest)) {
- char *arg;
-
- arg = strVal(lfirst(rest));
-
- tuple = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relId),
- PointerGetDatum(arg),0,0);
-
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN,
- "DefineIndex: attribute \"%s\" not found",
- arg);
+ *opOidP = tuple->t_oid;
+
+ memset(argTypes, 0, 8 * sizeof(Oid));
+
+ /*
+ * process the function arguments
+ */
+ for (rest = funcIndex->args; rest != NIL; rest = lnext(rest))
+ {
+ char *arg;
+
+ arg = strVal(lfirst(rest));
+
+ tuple = SearchSysCacheTuple(ATTNAME,
+ ObjectIdGetDatum(relId),
+ PointerGetDatum(arg), 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN,
+ "DefineIndex: attribute \"%s\" not found",
+ arg);
+ }
+ att = (AttributeTupleForm) GETSTRUCT(tuple);
+ *attNumP++ = att->attnum;
+ *argTypes++ = att->atttypid;
}
- att = (AttributeTupleForm)GETSTRUCT(tuple);
- *attNumP++ = att->attnum;
- *argTypes++ = att->atttypid;
- }
}
-static void
-NormIndexAttrs(List *attList, /* list of IndexElem's */
- AttrNumber *attNumP,
- Oid *opOidP,
- Oid relId)
+static void
+NormIndexAttrs(List * attList, /* list of IndexElem's */
+ AttrNumber * attNumP,
+ Oid * opOidP,
+ Oid relId)
{
- List *rest;
- HeapTuple tuple;
-
- /*
- * process attributeList
- */
-
- for (rest=attList; rest != NIL; rest = lnext(rest)) {
- IndexElem *attribute;
- AttributeTupleForm attform;
-
- attribute = lfirst(rest);
-
- if (attribute->name == NULL)
- elog(WARN, "missing attribute for define index");
-
- tuple = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relId),
- PointerGetDatum(attribute->name),
- 0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN,
- "DefineIndex: attribute \"%s\" not found",
- attribute->name);
- }
+ List *rest;
+ HeapTuple tuple;
- attform = (AttributeTupleForm)GETSTRUCT(tuple);
- *attNumP++ = attform->attnum;
-
- if (attribute->class == NULL) {
- /* no operator class specified, so find the default */
- attribute->class = GetDefaultOpClass(attform->atttypid);
- if(attribute->class == NULL) {
- elog(WARN,
- "Can't find a default operator class for type %d.",
- attform->atttypid);
- }
- }
-
- tuple = SearchSysCacheTuple(CLANAME,
- PointerGetDatum(attribute->class),
- 0,0,0);
-
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "DefineIndex: %s class not found",
- attribute->class);
+ /*
+ * process attributeList
+ */
+
+ for (rest = attList; rest != NIL; rest = lnext(rest))
+ {
+ IndexElem *attribute;
+ AttributeTupleForm attform;
+
+ attribute = lfirst(rest);
+
+ if (attribute->name == NULL)
+ elog(WARN, "missing attribute for define index");
+
+ tuple = SearchSysCacheTuple(ATTNAME,
+ ObjectIdGetDatum(relId),
+ PointerGetDatum(attribute->name),
+ 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN,
+ "DefineIndex: attribute \"%s\" not found",
+ attribute->name);
+ }
+
+ attform = (AttributeTupleForm) GETSTRUCT(tuple);
+ *attNumP++ = attform->attnum;
+
+ if (attribute->class == NULL)
+ {
+ /* no operator class specified, so find the default */
+ attribute->class = GetDefaultOpClass(attform->atttypid);
+ if (attribute->class == NULL)
+ {
+ elog(WARN,
+ "Can't find a default operator class for type %d.",
+ attform->atttypid);
+ }
+ }
+
+ tuple = SearchSysCacheTuple(CLANAME,
+ PointerGetDatum(attribute->class),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "DefineIndex: %s class not found",
+ attribute->class);
+ }
+ *opOidP++ = tuple->t_oid;
}
- *opOidP++ = tuple->t_oid;
- }
}
-static char *
+static char *
GetDefaultOpClass(Oid atttypid)
{
- HeapTuple tuple;
+ HeapTuple tuple;
- tuple = SearchSysCacheTuple(CLADEFTYPE,
- ObjectIdGetDatum(atttypid),
- 0, 0, 0);
- if(!HeapTupleIsValid(tuple)) {
- return 0;
- }
+ tuple = SearchSysCacheTuple(CLADEFTYPE,
+ ObjectIdGetDatum(atttypid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ return 0;
+ }
- return nameout(&(((Form_pg_opclass)GETSTRUCT(tuple))->opcname));
+ return nameout(&(((Form_pg_opclass) GETSTRUCT(tuple))->opcname));
}
/*
* RemoveIndex --
- * Deletes an index.
+ * Deletes an index.
*
* Exceptions:
- * BadArg if name is invalid.
- * "WARN" if index nonexistent.
- * ...
+ * BadArg if name is invalid.
+ * "WARN" if index nonexistent.
+ * ...
*/
void
RemoveIndex(char *name)
{
- HeapTuple tuple;
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(name),
- 0,0,0);
-
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "index \"%s\" nonexistent", name);
- }
-
- if (((Form_pg_class)GETSTRUCT(tuple))->relkind != RELKIND_INDEX) {
- elog(WARN, "relation \"%s\" is of type \"%c\"",
- name,
- ((Form_pg_class)GETSTRUCT(tuple))->relkind);
- }
-
- index_destroy(tuple->t_oid);
+ HeapTuple tuple;
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(name),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "index \"%s\" nonexistent", name);
+ }
+
+ if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
+ {
+ elog(WARN, "relation \"%s\" is of type \"%c\"",
+ name,
+ ((Form_pg_class) GETSTRUCT(tuple))->relkind);
+ }
+
+ index_destroy(tuple->t_oid);
}
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 800d85a48b8..fb1df213cec 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -2,33 +2,33 @@
*
* define.c--
*
- * These routines execute some of the CREATE statements. In an earlier
- * version of Postgres, these were "define" statements.
+ * These routines execute some of the CREATE statements. In an earlier
+ * version of Postgres, these were "define" statements.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.13 1997/08/12 22:52:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.14 1997/09/07 04:40:46 momjian Exp $
*
* DESCRIPTION
- * The "DefineFoo" routines take the parse tree and pick out the
- * appropriate arguments/flags, passing the results to the
- * corresponding "FooDefine" routines (in src/catalog) that do
- * the actual catalog-munging. These routines also verify permission
- * of the user to execute the command.
+ * The "DefineFoo" routines take the parse tree and pick out the
+ * appropriate arguments/flags, passing the results to the
+ * corresponding "FooDefine" routines (in src/catalog) that do
+ * the actual catalog-munging. These routines also verify permission
+ * of the user to execute the command.
*
* NOTES
- * These things must be defined and committed in the following order:
- * "create function":
- * input/output, recv/send procedures
- * "create type":
- * type
- * "create operator":
- * operators
+ * These things must be defined and committed in the following order:
+ * "create function":
+ * input/output, recv/send procedures
+ * "create type":
+ * type
+ * "create operator":
+ * operators
*
- * Most of the parse-tree manipulation routines are defined in
- * commands/manip.c.
+ * Most of the parse-tree manipulation routines are defined in
+ * commands/manip.c.
*
*-------------------------------------------------------------------------
*/
@@ -46,209 +46,259 @@
#include <catalog/pg_proc.h>
#include <catalog/pg_type.h>
#include <utils/syscache.h>
-#include <fmgr.h> /* for fmgr */
-#include <utils/builtins.h> /* prototype for textin() */
+#include <fmgr.h> /* for fmgr */
+#include <utils/builtins.h> /* prototype for textin() */
#include <commands/defrem.h>
#include <optimizer/xfunc.h>
#include <tcop/dest.h>
#include <catalog/pg_user.h>
-static char *defGetString(DefElem *def);
-static int defGetTypeLength(DefElem *def);
+static char *defGetString(DefElem * def);
+static int defGetTypeLength(DefElem * def);
-#define DEFAULT_TYPDELIM ','
+#define DEFAULT_TYPDELIM ','
static void
-case_translate_language_name(const char *input, char *output) {
+case_translate_language_name(const char *input, char *output)
+{
/*-------------------------------------------------------------------------
Translate the input language name to lower case, except if it's C,
- translate to upper case.
+ translate to upper case.
--------------------------------------------------------------------------*/
- int i;
+ int i;
- for (i = 0; i < NAMEDATALEN && input[i] != '\0'; ++i)
- output[i] = tolower(input[i]);
+ for (i = 0; i < NAMEDATALEN && input[i] != '\0'; ++i)
+ output[i] = tolower(input[i]);
- output[i] = '\0';
+ output[i] = '\0';
- if (strcmp(output, "c") == 0) output[0] = 'C';
-}
+ if (strcmp(output, "c") == 0)
+ output[0] = 'C';
+}
static void
-compute_return_type(const Node *returnType,
- char **prorettype_p, bool *returnsSet_p) {
+compute_return_type(const Node * returnType,
+ char **prorettype_p, bool * returnsSet_p)
+{
/*---------------------------------------------------------------------------
- Examine the "returns" clause returnType of the CREATE FUNCTION statement
+ Examine the "returns" clause returnType of the CREATE FUNCTION statement
and return information about it as **prorettype_p and **returnsSet.
----------------------------------------------------------------------------*/
- if (nodeTag(returnType) == T_TypeName) {
- /* a set of values */
- TypeName *setType = (TypeName *)returnType;
- *prorettype_p = setType->name;
- *returnsSet_p = true;
- }else {
- /* singleton */
- *prorettype_p = strVal(returnType);
- *returnsSet_p = false;
- }
+ if (nodeTag(returnType) == T_TypeName)
+ {
+ /* a set of values */
+ TypeName *setType = (TypeName *) returnType;
+
+ *prorettype_p = setType->name;
+ *returnsSet_p = true;
+ }
+ else
+ {
+ /* singleton */
+ *prorettype_p = strVal(returnType);
+ *returnsSet_p = false;
+ }
}
-
-static void
-compute_full_attributes(const List *parameters, int32 *byte_pct_p,
- int32 *perbyte_cpu_p, int32 *percall_cpu_p,
- int32 *outin_ratio_p, bool *canCache_p) {
+
+static void
+compute_full_attributes(const List * parameters, int32 * byte_pct_p,
+ int32 * perbyte_cpu_p, int32 * percall_cpu_p,
+ int32 * outin_ratio_p, bool * canCache_p)
+{
/*--------------------------------------------------------------------------
Interpret the parameters *parameters and return their contents as
*byte_pct_p, etc.
These are the full parameters of a C or internal function.
---------------------------------------------------------------------------*/
- List *pl;
-
- /* the defaults */
- *byte_pct_p = BYTE_PCT;
- *perbyte_cpu_p = PERBYTE_CPU;
- *percall_cpu_p = PERCALL_CPU;
- *outin_ratio_p = OUTIN_RATIO;
-
- foreach(pl, (List *)parameters) {
- ParamString *param = (ParamString*)lfirst(pl);
-
- if (strcasecmp(param->name, "iscachable") == 0) {
- *canCache_p = true;
- } else if (strcasecmp(param->name, "trusted") == 0) {
- /*
- * we don't have untrusted functions any more. The 4.2
- * implementation is lousy anyway so I took it out.
- * -ay 10/94
- */
- elog(WARN, "untrusted function has been decommissioned.");
- } else if (strcasecmp(param->name, "byte_pct") == 0) {
- /*
- ** handle expensive function parameters
- */
- *byte_pct_p = atoi(param->val);
- } else if (strcasecmp(param->name, "perbyte_cpu") == 0) {
- if (sscanf(param->val, "%d", perbyte_cpu_p) == 0) {
- int count;
- char *ptr;
- for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
- if (*ptr == '!') count++;
- *perbyte_cpu_p = (int) pow(10.0, (double) count);
- }
- } else if (strcasecmp(param->name, "percall_cpu") == 0) {
- if (sscanf(param->val, "%d", percall_cpu_p) == 0) {
- int count;
- char *ptr;
- for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
- if (*ptr == '!') count++;
- *percall_cpu_p = (int) pow(10.0, (double) count);
- }
- } else if (strcasecmp(param->name, "outin_ratio") == 0) {
- *outin_ratio_p = atoi(param->val);
- }
- }
+ List *pl;
+
+ /* the defaults */
+ *byte_pct_p = BYTE_PCT;
+ *perbyte_cpu_p = PERBYTE_CPU;
+ *percall_cpu_p = PERCALL_CPU;
+ *outin_ratio_p = OUTIN_RATIO;
+
+ foreach(pl, (List *) parameters)
+ {
+ ParamString *param = (ParamString *) lfirst(pl);
+
+ if (strcasecmp(param->name, "iscachable") == 0)
+ {
+ *canCache_p = true;
+ }
+ else if (strcasecmp(param->name, "trusted") == 0)
+ {
+
+ /*
+ * we don't have untrusted functions any more. The 4.2
+ * implementation is lousy anyway so I took it out. -ay 10/94
+ */
+ elog(WARN, "untrusted function has been decommissioned.");
+ }
+ else if (strcasecmp(param->name, "byte_pct") == 0)
+ {
+
+ /*
+ * * handle expensive function parameters
+ */
+ *byte_pct_p = atoi(param->val);
+ }
+ else if (strcasecmp(param->name, "perbyte_cpu") == 0)
+ {
+ if (sscanf(param->val, "%d", perbyte_cpu_p) == 0)
+ {
+ int count;
+ char *ptr;
+
+ for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
+ if (*ptr == '!')
+ count++;
+ *perbyte_cpu_p = (int) pow(10.0, (double) count);
+ }
+ }
+ else if (strcasecmp(param->name, "percall_cpu") == 0)
+ {
+ if (sscanf(param->val, "%d", percall_cpu_p) == 0)
+ {
+ int count;
+ char *ptr;
+
+ for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
+ if (*ptr == '!')
+ count++;
+ *percall_cpu_p = (int) pow(10.0, (double) count);
+ }
+ }
+ else if (strcasecmp(param->name, "outin_ratio") == 0)
+ {
+ *outin_ratio_p = atoi(param->val);
+ }
+ }
}
static void
interpret_AS_clause(const char languageName[], const char as[],
- char **prosrc_str_p, char **probin_str_p) {
-
- if ( strcmp(languageName, "C") == 0 ||
- strcmp(languageName, "internal") == 0 ) {
- *prosrc_str_p = "-";
- *probin_str_p = (char *)as;
- } else {
- *prosrc_str_p = (char *)as;
- *probin_str_p = "-";
- }
+ char **prosrc_str_p, char **probin_str_p)
+{
+
+ if (strcmp(languageName, "C") == 0 ||
+ strcmp(languageName, "internal") == 0)
+ {
+ *prosrc_str_p = "-";
+ *probin_str_p = (char *) as;
+ }
+ else
+ {
+ *prosrc_str_p = (char *) as;
+ *probin_str_p = "-";
+ }
}
/*
* CreateFunction --
- * Execute a CREATE FUNCTION utility statement.
+ * Execute a CREATE FUNCTION utility statement.
*
*/
void
-CreateFunction(ProcedureStmt *stmt, CommandDest dest)
+CreateFunction(ProcedureStmt * stmt, CommandDest dest)
{
- char *probin_str;
- /* pathname of executable file that executes this function, if any */
- char *prosrc_str;
- /* SQL that executes this function, if any */
- char *prorettype;
- /* Type of return value (or member of set of values) from function */
- char languageName[NAMEDATALEN];
- /* name of language of function, with case adjusted:
- "C", "internal", or "SQL"
- */
- /* The following are attributes of the function, as expressed in the
- CREATE FUNCTION statement, where applicable.
- */
- int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio;
- bool canCache;
- bool returnsSet;
- /* The function returns a set of values, as opposed to a singleton. */
-
-
- case_translate_language_name(stmt->language, languageName);
-
- compute_return_type(stmt->returnType, &prorettype, &returnsSet);
-
- if ( strcmp(languageName, "C") == 0 ||
- strcmp(languageName, "internal") == 0 ) {
- compute_full_attributes(stmt->withClause,
- &byte_pct, &perbyte_cpu, &percall_cpu,
- &outin_ratio, &canCache);
- } else if (strcmp(languageName, "sql") == 0) {
- /* query optimizer groks sql, these are meaningless */
- perbyte_cpu = percall_cpu = 0;
- byte_pct = outin_ratio = 100;
- canCache = false;
- } else {
- elog(WARN,
- "Unrecognized language specified in a CREATE FUNCTION: "
- "'%s'. Recognized languages are sql, C, and internal.",
- languageName);
- }
-
- interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
-
- if (strcmp(languageName, "sql") != 0 && !superuser())
- elog(WARN,
- "Only users with Postgres superuser privilege are permitted "
- "to create a function "
- "in the '%s' language. Others may use the 'sql' language.",
- languageName);
- /* Above does not return. */
- else {
- /* And now that we have all the parameters, and know we're permitted
- to do so, go ahead and create the function.
- */
- ProcedureCreate(stmt->funcname,
- returnsSet,
- prorettype,
- languageName,
- prosrc_str, /* converted to text later */
- probin_str, /* converted to text later */
- canCache,
- true, /* (obsolete "trusted") */
- byte_pct,
- perbyte_cpu,
- percall_cpu,
- outin_ratio,
- stmt->defArgs,
- dest);
- }
+ char *probin_str;
+
+ /* pathname of executable file that executes this function, if any */
+ char *prosrc_str;
+
+ /* SQL that executes this function, if any */
+ char *prorettype;
+
+ /* Type of return value (or member of set of values) from function */
+ char languageName[NAMEDATALEN];
+
+ /*
+ * name of language of function, with case adjusted: "C", "internal",
+ * or "SQL"
+ */
+
+ /*
+ * The following are attributes of the function, as expressed in the
+ * CREATE FUNCTION statement, where applicable.
+ */
+ int32 byte_pct,
+ perbyte_cpu,
+ percall_cpu,
+ outin_ratio;
+ bool canCache;
+ bool returnsSet;
+
+ /* The function returns a set of values, as opposed to a singleton. */
+
+
+ case_translate_language_name(stmt->language, languageName);
+
+ compute_return_type(stmt->returnType, &prorettype, &returnsSet);
+
+ if (strcmp(languageName, "C") == 0 ||
+ strcmp(languageName, "internal") == 0)
+ {
+ compute_full_attributes(stmt->withClause,
+ &byte_pct, &perbyte_cpu, &percall_cpu,
+ &outin_ratio, &canCache);
+ }
+ else if (strcmp(languageName, "sql") == 0)
+ {
+ /* query optimizer groks sql, these are meaningless */
+ perbyte_cpu = percall_cpu = 0;
+ byte_pct = outin_ratio = 100;
+ canCache = false;
+ }
+ else
+ {
+ elog(WARN,
+ "Unrecognized language specified in a CREATE FUNCTION: "
+ "'%s'. Recognized languages are sql, C, and internal.",
+ languageName);
+ }
+
+ interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
+
+ if (strcmp(languageName, "sql") != 0 && !superuser())
+ elog(WARN,
+ "Only users with Postgres superuser privilege are permitted "
+ "to create a function "
+ "in the '%s' language. Others may use the 'sql' language.",
+ languageName);
+ /* Above does not return. */
+ else
+ {
+
+ /*
+ * And now that we have all the parameters, and know we're
+ * permitted to do so, go ahead and create the function.
+ */
+ ProcedureCreate(stmt->funcname,
+ returnsSet,
+ prorettype,
+ languageName,
+ prosrc_str, /* converted to text later */
+ probin_str, /* converted to text later */
+ canCache,
+ true, /* (obsolete "trusted") */
+ byte_pct,
+ perbyte_cpu,
+ percall_cpu,
+ outin_ratio,
+ stmt->defArgs,
+ dest);
+ }
}
@@ -256,344 +306,437 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
/* --------------------------------
* DefineOperator--
*
- * this function extracts all the information from the
- * parameter list generated by the parser and then has
- * OperatorCreate() do all the actual work.
+ * this function extracts all the information from the
+ * parameter list generated by the parser and then has
+ * OperatorCreate() do all the actual work.
*
* 'parameters' is a list of DefElem
* --------------------------------
*/
void
-DefineOperator(char *oprName,
- List *parameters)
+DefineOperator(char *oprName,
+ List * parameters)
{
- uint16 precedence=0; /* operator precedence */
- bool canHash=false; /* operator hashes */
- bool isLeftAssociative=true; /* operator is left associative */
- char *functionName=NULL; /* function for operator */
- char *typeName1=NULL; /* first type name */
- char *typeName2=NULL; /* second type name */
- char *commutatorName=NULL; /* optional commutator operator name */
- char *negatorName=NULL; /* optional negator operator name */
- char *restrictionName=NULL; /* optional restrict. sel. procedure */
- char *joinName=NULL; /* optional join sel. procedure name */
- char *sortName1=NULL; /* optional first sort operator */
- char *sortName2=NULL; /* optional second sort operator */
- List *pl;
-
- /*
- * loop over the definition list and extract the information we need.
- */
- foreach (pl, parameters) {
- DefElem *defel = (DefElem *)lfirst(pl);
-
- if (!strcasecmp(defel->defname, "leftarg")) {
- /* see gram.y, must be setof */
- if (nodeTag(defel->arg)==T_TypeName)
- elog(WARN, "setof type not implemented for leftarg");
-
- if (nodeTag(defel->arg)==T_String) {
- typeName1 = defGetString(defel);
- }else {
- elog(WARN, "type for leftarg is malformed.");
- }
- } else if (!strcasecmp(defel->defname, "rightarg")) {
- /* see gram.y, must be setof */
- if (nodeTag(defel->arg)==T_TypeName)
- elog(WARN, "setof type not implemented for rightarg");
-
- if (nodeTag(defel->arg)==T_String) {
- typeName2 = defGetString(defel);
- }else {
- elog(WARN, "type for rightarg is malformed.");
- }
- } else if (!strcasecmp(defel->defname, "procedure")) {
- functionName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "precedence")) {
- /* NOT IMPLEMENTED (never worked in v4.2) */
- elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
- } else if (!strcasecmp(defel->defname, "associativity")) {
- /* NOT IMPLEMENTED (never worked in v4.2) */
- elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
- } else if (!strcasecmp(defel->defname, "commutator")) {
- commutatorName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "negator")) {
- negatorName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "restrict")) {
- restrictionName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "join")) {
- joinName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "hashes")) {
- canHash = TRUE;
- } else if (!strcasecmp(defel->defname, "sort1")) {
- /* ----------------
- * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
- * XXX is undocumented in the reference manual source as of
- * 89/8/22.
- * ----------------
- */
- sortName1 = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "sort2")) {
- sortName2 = defGetString(defel);
- } else {
- elog(NOTICE, "DefineOperator: attribute \"%s\" not recognized",
- defel->defname);
- }
- }
-
- /*
- * make sure we have our required definitions
- */
- if (functionName==NULL) {
- elog(WARN, "Define: \"procedure\" unspecified");
- }
-
- /* ----------------
- * now have OperatorCreate do all the work..
- * ----------------
- */
- OperatorCreate(oprName, /* operator name */
- typeName1, /* first type name */
- typeName2, /* second type name */
- functionName, /* function for operator */
- precedence, /* operator precedence */
- isLeftAssociative, /* operator is left associative */
- commutatorName, /* optional commutator operator name */
- negatorName, /* optional negator operator name */
- restrictionName, /* optional restrict. sel. procedure */
- joinName, /* optional join sel. procedure name */
- canHash, /* operator hashes */
- sortName1, /* optional first sort operator */
- sortName2); /* optional second sort operator */
-
+ uint16 precedence = 0; /* operator precedence */
+ bool canHash = false; /* operator hashes */
+ bool isLeftAssociative = true; /* operator is left
+ * associative */
+ char *functionName = NULL; /* function for operator */
+ char *typeName1 = NULL; /* first type name */
+ char *typeName2 = NULL; /* second type name */
+ char *commutatorName = NULL; /* optional commutator
+ * operator name */
+ char *negatorName = NULL; /* optional negator operator name */
+ char *restrictionName = NULL; /* optional restrict. sel.
+ * procedure */
+ char *joinName = NULL; /* optional join sel. procedure
+ * name */
+ char *sortName1 = NULL; /* optional first sort operator */
+ char *sortName2 = NULL; /* optional second sort operator */
+ List *pl;
+
+ /*
+ * loop over the definition list and extract the information we need.
+ */
+ foreach(pl, parameters)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ if (!strcasecmp(defel->defname, "leftarg"))
+ {
+ /* see gram.y, must be setof */
+ if (nodeTag(defel->arg) == T_TypeName)
+ elog(WARN, "setof type not implemented for leftarg");
+
+ if (nodeTag(defel->arg) == T_String)
+ {
+ typeName1 = defGetString(defel);
+ }
+ else
+ {
+ elog(WARN, "type for leftarg is malformed.");
+ }
+ }
+ else if (!strcasecmp(defel->defname, "rightarg"))
+ {
+ /* see gram.y, must be setof */
+ if (nodeTag(defel->arg) == T_TypeName)
+ elog(WARN, "setof type not implemented for rightarg");
+
+ if (nodeTag(defel->arg) == T_String)
+ {
+ typeName2 = defGetString(defel);
+ }
+ else
+ {
+ elog(WARN, "type for rightarg is malformed.");
+ }
+ }
+ else if (!strcasecmp(defel->defname, "procedure"))
+ {
+ functionName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "precedence"))
+ {
+ /* NOT IMPLEMENTED (never worked in v4.2) */
+ elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
+ }
+ else if (!strcasecmp(defel->defname, "associativity"))
+ {
+ /* NOT IMPLEMENTED (never worked in v4.2) */
+ elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
+ }
+ else if (!strcasecmp(defel->defname, "commutator"))
+ {
+ commutatorName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "negator"))
+ {
+ negatorName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "restrict"))
+ {
+ restrictionName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "join"))
+ {
+ joinName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "hashes"))
+ {
+ canHash = TRUE;
+ }
+ else if (!strcasecmp(defel->defname, "sort1"))
+ {
+ /* ----------------
+ * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
+ * XXX is undocumented in the reference manual source as of
+ * 89/8/22.
+ * ----------------
+ */
+ sortName1 = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "sort2"))
+ {
+ sortName2 = defGetString(defel);
+ }
+ else
+ {
+ elog(NOTICE, "DefineOperator: attribute \"%s\" not recognized",
+ defel->defname);
+ }
+ }
+
+ /*
+ * make sure we have our required definitions
+ */
+ if (functionName == NULL)
+ {
+ elog(WARN, "Define: \"procedure\" unspecified");
+ }
+
+ /* ----------------
+ * now have OperatorCreate do all the work..
+ * ----------------
+ */
+ OperatorCreate(oprName, /* operator name */
+ typeName1, /* first type name */
+ typeName2, /* second type name */
+ functionName,/* function for operator */
+ precedence, /* operator precedence */
+ isLeftAssociative, /* operator is left associative */
+ commutatorName, /* optional commutator operator
+ * name */
+ negatorName, /* optional negator operator name */
+ restrictionName, /* optional restrict. sel.
+ * procedure */
+ joinName, /* optional join sel. procedure name */
+ canHash, /* operator hashes */
+ sortName1, /* optional first sort operator */
+ sortName2); /* optional second sort operator */
+
}
/* -------------------
- * DefineAggregate
+ * DefineAggregate
* ------------------
*/
void
-DefineAggregate(char *aggName, List *parameters)
+DefineAggregate(char *aggName, List * parameters)
{
- char *stepfunc1Name = NULL;
- char *stepfunc2Name = NULL;
- char *finalfuncName = NULL;
- char *baseType = NULL;
- char *stepfunc1Type = NULL;
- char *stepfunc2Type = NULL;
- char *init1 = NULL;
- char *init2 = NULL;
- List *pl;
-
- foreach (pl, parameters) {
- DefElem *defel = (DefElem *)lfirst(pl);
-
- /*
- * sfunc1
- */
- if (!strcasecmp(defel->defname, "sfunc1")) {
- stepfunc1Name = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "basetype")) {
- baseType = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "stype1")) {
- stepfunc1Type = defGetString(defel);
-
- /*
- * sfunc2
- */
- } else if (!strcasecmp(defel->defname, "sfunc2")) {
- stepfunc2Name = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "stype2")) {
- stepfunc2Type = defGetString(defel);
- /*
- * final
- */
- } else if (!strcasecmp(defel->defname, "finalfunc")) {
- finalfuncName = defGetString(defel);
- /*
- * initial conditions
- */
- } else if (!strcasecmp(defel->defname, "initcond1")) {
- init1 = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "initcond2")) {
- init2 = defGetString(defel);
- } else {
- elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
- defel->defname);
- }
- }
-
- /*
- * make sure we have our required definitions
- */
- if (baseType==NULL)
- elog(WARN, "Define: \"basetype\" unspecified");
- if (stepfunc1Name!=NULL) {
- if (stepfunc1Type==NULL)
- elog(WARN, "Define: \"stype1\" unspecified");
- }
- if (stepfunc2Name!=NULL) {
- if (stepfunc2Type==NULL)
- elog(WARN, "Define: \"stype2\" unspecified");
- }
-
- /*
- * Most of the argument-checking is done inside of AggregateCreate
- */
- AggregateCreate(aggName, /* aggregate name */
- stepfunc1Name, /* first step function name */
- stepfunc2Name, /* second step function name */
- finalfuncName, /* final function name */
- baseType, /* type of object being aggregated */
- stepfunc1Type, /* return type of first function */
- stepfunc2Type, /* return type of second function */
- init1, /* first initial condition */
- init2); /* second initial condition */
-
- /* XXX free palloc'd memory */
+ char *stepfunc1Name = NULL;
+ char *stepfunc2Name = NULL;
+ char *finalfuncName = NULL;
+ char *baseType = NULL;
+ char *stepfunc1Type = NULL;
+ char *stepfunc2Type = NULL;
+ char *init1 = NULL;
+ char *init2 = NULL;
+ List *pl;
+
+ foreach(pl, parameters)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ /*
+ * sfunc1
+ */
+ if (!strcasecmp(defel->defname, "sfunc1"))
+ {
+ stepfunc1Name = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "basetype"))
+ {
+ baseType = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "stype1"))
+ {
+ stepfunc1Type = defGetString(defel);
+
+ /*
+ * sfunc2
+ */
+ }
+ else if (!strcasecmp(defel->defname, "sfunc2"))
+ {
+ stepfunc2Name = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "stype2"))
+ {
+ stepfunc2Type = defGetString(defel);
+
+ /*
+ * final
+ */
+ }
+ else if (!strcasecmp(defel->defname, "finalfunc"))
+ {
+ finalfuncName = defGetString(defel);
+
+ /*
+ * initial conditions
+ */
+ }
+ else if (!strcasecmp(defel->defname, "initcond1"))
+ {
+ init1 = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "initcond2"))
+ {
+ init2 = defGetString(defel);
+ }
+ else
+ {
+ elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
+ defel->defname);
+ }
+ }
+
+ /*
+ * make sure we have our required definitions
+ */
+ if (baseType == NULL)
+ elog(WARN, "Define: \"basetype\" unspecified");
+ if (stepfunc1Name != NULL)
+ {
+ if (stepfunc1Type == NULL)
+ elog(WARN, "Define: \"stype1\" unspecified");
+ }
+ if (stepfunc2Name != NULL)
+ {
+ if (stepfunc2Type == NULL)
+ elog(WARN, "Define: \"stype2\" unspecified");
+ }
+
+ /*
+ * Most of the argument-checking is done inside of AggregateCreate
+ */
+ AggregateCreate(aggName, /* aggregate name */
+ stepfunc1Name, /* first step function name */
+ stepfunc2Name, /* second step function name */
+ finalfuncName, /* final function name */
+ baseType, /* type of object being aggregated */
+ stepfunc1Type, /* return type of first function */
+ stepfunc2Type, /* return type of second function */
+ init1, /* first initial condition */
+ init2); /* second initial condition */
+
+ /* XXX free palloc'd memory */
}
/*
* DefineType --
- * Registers a new type.
+ * Registers a new type.
*
*/
void
-DefineType(char *typeName, List *parameters)
+DefineType(char *typeName, List * parameters)
{
- int16 internalLength= 0; /* int2 */
- int16 externalLength= 0; /* int2 */
- char *elemName = NULL;
- char *inputName = NULL;
- char *outputName = NULL;
- char *sendName = NULL;
- char *receiveName = NULL;
- char *defaultValue = NULL; /* Datum */
- bool byValue = false;
- char delimiter = DEFAULT_TYPDELIM;
- char *shadow_type;
- List *pl;
- char alignment = 'i'; /* default alignment */
-
- /*
- * Type names can only be 15 characters long, so that the shadow type
- * can be created using the 16th character as necessary.
- */
- if (strlen(typeName) >= (NAMEDATALEN - 1)) {
- elog(WARN, "DefineType: type names must be %d characters or less",
- NAMEDATALEN - 1);
- }
-
- foreach(pl, parameters) {
- DefElem *defel = (DefElem*)lfirst(pl);
-
- if (!strcasecmp(defel->defname, "internallength")) {
- internalLength = defGetTypeLength(defel);
- }else if (!strcasecmp(defel->defname, "externallength")) {
- externalLength = defGetTypeLength(defel);
- }else if (!strcasecmp(defel->defname, "input")) {
- inputName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "output")) {
- outputName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "send")) {
- sendName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "delimiter")) {
- char *p = defGetString(defel);
- delimiter = p[0];
- }else if (!strcasecmp(defel->defname, "receive")) {
- receiveName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "element")) {
- elemName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "default")) {
- defaultValue = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "passedbyvalue")) {
- byValue = true;
- }else if (!strcasecmp(defel->defname, "alignment")) {
- char *a = defGetString(defel);
- if (!strcasecmp(a, "double")) {
- alignment = 'd';
- } else if (!strcasecmp(a, "int")) {
- alignment = 'i';
- } else {
- elog(WARN, "DefineType: \"%s\" alignment not recognized",
- a);
- }
- }else {
- elog(NOTICE, "DefineType: attribute \"%s\" not recognized",
- defel->defname);
- }
- }
-
- /*
- * make sure we have our required definitions
- */
- if (inputName==NULL)
- elog(WARN, "Define: \"input\" unspecified");
- if (outputName==NULL)
- elog(WARN, "Define: \"output\" unspecified");
-
- /* ----------------
- * now have TypeCreate do all the real work.
- * ----------------
- */
- TypeCreate(typeName, /* type name */
- InvalidOid, /* relation oid (n/a here) */
- internalLength, /* internal size */
- externalLength, /* external size */
- 'b', /* type-type (base type) */
- delimiter, /* array element delimiter */
- inputName, /* input procedure */
- outputName, /* output procedure */
- sendName, /* send procedure */
- receiveName, /* receive procedure */
- elemName, /* element type name */
- defaultValue, /* default type value */
- byValue, /* passed by value */
- alignment);
-
- /* ----------------
- * When we create a true type (as opposed to a complex type)
- * we need to have an shadow array entry for it in pg_type as well.
- * ----------------
- */
- shadow_type = makeArrayTypeName(typeName);
-
- TypeCreate(shadow_type, /* type name */
- InvalidOid, /* relation oid (n/a here) */
- -1, /* internal size */
- -1, /* external size */
- 'b', /* type-type (base type) */
- DEFAULT_TYPDELIM, /* array element delimiter */
- "array_in", /* input procedure */
- "array_out", /* output procedure */
- "array_out", /* send procedure */
- "array_in", /* receive procedure */
- typeName, /* element type name */
- defaultValue, /* default type value */
- false, /* never passed by value */
- alignment);
-
- pfree(shadow_type);
+ int16 internalLength = 0; /* int2 */
+ int16 externalLength = 0; /* int2 */
+ char *elemName = NULL;
+ char *inputName = NULL;
+ char *outputName = NULL;
+ char *sendName = NULL;
+ char *receiveName = NULL;
+ char *defaultValue = NULL; /* Datum */
+ bool byValue = false;
+ char delimiter = DEFAULT_TYPDELIM;
+ char *shadow_type;
+ List *pl;
+ char alignment = 'i'; /* default alignment */
+
+ /*
+ * Type names can only be 15 characters long, so that the shadow type
+ * can be created using the 16th character as necessary.
+ */
+ if (strlen(typeName) >= (NAMEDATALEN - 1))
+ {
+ elog(WARN, "DefineType: type names must be %d characters or less",
+ NAMEDATALEN - 1);
+ }
+
+ foreach(pl, parameters)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ if (!strcasecmp(defel->defname, "internallength"))
+ {
+ internalLength = defGetTypeLength(defel);
+ }
+ else if (!strcasecmp(defel->defname, "externallength"))
+ {
+ externalLength = defGetTypeLength(defel);
+ }
+ else if (!strcasecmp(defel->defname, "input"))
+ {
+ inputName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "output"))
+ {
+ outputName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "send"))
+ {
+ sendName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "delimiter"))
+ {
+ char *p = defGetString(defel);
+
+ delimiter = p[0];
+ }
+ else if (!strcasecmp(defel->defname, "receive"))
+ {
+ receiveName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "element"))
+ {
+ elemName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "default"))
+ {
+ defaultValue = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "passedbyvalue"))
+ {
+ byValue = true;
+ }
+ else if (!strcasecmp(defel->defname, "alignment"))
+ {
+ char *a = defGetString(defel);
+
+ if (!strcasecmp(a, "double"))
+ {
+ alignment = 'd';
+ }
+ else if (!strcasecmp(a, "int"))
+ {
+ alignment = 'i';
+ }
+ else
+ {
+ elog(WARN, "DefineType: \"%s\" alignment not recognized",
+ a);
+ }
+ }
+ else
+ {
+ elog(NOTICE, "DefineType: attribute \"%s\" not recognized",
+ defel->defname);
+ }
+ }
+
+ /*
+ * make sure we have our required definitions
+ */
+ if (inputName == NULL)
+ elog(WARN, "Define: \"input\" unspecified");
+ if (outputName == NULL)
+ elog(WARN, "Define: \"output\" unspecified");
+
+ /* ----------------
+ * now have TypeCreate do all the real work.
+ * ----------------
+ */
+ TypeCreate(typeName, /* type name */
+ InvalidOid, /* relation oid (n/a here) */
+ internalLength, /* internal size */
+ externalLength, /* external size */
+ 'b', /* type-type (base type) */
+ delimiter, /* array element delimiter */
+ inputName, /* input procedure */
+ outputName, /* output procedure */
+ sendName, /* send procedure */
+ receiveName, /* receive procedure */
+ elemName, /* element type name */
+ defaultValue, /* default type value */
+ byValue, /* passed by value */
+ alignment);
+
+ /* ----------------
+ * When we create a true type (as opposed to a complex type)
+ * we need to have an shadow array entry for it in pg_type as well.
+ * ----------------
+ */
+ shadow_type = makeArrayTypeName(typeName);
+
+ TypeCreate(shadow_type, /* type name */
+ InvalidOid, /* relation oid (n/a here) */
+ -1, /* internal size */
+ -1, /* external size */
+ 'b', /* type-type (base type) */
+ DEFAULT_TYPDELIM,/* array element delimiter */
+ "array_in", /* input procedure */
+ "array_out", /* output procedure */
+ "array_out", /* send procedure */
+ "array_in", /* receive procedure */
+ typeName, /* element type name */
+ defaultValue, /* default type value */
+ false, /* never passed by value */
+ alignment);
+
+ pfree(shadow_type);
}
-static char *
-defGetString(DefElem *def)
+static char *
+defGetString(DefElem * def)
{
- if (nodeTag(def->arg)!=T_String)
- elog(WARN, "Define: \"%s\" = what?", def->defname);
- return (strVal(def->arg));
+ if (nodeTag(def->arg) != T_String)
+ elog(WARN, "Define: \"%s\" = what?", def->defname);
+ return (strVal(def->arg));
}
-static int
-defGetTypeLength(DefElem *def)
+static int
+defGetTypeLength(DefElem * def)
{
- if (nodeTag(def->arg)==T_Integer)
- return (intVal(def->arg));
- else if (nodeTag(def->arg)==T_String &&
- !strcasecmp(strVal(def->arg),"variable"))
- return -1; /* variable length */
-
- elog(WARN, "Define: \"%s\" = what?", def->defname);
- return -1;
+ if (nodeTag(def->arg) == T_Integer)
+ return (intVal(def->arg));
+ else if (nodeTag(def->arg) == T_String &&
+ !strcasecmp(strVal(def->arg), "variable"))
+ return -1; /* variable length */
+
+ elog(WARN, "Define: \"%s\" = what?", def->defname);
+ return -1;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 7d1f34d0327..192076e3911 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* explain.c--
- * Explain the query execution plan
+ * Explain the query execution plan
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.10 1997/08/18 20:52:17 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.11 1997/09/07 04:40:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include <postgres.h>
#include <parser/catalog_utils.h>
-#include <parser/parse_query.h> /* for MakeTimeRange() */
+#include <parser/parse_query.h> /* for MakeTimeRange() */
#include <nodes/plannodes.h>
#include <tcop/tcopprot.h>
#include <lib/stringinfo.h>
@@ -25,79 +25,86 @@
#include <optimizer/planner.h>
#include <access/xact.h>
-typedef struct ExplainState {
- /* options */
- bool printCost; /* print cost */
- bool printNodes; /* do nodeToString() instead */
- /* other states */
- List *rtable; /* range table */
-} ExplainState;
+typedef struct ExplainState
+{
+ /* options */
+ bool printCost; /* print cost */
+ bool printNodes; /* do nodeToString() instead */
+ /* other states */
+ List *rtable; /* range table */
+} ExplainState;
-static char *Explain_PlanToString(Plan *plan, ExplainState *es);
+static char *Explain_PlanToString(Plan * plan, ExplainState * es);
/*
* ExplainQuery -
- * print out the execution plan for a given query
+ * print out the execution plan for a given query
*
*/
void
-ExplainQuery(Query *query, bool verbose, CommandDest dest)
+ExplainQuery(Query * query, bool verbose, CommandDest dest)
{
- char *s = NULL, *s2;
- Plan *plan;
- ExplainState *es;
- int len;
-
- if (IsAbortedTransactionBlockState()) {
- char *tag = "*ABORT STATE*";
- EndCommand(tag, dest);
-
- elog(NOTICE, "(transaction aborted): %s",
- "queries ignored until END");
-
- return;
- }
+ char *s = NULL,
+ *s2;
+ Plan *plan;
+ ExplainState *es;
+ int len;
- /* plan the queries (XXX we've ignored rewrite!!) */
- plan = planner(query);
+ if (IsAbortedTransactionBlockState())
+ {
+ char *tag = "*ABORT STATE*";
- /* pg_plan could have failed */
- if (plan == NULL)
- return;
+ EndCommand(tag, dest);
+
+ elog(NOTICE, "(transaction aborted): %s",
+ "queries ignored until END");
+
+ return;
+ }
- es = (ExplainState*)malloc(sizeof(ExplainState));
- memset(es, 0, sizeof(ExplainState));
+ /* plan the queries (XXX we've ignored rewrite!!) */
+ plan = planner(query);
- es->printCost = true; /* default */
+ /* pg_plan could have failed */
+ if (plan == NULL)
+ return;
- if (verbose)
- es->printNodes = true;
+ es = (ExplainState *) malloc(sizeof(ExplainState));
+ memset(es, 0, sizeof(ExplainState));
- es->rtable = query->rtable;
+ es->printCost = true; /* default */
- if (es->printNodes)
- s = nodeToString(plan);
+ if (verbose)
+ es->printNodes = true;
- if (es->printCost) {
- s2 = Explain_PlanToString(plan, es);
- if (s == NULL)
- s = s2;
- else {
- strcat(s, "\n\n");
- strcat(s, s2);
+ es->rtable = query->rtable;
+
+ if (es->printNodes)
+ s = nodeToString(plan);
+
+ if (es->printCost)
+ {
+ s2 = Explain_PlanToString(plan, es);
+ if (s == NULL)
+ s = s2;
+ else
+ {
+ strcat(s, "\n\n");
+ strcat(s, s2);
+ }
}
- }
-
- /* output the plan */
- len = strlen(s);
- elog(NOTICE, "QUERY PLAN:\n\n%.*s", ELOG_MAXLEN-64, s);
- len -= ELOG_MAXLEN-64;
- while (len > 0) {
- s += ELOG_MAXLEN-64;
- elog(NOTICE, "%.*s", ELOG_MAXLEN-64, s);
- len -= ELOG_MAXLEN-64;
- }
- free(es);
+
+ /* output the plan */
+ len = strlen(s);
+ elog(NOTICE, "QUERY PLAN:\n\n%.*s", ELOG_MAXLEN - 64, s);
+ len -= ELOG_MAXLEN - 64;
+ while (len > 0)
+ {
+ s += ELOG_MAXLEN - 64;
+ elog(NOTICE, "%.*s", ELOG_MAXLEN - 64, s);
+ len -= ELOG_MAXLEN - 64;
+ }
+ free(es);
}
/*****************************************************************************
@@ -106,122 +113,130 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
/*
* explain_outNode -
- * converts a Node into ascii string and append it to 'str'
+ * converts a Node into ascii string and append it to 'str'
*/
static void
-explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
+explain_outNode(StringInfo str, Plan * plan, int indent, ExplainState * es)
{
- char *pname;
- char buf[1000];
- int i;
-
- if (plan==NULL) {
+ char *pname;
+ char buf[1000];
+ int i;
+
+ if (plan == NULL)
+ {
+ appendStringInfo(str, "\n");
+ return;
+ }
+
+ switch (nodeTag(plan))
+ {
+ case T_Result:
+ pname = "Result";
+ break;
+ case T_Append:
+ pname = "Append";
+ break;
+ case T_NestLoop:
+ pname = "Nested Loop";
+ break;
+ case T_MergeJoin:
+ pname = "Merge Join";
+ break;
+ case T_HashJoin:
+ pname = "Hash Join";
+ break;
+ case T_SeqScan:
+ pname = "Seq Scan";
+ break;
+ case T_IndexScan:
+ pname = "Index Scan";
+ break;
+ case T_Temp:
+ pname = "Temp Scan";
+ break;
+ case T_Sort:
+ pname = "Sort";
+ break;
+ case T_Group:
+ pname = "Group";
+ break;
+ case T_Agg:
+ pname = "Aggregate";
+ break;
+ case T_Unique:
+ pname = "Unique";
+ break;
+ case T_Hash:
+ pname = "Hash";
+ break;
+ case T_Tee:
+ pname = "Tee";
+ break;
+ default:
+ pname = "";
+ break;
+ }
+
+ for (i = 0; i < indent; i++)
+ appendStringInfo(str, " ");
+
+ appendStringInfo(str, pname);
+ switch (nodeTag(plan))
+ {
+ case T_SeqScan:
+ case T_IndexScan:
+ if (((Scan *) plan)->scanrelid > 0)
+ {
+ RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
+
+ sprintf(buf, " on %s", rte->refname);
+ appendStringInfo(str, buf);
+ }
+ break;
+ default:
+ break;
+ }
+ if (es->printCost)
+ {
+ sprintf(buf, " (cost=%.2f size=%d width=%d)",
+ plan->cost, plan->plan_size, plan->plan_width);
+ appendStringInfo(str, buf);
+ }
appendStringInfo(str, "\n");
- return;
- }
-
- switch(nodeTag(plan)) {
- case T_Result:
- pname = "Result";
- break;
- case T_Append:
- pname = "Append";
- break;
- case T_NestLoop:
- pname = "Nested Loop";
- break;
- case T_MergeJoin:
- pname = "Merge Join";
- break;
- case T_HashJoin:
- pname = "Hash Join";
- break;
- case T_SeqScan:
- pname = "Seq Scan";
- break;
- case T_IndexScan:
- pname = "Index Scan";
- break;
- case T_Temp:
- pname = "Temp Scan";
- break;
- case T_Sort:
- pname = "Sort";
- break;
- case T_Group:
- pname = "Group";
- break;
- case T_Agg:
- pname = "Aggregate";
- break;
- case T_Unique:
- pname = "Unique";
- break;
- case T_Hash:
- pname = "Hash";
- break;
- case T_Tee:
- pname = "Tee";
- break;
- default:
- pname = "";
- break;
- }
-
- for(i=0; i < indent; i++)
- appendStringInfo(str, " ");
-
- appendStringInfo(str, pname);
- switch(nodeTag(plan)) {
- case T_SeqScan:
- case T_IndexScan:
- if (((Scan*)plan)->scanrelid > 0) {
- RangeTblEntry *rte = nth(((Scan*)plan)->scanrelid-1, es->rtable);
- sprintf(buf, " on %s", rte->refname);
- appendStringInfo(str, buf);
+
+ /* lefttree */
+ if (outerPlan(plan))
+ {
+ for (i = 0; i < indent; i++)
+ appendStringInfo(str, " ");
+ appendStringInfo(str, " -> ");
+ explain_outNode(str, outerPlan(plan), indent + 1, es);
}
- break;
- default:
- break;
- }
- if (es->printCost) {
- sprintf(buf, " (cost=%.2f size=%d width=%d)",
- plan->cost, plan->plan_size, plan->plan_width);
- appendStringInfo(str, buf);
- }
- appendStringInfo(str, "\n");
-
- /* lefttree */
- if (outerPlan(plan)) {
- for(i=0; i < indent; i++)
- appendStringInfo(str, " ");
- appendStringInfo(str, " -> ");
- explain_outNode(str, outerPlan(plan), indent+1, es);
- }
-
- /* righttree */
- if (innerPlan(plan)) {
- for(i=0; i < indent; i++)
- appendStringInfo(str, " ");
- appendStringInfo(str, " -> ");
- explain_outNode(str, innerPlan(plan), indent+1, es);
- }
- return;
+
+ /* righttree */
+ if (innerPlan(plan))
+ {
+ for (i = 0; i < indent; i++)
+ appendStringInfo(str, " ");
+ appendStringInfo(str, " -> ");
+ explain_outNode(str, innerPlan(plan), indent + 1, es);
+ }
+ return;
}
-static char *
-Explain_PlanToString(Plan *plan, ExplainState *es)
+static char *
+Explain_PlanToString(Plan * plan, ExplainState * es)
{
- StringInfo str;
- char *s;
-
- if (plan==NULL)
- return "";
- Assert(plan!=NULL);
- str = makeStringInfo();
- explain_outNode(str, plan, 0, es);
- s = str->data;
- pfree(str);
-
- return s;
+ StringInfo str;
+ char *s;
+
+ if (plan == NULL)
+ return "";
+ Assert(plan != NULL);
+ str = makeStringInfo();
+ explain_outNode(str, plan, 0, es);
+ s = str->data;
+ pfree(str);
+
+ return s;
}
diff --git a/src/backend/commands/purge.c b/src/backend/commands/purge.c
index 5c514fc8675..8000bbc7352 100644
--- a/src/backend/commands/purge.c
+++ b/src/backend/commands/purge.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* purge.c--
- * the POSTGRES purge command.
+ * the POSTGRES purge command.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/purge.c,v 1.6 1997/08/12 22:52:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/purge.c,v 1.7 1997/09/07 04:40:51 momjian Exp $
*
* Note:
- * XXX There are many instances of int32 instead of ...Time. These
- * should be changed once it is decided the signed'ness will be.
+ * XXX There are many instances of int32 instead of ...Time. These
+ * should be changed once it is decided the signed'ness will be.
*
*-------------------------------------------------------------------------
*/
@@ -21,145 +21,156 @@
#include <access/heapam.h>
#include <access/xact.h>
-#include <utils/tqual.h> /* for NowTimeQual */
+#include <utils/tqual.h> /* for NowTimeQual */
#include <catalog/catname.h>
#include <catalog/indexing.h>
#include <fmgr.h>
#include <commands/purge.h>
-#include <utils/builtins.h> /* for isreltime() */
+#include <utils/builtins.h> /* for isreltime() */
-static char cmdname[] = "RelationPurge";
+static char cmdname[] = "RelationPurge";
-#define RELATIVE 01
-#define ABSOLUTE 02
+#define RELATIVE 01
+#define ABSOLUTE 02
int32
RelationPurge(char *relationName,
- char *absoluteTimeString,
- char *relativeTimeString)
+ char *absoluteTimeString,
+ char *relativeTimeString)
{
- register i;
- AbsoluteTime absoluteTime = INVALID_ABSTIME;
- RelativeTime relativeTime = INVALID_RELTIME;
- bits8 dateTag;
- Relation relation;
- HeapScanDesc scan;
- static ScanKeyData key[1] = {
- { 0, Anum_pg_class_relname, F_NAMEEQ }
- };
- Buffer buffer;
- HeapTuple newTuple, oldTuple;
- AbsoluteTime currentTime;
- char *values[Natts_pg_class];
- char nulls[Natts_pg_class];
- char replace[Natts_pg_class];
- Relation idescs[Num_pg_class_indices];
-
- /*
- * XXX for some reason getmyrelids (in inval.c) barfs when
- * you heap_replace tuples from these classes. i thought
- * setheapoverride would fix it but it didn't. for now,
- * just disallow purge on these classes.
- */
- if (strcmp(RelationRelationName, relationName) == 0 ||
- strcmp(AttributeRelationName, relationName) == 0 ||
- strcmp(AccessMethodRelationName, relationName) == 0 ||
- strcmp(AccessMethodOperatorRelationName, relationName) == 0) {
- elog(WARN, "%s: cannot purge catalog \"%s\"",
- cmdname, relationName);
- }
-
- if (PointerIsValid(absoluteTimeString)) {
- absoluteTime = (int32) nabstimein(absoluteTimeString);
- absoluteTimeString[0] = '\0';
- if (absoluteTime == INVALID_ABSTIME) {
- elog(NOTICE, "%s: bad absolute time string \"%s\"",
- cmdname, absoluteTimeString);
- elog(WARN, "purge not executed");
+ register i;
+ AbsoluteTime absoluteTime = INVALID_ABSTIME;
+ RelativeTime relativeTime = INVALID_RELTIME;
+ bits8 dateTag;
+ Relation relation;
+ HeapScanDesc scan;
+ static ScanKeyData key[1] = {
+ {0, Anum_pg_class_relname, F_NAMEEQ}
+ };
+ Buffer buffer;
+ HeapTuple newTuple,
+ oldTuple;
+ AbsoluteTime currentTime;
+ char *values[Natts_pg_class];
+ char nulls[Natts_pg_class];
+ char replace[Natts_pg_class];
+ Relation idescs[Num_pg_class_indices];
+
+ /*
+ * XXX for some reason getmyrelids (in inval.c) barfs when you
+ * heap_replace tuples from these classes. i thought setheapoverride
+ * would fix it but it didn't. for now, just disallow purge on these
+ * classes.
+ */
+ if (strcmp(RelationRelationName, relationName) == 0 ||
+ strcmp(AttributeRelationName, relationName) == 0 ||
+ strcmp(AccessMethodRelationName, relationName) == 0 ||
+ strcmp(AccessMethodOperatorRelationName, relationName) == 0)
+ {
+ elog(WARN, "%s: cannot purge catalog \"%s\"",
+ cmdname, relationName);
}
- }
-
-#ifdef PURGEDEBUG
- elog(DEBUG, "%s: absolute time `%s' is %d.",
- cmdname, absoluteTimeString, absoluteTime);
-#endif /* defined(PURGEDEBUG) */
-
- if (PointerIsValid(relativeTimeString)) {
- if (isreltime(relativeTimeString) != 1) {
- elog(WARN, "%s: bad relative time string \"%s\"",
- cmdname, relativeTimeString);
+
+ if (PointerIsValid(absoluteTimeString))
+ {
+ absoluteTime = (int32) nabstimein(absoluteTimeString);
+ absoluteTimeString[0] = '\0';
+ if (absoluteTime == INVALID_ABSTIME)
+ {
+ elog(NOTICE, "%s: bad absolute time string \"%s\"",
+ cmdname, absoluteTimeString);
+ elog(WARN, "purge not executed");
+ }
}
- relativeTime = reltimein(relativeTimeString);
-
+
+#ifdef PURGEDEBUG
+ elog(DEBUG, "%s: absolute time `%s' is %d.",
+ cmdname, absoluteTimeString, absoluteTime);
+#endif /* defined(PURGEDEBUG) */
+
+ if (PointerIsValid(relativeTimeString))
+ {
+ if (isreltime(relativeTimeString) != 1)
+ {
+ elog(WARN, "%s: bad relative time string \"%s\"",
+ cmdname, relativeTimeString);
+ }
+ relativeTime = reltimein(relativeTimeString);
+
#ifdef PURGEDEBUG
- elog(DEBUG, "%s: relative time `%s' is %d.",
- cmdname, relativeTimeString, relativeTime);
-#endif /* defined(PURGEDEBUG) */
- }
-
- /*
- * Find the RELATION relation tuple for the given relation.
- */
- relation = heap_openr(RelationRelationName);
- key[0].sk_argument = PointerGetDatum(relationName);
- fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
-
- scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
- oldTuple = heap_getnext(scan, 0, &buffer);
- if (!HeapTupleIsValid(oldTuple)) {
+ elog(DEBUG, "%s: relative time `%s' is %d.",
+ cmdname, relativeTimeString, relativeTime);
+#endif /* defined(PURGEDEBUG) */
+ }
+
+ /*
+ * Find the RELATION relation tuple for the given relation.
+ */
+ relation = heap_openr(RelationRelationName);
+ key[0].sk_argument = PointerGetDatum(relationName);
+ fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
+
+ scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
+ oldTuple = heap_getnext(scan, 0, &buffer);
+ if (!HeapTupleIsValid(oldTuple))
+ {
+ heap_endscan(scan);
+ heap_close(relation);
+ elog(WARN, "%s: no such relation: %s", cmdname, relationName);
+ return (0);
+ }
+
+ /*
+ * Dig around in the tuple.
+ */
+ currentTime = GetCurrentTransactionStartTime();
+ if (!RelativeTimeIsValid(relativeTime))
+ {
+ dateTag = ABSOLUTE;
+ if (!AbsoluteTimeIsValid(absoluteTime))
+ absoluteTime = currentTime;
+ }
+ else if (!AbsoluteTimeIsValid(absoluteTime))
+ dateTag = RELATIVE;
+ else
+ dateTag = ABSOLUTE | RELATIVE;
+
+ for (i = 0; i < Natts_pg_class; ++i)
+ {
+ nulls[i] = heap_attisnull(oldTuple, i + 1) ? 'n' : ' ';
+ values[i] = NULL;
+ replace[i] = ' ';
+ }
+ if (dateTag & ABSOLUTE)
+ {
+ values[Anum_pg_class_relexpires - 1] =
+ (char *) UInt32GetDatum(absoluteTime);
+ replace[Anum_pg_class_relexpires - 1] = 'r';
+ }
+ if (dateTag & RELATIVE)
+ {
+ values[Anum_pg_class_relpreserved - 1] =
+ (char *) UInt32GetDatum(relativeTime);
+ replace[Anum_pg_class_relpreserved - 1] = 'r';
+ }
+
+ /*
+ * Change the RELATION relation tuple for the given relation.
+ */
+ newTuple = heap_modifytuple(oldTuple, buffer, relation, (Datum *) values,
+ nulls, replace);
+
+ /* XXX How do you detect an insertion error?? */
+ heap_replace(relation, &newTuple->t_ctid, newTuple);
+
+ /* keep the system catalog indices current */
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newTuple);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+ pfree(newTuple);
+
heap_endscan(scan);
heap_close(relation);
- elog(WARN, "%s: no such relation: %s", cmdname, relationName);
- return(0);
- }
-
- /*
- * Dig around in the tuple.
- */
- currentTime = GetCurrentTransactionStartTime();
- if (!RelativeTimeIsValid(relativeTime)) {
- dateTag = ABSOLUTE;
- if (!AbsoluteTimeIsValid(absoluteTime))
- absoluteTime = currentTime;
- } else if (!AbsoluteTimeIsValid(absoluteTime))
- dateTag = RELATIVE;
- else
- dateTag = ABSOLUTE | RELATIVE;
-
- for (i = 0; i < Natts_pg_class; ++i) {
- nulls[i] = heap_attisnull(oldTuple, i+1) ? 'n' : ' ';
- values[i] = NULL;
- replace[i] = ' ';
- }
- if (dateTag & ABSOLUTE) {
- values[Anum_pg_class_relexpires-1] =
- (char *) UInt32GetDatum(absoluteTime);
- replace[Anum_pg_class_relexpires-1] = 'r';
- }
- if (dateTag & RELATIVE) {
- values[Anum_pg_class_relpreserved-1] =
- (char *) UInt32GetDatum(relativeTime);
- replace[Anum_pg_class_relpreserved-1] = 'r';
- }
-
- /*
- * Change the RELATION relation tuple for the given relation.
- */
- newTuple = heap_modifytuple(oldTuple, buffer, relation, (Datum*)values,
- nulls, replace);
-
- /* XXX How do you detect an insertion error?? */
- heap_replace(relation, &newTuple->t_ctid, newTuple);
-
- /* keep the system catalog indices current */
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newTuple);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
-
- pfree(newTuple);
-
- heap_endscan(scan);
- heap_close(relation);
- return(1);
+ return (1);
}
-
diff --git a/src/backend/commands/recipe.c b/src/backend/commands/recipe.c
index e6aa009bd33..bf05c293d13 100644
--- a/src/backend/commands/recipe.c
+++ b/src/backend/commands/recipe.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* recipe.c--
- * routines for handling execution of Tioga recipes
+ * routines for handling execution of Tioga recipes
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.6 1997/08/12 20:15:11 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.7 1997/09/07 04:40:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,7 +21,7 @@
#include <commands/recipe.h>
#include <libpq/libpq-be.h>
#include <utils/builtins.h>
-#include <utils/relcache.h> /* for RelationNameGetRelation*/
+#include <utils/relcache.h> /* for RelationNameGetRelation */
#include <parser/parse_query.h>
#include <rewrite/rewriteHandler.h>
#include <rewrite/rewriteManip.h>
@@ -35,9 +35,12 @@ extern CommandDest whereToSendOutput;
#ifndef TIOGA
-void beginRecipe(RecipeStmt *stmt) {
- elog(NOTICE,"You must compile with TIOGA defined in order to use recipes\n");
+void
+beginRecipe(RecipeStmt * stmt)
+{
+ elog(NOTICE, "You must compile with TIOGA defined in order to use recipes\n");
}
+
#else
#include <tioga/tgRecipe.h>
@@ -45,49 +48,59 @@ void beginRecipe(RecipeStmt *stmt) {
#define DEBUG_RECIPE 1
/* structure to keep track of the tee node plans */
-typedef struct _teePlanInfo {
- char* tpi_relName;
- Query* tpi_parsetree;
- Plan* tpi_plan;
-} TeePlanInfo;
-
-typedef struct _teeInfo {
- int num;
- TeePlanInfo *val;
-} TeeInfo;
-
-QueryTreeList *appendQlist(QueryTreeList *q1, QueryTreeList *q2);
-void OffsetVarAttno(Node* node, int varno, int offset);
-
-static void appendTeeQuery(TeeInfo *teeInfo,
- QueryTreeList *q,
- char* teeNodeName);
-
-static Plan* replaceTeeScans(Plan* plan,
- Query* parsetree,
- TeeInfo *teeInfo);
-static void replaceSeqScan(Plan* plan,
- Plan* parent,
- int rt_ind,
- Plan* tplan);
-
-static void tg_rewriteQuery(TgRecipe* r, TgNode *n,
- QueryTreeList *q,
- QueryTreeList *inputQlist);
-static Node *tg_replaceNumberedParam(Node* expression,
- int pnum,
- int rt_ind,
- char *teeRelName);
-static Node *tg_rewriteParamsInExpr(Node *expression,
- QueryTreeList *inputQlist);
-static QueryTreeList *tg_parseSubQuery(TgRecipe* r,
- TgNode* n,
- TeeInfo* teeInfo);
-static QueryTreeList* tg_parseTeeNode(TgRecipe *r,
- TgNode *n,
- int i,
- QueryTreeList *qList,
- TeeInfo* teeInfo);
+typedef struct _teePlanInfo
+{
+ char *tpi_relName;
+ Query *tpi_parsetree;
+ Plan *tpi_plan;
+} TeePlanInfo;
+
+typedef struct _teeInfo
+{
+ int num;
+ TeePlanInfo *val;
+} TeeInfo;
+
+QueryTreeList *appendQlist(QueryTreeList * q1, QueryTreeList * q2);
+void OffsetVarAttno(Node * node, int varno, int offset);
+
+static void
+appendTeeQuery(TeeInfo * teeInfo,
+ QueryTreeList * q,
+ char *teeNodeName);
+
+static Plan *
+replaceTeeScans(Plan * plan,
+ Query * parsetree,
+ TeeInfo * teeInfo);
+static void
+replaceSeqScan(Plan * plan,
+ Plan * parent,
+ int rt_ind,
+ Plan * tplan);
+
+static void
+tg_rewriteQuery(TgRecipe * r, TgNode * n,
+ QueryTreeList * q,
+ QueryTreeList * inputQlist);
+static Node *
+tg_replaceNumberedParam(Node * expression,
+ int pnum,
+ int rt_ind,
+ char *teeRelName);
+static Node *
+tg_rewriteParamsInExpr(Node * expression,
+ QueryTreeList * inputQlist);
+static QueryTreeList *
+tg_parseSubQuery(TgRecipe * r,
+ TgNode * n,
+ TeeInfo * teeInfo);
+static QueryTreeList *
+tg_parseTeeNode(TgRecipe * r,
+ TgNode * n,
+ int i,
+ QueryTreeList * qList,
+ TeeInfo * teeInfo);
/*
@@ -96,172 +109,192 @@ static QueryTreeList* tg_parseTeeNode(TgRecipe *r,
To parse a Tioga recipe, we start from an eye node and go backwards through
its input nodes. To rewrite a Tioga node, we do the following:
- 1) parse the node we're at in the standard way (calling parser() )
- 2) rewrite its input nodes recursively using Tioga rewrite
- 3) now, with the rewritten input parse trees and the original parse tree
- of the node, we rewrite the the node.
- To do the rewrite, we use the target lists, range tables, and
- qualifications of the input parse trees
+ 1) parse the node we're at in the standard way (calling parser() )
+ 2) rewrite its input nodes recursively using Tioga rewrite
+ 3) now, with the rewritten input parse trees and the original parse tree
+ of the node, we rewrite the the node.
+ To do the rewrite, we use the target lists, range tables, and
+ qualifications of the input parse trees
*/
/*
* beginRecipe:
- * this is the main function to recipe execution
- * this function is invoked for EXECUTE RECIPE ... statements
- *
- * takes in a RecipeStmt structure from the parser
+ * this is the main function to recipe execution
+ * this function is invoked for EXECUTE RECIPE ... statements
+ *
+ * takes in a RecipeStmt structure from the parser
* and returns a list of cursor names
*/
void
-beginRecipe(RecipeStmt* stmt)
+beginRecipe(RecipeStmt * stmt)
{
- TgRecipe* r;
- int i;
- QueryTreeList *qList;
- char portalName[1024];
-
- Plan *plan;
- TupleDesc attinfo;
- QueryDesc *queryDesc;
- Query *parsetree;
-
- int numTees;
- TeeInfo* teeInfo;
-
- /* retrieveRecipe() reads the recipe from the database
- and returns a TgRecipe* structure we can work with */
-
- r = retrieveRecipe(stmt->recipeName);
-
- if (r == NULL) return;
-
- /* find the number of tees in the recipe */
- numTees = r->tees->num;
-
- if (numTees > 0) {
- /* allocate a teePlan structure */
- teeInfo = (TeeInfo*)malloc(sizeof(TeeInfo));
- teeInfo->num = numTees;
- teeInfo->val = (TeePlanInfo*)malloc(numTees * sizeof(TeePlanInfo));
- for (i=0;i<numTees;i++) {
- teeInfo->val[i].tpi_relName = r->tees->val[i]->nodeName;
- teeInfo->val[i].tpi_parsetree = NULL;
- teeInfo->val[i].tpi_plan = NULL;
- }
- } else
- teeInfo = NULL;
-
- /*
- * for each viewer in the recipe, go backwards from each viewer input
- * and generate a plan. Attach the plan to cursors.
- **/
- for (i=0;i<r->eyes->num;i++) {
- TgNodePtr e;
-
- e = r->eyes->val[i];
- if (e->inNodes->num > 1) {
- elog(NOTICE,
- "beginRecipe: Currently eyes cannot have more than one input");
- }
- if (e->inNodes->num == 0) {
- /* no input to this eye, skip it */
- continue;
- }
+ TgRecipe *r;
+ int i;
+ QueryTreeList *qList;
+ char portalName[1024];
+
+ Plan *plan;
+ TupleDesc attinfo;
+ QueryDesc *queryDesc;
+ Query *parsetree;
+
+ int numTees;
+ TeeInfo *teeInfo;
+
+ /*
+ * retrieveRecipe() reads the recipe from the database and returns a
+ * TgRecipe* structure we can work with
+ */
+
+ r = retrieveRecipe(stmt->recipeName);
+
+ if (r == NULL)
+ return;
+
+ /* find the number of tees in the recipe */
+ numTees = r->tees->num;
+
+ if (numTees > 0)
+ {
+ /* allocate a teePlan structure */
+ teeInfo = (TeeInfo *) malloc(sizeof(TeeInfo));
+ teeInfo->num = numTees;
+ teeInfo->val = (TeePlanInfo *) malloc(numTees * sizeof(TeePlanInfo));
+ for (i = 0; i < numTees; i++)
+ {
+ teeInfo->val[i].tpi_relName = r->tees->val[i]->nodeName;
+ teeInfo->val[i].tpi_parsetree = NULL;
+ teeInfo->val[i].tpi_plan = NULL;
+ }
+ }
+ else
+ teeInfo = NULL;
+
+ /*
+ * for each viewer in the recipe, go backwards from each viewer input
+ * and generate a plan. Attach the plan to cursors.
+ */
+ for (i = 0; i < r->eyes->num; i++)
+ {
+ TgNodePtr e;
+
+ e = r->eyes->val[i];
+ if (e->inNodes->num > 1)
+ {
+ elog(NOTICE,
+ "beginRecipe: Currently eyes cannot have more than one input");
+ }
+ if (e->inNodes->num == 0)
+ {
+ /* no input to this eye, skip it */
+ continue;
+ }
#ifdef DEBUG_RECIPE
- elog(NOTICE,"beginRecipe: eyes[%d] = %s\n", i, e->nodeName);
-#endif /* DEBUG_RECIPE */
-
- qList = tg_parseSubQuery(r,e->inNodes->val[0], teeInfo);
-
- if (qList == NULL) {
- /* eye is directly connected to a tee node */
- /* XXX TODO: handle this case */
- }
-
- /* now, plan the queries */
- /* should really do everything pg_plan() does, but for now,
- we skip the rule rewrite and time qual stuff */
-
- /* ----------------------------------------------------------
- * 1) plan the main query, everything from an eye node back to
- a Tee
- * ---------------------------------------------------------- */
- parsetree = qList->qtrees[0];
-
- /* before we plan, we want to see all the changes
- we did, during the rewrite phase, such as
- creating the tee tables,
- setheapoverride() allows us to see the changes */
- setheapoverride(true);
- plan = planner(parsetree);
-
- /* ----------------------------------------------------------
- * 2) plan the tee queries, (subgraphs rooted from a Tee)
- by the time the eye is processed, all tees that contribute
- to that eye will have been included in the teeInfo list
- * ---------------------------------------------------------- */
- if (teeInfo) {
- int t;
- Plan* tplan;
- Tee* newplan;
-
- for (t=0; t<teeInfo->num;t++) {
- if (teeInfo->val[t].tpi_plan == NULL) {
- /* plan it in the usual fashion */
- tplan = planner(teeInfo->val[t].tpi_parsetree);
-
- /* now add a tee node to the root of the plan */
-elog(NOTICE, "adding tee plan node to the root of the %s\n",
- teeInfo->val[t].tpi_relName);
- newplan = (Tee*)makeNode(Tee);
- newplan->plan.targetlist = tplan->targetlist;
- newplan->plan.qual = NULL; /* tplan->qual; */
- newplan->plan.lefttree = tplan;
- newplan->plan.righttree = NULL;
- newplan->leftParent = NULL;
- newplan->rightParent = NULL;
- /* the range table of the tee is the range table
- of the tplan */
- newplan->rtentries = teeInfo->val[t].tpi_parsetree->rtable;
- strcpy(newplan->teeTableName,
- teeInfo->val[t].tpi_relName);
- teeInfo->val[t].tpi_plan = (Plan*)newplan;
- }
- }
-
- /* ----------------------------------------------------------
- * 3) replace the tee table scans in the main plan with
- actual tee plannodes
- * ---------------------------------------------------------- */
-
- plan = replaceTeeScans(plan, parsetree, teeInfo);
-
- } /* if (teeInfo) */
-
- setheapoverride(false);
-
- /* define a portal for this viewer input */
- /* for now, eyes can only have one input */
- sprintf(portalName, "%s%d",e->nodeName,0);
-
- queryDesc = CreateQueryDesc(parsetree,
- plan,
- whereToSendOutput);
- /* ----------------
- * call ExecStart to prepare the plan for execution
- * ----------------
- */
- attinfo = ExecutorStart(queryDesc,NULL);
-
- ProcessPortal(portalName,
- parsetree,
- plan,
- attinfo,
- whereToSendOutput);
-elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName);
- }
+ elog(NOTICE, "beginRecipe: eyes[%d] = %s\n", i, e->nodeName);
+#endif /* DEBUG_RECIPE */
+
+ qList = tg_parseSubQuery(r, e->inNodes->val[0], teeInfo);
+
+ if (qList == NULL)
+ {
+ /* eye is directly connected to a tee node */
+ /* XXX TODO: handle this case */
+ }
+
+ /* now, plan the queries */
+
+ /*
+ * should really do everything pg_plan() does, but for now, we
+ * skip the rule rewrite and time qual stuff
+ */
+
+ /* ----------------------------------------------------------
+ * 1) plan the main query, everything from an eye node back to
+ a Tee
+ * ---------------------------------------------------------- */
+ parsetree = qList->qtrees[0];
+
+ /*
+ * before we plan, we want to see all the changes we did, during
+ * the rewrite phase, such as creating the tee tables,
+ * setheapoverride() allows us to see the changes
+ */
+ setheapoverride(true);
+ plan = planner(parsetree);
+
+ /* ----------------------------------------------------------
+ * 2) plan the tee queries, (subgraphs rooted from a Tee)
+ by the time the eye is processed, all tees that contribute
+ to that eye will have been included in the teeInfo list
+ * ---------------------------------------------------------- */
+ if (teeInfo)
+ {
+ int t;
+ Plan *tplan;
+ Tee *newplan;
+
+ for (t = 0; t < teeInfo->num; t++)
+ {
+ if (teeInfo->val[t].tpi_plan == NULL)
+ {
+ /* plan it in the usual fashion */
+ tplan = planner(teeInfo->val[t].tpi_parsetree);
+
+ /* now add a tee node to the root of the plan */
+ elog(NOTICE, "adding tee plan node to the root of the %s\n",
+ teeInfo->val[t].tpi_relName);
+ newplan = (Tee *) makeNode(Tee);
+ newplan->plan.targetlist = tplan->targetlist;
+ newplan->plan.qual = NULL; /* tplan->qual; */
+ newplan->plan.lefttree = tplan;
+ newplan->plan.righttree = NULL;
+ newplan->leftParent = NULL;
+ newplan->rightParent = NULL;
+
+ /*
+ * the range table of the tee is the range table of
+ * the tplan
+ */
+ newplan->rtentries = teeInfo->val[t].tpi_parsetree->rtable;
+ strcpy(newplan->teeTableName,
+ teeInfo->val[t].tpi_relName);
+ teeInfo->val[t].tpi_plan = (Plan *) newplan;
+ }
+ }
+
+ /* ----------------------------------------------------------
+ * 3) replace the tee table scans in the main plan with
+ actual tee plannodes
+ * ---------------------------------------------------------- */
+
+ plan = replaceTeeScans(plan, parsetree, teeInfo);
+
+ } /* if (teeInfo) */
+
+ setheapoverride(false);
+
+ /* define a portal for this viewer input */
+ /* for now, eyes can only have one input */
+ sprintf(portalName, "%s%d", e->nodeName, 0);
+
+ queryDesc = CreateQueryDesc(parsetree,
+ plan,
+ whereToSendOutput);
+ /* ----------------
+ * call ExecStart to prepare the plan for execution
+ * ----------------
+ */
+ attinfo = ExecutorStart(queryDesc, NULL);
+
+ ProcessPortal(portalName,
+ parsetree,
+ plan,
+ attinfo,
+ whereToSendOutput);
+ elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName);
+ }
}
@@ -269,109 +302,122 @@ elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName);
/*
* tg_rewriteQuery -
- * r - the recipe being rewritten
- * n - the node that we're current at
- * q - a QueryTree List containing the parse tree of the node
- * inputQlist - the parsetrees of its input nodes,
- * the size of inputQlist must be the same as the
- * number of input nodes. Some elements in the inpuQlist
- * may be null if the inputs to those nodes are unconnected
+ * r - the recipe being rewritten
+ * n - the node that we're current at
+ * q - a QueryTree List containing the parse tree of the node
+ * inputQlist - the parsetrees of its input nodes,
+ * the size of inputQlist must be the same as the
+ * number of input nodes. Some elements in the inpuQlist
+ * may be null if the inputs to those nodes are unconnected
*
- * this is the main routine for rewriting the recipe queries
- * the original query tree 'q' is modified
+ * this is the main routine for rewriting the recipe queries
+ * the original query tree 'q' is modified
*/
-static void
-tg_rewriteQuery(TgRecipe* r,
- TgNode *n,
- QueryTreeList *q,
- QueryTreeList *inputQlist)
+static void
+tg_rewriteQuery(TgRecipe * r,
+ TgNode * n,
+ QueryTreeList * q,
+ QueryTreeList * inputQlist)
{
- Query* orig;
- Query* inputQ;
- int i;
- List *rtable;
- List *input_rtable;
- int rt_length;
-
- /* orig is the original parse tree of the node */
- orig = q->qtrees[0];
-
-
- /*-------------------------------------------------------------------
- step 1:
-
- form a combined range table from all the range tables in the original
- query as well as the input nodes
-
- form a combined qualification from the qual in the original plus
- the quals of the input nodes
- -------------------------------------------------------------------
- */
-
- /* start with the original range table */
- rtable = orig->rtable;
- rt_length = length(rtable);
-
- for (i=0;i<n->inNodes->num;i++) {
- if (n->inNodes->val[i] != NULL &&
- n->inNodes->val[i]->nodeType != TG_TEE_NODE) {
- inputQ = inputQlist->qtrees[i];
- input_rtable = inputQ->rtable;
-
- /* need to offset the var nodes in the qual and targetlist
- because they are indexed off the original rtable */
- OffsetVarNodes((Node*)inputQ->qual, rt_length);
- OffsetVarNodes((Node*)inputQ->targetList, rt_length);
-
- /* append the range tables from the children nodes */
- rtable = nconc (rtable, input_rtable);
-
- /* append the qualifications of the child node into the
- original qual list */
- AddQual(orig, inputQ->qual);
+ Query *orig;
+ Query *inputQ;
+ int i;
+ List *rtable;
+ List *input_rtable;
+ int rt_length;
+
+ /* orig is the original parse tree of the node */
+ orig = q->qtrees[0];
+
+
+ /*-------------------------------------------------------------------
+ step 1:
+
+ form a combined range table from all the range tables in the original
+ query as well as the input nodes
+
+ form a combined qualification from the qual in the original plus
+ the quals of the input nodes
+ -------------------------------------------------------------------
+ */
+
+ /* start with the original range table */
+ rtable = orig->rtable;
+ rt_length = length(rtable);
+
+ for (i = 0; i < n->inNodes->num; i++)
+ {
+ if (n->inNodes->val[i] != NULL &&
+ n->inNodes->val[i]->nodeType != TG_TEE_NODE)
+ {
+ inputQ = inputQlist->qtrees[i];
+ input_rtable = inputQ->rtable;
+
+ /*
+ * need to offset the var nodes in the qual and targetlist
+ * because they are indexed off the original rtable
+ */
+ OffsetVarNodes((Node *) inputQ->qual, rt_length);
+ OffsetVarNodes((Node *) inputQ->targetList, rt_length);
+
+ /* append the range tables from the children nodes */
+ rtable = nconc(rtable, input_rtable);
+
+ /*
+ * append the qualifications of the child node into the
+ * original qual list
+ */
+ AddQual(orig, inputQ->qual);
+ }
}
- }
- orig->rtable = rtable;
-
- /* step 2:
- rewrite the target list of the original parse tree
- if there are any references to params, replace them with
- the appropriate target list entry of the children node
- */
- if (orig->targetList != NIL) {
- List *tl;
- TargetEntry *tle;
-
- foreach (tl, orig->targetList) {
- tle = lfirst(tl);
- if (tle->resdom != NULL) {
- tle->expr = tg_rewriteParamsInExpr(tle->expr, inputQlist);
- }
- }
- }
-
- /* step 3:
- rewrite the qual of the original parse tree
- if there are any references to params, replace them with
- the appropriate target list entry of the children node
- */
- if (orig->qual) {
- if (nodeTag(orig->qual) == T_List) {
- elog(WARN, "tg_rewriteQuery: Whoa! why is my qual a List???");
+ orig->rtable = rtable;
+
+ /*
+ * step 2: rewrite the target list of the original parse tree if there
+ * are any references to params, replace them with the appropriate
+ * target list entry of the children node
+ */
+ if (orig->targetList != NIL)
+ {
+ List *tl;
+ TargetEntry *tle;
+
+ foreach(tl, orig->targetList)
+ {
+ tle = lfirst(tl);
+ if (tle->resdom != NULL)
+ {
+ tle->expr = tg_rewriteParamsInExpr(tle->expr, inputQlist);
+ }
+ }
+ }
+
+ /*
+ * step 3: rewrite the qual of the original parse tree if there are
+ * any references to params, replace them with the appropriate target
+ * list entry of the children node
+ */
+ if (orig->qual)
+ {
+ if (nodeTag(orig->qual) == T_List)
+ {
+ elog(WARN, "tg_rewriteQuery: Whoa! why is my qual a List???");
+ }
+ orig->qual = tg_rewriteParamsInExpr(orig->qual, inputQlist);
}
- orig->qual = tg_rewriteParamsInExpr(orig->qual, inputQlist);
- }
- /* at this point, we're done with the rewrite, the querytreelist q
- has been modified */
+ /*
+ * at this point, we're done with the rewrite, the querytreelist q has
+ * been modified
+ */
}
/* tg_replaceNumberedParam:
- this procedure replaces the specified numbered param with a
+ this procedure replaces the specified numbered param with a
reference to a range table
this procedure recursively calls itself
@@ -379,104 +425,137 @@ tg_rewriteQuery(TgRecipe* r,
it returns a (possibly modified) Node*.
*/
-static Node*
-tg_replaceNumberedParam(Node *expression,
- int pnum, /* the number of the parameter */
- int rt_ind, /* the range table index */
- char *teeRelName) /* the relname of the tee table */
+static Node *
+tg_replaceNumberedParam(Node * expression,
+ int pnum, /* the number of the parameter */
+ int rt_ind, /* the range table index */
+ char *teeRelName) /* the relname of the tee
+ * table */
{
- TargetEntry *param_tle;
- Param* p;
- Var *newVar,*oldVar;
-
- if (expression == NULL) return NULL;
-
- switch (nodeTag(expression)) {
- case T_Param:
- {
- /* the node is a parameter,
- substitute the entry from the target list of the child that
- corresponds to the parameter number*/
- p = (Param*)expression;
-
- /* we only deal with the case of numbered parameters */
- if (p->paramkind == PARAM_NUM && p->paramid == pnum) {
-
- if (p->param_tlist) {
- /* we have a parameter with an attribute like $N.foo
- so replace it with a new var node */
-
- /* param tlist can only have one entry in them! */
- param_tle = (TargetEntry*)(lfirst(p->param_tlist));
- oldVar = (Var*)param_tle->expr;
- oldVar->varno = rt_ind;
- oldVar->varnoold = rt_ind;
- return (Node*)oldVar;
- } else {
- /* we have $N without the .foo */
- bool defined;
- bool isRel;
- /* TODO here, we need to check to see whether the type of the
- tee is a complex type (relation) or a simple type */
- /* if it is a simple type, then we need to get the "result"
- attribute from the tee relation */
-
- isRel = (typeid_get_relid(p->paramtype) != 0);
- if (isRel) {
- newVar = makeVar(rt_ind,
- 0, /* the whole tuple */
- TypeGet(teeRelName,&defined),
- rt_ind,
- 0);
- return (Node*)newVar;
- } else
- newVar = makeVar(rt_ind,
- 1, /* just the first field, which is 'result' */
- TypeGet(teeRelName,&defined),
- rt_ind,
- 0);
- return (Node*)newVar;
-
- }
- }
- else {
- elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind);
- }
- }
- break;
- case T_Expr:
- {
- /* the node is an expression, we need to recursively
- call ourselves until we find parameter nodes */
- List *l;
- Expr *expr = (Expr*)expression;
- List *newArgs;
-
- /* we have to make a new args lists because Params
- can be replaced by Var nodes in tg_replaceNumberedParam()*/
- newArgs = NIL;
-
- /* we only care about argument to expressions,
- it doesn't matter when the opType is */
- /* recursively rewrite the arguments of this expression */
- foreach (l, expr->args) {
- newArgs = lappend(newArgs,
- tg_replaceNumberedParam(lfirst(l),
- pnum,
- rt_ind,
- teeRelName));
- }
- /* change the arguments of the expression */
- expr->args = newArgs;
- }
- break;
- default:
- {
- /* ignore other expr types */
- }
- }
-
- return expression;
+ TargetEntry *param_tle;
+ Param *p;
+ Var *newVar,
+ *oldVar;
+
+ if (expression == NULL)
+ return NULL;
+
+ switch (nodeTag(expression))
+ {
+ case T_Param:
+ {
+
+ /*
+ * the node is a parameter, substitute the entry from the
+ * target list of the child that corresponds to the parameter
+ * number
+ */
+ p = (Param *) expression;
+
+ /* we only deal with the case of numbered parameters */
+ if (p->paramkind == PARAM_NUM && p->paramid == pnum)
+ {
+
+ if (p->param_tlist)
+ {
+
+ /*
+ * we have a parameter with an attribute like $N.foo
+ * so replace it with a new var node
+ */
+
+ /* param tlist can only have one entry in them! */
+ param_tle = (TargetEntry *) (lfirst(p->param_tlist));
+ oldVar = (Var *) param_tle->expr;
+ oldVar->varno = rt_ind;
+ oldVar->varnoold = rt_ind;
+ return (Node *) oldVar;
+ }
+ else
+ {
+ /* we have $N without the .foo */
+ bool defined;
+ bool isRel;
+
+ /*
+ * TODO here, we need to check to see whether the type
+ * of the tee is a complex type (relation) or a simple
+ * type
+ */
+
+ /*
+ * if it is a simple type, then we need to get the
+ * "result" attribute from the tee relation
+ */
+
+ isRel = (typeid_get_relid(p->paramtype) != 0);
+ if (isRel)
+ {
+ newVar = makeVar(rt_ind,
+ 0, /* the whole tuple */
+ TypeGet(teeRelName, &defined),
+ rt_ind,
+ 0);
+ return (Node *) newVar;
+ }
+ else
+ newVar = makeVar(rt_ind,
+ 1, /* just the first field,
+ * which is 'result' */
+ TypeGet(teeRelName, &defined),
+ rt_ind,
+ 0);
+ return (Node *) newVar;
+
+ }
+ }
+ else
+ {
+ elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind);
+ }
+ }
+ break;
+ case T_Expr:
+ {
+
+ /*
+ * the node is an expression, we need to recursively call
+ * ourselves until we find parameter nodes
+ */
+ List *l;
+ Expr *expr = (Expr *) expression;
+ List *newArgs;
+
+ /*
+ * we have to make a new args lists because Params can be
+ * replaced by Var nodes in tg_replaceNumberedParam()
+ */
+ newArgs = NIL;
+
+ /*
+ * we only care about argument to expressions, it doesn't
+ * matter when the opType is
+ */
+ /* recursively rewrite the arguments of this expression */
+ foreach(l, expr->args)
+ {
+ newArgs = lappend(newArgs,
+ tg_replaceNumberedParam(lfirst(l),
+ pnum,
+ rt_ind,
+ teeRelName));
+ }
+ /* change the arguments of the expression */
+ expr->args = newArgs;
+ }
+ break;
+ default:
+ {
+ /* ignore other expr types */
+ }
+ }
+
+ return expression;
}
@@ -485,694 +564,817 @@ tg_replaceNumberedParam(Node *expression,
/* tg_rewriteParamsInExpr:
- rewrite the params in expressions by using the targetlist entries
- from the input parsetrees
+ rewrite the params in expressions by using the targetlist entries
+ from the input parsetrees
this procedure recursively calls itself
it returns a (possibly modified) Node*.
*/
-static Node*
-tg_rewriteParamsInExpr(Node *expression, QueryTreeList *inputQlist)
+static Node *
+tg_rewriteParamsInExpr(Node * expression, QueryTreeList * inputQlist)
{
- List *tl;
- TargetEntry *param_tle, *tle;
- Param* p;
- int childno;
- char *resname;
-
- if (expression == NULL) return NULL;
-
- switch (nodeTag(expression)) {
- case T_Param:
- {
- /* the node is a parameter,
- substitute the entry from the target list of the child that
- corresponds to the parameter number*/
- p = (Param*)expression;
-
- /* we only deal with the case of numbered parameters */
- if (p->paramkind == PARAM_NUM) {
- /* paramid's start from 1*/
- childno = p->paramid - 1;
-
- if (p->param_tlist) {
- /* we have a parameter with an attribute like $N.foo
- so match the resname "foo" against the target list
- of the (N-1)th inputQlist */
-
- /* param tlist can only have one entry in them! */
- param_tle = (TargetEntry*)(lfirst(p->param_tlist));
- resname = param_tle->resdom->resname;
-
- if (inputQlist->qtrees[childno]) {
- foreach (tl, inputQlist->qtrees[childno]->targetList) {
- tle = lfirst(tl);
- if (strcmp(resname, tle->resdom->resname) == 0) {
- return tle->expr;
- }
- }
- }
- else {
- elog(WARN,"tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid);
- }
-
- } else {
- /* we have $N without the .foo */
- /* use the first resdom in the targetlist of the */
- /* appropriate child query */
- tl = inputQlist->qtrees[childno]->targetList;
- tle = lfirst(tl);
- return tle->expr;
- }
- }
- else {
- elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind);
- }
- }
- break;
- case T_Expr:
- {
- /* the node is an expression, we need to recursively
- call ourselves until we find parameter nodes */
- List *l;
- Expr *expr = (Expr*)expression;
- List *newArgs;
-
- /* we have to make a new args lists because Params
- can be replaced by Var nodes in tg_rewriteParamsInExpr()*/
- newArgs = NIL;
-
- /* we only care about argument to expressions,
- it doesn't matter when the opType is */
- /* recursively rewrite the arguments of this expression */
- foreach (l, expr->args) {
- newArgs = lappend(newArgs,
- tg_rewriteParamsInExpr(lfirst(l), inputQlist));
- }
- /* change the arguments of the expression */
- expr->args = newArgs;
- }
- break;
- default:
- {
- /* ignore other expr types */
- }
- }
-
- return expression;
+ List *tl;
+ TargetEntry *param_tle,
+ *tle;
+ Param *p;
+ int childno;
+ char *resname;
+
+ if (expression == NULL)
+ return NULL;
+
+ switch (nodeTag(expression))
+ {
+ case T_Param:
+ {
+
+ /*
+ * the node is a parameter, substitute the entry from the
+ * target list of the child that corresponds to the parameter
+ * number
+ */
+ p = (Param *) expression;
+
+ /* we only deal with the case of numbered parameters */
+ if (p->paramkind == PARAM_NUM)
+ {
+ /* paramid's start from 1 */
+ childno = p->paramid - 1;
+
+ if (p->param_tlist)
+ {
+
+ /*
+ * we have a parameter with an attribute like $N.foo
+ * so match the resname "foo" against the target list
+ * of the (N-1)th inputQlist
+ */
+
+ /* param tlist can only have one entry in them! */
+ param_tle = (TargetEntry *) (lfirst(p->param_tlist));
+ resname = param_tle->resdom->resname;
+
+ if (inputQlist->qtrees[childno])
+ {
+ foreach(tl, inputQlist->qtrees[childno]->targetList)
+ {
+ tle = lfirst(tl);
+ if (strcmp(resname, tle->resdom->resname) == 0)
+ {
+ return tle->expr;
+ }
+ }
+ }
+ else
+ {
+ elog(WARN, "tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid);
+ }
+
+ }
+ else
+ {
+ /* we have $N without the .foo */
+ /* use the first resdom in the targetlist of the */
+ /* appropriate child query */
+ tl = inputQlist->qtrees[childno]->targetList;
+ tle = lfirst(tl);
+ return tle->expr;
+ }
+ }
+ else
+ {
+ elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind);
+ }
+ }
+ break;
+ case T_Expr:
+ {
+
+ /*
+ * the node is an expression, we need to recursively call
+ * ourselves until we find parameter nodes
+ */
+ List *l;
+ Expr *expr = (Expr *) expression;
+ List *newArgs;
+
+ /*
+ * we have to make a new args lists because Params can be
+ * replaced by Var nodes in tg_rewriteParamsInExpr()
+ */
+ newArgs = NIL;
+
+ /*
+ * we only care about argument to expressions, it doesn't
+ * matter when the opType is
+ */
+ /* recursively rewrite the arguments of this expression */
+ foreach(l, expr->args)
+ {
+ newArgs = lappend(newArgs,
+ tg_rewriteParamsInExpr(lfirst(l), inputQlist));
+ }
+ /* change the arguments of the expression */
+ expr->args = newArgs;
+ }
+ break;
+ default:
+ {
+ /* ignore other expr types */
+ }
+ }
+
+ return expression;
}
/*
getParamTypes:
- given an element, finds its parameter types.
- the typev array argument is set to the parameter types.
- the parameterCount is returned
-
- this code is very similar to ProcedureDefine() in pg_proc.c
+ given an element, finds its parameter types.
+ the typev array argument is set to the parameter types.
+ the parameterCount is returned
+
+ this code is very similar to ProcedureDefine() in pg_proc.c
*/
static int
-getParamTypes (TgElement *elem, Oid typev[])
+getParamTypes(TgElement * elem, Oid typev[])
{
- /* this code is similar to ProcedureDefine() */
- int16 parameterCount;
- bool defined;
- Oid toid;
- char *t;
- int i,j;
-
- parameterCount = 0;
- for (i=0;i<8;i++) {
- typev[i] = 0;
- }
- for (j=0;j<elem->inTypes->num;j++) {
- if (parameterCount == 8) {
- elog(WARN,
- "getParamTypes: Ingredients cannot take > 8 arguments");
+ /* this code is similar to ProcedureDefine() */
+ int16 parameterCount;
+ bool defined;
+ Oid toid;
+ char *t;
+ int i,
+ j;
+
+ parameterCount = 0;
+ for (i = 0; i < 8; i++)
+ {
+ typev[i] = 0;
}
- t = elem->inTypes->val[j];
- if (strcmp(t,"opaque") == 0) {
- elog(WARN,
- "getParamTypes: Ingredient functions cannot take type 'opaque'");
- } else {
- toid = TypeGet(elem->inTypes->val[j], &defined);
- if (!OidIsValid(toid)) {
- elog(WARN, "getParamTypes: arg type '%s' is not defined",t);
- }
- if (!defined) {
- elog(NOTICE, "getParamTypes: arg type '%s' is only a shell",t);
- }
+ for (j = 0; j < elem->inTypes->num; j++)
+ {
+ if (parameterCount == 8)
+ {
+ elog(WARN,
+ "getParamTypes: Ingredients cannot take > 8 arguments");
+ }
+ t = elem->inTypes->val[j];
+ if (strcmp(t, "opaque") == 0)
+ {
+ elog(WARN,
+ "getParamTypes: Ingredient functions cannot take type 'opaque'");
+ }
+ else
+ {
+ toid = TypeGet(elem->inTypes->val[j], &defined);
+ if (!OidIsValid(toid))
+ {
+ elog(WARN, "getParamTypes: arg type '%s' is not defined", t);
+ }
+ if (!defined)
+ {
+ elog(NOTICE, "getParamTypes: arg type '%s' is only a shell", t);
+ }
+ }
+ typev[parameterCount++] = toid;
}
- typev[parameterCount++] = toid;
- }
- return parameterCount;
+ return parameterCount;
}
/*
* tg_parseTeeNode
- *
- * handles the parsing of the tee node
- *
+ *
+ * handles the parsing of the tee node
+ *
*
*/
-static QueryTreeList*
-tg_parseTeeNode(TgRecipe *r,
- TgNode *n, /* the tee node */
- int i, /* which input this node is to its parent */
- QueryTreeList *qList,
- TeeInfo* teeInfo)
+static QueryTreeList *
+tg_parseTeeNode(TgRecipe * r,
+ TgNode * n, /* the tee node */
+ int i, /* which input this node is to its parent */
+ QueryTreeList * qList,
+ TeeInfo * teeInfo)
{
- QueryTreeList *q;
- char* tt;
- int rt_ind;
- Query* orig;
-
- /* the input Node is a tee node, so we need to do the following:
- * we need to parse the child of the tee node,
- we add that to our query tree list
- * we need the name of the tee node table
- the tee node table is the table into which the tee node
- may materialize results. Call it TT
- * we add a range table to our existing query with TT in it
- * we need to replace the parameter $i with TT
- (otherwise the optimizer won't know to use the table
- on expression containining $i)
- After that rewrite, the optimizer will generate
- sequential scans of TT
-
- Later, in the glue phase, we replace all instances of TT
- sequential scans with the actual Tee node
- */
- q = tg_parseSubQuery(r,n, teeInfo);
-
- /* tt is the name of the tee node table */
- tt = n->nodeName;
-
- if (q)
- appendTeeQuery(teeInfo,q,tt);
-
- orig = qList->qtrees[0];
- rt_ind = RangeTablePosn(orig->rtable,tt);
- /* check to see that this table is not part of
- the range table already. This usually only
- happens if multiple inputs are connected to the
- same Tee. */
- if (rt_ind == 0) {
- orig->rtable = lappend(orig->rtable,
- addRangeTableEntry(NULL,
- tt,
- tt,
- FALSE,
- FALSE,
- NULL));
- rt_ind = length(orig->rtable);
- }
-
- orig->qual = tg_replaceNumberedParam(orig->qual,
- i+1, /* params start at 1*/
- rt_ind,
- tt);
- return qList;
+ QueryTreeList *q;
+ char *tt;
+ int rt_ind;
+ Query *orig;
+
+ /*
+ * the input Node is a tee node, so we need to do the following: we
+ * need to parse the child of the tee node, we add that to our query
+ * tree list we need the name of the tee node table the tee node table
+ * is the table into which the tee node may materialize results. Call
+ * it TT we add a range table to our existing query with TT in it we
+ * need to replace the parameter $i with TT (otherwise the optimizer
+ * won't know to use the table on expression containining $i) After
+ * that rewrite, the optimizer will generate sequential scans of TT
+ *
+ * Later, in the glue phase, we replace all instances of TT sequential
+ * scans with the actual Tee node
+ */
+ q = tg_parseSubQuery(r, n, teeInfo);
+
+ /* tt is the name of the tee node table */
+ tt = n->nodeName;
+
+ if (q)
+ appendTeeQuery(teeInfo, q, tt);
+
+ orig = qList->qtrees[0];
+ rt_ind = RangeTablePosn(orig->rtable, tt);
+
+ /*
+ * check to see that this table is not part of the range table
+ * already. This usually only happens if multiple inputs are
+ * connected to the same Tee.
+ */
+ if (rt_ind == 0)
+ {
+ orig->rtable = lappend(orig->rtable,
+ addRangeTableEntry(NULL,
+ tt,
+ tt,
+ FALSE,
+ FALSE,
+ NULL));
+ rt_ind = length(orig->rtable);
+ }
+
+ orig->qual = tg_replaceNumberedParam(orig->qual,
+ i + 1, /* params start at 1 */
+ rt_ind,
+ tt);
+ return qList;
}
/*
* tg_parseSubQuery:
- * go backwards from a node and parse the query
+ * go backwards from a node and parse the query
*
- * the result parse tree is passed back
- *
- * could return NULL if trying to parse a teeNode
+ * the result parse tree is passed back
+ *
+ * could return NULL if trying to parse a teeNode
* that's already been processed by another parent
- *
+ *
*/
-static QueryTreeList*
-tg_parseSubQuery(TgRecipe* r, TgNode* n, TeeInfo* teeInfo)
+static QueryTreeList *
+tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
{
- TgElement *elem;
- char* funcName;
- Oid typev[8]; /* eight arguments maximum */
- int i;
- int parameterCount;
-
- QueryTreeList *qList; /* the parse tree of the nodeElement */
- QueryTreeList *inputQlist; /* the list of parse trees for the
- inputs to this node */
- QueryTreeList *q;
- Oid relid;
- TgNode* child;
- Relation rel;
- unsigned int len;
- TupleDesc tupdesc;
-
- qList = NULL;
-
- if (n->nodeType == TG_INGRED_NODE) {
- /* parse each ingredient node in turn */
-
- elem = n->nodeElem;
- switch (elem->srcLang) {
- case TG_SQL:
- {
- /* for SQL ingredients, the SQL query is contained in the
- 'src' field */
+ TgElement *elem;
+ char *funcName;
+ Oid typev[8]; /* eight arguments maximum */
+ int i;
+ int parameterCount;
+
+ QueryTreeList *qList; /* the parse tree of the nodeElement */
+ QueryTreeList *inputQlist; /* the list of parse trees for the inputs
+ * to this node */
+ QueryTreeList *q;
+ Oid relid;
+ TgNode *child;
+ Relation rel;
+ unsigned int len;
+ TupleDesc tupdesc;
+
+ qList = NULL;
+
+ if (n->nodeType == TG_INGRED_NODE)
+ {
+ /* parse each ingredient node in turn */
+
+ elem = n->nodeElem;
+ switch (elem->srcLang)
+ {
+ case TG_SQL:
+ {
+
+ /*
+ * for SQL ingredients, the SQL query is contained in the
+ * 'src' field
+ */
#ifdef DEBUG_RECIPE
-elog(NOTICE,"calling parser with %s",elem->src);
-#endif /* DEBUG_RECIPE */
+ elog(NOTICE, "calling parser with %s", elem->src);
+#endif /* DEBUG_RECIPE */
- parameterCount = getParamTypes(elem,typev);
+ parameterCount = getParamTypes(elem, typev);
- qList = parser(elem->src,typev,parameterCount);
+ qList = parser(elem->src, typev, parameterCount);
- if (qList->len > 1) {
- elog(NOTICE,
- "tg_parseSubQuery: parser produced > 1 query tree");
- }
- }
- break;
- case TG_C:
- {
- /* C ingredients are registered functions in postgres */
- /* we create a new query string by using the function name
- (found in the 'src' field) and adding parameters to it
- so if the function was FOOBAR and took in two arguments,
- we would create a string
- select FOOBAR($1,$2)
- */
- char newquery[1000];
-
- funcName = elem->src;
- parameterCount = getParamTypes(elem,typev);
-
- if (parameterCount > 0) {
- int i;
- sprintf(newquery,"select %s($1",funcName);
- for (i=1;i<parameterCount;i++) {
- sprintf(newquery,"%s,$%d",newquery,i);
- }
- sprintf(newquery,"%s)",newquery);
- } else
- sprintf(newquery,"select %s()",funcName);
+ if (qList->len > 1)
+ {
+ elog(NOTICE,
+ "tg_parseSubQuery: parser produced > 1 query tree");
+ }
+ }
+ break;
+ case TG_C:
+ {
+ /* C ingredients are registered functions in postgres */
+
+ /*
+ * we create a new query string by using the function name
+ * (found in the 'src' field) and adding parameters to it
+ * so if the function was FOOBAR and took in two
+ * arguments, we would create a string select
+ * FOOBAR($1,$2)
+ */
+ char newquery[1000];
+
+ funcName = elem->src;
+ parameterCount = getParamTypes(elem, typev);
+
+ if (parameterCount > 0)
+ {
+ int i;
+
+ sprintf(newquery, "select %s($1", funcName);
+ for (i = 1; i < parameterCount; i++)
+ {
+ sprintf(newquery, "%s,$%d", newquery, i);
+ }
+ sprintf(newquery, "%s)", newquery);
+ }
+ else
+ sprintf(newquery, "select %s()", funcName);
#ifdef DEBUG_RECIPE
-elog(NOTICE,"calling parser with %s", newquery);
-#endif /* DEBUG_RECIPE */
+ elog(NOTICE, "calling parser with %s", newquery);
+#endif /* DEBUG_RECIPE */
+
+ qList = parser(newquery, typev, parameterCount);
+ if (qList->len > 1)
+ {
+ elog(NOTICE,
+ "tg_parseSubQuery: parser produced > 1 query tree");
+ }
+ }
+ break;
+ case TG_RECIPE_GRAPH:
+ elog(NOTICE, "tg_parseSubQuery: can't parse recipe graph ingredients yet!");
+ break;
+ case TG_COMPILED:
+ elog(NOTICE, "tg_parseSubQuery: can't parse compiled ingredients yet!");
+ break;
+ default:
+ elog(NOTICE, "tg_parseSubQuery: unknown srcLang: %d", elem->srcLang);
+ }
+
+ /* parse each of the subrecipes that are input to this node */
+
+ if (n->inNodes->num > 0)
+ {
+ inputQlist = malloc(sizeof(QueryTreeList));
+ inputQlist->len = n->inNodes->num + 1;
+ inputQlist->qtrees = (Query **) malloc(inputQlist->len * sizeof(Query *));
+ for (i = 0; i < n->inNodes->num; i++)
+ {
+
+ inputQlist->qtrees[i] = NULL;
+ if (n->inNodes->val[i])
+ {
+ if (n->inNodes->val[i]->nodeType == TG_TEE_NODE)
+ {
+ qList = tg_parseTeeNode(r, n->inNodes->val[i],
+ i, qList, teeInfo);
+ }
+ else
+ { /* input node is not a Tee */
+ q = tg_parseSubQuery(r, n->inNodes->val[i],
+ teeInfo);
+ Assert(q->len == 1);
+ inputQlist->qtrees[i] = q->qtrees[0];
+ }
+ }
+ }
- qList = parser(newquery,typev,parameterCount);
- if (qList->len > 1) {
- elog(NOTICE,
- "tg_parseSubQuery: parser produced > 1 query tree");
+ /* now, we have all the query trees from our input nodes */
+ /* transform the original parse tree appropriately */
+ tg_rewriteQuery(r, n, qList, inputQlist);
}
- }
- break;
- case TG_RECIPE_GRAPH:
- elog(NOTICE,"tg_parseSubQuery: can't parse recipe graph ingredients yet!");
- break;
- case TG_COMPILED:
- elog(NOTICE,"tg_parseSubQuery: can't parse compiled ingredients yet!");
- break;
- default:
- elog(NOTICE,"tg_parseSubQuery: unknown srcLang: %d",elem->srcLang);
}
+ else if (n->nodeType == TG_EYE_NODE)
+ {
- /* parse each of the subrecipes that are input to this node*/
-
- if (n->inNodes->num > 0) {
- inputQlist = malloc(sizeof(QueryTreeList));
- inputQlist->len = n->inNodes->num + 1 ;
- inputQlist->qtrees = (Query**)malloc(inputQlist->len * sizeof(Query*));
- for (i=0;i<n->inNodes->num;i++) {
-
- inputQlist->qtrees[i] = NULL;
- if (n->inNodes->val[i]) {
- if (n->inNodes->val[i]->nodeType == TG_TEE_NODE) {
- qList = tg_parseTeeNode(r,n->inNodes->val[i],
- i,qList,teeInfo);
- }
- else
- { /* input node is not a Tee */
- q = tg_parseSubQuery(r,n->inNodes->val[i],
- teeInfo);
- Assert (q->len == 1);
- inputQlist->qtrees[i] = q->qtrees[0];
- }
+ /*
+ * if we hit an eye, we need to stop and make what we have into a
+ * subrecipe query block
+ */
+ elog(NOTICE, "tg_parseSubQuery: can't handle eye nodes yet");
+ }
+ else if (n->nodeType == TG_TEE_NODE)
+ {
+
+ /*
+ * if we hit a tee, check to see if the parsing has been done for
+ * this tee already by the other parent
+ */
+
+ rel = RelationNameGetRelation(n->nodeName);
+ if (RelationIsValid(rel))
+ {
+
+ /*
+ * this tee has already been visited, no need to do any
+ * further processing
+ */
+ return NULL;
}
- }
+ else
+ {
+ /* we need to process the child of the tee first, */
+ child = n->inNodes->val[0];
+
+ if (child->nodeType == TG_TEE_NODE)
+ {
+ /* nested Tee nodes */
+ qList = tg_parseTeeNode(r, child, 0, qList, teeInfo);
+ return qList;
+ }
- /* now, we have all the query trees from our input nodes */
- /* transform the original parse tree appropriately */
- tg_rewriteQuery(r,n,qList,inputQlist);
+ Assert(child != NULL);
+
+ /* parse the input node */
+ q = tg_parseSubQuery(r, child, teeInfo);
+ Assert(q->len == 1);
+
+ /* add the parsed query to the main list of queries */
+ qList = appendQlist(qList, q);
+
+ /* need to create the tee table here */
+
+ /*
+ * the tee table created is used both for materializing the
+ * values at the tee node, and for parsing and optimization.
+ * The optimization needs to have a real table before it will
+ * consider scans on it
+ */
+
+ /*
+ * first, find the type of the tuples being produced by the
+ * tee. The type is the same as the output type of the child
+ * node.
+ *
+ * NOTE: we are assuming that the child node only has a single
+ * output here!
+ */
+ getParamTypes(child->nodeElem, typev);
+
+ /*
+ * the output type is either a complex type, (and is thus a
+ * relation) or is a simple type
+ */
+
+ rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]);
+
+ if (RelationIsValid(rel))
+ {
+
+ /*
+ * for complex types, create new relation with the same
+ * tuple descriptor as the output table type
+ */
+ len = length(q->qtrees[0]->targetList);
+ tupdesc = rel->rd_att;
+
+ relid = heap_create(child->nodeElem->outTypes->val[0],
+ NULL, /* XXX */
+ 'n',
+ DEFAULT_SMGR,
+ tupdesc);
+ }
+ else
+ {
+
+ /*
+ * we have to create a relation with one attribute of the
+ * simple base type. That attribute will have an attr
+ * name of "result"
+ */
+ /* NOTE: ignore array types for the time being */
+
+ len = 1;
+ tupdesc = CreateTemplateTupleDesc(len);
+
+ if (!TupleDescInitEntry(tupdesc, 1,
+ "result",
+ NULL,
+ 0, false))
+ {
+ elog(NOTICE, "tg_parseSubQuery: unexpected result from TupleDescInitEntry");
+ }
+ else
+ {
+ relid = heap_create(child->nodeElem->outTypes->val[0],
+ NULL, /* XXX */
+ 'n',
+ DEFAULT_SMGR,
+ tupdesc);
+ }
+ }
+ }
}
- }
- else if (n->nodeType == TG_EYE_NODE) {
- /* if we hit an eye, we need to stop and make what we have
- into a subrecipe query block*/
- elog(NOTICE,"tg_parseSubQuery: can't handle eye nodes yet");
- }
- else if (n->nodeType == TG_TEE_NODE) {
- /* if we hit a tee, check to see if the parsing has been done
- for this tee already by the other parent */
-
- rel = RelationNameGetRelation(n->nodeName);
- if (RelationIsValid(rel)) {
- /* this tee has already been visited,
- no need to do any further processing */
- return NULL;
- } else {
- /* we need to process the child of the tee first, */
- child = n->inNodes->val[0];
-
- if (child->nodeType == TG_TEE_NODE) {
- /* nested Tee nodes */
- qList = tg_parseTeeNode(r,child,0,qList,teeInfo);
- return qList;
- }
-
- Assert (child != NULL);
-
- /* parse the input node */
- q = tg_parseSubQuery(r,child, teeInfo);
- Assert (q->len == 1);
-
- /* add the parsed query to the main list of queries */
- qList = appendQlist(qList,q);
-
- /* need to create the tee table here */
- /* the tee table created is used both for materializing the values
- at the tee node, and for parsing and optimization.
- The optimization needs to have a real table before it will
- consider scans on it */
-
- /* first, find the type of the tuples being produced by the
- tee. The type is the same as the output type of
- the child node.
-
- NOTE: we are assuming that the child node only has a single
- output here! */
- getParamTypes(child->nodeElem,typev);
-
- /* the output type is either a complex type,
- (and is thus a relation) or is a simple type */
-
- rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]);
-
- if (RelationIsValid(rel)) {
- /* for complex types, create new relation with the same
- tuple descriptor as the output table type*/
- len = length(q->qtrees[0]->targetList);
- tupdesc = rel->rd_att;
-
- relid = heap_create(child->nodeElem->outTypes->val[0],
- NULL, /* XXX */
- 'n',
- DEFAULT_SMGR,
- tupdesc);
- }
- else {
- /* we have to create a relation with one attribute of
- the simple base type. That attribute will have
- an attr name of "result" */
- /*NOTE: ignore array types for the time being */
-
- len = 1;
- tupdesc = CreateTemplateTupleDesc(len);
-
- if ( !TupleDescInitEntry(tupdesc,1,
- "result",
- NULL,
- 0, false)) {
- elog(NOTICE,"tg_parseSubQuery: unexpected result from TupleDescInitEntry");
- } else {
- relid = heap_create(child->nodeElem->outTypes->val[0],
- NULL, /* XXX */
- 'n',
- DEFAULT_SMGR,
- tupdesc);
- }
- }
+ else if (n->nodeType == TG_RECIPE_NODE)
+ {
+ elog(NOTICE, "tg_parseSubQuery: can't handle embedded recipes yet!");
}
- }
- else if (n->nodeType == TG_RECIPE_NODE) {
- elog(NOTICE,"tg_parseSubQuery: can't handle embedded recipes yet!");
- } else
- elog (NOTICE, "unknown nodeType: %d", n->nodeType);
+ else
+ elog(NOTICE, "unknown nodeType: %d", n->nodeType);
- return qList;
+ return qList;
}
/*
* OffsetVarAttno -
- * recursively find all the var nodes with the specified varno
+ * recursively find all the var nodes with the specified varno
* and offset their varattno with the offset
- *
- * code is similar to OffsetVarNodes in rewriteManip.c
+ *
+ * code is similar to OffsetVarNodes in rewriteManip.c
*/
void
-OffsetVarAttno(Node* node, int varno, int offset)
+OffsetVarAttno(Node * node, int varno, int offset)
{
- if (node == NULL) return;
- switch (nodeTag(node)) {
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *)node;
- OffsetVarAttno(tle->expr, varno, offset);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr*)node;
- OffsetVarAttno((Node*)expr->args, varno, offset);
- }
- break;
- case T_Var:
+ if (node == NULL)
+ return;
+ switch (nodeTag(node))
{
- Var *var = (Var*)node;
- if (var->varno == varno)
- var->varattno += offset;
- }
- break;
- case T_List:
- {
- List *l;
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ OffsetVarAttno(tle->expr, varno, offset);
+ }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
+
+ OffsetVarAttno((Node *) expr->args, varno, offset);
+ }
+ break;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
- foreach(l, (List*)node) {
- OffsetVarAttno(lfirst(l), varno, offset);
- }
+ if (var->varno == varno)
+ var->varattno += offset;
+ }
+ break;
+ case T_List:
+ {
+ List *l;
+
+ foreach(l, (List *) node)
+ {
+ OffsetVarAttno(lfirst(l), varno, offset);
+ }
+ }
+ break;
+ default:
+ /* ignore the others */
+ break;
}
- break;
- default:
- /* ignore the others */
- break;
- }
}
/*
- * appendQlist
- * add the contents of a QueryTreeList q2 to the end of the QueryTreeList
- * q1
+ * appendQlist
+ * add the contents of a QueryTreeList q2 to the end of the QueryTreeList
+ * q1
*
- * returns a new querytree list
+ * returns a new querytree list
*/
-QueryTreeList*
-appendQlist(QueryTreeList *q1, QueryTreeList *q2)
+QueryTreeList *
+appendQlist(QueryTreeList * q1, QueryTreeList * q2)
{
- QueryTreeList* newq;
- int i,j;
- int newlen;
-
- if (q1 == NULL)
- return q2;
-
- if (q2 == NULL)
- return q1;
-
- newlen = q1->len + q2->len;
- newq = (QueryTreeList*)malloc(sizeof(QueryTreeList));
- newq->len = newlen;
- newq->qtrees = (Query**)malloc(newlen * sizeof(Query*));
- for (i=0;i<q1->len;i++)
- newq->qtrees[i] = q1->qtrees[i];
- for (j=0;j<q2->len;j++) {
- newq->qtrees[i + j] = q2->qtrees[j];
- }
- return newq;
+ QueryTreeList *newq;
+ int i,
+ j;
+ int newlen;
+
+ if (q1 == NULL)
+ return q2;
+
+ if (q2 == NULL)
+ return q1;
+
+ newlen = q1->len + q2->len;
+ newq = (QueryTreeList *) malloc(sizeof(QueryTreeList));
+ newq->len = newlen;
+ newq->qtrees = (Query **) malloc(newlen * sizeof(Query *));
+ for (i = 0; i < q1->len; i++)
+ newq->qtrees[i] = q1->qtrees[i];
+ for (j = 0; j < q2->len; j++)
+ {
+ newq->qtrees[i + j] = q2->qtrees[j];
+ }
+ return newq;
}
/*
- * appendTeeQuery
- *
- * modify the query field of the teeInfo list of the particular tee node
+ * appendTeeQuery
+ *
+ * modify the query field of the teeInfo list of the particular tee node
*/
static void
-appendTeeQuery(TeeInfo *teeInfo, QueryTreeList *q, char* teeNodeName)
+appendTeeQuery(TeeInfo * teeInfo, QueryTreeList * q, char *teeNodeName)
{
- int i;
-
- Assert(teeInfo);
+ int i;
- for (i=0;i<teeInfo->num;i++) {
- if ( strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0) {
+ Assert(teeInfo);
+
+ for (i = 0; i < teeInfo->num; i++)
+ {
+ if (strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0)
+ {
- Assert(q->len == 1);
- teeInfo->val[i].tpi_parsetree = q->qtrees[0];
- return;
+ Assert(q->len == 1);
+ teeInfo->val[i].tpi_parsetree = q->qtrees[0];
+ return;
+ }
}
- }
- elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo");
+ elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo");
}
/*
- * replaceSeqScan
- * replaces sequential scans of a specified relation with the tee plan
- * the relation is specified by its index in the range table, rt_ind
+ * replaceSeqScan
+ * replaces sequential scans of a specified relation with the tee plan
+ * the relation is specified by its index in the range table, rt_ind
*
* returns the modified plan
* the offset_attno is the offset that needs to be added to the parent's
* qual or targetlist because the child plan has been replaced with a tee node
*/
static void
-replaceSeqScan(Plan* plan, Plan* parent,
- int rt_ind, Plan* tplan)
+replaceSeqScan(Plan * plan, Plan * parent,
+ int rt_ind, Plan * tplan)
{
- Scan* snode;
- Tee* teePlan;
- Result* newPlan;
-
- if (plan == NULL) {
- return;
- }
-
- if (plan->type == T_SeqScan) {
- snode = (Scan*)plan;
- if (snode->scanrelid == rt_ind) {
- /* found the sequential scan that should be replaced
- with the tplan. */
- /* we replace the plan, but we also need to modify its parent*/
-
- /* replace the sequential scan with a Result node
- the reason we use a result node is so that we get the proper
- projection behavior. The Result node is simply (ab)used as
- a projection node */
-
- newPlan = makeNode(Result);
- newPlan->plan.cost = 0.0;
- newPlan->plan.state = (EState*)NULL;
- newPlan->plan.targetlist = plan->targetlist;
- newPlan->plan.lefttree = tplan;
- newPlan->plan.righttree = NULL;
- newPlan->resconstantqual = NULL;
- newPlan->resstate = NULL;
-
- /* change all the varno's to 1*/
- ChangeVarNodes((Node*)newPlan->plan.targetlist,
- snode->scanrelid, 1);
-
- if (parent) {
- teePlan = (Tee*)tplan;
-
- if (parent->lefttree == plan)
- parent->lefttree = (Plan*)newPlan;
- else
- parent->righttree = (Plan*)newPlan;
-
+ Scan *snode;
+ Tee *teePlan;
+ Result *newPlan;
- if (teePlan->leftParent == NULL)
- teePlan->leftParent = (Plan*)newPlan;
- else
- teePlan->rightParent = (Plan*)newPlan;
+ if (plan == NULL)
+ {
+ return;
+ }
+
+ if (plan->type == T_SeqScan)
+ {
+ snode = (Scan *) plan;
+ if (snode->scanrelid == rt_ind)
+ {
+
+ /*
+ * found the sequential scan that should be replaced with the
+ * tplan.
+ */
+ /* we replace the plan, but we also need to modify its parent */
+
+ /*
+ * replace the sequential scan with a Result node the reason
+ * we use a result node is so that we get the proper
+ * projection behavior. The Result node is simply (ab)used as
+ * a projection node
+ */
+
+ newPlan = makeNode(Result);
+ newPlan->plan.cost = 0.0;
+ newPlan->plan.state = (EState *) NULL;
+ newPlan->plan.targetlist = plan->targetlist;
+ newPlan->plan.lefttree = tplan;
+ newPlan->plan.righttree = NULL;
+ newPlan->resconstantqual = NULL;
+ newPlan->resstate = NULL;
+
+ /* change all the varno's to 1 */
+ ChangeVarNodes((Node *) newPlan->plan.targetlist,
+ snode->scanrelid, 1);
+
+ if (parent)
+ {
+ teePlan = (Tee *) tplan;
+
+ if (parent->lefttree == plan)
+ parent->lefttree = (Plan *) newPlan;
+ else
+ parent->righttree = (Plan *) newPlan;
+
+
+ if (teePlan->leftParent == NULL)
+ teePlan->leftParent = (Plan *) newPlan;
+ else
+ teePlan->rightParent = (Plan *) newPlan;
/* comment for now to test out executor-stuff
- if (parent->state) {
- ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan);
- }
+ if (parent->state) {
+ ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan);
+ }
*/
- }
- }
+ }
+ }
- } else {
- if (plan->lefttree) {
- replaceSeqScan(plan->lefttree, plan, rt_ind, tplan);
}
- if (plan->righttree) {
- replaceSeqScan(plan->righttree, plan, rt_ind, tplan);
+ else
+ {
+ if (plan->lefttree)
+ {
+ replaceSeqScan(plan->lefttree, plan, rt_ind, tplan);
+ }
+ if (plan->righttree)
+ {
+ replaceSeqScan(plan->righttree, plan, rt_ind, tplan);
+ }
}
- }
}
/*
- * replaceTeeScans
- * places the sequential scans of the Tee table with
+ * replaceTeeScans
+ * places the sequential scans of the Tee table with
* a connection to the actual tee plan node
*/
-static Plan*
-replaceTeeScans(Plan* plan, Query* parsetree, TeeInfo *teeInfo)
+static Plan *
+replaceTeeScans(Plan * plan, Query * parsetree, TeeInfo * teeInfo)
{
- int i;
- List* rtable;
- RangeTblEntry *rte;
- char prefix[5];
- int rt_ind;
- Plan* tplan;
-
- rtable = parsetree->rtable;
- if (rtable == NULL)
- return plan;
+ int i;
+ List *rtable;
+ RangeTblEntry *rte;
+ char prefix[5];
+ int rt_ind;
+ Plan *tplan;
+
+ rtable = parsetree->rtable;
+ if (rtable == NULL)
+ return plan;
+
+ /*
+ * look through the range table for the tee relation entry, that will
+ * give use the varno we need to detect which sequential scans need to
+ * be replaced with tee nodes
+ */
+
+ rt_ind = 0;
+ while (rtable != NIL)
+ {
+ rte = lfirst(rtable);
+ rtable = lnext(rtable);
+ rt_ind++; /* range table references in varno fields
+ * start w/ 1 */
+
+ /*
+ * look for the "tee_" prefix in the refname, also check to see
+ * that the relname and the refname are the same this should
+ * eliminate any user-specified table and leave us with the tee
+ * table entries only
+ */
+ if ((strlen(rte->refname) < 4) ||
+ (strcmp(rte->relname, rte->refname) != 0))
+ continue;
+ strNcpy(prefix, rte->refname, 4);
+ if (strcmp(prefix, "tee_") == 0)
+ {
+ /* okay, we found a tee node entry in the range table */
+
+ /* find the appropriate plan in the teeInfo list */
+ tplan = NULL;
+ for (i = 0; i < teeInfo->num; i++)
+ {
+ if (strcmp(teeInfo->val[i].tpi_relName,
+ rte->refname) == 0)
+ {
+ tplan = teeInfo->val[i].tpi_plan;
+ }
+ }
+ if (tplan == NULL)
+ {
+ elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan");
+ }
- /* look through the range table for the tee relation entry,
- that will give use the varno we need to detect which
- sequential scans need to be replaced with tee nodes*/
-
- rt_ind = 0;
- while (rtable != NIL) {
- rte = lfirst(rtable);
- rtable = lnext(rtable);
- rt_ind++; /* range table references in varno fields start w/ 1 */
-
- /* look for the "tee_" prefix in the refname,
- also check to see that the relname and the refname are the same
- this should eliminate any user-specified table and leave
- us with the tee table entries only*/
- if ((strlen(rte->refname) < 4) ||
- (strcmp (rte->relname, rte->refname) != 0))
- continue;
- strNcpy(prefix,rte->refname,4);
- if (strcmp(prefix,"tee_") == 0) {
- /* okay, we found a tee node entry in the range table */
-
- /* find the appropriate plan in the teeInfo list */
- tplan = NULL;
- for (i=0;i<teeInfo->num;i++) {
- if (strcmp(teeInfo->val[i].tpi_relName,
- rte->refname) == 0) {
- tplan = teeInfo->val[i].tpi_plan;
+ /*
+ * replace the sequential scan node with that var number with
+ * the tee plan node
+ */
+ replaceSeqScan(plan, NULL, rt_ind, tplan);
}
- }
- if (tplan == NULL) {
- elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan"); }
-
- /* replace the sequential scan node with that var number
- with the tee plan node */
- replaceSeqScan(plan, NULL, rt_ind, tplan);
}
- }
- return plan;
+ return plan;
}
-#endif /* TIOGA */
+#endif /* TIOGA */
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index 7f0198a10b7..cafe4d09710 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* remove.c--
- * POSTGRES remove (function | type | operator ) utilty code.
+ * POSTGRES remove (function | type | operator ) utilty code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.10 1997/08/18 20:52:17 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.11 1997/09/07 04:40:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,100 +28,112 @@
#include <storage/bufmgr.h>
#include <fmgr.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/*
* RemoveOperator --
- * Deletes an operator.
+ * Deletes an operator.
*
* Exceptions:
- * BadArg if name is invalid.
- * BadArg if type1 is invalid.
- * "WARN" if operator nonexistent.
- * ...
+ * BadArg if name is invalid.
+ * BadArg if type1 is invalid.
+ * "WARN" if operator nonexistent.
+ * ...
*/
void
-RemoveOperator(char *operatorName, /* operator name */
- char *typeName1, /* first type name */
- char *typeName2) /* optional second type name */
+RemoveOperator(char *operatorName, /* operator name */
+ char *typeName1, /* first type name */
+ char *typeName2) /* optional second type name */
{
- Relation relation;
- HeapScanDesc scan;
- HeapTuple tup;
- Oid typeId1 = InvalidOid;
- Oid typeId2 = InvalidOid;
- bool defined;
- ItemPointerData itemPointerData;
- Buffer buffer;
- ScanKeyData operatorKey[3];
- char *userName;
-
- if (typeName1) {
- typeId1 = TypeGet(typeName1, &defined);
- if (!OidIsValid(typeId1)) {
- elog(WARN, "RemoveOperator: type '%s' does not exist", typeName1);
- return;
+ Relation relation;
+ HeapScanDesc scan;
+ HeapTuple tup;
+ Oid typeId1 = InvalidOid;
+ Oid typeId2 = InvalidOid;
+ bool defined;
+ ItemPointerData itemPointerData;
+ Buffer buffer;
+ ScanKeyData operatorKey[3];
+ char *userName;
+
+ if (typeName1)
+ {
+ typeId1 = TypeGet(typeName1, &defined);
+ if (!OidIsValid(typeId1))
+ {
+ elog(WARN, "RemoveOperator: type '%s' does not exist", typeName1);
+ return;
+ }
}
- }
-
- if (typeName2) {
- typeId2 = TypeGet(typeName2, &defined);
- if (!OidIsValid(typeId2)) {
- elog(WARN, "RemoveOperator: type '%s' does not exist", typeName2);
- return;
+
+ if (typeName2)
+ {
+ typeId2 = TypeGet(typeName2, &defined);
+ if (!OidIsValid(typeId2))
+ {
+ elog(WARN, "RemoveOperator: type '%s' does not exist", typeName2);
+ return;
+ }
}
- }
-
- ScanKeyEntryInitialize(&operatorKey[0], 0x0,
- Anum_pg_operator_oprname,
- NameEqualRegProcedure,
- PointerGetDatum(operatorName));
-
- ScanKeyEntryInitialize(&operatorKey[1], 0x0,
- Anum_pg_operator_oprleft,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(typeId1));
-
- ScanKeyEntryInitialize(&operatorKey[2], 0x0,
- Anum_pg_operator_oprright,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(typeId2));
-
- relation = heap_openr(OperatorRelationName);
- scan = heap_beginscan(relation, 0, NowTimeQual, 3, operatorKey);
- tup = heap_getnext(scan, 0, &buffer);
- if (HeapTupleIsValid(tup)) {
+
+ ScanKeyEntryInitialize(&operatorKey[0], 0x0,
+ Anum_pg_operator_oprname,
+ NameEqualRegProcedure,
+ PointerGetDatum(operatorName));
+
+ ScanKeyEntryInitialize(&operatorKey[1], 0x0,
+ Anum_pg_operator_oprleft,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(typeId1));
+
+ ScanKeyEntryInitialize(&operatorKey[2], 0x0,
+ Anum_pg_operator_oprright,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(typeId2));
+
+ relation = heap_openr(OperatorRelationName);
+ scan = heap_beginscan(relation, 0, NowTimeQual, 3, operatorKey);
+ tup = heap_getnext(scan, 0, &buffer);
+ if (HeapTupleIsValid(tup))
+ {
#ifndef NO_SECURITY
- userName = GetPgUserName();
- if (!pg_ownercheck(userName,
- (char *) ObjectIdGetDatum(tup->t_oid),
- OPROID))
- elog(WARN, "RemoveOperator: operator '%s': permission denied",
- operatorName);
+ userName = GetPgUserName();
+ if (!pg_ownercheck(userName,
+ (char *) ObjectIdGetDatum(tup->t_oid),
+ OPROID))
+ elog(WARN, "RemoveOperator: operator '%s': permission denied",
+ operatorName);
#endif
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- heap_delete(relation, &itemPointerData);
- } else {
- if (OidIsValid(typeId1) && OidIsValid(typeId2)) {
- elog(WARN, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
- operatorName,
- typeName1,
- typeName2);
- } else if (OidIsValid(typeId1)) {
- elog(WARN, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
- operatorName,
- typeName1);
- } else {
- elog(WARN, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
- operatorName,
- typeName2);
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ heap_delete(relation, &itemPointerData);
}
- }
- heap_endscan(scan);
- heap_close(relation);
+ else
+ {
+ if (OidIsValid(typeId1) && OidIsValid(typeId2))
+ {
+ elog(WARN, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
+ operatorName,
+ typeName1,
+ typeName2);
+ }
+ else if (OidIsValid(typeId1))
+ {
+ elog(WARN, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
+ operatorName,
+ typeName1);
+ }
+ else
+ {
+ elog(WARN, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
+ operatorName,
+ typeName2);
+ }
+ }
+ heap_endscan(scan);
+ heap_close(relation);
}
#ifdef NOTYET
@@ -130,353 +142,379 @@ RemoveOperator(char *operatorName, /* operator name */
* don't use it - pma 2/1/94
*/
/*
- * SingleOpOperatorRemove
- * Removes all operators that have operands or a result of type 'typeOid'.
+ * SingleOpOperatorRemove
+ * Removes all operators that have operands or a result of type 'typeOid'.
*/
static void
SingleOpOperatorRemove(Oid typeOid)
{
- Relation rdesc;
- ScanKeyData key[3];
- HeapScanDesc sdesc;
- HeapTuple tup;
- ItemPointerData itemPointerData;
- Buffer buffer;
- static attnums[3] = { 7, 8, 9 }; /* left, right, return */
- register i;
-
- ScanKeyEntryInitialize(&key[0],
- 0, 0, ObjectIdEqualRegProcedure, (Datum)typeOid);
- rdesc = heap_openr(OperatorRelationName);
- for (i = 0; i < 3; ++i) {
- key[0].sk_attno = attnums[i];
- sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
- while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer))) {
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- /* XXX LOCK not being passed */
- heap_delete(rdesc, &itemPointerData);
+ Relation rdesc;
+ ScanKeyData key[3];
+ HeapScanDesc sdesc;
+ HeapTuple tup;
+ ItemPointerData itemPointerData;
+ Buffer buffer;
+ static attnums[3] = {7, 8, 9}; /* left, right, return */
+ register i;
+
+ ScanKeyEntryInitialize(&key[0],
+ 0, 0, ObjectIdEqualRegProcedure, (Datum) typeOid);
+ rdesc = heap_openr(OperatorRelationName);
+ for (i = 0; i < 3; ++i)
+ {
+ key[0].sk_attno = attnums[i];
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer)))
+ {
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ /* XXX LOCK not being passed */
+ heap_delete(rdesc, &itemPointerData);
+ }
+ heap_endscan(sdesc);
}
- heap_endscan(sdesc);
- }
- heap_close(rdesc);
+ heap_close(rdesc);
}
/*
- * AttributeAndRelationRemove
- * Removes all entries in the attribute and relation relations
- * that contain entries of type 'typeOid'.
- * Currently nothing calls this code, it is untested.
+ * AttributeAndRelationRemove
+ * Removes all entries in the attribute and relation relations
+ * that contain entries of type 'typeOid'.
+ * Currently nothing calls this code, it is untested.
*/
static void
AttributeAndRelationRemove(Oid typeOid)
{
- struct oidlist {
- Oid reloid;
- struct oidlist *next;
- };
- struct oidlist *oidptr, *optr;
- Relation rdesc;
- ScanKeyData key[1];
- HeapScanDesc sdesc;
- HeapTuple tup;
- ItemPointerData itemPointerData;
- Buffer buffer;
-
- /*
- * Get the oid's of the relations to be removed by scanning the
- * entire attribute relation.
- * We don't need to remove the attributes here,
- * because amdestroy will remove all attributes of the relation.
- * XXX should check for duplicate relations
- */
-
- ScanKeyEntryInitialize(&key[0],
- 0, 3, ObjectIdEqualRegProcedure, (Datum)typeOid);
-
- oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
- oidptr->next = NULL;
- optr = oidptr;
- rdesc = heap_openr(AttributeRelationName);
- sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
- while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer))) {
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- optr->reloid = ((AttributeTupleForm)GETSTRUCT(tup))->attrelid;
- optr->next = (struct oidlist *) palloc(sizeof(*oidptr));
- optr = optr->next;
- }
- optr->next = NULL;
- heap_endscan(sdesc);
- heap_close(rdesc);
-
-
- ScanKeyEntryInitialize(&key[0], 0,
- ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure, (Datum)0);
- optr = oidptr;
- rdesc = heap_openr(RelationRelationName);
- while (PointerIsValid((char *) optr->next)) {
- key[0].sk_argument = (Datum) (optr++)->reloid;
+ struct oidlist
+ {
+ Oid reloid;
+ struct oidlist *next;
+ };
+ struct oidlist *oidptr,
+ *optr;
+ Relation rdesc;
+ ScanKeyData key[1];
+ HeapScanDesc sdesc;
+ HeapTuple tup;
+ ItemPointerData itemPointerData;
+ Buffer buffer;
+
+ /*
+ * Get the oid's of the relations to be removed by scanning the entire
+ * attribute relation. We don't need to remove the attributes here,
+ * because amdestroy will remove all attributes of the relation. XXX
+ * should check for duplicate relations
+ */
+
+ ScanKeyEntryInitialize(&key[0],
+ 0, 3, ObjectIdEqualRegProcedure, (Datum) typeOid);
+
+ oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
+ oidptr->next = NULL;
+ optr = oidptr;
+ rdesc = heap_openr(AttributeRelationName);
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
- tup = heap_getnext(sdesc, 0, &buffer);
- if (PointerIsValid(tup)) {
- char *name;
-
- name = (((Form_pg_class)GETSTRUCT(tup))->relname).data;
- heap_destroy(name);
+ while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer)))
+ {
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ optr->reloid = ((AttributeTupleForm) GETSTRUCT(tup))->attrelid;
+ optr->next = (struct oidlist *) palloc(sizeof(*oidptr));
+ optr = optr->next;
}
- }
- heap_endscan(sdesc);
- heap_close(rdesc);
+ optr->next = NULL;
+ heap_endscan(sdesc);
+ heap_close(rdesc);
+
+
+ ScanKeyEntryInitialize(&key[0], 0,
+ ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure, (Datum) 0);
+ optr = oidptr;
+ rdesc = heap_openr(RelationRelationName);
+ while (PointerIsValid((char *) optr->next))
+ {
+ key[0].sk_argument = (Datum) (optr++)->reloid;
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
+ tup = heap_getnext(sdesc, 0, &buffer);
+ if (PointerIsValid(tup))
+ {
+ char *name;
+
+ name = (((Form_pg_class) GETSTRUCT(tup))->relname).data;
+ heap_destroy(name);
+ }
+ }
+ heap_endscan(sdesc);
+ heap_close(rdesc);
}
-#endif /* NOTYET */
+
+#endif /* NOTYET */
/*
- * TypeRemove
- * Removes the type 'typeName' and all attributes and relations that
- * use it.
+ * TypeRemove
+ * Removes the type 'typeName' and all attributes and relations that
+ * use it.
*/
void
-RemoveType(char *typeName) /* type name to be removed */
+RemoveType(char *typeName) /* type name to be removed */
{
- Relation relation;
- HeapScanDesc scan;
- HeapTuple tup;
- Oid typeOid;
- ItemPointerData itemPointerData;
- static ScanKeyData typeKey[1] = {
- { 0, Anum_pg_type_typname, NameEqualRegProcedure }
- };
- char *shadow_type;
- char *userName;
-
+ Relation relation;
+ HeapScanDesc scan;
+ HeapTuple tup;
+ Oid typeOid;
+ ItemPointerData itemPointerData;
+ static ScanKeyData typeKey[1] = {
+ {0, Anum_pg_type_typname, NameEqualRegProcedure}
+ };
+ char *shadow_type;
+ char *userName;
+
#ifndef NO_SECURITY
- userName = GetPgUserName();
- if (!pg_ownercheck(userName, typeName, TYPNAME))
- elog(WARN, "RemoveType: type '%s': permission denied",
- typeName);
+ userName = GetPgUserName();
+ if (!pg_ownercheck(userName, typeName, TYPNAME))
+ elog(WARN, "RemoveType: type '%s': permission denied",
+ typeName);
#endif
-
- relation = heap_openr(TypeRelationName);
- fmgr_info(typeKey[0].sk_procedure, &typeKey[0].sk_func,
- &typeKey[0].sk_nargs);
-
- /* Delete the primary type */
-
- typeKey[0].sk_argument = PointerGetDatum(typeName);
-
- scan = heap_beginscan(relation, 0, NowTimeQual, 1, typeKey);
- tup = heap_getnext(scan, 0, (Buffer *) 0);
- if (!HeapTupleIsValid(tup)) {
+
+ relation = heap_openr(TypeRelationName);
+ fmgr_info(typeKey[0].sk_procedure, &typeKey[0].sk_func,
+ &typeKey[0].sk_nargs);
+
+ /* Delete the primary type */
+
+ typeKey[0].sk_argument = PointerGetDatum(typeName);
+
+ scan = heap_beginscan(relation, 0, NowTimeQual, 1, typeKey);
+ tup = heap_getnext(scan, 0, (Buffer *) 0);
+ if (!HeapTupleIsValid(tup))
+ {
+ heap_endscan(scan);
+ heap_close(relation);
+ elog(WARN, "RemoveType: type '%s' does not exist",
+ typeName);
+ }
+ typeOid = tup->t_oid;
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ heap_delete(relation, &itemPointerData);
heap_endscan(scan);
- heap_close(relation);
- elog(WARN, "RemoveType: type '%s' does not exist",
- typeName);
- }
- typeOid = tup->t_oid;
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- heap_delete(relation, &itemPointerData);
- heap_endscan(scan);
-
- /* Now, Delete the "array of" that type */
- shadow_type = makeArrayTypeName(typeName);
- typeKey[0].sk_argument = NameGetDatum(shadow_type);
-
- scan = heap_beginscan(relation, 0, NowTimeQual,
- 1, (ScanKey) typeKey);
- tup = heap_getnext(scan, 0, (Buffer *) 0);
-
- if (!HeapTupleIsValid(tup))
+
+ /* Now, Delete the "array of" that type */
+ shadow_type = makeArrayTypeName(typeName);
+ typeKey[0].sk_argument = NameGetDatum(shadow_type);
+
+ scan = heap_beginscan(relation, 0, NowTimeQual,
+ 1, (ScanKey) typeKey);
+ tup = heap_getnext(scan, 0, (Buffer *) 0);
+
+ if (!HeapTupleIsValid(tup))
{
- elog(WARN, "RemoveType: type '%s': array stub not found",
- typeName);
+ elog(WARN, "RemoveType: type '%s': array stub not found",
+ typeName);
}
- typeOid = tup->t_oid;
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- heap_delete(relation, &itemPointerData);
- heap_endscan(scan);
-
- heap_close(relation);
+ typeOid = tup->t_oid;
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ heap_delete(relation, &itemPointerData);
+ heap_endscan(scan);
+
+ heap_close(relation);
}
/*
* RemoveFunction --
- * Deletes a function.
+ * Deletes a function.
*
* Exceptions:
- * BadArg if name is invalid.
- * "WARN" if function nonexistent.
- * ...
+ * BadArg if name is invalid.
+ * "WARN" if function nonexistent.
+ * ...
*/
void
-RemoveFunction(char *functionName, /* function name to be removed */
- int nargs,
- List *argNameList /* list of TypeNames */)
+RemoveFunction(char *functionName, /* function name to be removed */
+ int nargs,
+ List * argNameList /* list of TypeNames */ )
{
- Relation relation;
- HeapScanDesc scan;
- HeapTuple tup;
- Buffer buffer = InvalidBuffer;
- bool bufferUsed = FALSE;
- Oid argList[8];
- Form_pg_proc the_proc = NULL;
- ItemPointerData itemPointerData;
- static ScanKeyData key[3] = {
- { 0, Anum_pg_proc_proname, NameEqualRegProcedure }
- };
- char *userName;
- char *typename;
- int i;
-
- memset(argList, 0, 8 * sizeof(Oid));
- for (i=0; i<nargs; i++) {
-/* typename = ((TypeName*)(lfirst(argNameList)))->name; */
- typename = strVal(lfirst(argNameList));
- argNameList = lnext(argNameList);
-
- if (strcmp(typename, "opaque") == 0)
- argList[i] = 0;
- else {
- tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typename),
- 0,0,0);
-
- if (!HeapTupleIsValid(tup)) {
- elog(WARN, "RemoveFunction: type '%s' not found",typename);
- }
- argList[i] = tup->t_oid;
+ Relation relation;
+ HeapScanDesc scan;
+ HeapTuple tup;
+ Buffer buffer = InvalidBuffer;
+ bool bufferUsed = FALSE;
+ Oid argList[8];
+ Form_pg_proc the_proc = NULL;
+ ItemPointerData itemPointerData;
+ static ScanKeyData key[3] = {
+ {0, Anum_pg_proc_proname, NameEqualRegProcedure}
+ };
+ char *userName;
+ char *typename;
+ int i;
+
+ memset(argList, 0, 8 * sizeof(Oid));
+ for (i = 0; i < nargs; i++)
+ {
+/* typename = ((TypeName*)(lfirst(argNameList)))->name; */
+ typename = strVal(lfirst(argNameList));
+ argNameList = lnext(argNameList);
+
+ if (strcmp(typename, "opaque") == 0)
+ argList[i] = 0;
+ else
+ {
+ tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typename),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tup))
+ {
+ elog(WARN, "RemoveFunction: type '%s' not found", typename);
+ }
+ argList[i] = tup->t_oid;
+ }
}
- }
-
- tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(functionName),
- Int32GetDatum(nargs),
- PointerGetDatum(argList),0);
- if (!HeapTupleIsValid(tup))
- func_error("RemoveFunction", functionName, nargs, argList);
-
+
+ tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(functionName),
+ Int32GetDatum(nargs),
+ PointerGetDatum(argList), 0);
+ if (!HeapTupleIsValid(tup))
+ func_error("RemoveFunction", functionName, nargs, argList);
+
#ifndef NO_SECURITY
- userName = GetPgUserName();
- if (!pg_func_ownercheck(userName, functionName, nargs, argList)) {
- elog(WARN, "RemoveFunction: function '%s': permission denied",
- functionName);
- }
-#endif
-
- key[0].sk_argument = PointerGetDatum(functionName);
-
- fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
-
- relation = heap_openr(ProcedureRelationName);
- scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
-
- do { /* hope this is ok because it's indexed */
- if (bufferUsed) {
- ReleaseBuffer(buffer);
- bufferUsed = FALSE;
+ userName = GetPgUserName();
+ if (!pg_func_ownercheck(userName, functionName, nargs, argList))
+ {
+ elog(WARN, "RemoveFunction: function '%s': permission denied",
+ functionName);
}
- tup = heap_getnext(scan, 0, (Buffer *) &buffer);
- if (!HeapTupleIsValid(tup))
- break;
- bufferUsed = TRUE;
- the_proc = (Form_pg_proc) GETSTRUCT(tup);
- } while ( (namestrcmp(&(the_proc->proname), functionName) == 0) &&
- (the_proc->pronargs != nargs ||
- !oid8eq(&(the_proc->proargtypes[0]), &argList[0])));
-
-
- if (!HeapTupleIsValid(tup) || namestrcmp(&(the_proc->proname),
- functionName) != 0)
- {
- heap_endscan(scan);
- heap_close(relation);
- func_error("RemoveFunction", functionName,nargs, argList);
+#endif
+
+ key[0].sk_argument = PointerGetDatum(functionName);
+
+ fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
+
+ relation = heap_openr(ProcedureRelationName);
+ scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
+
+ do
+ { /* hope this is ok because it's indexed */
+ if (bufferUsed)
+ {
+ ReleaseBuffer(buffer);
+ bufferUsed = FALSE;
+ }
+ tup = heap_getnext(scan, 0, (Buffer *) & buffer);
+ if (!HeapTupleIsValid(tup))
+ break;
+ bufferUsed = TRUE;
+ the_proc = (Form_pg_proc) GETSTRUCT(tup);
+ } while ((namestrcmp(&(the_proc->proname), functionName) == 0) &&
+ (the_proc->pronargs != nargs ||
+ !oid8eq(&(the_proc->proargtypes[0]), &argList[0])));
+
+
+ if (!HeapTupleIsValid(tup) || namestrcmp(&(the_proc->proname),
+ functionName) != 0)
+ {
+ heap_endscan(scan);
+ heap_close(relation);
+ func_error("RemoveFunction", functionName, nargs, argList);
}
-
- /* ok, function has been found */
-
- if (the_proc->prolang == INTERNALlanguageId)
- elog(WARN, "RemoveFunction: function \"%s\" is built-in",
- functionName);
-
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- heap_delete(relation, &itemPointerData);
- heap_endscan(scan);
- heap_close(relation);
+
+ /* ok, function has been found */
+
+ if (the_proc->prolang == INTERNALlanguageId)
+ elog(WARN, "RemoveFunction: function \"%s\" is built-in",
+ functionName);
+
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ heap_delete(relation, &itemPointerData);
+ heap_endscan(scan);
+ heap_close(relation);
}
void
RemoveAggregate(char *aggName, char *aggType)
{
- Relation relation;
- HeapScanDesc scan;
- HeapTuple tup;
- ItemPointerData itemPointerData;
- char *userName;
- Oid basetypeID = InvalidOid;
- bool defined;
- ScanKeyData aggregateKey[3];
-
-
- /*
- * if a basetype is passed in, then attempt to find an aggregate for that
- * specific type.
- *
- * else if the basetype is blank, then attempt to find an aggregate with a
- * basetype of zero. This is valid. It means that the aggregate is to apply
- * to all basetypes. ie, a counter of some sort.
- *
- */
-
- if (aggType) {
- basetypeID = TypeGet(aggType, &defined);
- if (!OidIsValid(basetypeID)) {
- elog(WARN, "RemoveAggregate: type '%s' does not exist", aggType);
- }
- } else {
- basetypeID = 0;
- }
+ Relation relation;
+ HeapScanDesc scan;
+ HeapTuple tup;
+ ItemPointerData itemPointerData;
+ char *userName;
+ Oid basetypeID = InvalidOid;
+ bool defined;
+ ScanKeyData aggregateKey[3];
+
+
+ /*
+ * if a basetype is passed in, then attempt to find an aggregate for
+ * that specific type.
+ *
+ * else if the basetype is blank, then attempt to find an aggregate with
+ * a basetype of zero. This is valid. It means that the aggregate is
+ * to apply to all basetypes. ie, a counter of some sort.
+ *
+ */
+
+ if (aggType)
+ {
+ basetypeID = TypeGet(aggType, &defined);
+ if (!OidIsValid(basetypeID))
+ {
+ elog(WARN, "RemoveAggregate: type '%s' does not exist", aggType);
+ }
+ }
+ else
+ {
+ basetypeID = 0;
+ }
/*
#ifndef NO_SECURITY
*/
- userName = GetPgUserName();
- if (!pg_aggr_ownercheck(userName, aggName, basetypeID)) {
- if (aggType) {
- elog(WARN, "RemoveAggregate: aggregate '%s' on type '%s': permission denied",
- aggName, aggType);
- } else {
- elog(WARN, "RemoveAggregate: aggregate '%s': permission denied",
- aggName);
- }
- }
+ userName = GetPgUserName();
+ if (!pg_aggr_ownercheck(userName, aggName, basetypeID))
+ {
+ if (aggType)
+ {
+ elog(WARN, "RemoveAggregate: aggregate '%s' on type '%s': permission denied",
+ aggName, aggType);
+ }
+ else
+ {
+ elog(WARN, "RemoveAggregate: aggregate '%s': permission denied",
+ aggName);
+ }
+ }
/*
#endif
*/
- ScanKeyEntryInitialize(&aggregateKey[0], 0x0,
- Anum_pg_aggregate_aggname,
- NameEqualRegProcedure,
- PointerGetDatum(aggName));
-
- ScanKeyEntryInitialize(&aggregateKey[1], 0x0,
- Anum_pg_aggregate_aggbasetype,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(basetypeID));
-
- relation = heap_openr(AggregateRelationName);
- scan = heap_beginscan(relation, 0, NowTimeQual, 2, aggregateKey);
- tup = heap_getnext(scan, 0, (Buffer *) 0);
- if (!HeapTupleIsValid(tup)) {
- heap_endscan(scan);
- heap_close(relation);
- if (aggType) {
- elog(WARN, "RemoveAggregate: aggregate '%s' for '%s' does not exist",
- aggName, aggType);
- } else {
- elog(WARN, "RemoveAggregate: aggregate '%s' for all types does not exist",
- aggName);
- }
- }
- ItemPointerCopy(&tup->t_ctid, &itemPointerData);
- heap_delete(relation, &itemPointerData);
- heap_endscan(scan);
- heap_close(relation);
+ ScanKeyEntryInitialize(&aggregateKey[0], 0x0,
+ Anum_pg_aggregate_aggname,
+ NameEqualRegProcedure,
+ PointerGetDatum(aggName));
+
+ ScanKeyEntryInitialize(&aggregateKey[1], 0x0,
+ Anum_pg_aggregate_aggbasetype,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(basetypeID));
+
+ relation = heap_openr(AggregateRelationName);
+ scan = heap_beginscan(relation, 0, NowTimeQual, 2, aggregateKey);
+ tup = heap_getnext(scan, 0, (Buffer *) 0);
+ if (!HeapTupleIsValid(tup))
+ {
+ heap_endscan(scan);
+ heap_close(relation);
+ if (aggType)
+ {
+ elog(WARN, "RemoveAggregate: aggregate '%s' for '%s' does not exist",
+ aggName, aggType);
+ }
+ else
+ {
+ elog(WARN, "RemoveAggregate: aggregate '%s' for all types does not exist",
+ aggName);
+ }
+ }
+ ItemPointerCopy(&tup->t_ctid, &itemPointerData);
+ heap_delete(relation, &itemPointerData);
+ heap_endscan(scan);
+ heap_close(relation);
}
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index 5d4e4ab2bb8..9b8df698346 100644
--- a/src/backend/commands/rename.c
+++ b/src/backend/commands/rename.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rename.c--
- * renameatt() and renamerel() reside here.
+ * renameatt() and renamerel() reside here.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.7 1997/08/18 20:52:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.8 1997/09/07 04:40:55 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,227 +32,246 @@
#include <catalog/pg_proc.h>
#include <catalog/pg_class.h>
#include <optimizer/internal.h>
-#include <optimizer/prep.h> /* for find_all_inheritors */
+#include <optimizer/prep.h> /* for find_all_inheritors */
#ifndef NO_SECURITY
-# include <utils/acl.h>
-#endif /* !NO_SECURITY */
+#include <utils/acl.h>
+#endif /* !NO_SECURITY */
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
/*
- * renameatt - changes the name of a attribute in a relation
+ * renameatt - changes the name of a attribute in a relation
*
- * Attname attribute is changed in attribute catalog.
- * No record of the previous attname is kept (correct?).
+ * Attname attribute is changed in attribute catalog.
+ * No record of the previous attname is kept (correct?).
*
- * get proper reldesc from relation catalog (if not arg)
- * scan attribute catalog
- * for name conflict (within rel)
- * for original attribute (if not arg)
- * modify attname in attribute tuple
- * insert modified attribute in attribute catalog
- * delete original attribute from attribute catalog
+ * get proper reldesc from relation catalog (if not arg)
+ * scan attribute catalog
+ * for name conflict (within rel)
+ * for original attribute (if not arg)
+ * modify attname in attribute tuple
+ * insert modified attribute in attribute catalog
+ * delete original attribute from attribute catalog
*
- * XXX Renaming an indexed attribute must (eventually) also change
- * the attribute name in the associated indexes.
+ * XXX Renaming an indexed attribute must (eventually) also change
+ * the attribute name in the associated indexes.
*/
void
renameatt(char *relname,
- char *oldattname,
- char *newattname,
- char *userName,
- int recurse)
+ char *oldattname,
+ char *newattname,
+ char *userName,
+ int recurse)
{
- Relation relrdesc, attrdesc;
- HeapTuple reltup, oldatttup, newatttup;
- ItemPointerData oldTID;
- Relation idescs[Num_pg_attr_indices];
-
- /*
- * permissions checking. this would normally be done in utility.c,
- * but this particular routine is recursive.
- *
- * normally, only the owner of a class can change its schema.
- */
- if (IsSystemRelationName(relname))
- elog(WARN, "renameatt: class \"%s\" is a system catalog",
- relname);
+ Relation relrdesc,
+ attrdesc;
+ HeapTuple reltup,
+ oldatttup,
+ newatttup;
+ ItemPointerData oldTID;
+ Relation idescs[Num_pg_attr_indices];
+
+ /*
+ * permissions checking. this would normally be done in utility.c,
+ * but this particular routine is recursive.
+ *
+ * normally, only the owner of a class can change its schema.
+ */
+ if (IsSystemRelationName(relname))
+ elog(WARN, "renameatt: class \"%s\" is a system catalog",
+ relname);
#ifndef NO_SECURITY
- if (!IsBootstrapProcessingMode() &&
- !pg_ownercheck(userName, relname, RELNAME))
- elog(WARN, "renameatt: you do not own class \"%s\"",
- relname);
+ if (!IsBootstrapProcessingMode() &&
+ !pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "renameatt: you do not own class \"%s\"",
+ relname);
#endif
-
- /*
- * if the 'recurse' flag is set then we are supposed to rename this
- * attribute in all classes that inherit from 'relname' (as well as
- * in 'relname').
- *
- * any permissions or problems with duplicate attributes will cause
- * the whole transaction to abort, which is what we want -- all or
- * nothing.
- */
- if (recurse) {
- Oid myrelid, childrelid;
- List *child, *children;
-
- relrdesc = heap_openr(relname);
- if (!RelationIsValid(relrdesc)) {
- elog(WARN, "renameatt: unknown relation: \"%s\"",
- relname);
- }
- myrelid = relrdesc->rd_id;
- heap_close(relrdesc);
-
- /* this routine is actually in the planner */
- children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
-
/*
- * find_all_inheritors does the recursive search of the
- * inheritance hierarchy, so all we have to do is process
- * all of the relids in the list that it returns.
+ * if the 'recurse' flag is set then we are supposed to rename this
+ * attribute in all classes that inherit from 'relname' (as well as in
+ * 'relname').
+ *
+ * any permissions or problems with duplicate attributes will cause the
+ * whole transaction to abort, which is what we want -- all or
+ * nothing.
*/
- foreach (child, children) {
- char *childname;
-
- childrelid = lfirsti(child);
- if (childrelid == myrelid)
- continue;
- relrdesc = heap_open(childrelid);
- if (!RelationIsValid(relrdesc)) {
- elog(WARN, "renameatt: can't find catalog entry for inheriting class with oid %d",
- childrelid);
- }
- childname = (relrdesc->rd_rel->relname).data;
- heap_close(relrdesc);
- renameatt(childname, oldattname, newattname,
- userName, 0); /* no more recursion! */
+ if (recurse)
+ {
+ Oid myrelid,
+ childrelid;
+ List *child,
+ *children;
+
+ relrdesc = heap_openr(relname);
+ if (!RelationIsValid(relrdesc))
+ {
+ elog(WARN, "renameatt: unknown relation: \"%s\"",
+ relname);
+ }
+ myrelid = relrdesc->rd_id;
+ heap_close(relrdesc);
+
+ /* this routine is actually in the planner */
+ children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
+
+
+ /*
+ * find_all_inheritors does the recursive search of the
+ * inheritance hierarchy, so all we have to do is process all of
+ * the relids in the list that it returns.
+ */
+ foreach(child, children)
+ {
+ char *childname;
+
+ childrelid = lfirsti(child);
+ if (childrelid == myrelid)
+ continue;
+ relrdesc = heap_open(childrelid);
+ if (!RelationIsValid(relrdesc))
+ {
+ elog(WARN, "renameatt: can't find catalog entry for inheriting class with oid %d",
+ childrelid);
+ }
+ childname = (relrdesc->rd_rel->relname).data;
+ heap_close(relrdesc);
+ renameatt(childname, oldattname, newattname,
+ userName, 0); /* no more recursion! */
+ }
+ }
+
+ relrdesc = heap_openr(RelationRelationName);
+ reltup = ClassNameIndexScan(relrdesc, relname);
+ if (!PointerIsValid(reltup))
+ {
+ heap_close(relrdesc);
+ elog(WARN, "renameatt: relation \"%s\" nonexistent",
+ relname);
+ return;
}
- }
-
- relrdesc = heap_openr(RelationRelationName);
- reltup = ClassNameIndexScan(relrdesc, relname);
- if (!PointerIsValid(reltup)) {
heap_close(relrdesc);
- elog(WARN, "renameatt: relation \"%s\" nonexistent",
- relname);
- return;
- }
- heap_close(relrdesc);
-
- attrdesc = heap_openr(AttributeRelationName);
- oldatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, oldattname);
- if (!PointerIsValid(oldatttup)) {
+
+ attrdesc = heap_openr(AttributeRelationName);
+ oldatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, oldattname);
+ if (!PointerIsValid(oldatttup))
+ {
+ heap_close(attrdesc);
+ elog(WARN, "renameatt: attribute \"%s\" nonexistent",
+ oldattname);
+ }
+ if (((AttributeTupleForm) GETSTRUCT(oldatttup))->attnum < 0)
+ {
+ elog(WARN, "renameatt: system attribute \"%s\" not renamed",
+ oldattname);
+ }
+
+ newatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, newattname);
+ if (PointerIsValid(newatttup))
+ {
+ pfree(oldatttup);
+ heap_close(attrdesc);
+ elog(WARN, "renameatt: attribute \"%s\" exists",
+ newattname);
+ }
+
+ namestrcpy(&(((AttributeTupleForm) (GETSTRUCT(oldatttup)))->attname),
+ newattname);
+ oldTID = oldatttup->t_ctid;
+
+ /* insert "fixed" tuple */
+ heap_replace(attrdesc, &oldTID, oldatttup);
+
+ /* keep system catalog indices current */
+ CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_attr_indices, attrdesc, oldatttup);
+ CatalogCloseIndices(Num_pg_attr_indices, idescs);
+
heap_close(attrdesc);
- elog(WARN, "renameatt: attribute \"%s\" nonexistent",
- oldattname);
- }
- if (((AttributeTupleForm ) GETSTRUCT(oldatttup))->attnum < 0) {
- elog(WARN, "renameatt: system attribute \"%s\" not renamed",
- oldattname);
- }
-
- newatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, newattname);
- if (PointerIsValid(newatttup)) {
pfree(oldatttup);
- heap_close(attrdesc);
- elog(WARN, "renameatt: attribute \"%s\" exists",
- newattname);
- }
-
- namestrcpy(&(((AttributeTupleForm)(GETSTRUCT(oldatttup)))->attname),
- newattname);
- oldTID = oldatttup->t_ctid;
-
- /* insert "fixed" tuple */
- heap_replace(attrdesc, &oldTID, oldatttup);
-
- /* keep system catalog indices current */
- CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_attr_indices, attrdesc, oldatttup);
- CatalogCloseIndices(Num_pg_attr_indices, idescs);
-
- heap_close(attrdesc);
- pfree(oldatttup);
}
/*
- * renamerel - change the name of a relation
+ * renamerel - change the name of a relation
*
- * Relname attribute is changed in relation catalog.
- * No record of the previous relname is kept (correct?).
+ * Relname attribute is changed in relation catalog.
+ * No record of the previous relname is kept (correct?).
*
- * scan relation catalog
- * for name conflict
- * for original relation (if not arg)
- * modify relname in relation tuple
- * insert modified relation in relation catalog
- * delete original relation from relation catalog
+ * scan relation catalog
+ * for name conflict
+ * for original relation (if not arg)
+ * modify relname in relation tuple
+ * insert modified relation in relation catalog
+ * delete original relation from relation catalog
*
- * XXX Will currently lose track of a relation if it is unable to
- * properly replace the new relation tuple.
+ * XXX Will currently lose track of a relation if it is unable to
+ * properly replace the new relation tuple.
*/
void
renamerel(char oldrelname[], char newrelname[])
{
- Relation relrdesc; /* for RELATION relation */
- HeapTuple oldreltup, newreltup;
- ItemPointerData oldTID;
- char oldpath[MAXPGPATH], newpath[MAXPGPATH];
- Relation idescs[Num_pg_class_indices];
-
- if (IsSystemRelationName(oldrelname)) {
- elog(WARN, "renamerel: system relation \"%s\" not renamed",
- oldrelname);
- return;
- }
- if (IsSystemRelationName(newrelname)) {
- elog(WARN, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
- newrelname);
- return;
- }
-
- relrdesc = heap_openr(RelationRelationName);
- oldreltup = ClassNameIndexScan(relrdesc, oldrelname);
-
- if (!PointerIsValid(oldreltup)) {
- heap_close(relrdesc);
- elog(WARN, "renamerel: relation \"%s\" does not exist",
- oldrelname);
- }
-
- newreltup = ClassNameIndexScan(relrdesc, newrelname);
- if (PointerIsValid(newreltup)) {
+ Relation relrdesc; /* for RELATION relation */
+ HeapTuple oldreltup,
+ newreltup;
+ ItemPointerData oldTID;
+ char oldpath[MAXPGPATH],
+ newpath[MAXPGPATH];
+ Relation idescs[Num_pg_class_indices];
+
+ if (IsSystemRelationName(oldrelname))
+ {
+ elog(WARN, "renamerel: system relation \"%s\" not renamed",
+ oldrelname);
+ return;
+ }
+ if (IsSystemRelationName(newrelname))
+ {
+ elog(WARN, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
+ newrelname);
+ return;
+ }
+
+ relrdesc = heap_openr(RelationRelationName);
+ oldreltup = ClassNameIndexScan(relrdesc, oldrelname);
+
+ if (!PointerIsValid(oldreltup))
+ {
+ heap_close(relrdesc);
+ elog(WARN, "renamerel: relation \"%s\" does not exist",
+ oldrelname);
+ }
+
+ newreltup = ClassNameIndexScan(relrdesc, newrelname);
+ if (PointerIsValid(newreltup))
+ {
+ pfree(oldreltup);
+ heap_close(relrdesc);
+ elog(WARN, "renamerel: relation \"%s\" exists",
+ newrelname);
+ }
+
+ /* rename the directory first, so if this fails the rename's not done */
+ strcpy(oldpath, relpath(oldrelname));
+ strcpy(newpath, relpath(newrelname));
+ if (rename(oldpath, newpath) < 0)
+ elog(WARN, "renamerel: unable to rename file: %m");
+
+ memmove((char *) (((Form_pg_class) GETSTRUCT(oldreltup))->relname.data),
+ newrelname,
+ NAMEDATALEN);
+ oldTID = oldreltup->t_ctid;
+
+ /* insert fixed rel tuple */
+ heap_replace(relrdesc, &oldTID, oldreltup);
+
+ /* keep the system catalog indices current */
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, relrdesc, oldreltup);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+
pfree(oldreltup);
heap_close(relrdesc);
- elog(WARN, "renamerel: relation \"%s\" exists",
- newrelname);
- }
-
- /* rename the directory first, so if this fails the rename's not done */
- strcpy(oldpath, relpath(oldrelname));
- strcpy(newpath, relpath(newrelname));
- if (rename(oldpath, newpath) < 0)
- elog(WARN, "renamerel: unable to rename file: %m");
-
- memmove((char *) (((Form_pg_class) GETSTRUCT(oldreltup))->relname.data),
- newrelname,
- NAMEDATALEN);
- oldTID = oldreltup->t_ctid;
-
- /* insert fixed rel tuple */
- heap_replace(relrdesc, &oldTID, oldreltup);
-
- /* keep the system catalog indices current */
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, relrdesc, oldreltup);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
-
- pfree(oldreltup);
- heap_close(relrdesc);
}
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 5d35f7b60f5..c4bd8c40dcf 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* sequence.c--
- * PostgreSQL sequences support code.
+ * PostgreSQL sequences support code.
*
*-------------------------------------------------------------------------
*/
@@ -19,523 +19,539 @@
#include <commands/sequence.h>
#include <utils/builtins.h>
-#define SEQ_MAGIC 0x1717
+#define SEQ_MAGIC 0x1717
#define SEQ_MAXVALUE ((int4)0x7FFFFFFF)
#define SEQ_MINVALUE -(SEQ_MAXVALUE)
-bool ItsSequenceCreation = false;
+bool ItsSequenceCreation = false;
-typedef struct FormData_pg_sequence {
- NameData sequence_name;
- int4 last_value;
- int4 increment_by;
- int4 max_value;
- int4 min_value;
- int4 cache_value;
- char is_cycled;
- char is_called;
-} FormData_pg_sequence;
-
-typedef FormData_pg_sequence *SequenceTupleForm;
-
-typedef struct sequence_magic {
- uint32 magic;
-} sequence_magic;
+typedef struct FormData_pg_sequence
+{
+ NameData sequence_name;
+ int4 last_value;
+ int4 increment_by;
+ int4 max_value;
+ int4 min_value;
+ int4 cache_value;
+ char is_cycled;
+ char is_called;
+} FormData_pg_sequence;
+
+typedef FormData_pg_sequence *SequenceTupleForm;
+
+typedef struct sequence_magic
+{
+ uint32 magic;
+} sequence_magic;
-typedef struct SeqTableData {
- char *name;
- Oid relid;
+typedef struct SeqTableData
+{
+ char *name;
+ Oid relid;
Relation rel;
int4 cached;
int4 last;
int4 increment;
- struct SeqTableData *next;
-} SeqTableData;
+ struct SeqTableData *next;
+} SeqTableData;
typedef SeqTableData *SeqTable;
static SeqTable seqtab = NULL;
-static SeqTable init_sequence (char *caller, char *name);
-static SequenceTupleForm read_info (char * caller, SeqTable elm, Buffer * buf);
-static void init_params (CreateSeqStmt *seq, SequenceTupleForm new);
-static int get_param (DefElem *def);
+static SeqTable init_sequence(char *caller, char *name);
+static SequenceTupleForm read_info(char *caller, SeqTable elm, Buffer * buf);
+static void init_params(CreateSeqStmt * seq, SequenceTupleForm new);
+static int get_param(DefElem * def);
/*
* DefineSequence --
- * Creates a new sequence relation
+ * Creates a new sequence relation
*/
void
-DefineSequence (CreateSeqStmt *seq)
+DefineSequence(CreateSeqStmt * seq)
{
- FormData_pg_sequence new;
- CreateStmt *stmt = makeNode (CreateStmt);
- ColumnDef *coldef;
- TypeName *typnam;
- Relation rel;
- Buffer buf;
- PageHeader page;
- sequence_magic *sm;
- HeapTuple tuple;
- TupleDesc tupDesc;
- Datum value[SEQ_COL_LASTCOL];
- char null[SEQ_COL_LASTCOL];
- int i;
-
- /* Check and set values */
- init_params (seq, &new);
-
- /*
- * Create relation (and fill null[] & value[])
- */
- stmt->tableElts = NIL;
- for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
- {
- typnam = makeNode(TypeName);
- typnam->setof = FALSE;
- typnam->arrayBounds = NULL;
- coldef = makeNode(ColumnDef);
- coldef->typename = typnam;
- coldef->defval = NULL;
- coldef->is_not_null = false;
- null[i-1] = ' ';
-
- switch (i)
+ FormData_pg_sequence new;
+ CreateStmt *stmt = makeNode(CreateStmt);
+ ColumnDef *coldef;
+ TypeName *typnam;
+ Relation rel;
+ Buffer buf;
+ PageHeader page;
+ sequence_magic *sm;
+ HeapTuple tuple;
+ TupleDesc tupDesc;
+ Datum value[SEQ_COL_LASTCOL];
+ char null[SEQ_COL_LASTCOL];
+ int i;
+
+ /* Check and set values */
+ init_params(seq, &new);
+
+ /*
+ * Create relation (and fill null[] & value[])
+ */
+ stmt->tableElts = NIL;
+ for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
{
- case SEQ_COL_NAME:
- typnam->name = "name";
- coldef->colname = "sequence_name";
- value[i-1] = PointerGetDatum (seq->seqname);
- break;
- case SEQ_COL_LASTVAL:
- typnam->name = "int4";
- coldef->colname = "last_value";
- value[i-1] = Int32GetDatum (new.last_value);
- break;
- case SEQ_COL_INCBY:
- typnam->name = "int4";
- coldef->colname = "increment_by";
- value[i-1] = Int32GetDatum (new.increment_by);
- break;
- case SEQ_COL_MAXVALUE:
- typnam->name = "int4";
- coldef->colname = "max_value";
- value[i-1] = Int32GetDatum (new.max_value);
- break;
- case SEQ_COL_MINVALUE:
- typnam->name = "int4";
- coldef->colname = "min_value";
- value[i-1] = Int32GetDatum (new.min_value);
- break;
- case SEQ_COL_CACHE:
- typnam->name = "int4";
- coldef->colname = "cache_value";
- value[i-1] = Int32GetDatum (new.cache_value);
- break;
- case SEQ_COL_CYCLE:
- typnam->name = "char";
- coldef->colname = "is_cycled";
- value[i-1] = CharGetDatum (new.is_cycled);
- break;
- case SEQ_COL_CALLED:
- typnam->name = "char";
- coldef->colname = "is_called";
- value[i-1] = CharGetDatum ('f');
- break;
- }
- stmt->tableElts = lappend (stmt->tableElts, coldef);
- }
-
- stmt->relname = seq->seqname;
- stmt->archiveLoc = -1; /* default */
- stmt->archiveType = ARCH_NONE;
- stmt->inhRelnames = NIL;
- stmt->constraints = NIL;
-
- ItsSequenceCreation = true; /* hack */
-
- DefineRelation (stmt);
-
- /* Xact abort calls CloseSequences, which turns ItsSequenceCreation off */
- ItsSequenceCreation = false; /* hack */
-
- rel = heap_openr (seq->seqname);
- Assert ( RelationIsValid (rel) );
-
- RelationSetLockForWrite (rel);
-
- tupDesc = RelationGetTupleDescriptor(rel);
-
- Assert ( RelationGetNumberOfBlocks (rel) == 0 );
- buf = ReadBuffer (rel, P_NEW);
-
- if ( !BufferIsValid (buf) )
- elog (WARN, "DefineSequence: ReadBuffer failed");
-
- page = (PageHeader) BufferGetPage (buf);
-
- PageInit((Page)page, BufferGetPageSize(buf), sizeof(sequence_magic));
- sm = (sequence_magic *) PageGetSpecialPointer (page);
- sm->magic = SEQ_MAGIC;
-
- /* Now - form & insert sequence tuple */
- tuple = heap_formtuple (tupDesc, value, null);
- heap_insert (rel, tuple);
-
- if ( WriteBuffer (buf) == STATUS_ERROR )
- elog (WARN, "DefineSequence: WriteBuffer failed");
-
- RelationUnsetLockForWrite (rel);
- heap_close (rel);
-
- return;
+ typnam = makeNode(TypeName);
+ typnam->setof = FALSE;
+ typnam->arrayBounds = NULL;
+ coldef = makeNode(ColumnDef);
+ coldef->typename = typnam;
+ coldef->defval = NULL;
+ coldef->is_not_null = false;
+ null[i - 1] = ' ';
+
+ switch (i)
+ {
+ case SEQ_COL_NAME:
+ typnam->name = "name";
+ coldef->colname = "sequence_name";
+ value[i - 1] = PointerGetDatum(seq->seqname);
+ break;
+ case SEQ_COL_LASTVAL:
+ typnam->name = "int4";
+ coldef->colname = "last_value";
+ value[i - 1] = Int32GetDatum(new.last_value);
+ break;
+ case SEQ_COL_INCBY:
+ typnam->name = "int4";
+ coldef->colname = "increment_by";
+ value[i - 1] = Int32GetDatum(new.increment_by);
+ break;
+ case SEQ_COL_MAXVALUE:
+ typnam->name = "int4";
+ coldef->colname = "max_value";
+ value[i - 1] = Int32GetDatum(new.max_value);
+ break;
+ case SEQ_COL_MINVALUE:
+ typnam->name = "int4";
+ coldef->colname = "min_value";
+ value[i - 1] = Int32GetDatum(new.min_value);
+ break;
+ case SEQ_COL_CACHE:
+ typnam->name = "int4";
+ coldef->colname = "cache_value";
+ value[i - 1] = Int32GetDatum(new.cache_value);
+ break;
+ case SEQ_COL_CYCLE:
+ typnam->name = "char";
+ coldef->colname = "is_cycled";
+ value[i - 1] = CharGetDatum(new.is_cycled);
+ break;
+ case SEQ_COL_CALLED:
+ typnam->name = "char";
+ coldef->colname = "is_called";
+ value[i - 1] = CharGetDatum('f');
+ break;
+ }
+ stmt->tableElts = lappend(stmt->tableElts, coldef);
+ }
+
+ stmt->relname = seq->seqname;
+ stmt->archiveLoc = -1; /* default */
+ stmt->archiveType = ARCH_NONE;
+ stmt->inhRelnames = NIL;
+ stmt->constraints = NIL;
+
+ ItsSequenceCreation = true; /* hack */
+
+ DefineRelation(stmt);
+
+ /*
+ * Xact abort calls CloseSequences, which turns ItsSequenceCreation
+ * off
+ */
+ ItsSequenceCreation = false;/* hack */
+
+ rel = heap_openr(seq->seqname);
+ Assert(RelationIsValid(rel));
+
+ RelationSetLockForWrite(rel);
+
+ tupDesc = RelationGetTupleDescriptor(rel);
+
+ Assert(RelationGetNumberOfBlocks(rel) == 0);
+ buf = ReadBuffer(rel, P_NEW);
+
+ if (!BufferIsValid(buf))
+ elog(WARN, "DefineSequence: ReadBuffer failed");
+
+ page = (PageHeader) BufferGetPage(buf);
+
+ PageInit((Page) page, BufferGetPageSize(buf), sizeof(sequence_magic));
+ sm = (sequence_magic *) PageGetSpecialPointer(page);
+ sm->magic = SEQ_MAGIC;
+
+ /* Now - form & insert sequence tuple */
+ tuple = heap_formtuple(tupDesc, value, null);
+ heap_insert(rel, tuple);
+
+ if (WriteBuffer(buf) == STATUS_ERROR)
+ elog(WARN, "DefineSequence: WriteBuffer failed");
+
+ RelationUnsetLockForWrite(rel);
+ heap_close(rel);
+
+ return;
}
int4
-nextval (struct varlena * seqin)
+nextval(struct varlena * seqin)
{
- char *seqname = textout(seqin);
- SeqTable elm;
- Buffer buf;
- SequenceTupleForm seq;
- ItemPointerData iptr;
- int4 incby, maxv, minv, cache;
- int4 result, next, rescnt = 0;
-
- /* open and WIntentLock sequence */
- elm = init_sequence ("nextval", seqname);
- pfree (seqname);
-
- if ( elm->last != elm->cached ) /* some numbers were cached */
- {
- elm->last += elm->increment;
- return (elm->last);
- }
-
- seq = read_info ("nextval", elm, &buf); /* lock page and read tuple */
-
- next = result = seq->last_value;
- incby = seq->increment_by;
- maxv = seq->max_value;
- minv = seq->min_value;
- cache = seq->cache_value;
-
- if ( seq->is_called != 't' )
- rescnt++; /* last_value if not called */
-
- while ( rescnt < cache ) /* try to fetch cache numbers */
- {
- /*
- * Check MAXVALUE for ascending sequences
- * and MINVALUE for descending sequences
- */
- if ( incby > 0 ) /* ascending sequence */
- {
- if ( ( maxv >= 0 && next > maxv - incby) ||
- ( maxv < 0 && next + incby > maxv ) )
- {
- if ( rescnt > 0 )
- break; /* stop caching */
- if ( seq->is_cycled != 't' )
- elog (WARN, "%s.nextval: got MAXVALUE (%d)",
- elm->name, maxv);
- next = minv;
- }
- else
- next += incby;
+ char *seqname = textout(seqin);
+ SeqTable elm;
+ Buffer buf;
+ SequenceTupleForm seq;
+ ItemPointerData iptr;
+ int4 incby,
+ maxv,
+ minv,
+ cache;
+ int4 result,
+ next,
+ rescnt = 0;
+
+ /* open and WIntentLock sequence */
+ elm = init_sequence("nextval", seqname);
+ pfree(seqname);
+
+ if (elm->last != elm->cached) /* some numbers were cached */
+ {
+ elm->last += elm->increment;
+ return (elm->last);
}
- else /* descending sequence */
+
+ seq = read_info("nextval", elm, &buf); /* lock page and read
+ * tuple */
+
+ next = result = seq->last_value;
+ incby = seq->increment_by;
+ maxv = seq->max_value;
+ minv = seq->min_value;
+ cache = seq->cache_value;
+
+ if (seq->is_called != 't')
+ rescnt++; /* last_value if not called */
+
+ while (rescnt < cache) /* try to fetch cache numbers */
{
- if ( ( minv < 0 && next < minv - incby ) ||
- ( minv >= 0 && next + incby < minv ) )
- {
- if ( rescnt > 0 )
- break; /* stop caching */
- if ( seq->is_cycled != 't' )
- elog (WARN, "%s.nextval: got MINVALUE (%d)",
- elm->name, minv);
- next = maxv;
- }
- else
- next += incby;
- }
- rescnt++; /* got result */
- if ( rescnt == 1 ) /* if it's first one - */
- result = next; /* it's what to return */
- }
-
- /* save info in local cache */
- elm->last = result; /* last returned number */
- elm->cached = next; /* last cached number */
-
- /* save info in sequence relation */
- seq->last_value = next; /* last fetched number */
- seq->is_called = 't';
-
- if ( WriteBuffer (buf) == STATUS_ERROR )
- elog (WARN, "%s.nextval: WriteBuffer failed", elm->name);
-
- ItemPointerSet(&iptr, 0, FirstOffsetNumber);
- RelationUnsetSingleWLockPage (elm->rel, &iptr);
-
- return (result);
-
+
+ /*
+ * Check MAXVALUE for ascending sequences and MINVALUE for
+ * descending sequences
+ */
+ if (incby > 0) /* ascending sequence */
+ {
+ if ((maxv >= 0 && next > maxv - incby) ||
+ (maxv < 0 && next + incby > maxv))
+ {
+ if (rescnt > 0)
+ break; /* stop caching */
+ if (seq->is_cycled != 't')
+ elog(WARN, "%s.nextval: got MAXVALUE (%d)",
+ elm->name, maxv);
+ next = minv;
+ }
+ else
+ next += incby;
+ }
+ else
+/* descending sequence */
+ {
+ if ((minv < 0 && next < minv - incby) ||
+ (minv >= 0 && next + incby < minv))
+ {
+ if (rescnt > 0)
+ break; /* stop caching */
+ if (seq->is_cycled != 't')
+ elog(WARN, "%s.nextval: got MINVALUE (%d)",
+ elm->name, minv);
+ next = maxv;
+ }
+ else
+ next += incby;
+ }
+ rescnt++; /* got result */
+ if (rescnt == 1) /* if it's first one - */
+ result = next; /* it's what to return */
+ }
+
+ /* save info in local cache */
+ elm->last = result; /* last returned number */
+ elm->cached = next; /* last cached number */
+
+ /* save info in sequence relation */
+ seq->last_value = next; /* last fetched number */
+ seq->is_called = 't';
+
+ if (WriteBuffer(buf) == STATUS_ERROR)
+ elog(WARN, "%s.nextval: WriteBuffer failed", elm->name);
+
+ ItemPointerSet(&iptr, 0, FirstOffsetNumber);
+ RelationUnsetSingleWLockPage(elm->rel, &iptr);
+
+ return (result);
+
}
int4
-currval (struct varlena * seqin)
+currval(struct varlena * seqin)
{
- char *seqname = textout(seqin);
- SeqTable elm;
- int4 result;
-
- /* open and WIntentLock sequence */
- elm = init_sequence ("currval", seqname);
- pfree (seqname);
-
- if ( elm->increment == 0 ) /* nextval/read_info were not called */
- {
- elog (WARN, "%s.currval is not yet defined in this session", elm->name);
- }
-
- result = elm->last;
-
- return (result);
-
+ char *seqname = textout(seqin);
+ SeqTable elm;
+ int4 result;
+
+ /* open and WIntentLock sequence */
+ elm = init_sequence("currval", seqname);
+ pfree(seqname);
+
+ if (elm->increment == 0) /* nextval/read_info were not called */
+ {
+ elog(WARN, "%s.currval is not yet defined in this session", elm->name);
+ }
+
+ result = elm->last;
+
+ return (result);
+
}
-static SequenceTupleForm
-read_info (char * caller, SeqTable elm, Buffer * buf)
+static SequenceTupleForm
+read_info(char *caller, SeqTable elm, Buffer * buf)
{
- ItemPointerData iptr;
- PageHeader page;
- ItemId lp;
- HeapTuple tuple;
- sequence_magic *sm;
- SequenceTupleForm seq;
-
- ItemPointerSet(&iptr, 0, FirstOffsetNumber);
- RelationSetSingleWLockPage (elm->rel, &iptr);
-
- if ( RelationGetNumberOfBlocks (elm->rel) != 1 )
- elog (WARN, "%s.%s: invalid number of blocks in sequence",
- elm->name, caller);
-
- *buf = ReadBuffer (elm->rel, 0);
- if ( !BufferIsValid (*buf) )
- elog (WARN, "%s.%s: ReadBuffer failed", elm->name, caller);
-
- page = (PageHeader) BufferGetPage (*buf);
- sm = (sequence_magic *) PageGetSpecialPointer (page);
-
- if ( sm->magic != SEQ_MAGIC )
- elog (WARN, "%s.%s: bad magic (%08X)", elm->name, caller, sm->magic);
-
- lp = PageGetItemId (page, FirstOffsetNumber);
- Assert (ItemIdIsUsed (lp));
- tuple = (HeapTuple) PageGetItem ((Page) page, lp);
-
- seq = (SequenceTupleForm) GETSTRUCT(tuple);
-
- elm->increment = seq->increment_by;
-
- return (seq);
+ ItemPointerData iptr;
+ PageHeader page;
+ ItemId lp;
+ HeapTuple tuple;
+ sequence_magic *sm;
+ SequenceTupleForm seq;
+
+ ItemPointerSet(&iptr, 0, FirstOffsetNumber);
+ RelationSetSingleWLockPage(elm->rel, &iptr);
+
+ if (RelationGetNumberOfBlocks(elm->rel) != 1)
+ elog(WARN, "%s.%s: invalid number of blocks in sequence",
+ elm->name, caller);
+
+ *buf = ReadBuffer(elm->rel, 0);
+ if (!BufferIsValid(*buf))
+ elog(WARN, "%s.%s: ReadBuffer failed", elm->name, caller);
+
+ page = (PageHeader) BufferGetPage(*buf);
+ sm = (sequence_magic *) PageGetSpecialPointer(page);
+
+ if (sm->magic != SEQ_MAGIC)
+ elog(WARN, "%s.%s: bad magic (%08X)", elm->name, caller, sm->magic);
+
+ lp = PageGetItemId(page, FirstOffsetNumber);
+ Assert(ItemIdIsUsed(lp));
+ tuple = (HeapTuple) PageGetItem((Page) page, lp);
+
+ seq = (SequenceTupleForm) GETSTRUCT(tuple);
+
+ elm->increment = seq->increment_by;
+
+ return (seq);
}
-static SeqTable
-init_sequence (char * caller, char * name)
+static SeqTable
+init_sequence(char *caller, char *name)
{
- SeqTable elm, priv = (SeqTable) NULL;
- SeqTable temp;
-
- for (elm = seqtab; elm != (SeqTable) NULL; )
- {
- if ( strcmp (elm->name, name) == 0 )
- break;
- priv = elm;
- elm = elm->next;
- }
-
- if ( elm == (SeqTable) NULL ) /* not found */
- {
- temp = (SeqTable) malloc (sizeof(SeqTableData));
- temp->name = malloc (strlen(name) + 1);
- strcpy (temp->name, name);
- temp->rel = (Relation) NULL;
- temp->cached = temp->last = temp->increment = 0;
- temp->next = (SeqTable) NULL;
- }
- else /* found */
- {
- if ( elm->rel != (Relation) NULL) /* already opened */
- return (elm);
- temp = elm;
- }
-
- temp->rel = heap_openr (name);
-
- if ( ! RelationIsValid (temp->rel) )
- elog (WARN, "%s.%s: sequence does not exist", name, caller);
-
- RelationSetWIntentLock (temp->rel);
-
- if ( temp->rel->rd_rel->relkind != RELKIND_SEQUENCE )
- elog (WARN, "%s.%s: %s is not sequence !", name, caller, name);
-
- if ( elm != (SeqTable) NULL ) /* we opened sequence from our */
- { /* SeqTable - check relid ! */
- if ( RelationGetRelationId (elm->rel) != elm->relid )
- {
- elog (NOTICE, "%s.%s: sequence was re-created",
- name, caller, name);
- elm->cached = elm->last = elm->increment = 0;
- elm->relid = RelationGetRelationId (elm->rel);
- }
- }
- else
- {
- elm = temp;
- elm->relid = RelationGetRelationId (elm->rel);
- if ( seqtab == (SeqTable) NULL )
- seqtab = elm;
- else
- priv->next = elm;
- }
-
- return (elm);
-
+ SeqTable elm,
+ priv = (SeqTable) NULL;
+ SeqTable temp;
+
+ for (elm = seqtab; elm != (SeqTable) NULL;)
+ {
+ if (strcmp(elm->name, name) == 0)
+ break;
+ priv = elm;
+ elm = elm->next;
+ }
+
+ if (elm == (SeqTable) NULL) /* not found */
+ {
+ temp = (SeqTable) malloc(sizeof(SeqTableData));
+ temp->name = malloc(strlen(name) + 1);
+ strcpy(temp->name, name);
+ temp->rel = (Relation) NULL;
+ temp->cached = temp->last = temp->increment = 0;
+ temp->next = (SeqTable) NULL;
+ }
+ else
+/* found */
+ {
+ if (elm->rel != (Relation) NULL) /* already opened */
+ return (elm);
+ temp = elm;
+ }
+
+ temp->rel = heap_openr(name);
+
+ if (!RelationIsValid(temp->rel))
+ elog(WARN, "%s.%s: sequence does not exist", name, caller);
+
+ RelationSetWIntentLock(temp->rel);
+
+ if (temp->rel->rd_rel->relkind != RELKIND_SEQUENCE)
+ elog(WARN, "%s.%s: %s is not sequence !", name, caller, name);
+
+ if (elm != (SeqTable) NULL) /* we opened sequence from our */
+ { /* SeqTable - check relid ! */
+ if (RelationGetRelationId(elm->rel) != elm->relid)
+ {
+ elog(NOTICE, "%s.%s: sequence was re-created",
+ name, caller, name);
+ elm->cached = elm->last = elm->increment = 0;
+ elm->relid = RelationGetRelationId(elm->rel);
+ }
+ }
+ else
+ {
+ elm = temp;
+ elm->relid = RelationGetRelationId(elm->rel);
+ if (seqtab == (SeqTable) NULL)
+ seqtab = elm;
+ else
+ priv->next = elm;
+ }
+
+ return (elm);
+
}
/*
* CloseSequences --
- * is calling by xact mgr at commit/abort.
+ * is calling by xact mgr at commit/abort.
*/
void
-CloseSequences (void)
+CloseSequences(void)
{
- SeqTable elm;
- Relation rel;
-
- ItsSequenceCreation = false;
-
- for (elm = seqtab; elm != (SeqTable) NULL; )
- {
- if ( elm->rel != (Relation) NULL ) /* opened in current xact */
+ SeqTable elm;
+ Relation rel;
+
+ ItsSequenceCreation = false;
+
+ for (elm = seqtab; elm != (SeqTable) NULL;)
{
- rel = elm->rel;
- elm->rel = (Relation) NULL;
- RelationUnsetWIntentLock (rel);
- heap_close (rel);
- }
- elm = elm->next;
- }
-
- return;
-
+ if (elm->rel != (Relation) NULL) /* opened in current xact */
+ {
+ rel = elm->rel;
+ elm->rel = (Relation) NULL;
+ RelationUnsetWIntentLock(rel);
+ heap_close(rel);
+ }
+ elm = elm->next;
+ }
+
+ return;
+
}
-static void
-init_params (CreateSeqStmt *seq, SequenceTupleForm new)
+static void
+init_params(CreateSeqStmt * seq, SequenceTupleForm new)
{
- DefElem *last_value = NULL;
- DefElem *increment_by = NULL;
- DefElem *max_value = NULL;
- DefElem *min_value = NULL;
- DefElem *cache_value = NULL;
- List *option;
-
- new->is_cycled = 'f';
- foreach (option, seq->options)
- {
- DefElem *defel = (DefElem *)lfirst(option);
-
- if ( !strcasecmp(defel->defname, "increment") )
- increment_by = defel;
- else if ( !strcasecmp(defel->defname, "start") )
- last_value = defel;
- else if ( !strcasecmp(defel->defname, "maxvalue") )
- max_value = defel;
- else if ( !strcasecmp(defel->defname, "minvalue") )
- min_value = defel;
- else if ( !strcasecmp(defel->defname, "cache") )
- cache_value = defel;
- else if ( !strcasecmp(defel->defname, "cycle") )
- {
- if ( defel->arg != (Node*) NULL )
- elog (WARN, "DefineSequence: CYCLE ??");
- new->is_cycled = 't';
- }
- else
- elog (WARN, "DefineSequence: option \"%s\" not recognized",
- defel->defname);
- }
-
- if ( increment_by == (DefElem*) NULL ) /* INCREMENT BY */
- new->increment_by = 1;
- else if ( ( new->increment_by = get_param (increment_by) ) == 0 )
- elog (WARN, "DefineSequence: can't INCREMENT by 0");
-
- if ( max_value == (DefElem*) NULL ) /* MAXVALUE */
- if ( new->increment_by > 0 )
- new->max_value = SEQ_MAXVALUE; /* ascending seq */
+ DefElem *last_value = NULL;
+ DefElem *increment_by = NULL;
+ DefElem *max_value = NULL;
+ DefElem *min_value = NULL;
+ DefElem *cache_value = NULL;
+ List *option;
+
+ new->is_cycled = 'f';
+ foreach(option, seq->options)
+ {
+ DefElem *defel = (DefElem *) lfirst(option);
+
+ if (!strcasecmp(defel->defname, "increment"))
+ increment_by = defel;
+ else if (!strcasecmp(defel->defname, "start"))
+ last_value = defel;
+ else if (!strcasecmp(defel->defname, "maxvalue"))
+ max_value = defel;
+ else if (!strcasecmp(defel->defname, "minvalue"))
+ min_value = defel;
+ else if (!strcasecmp(defel->defname, "cache"))
+ cache_value = defel;
+ else if (!strcasecmp(defel->defname, "cycle"))
+ {
+ if (defel->arg != (Node *) NULL)
+ elog(WARN, "DefineSequence: CYCLE ??");
+ new->is_cycled = 't';
+ }
+ else
+ elog(WARN, "DefineSequence: option \"%s\" not recognized",
+ defel->defname);
+ }
+
+ if (increment_by == (DefElem *) NULL) /* INCREMENT BY */
+ new->increment_by = 1;
+ else if ((new->increment_by = get_param(increment_by)) == 0)
+ elog(WARN, "DefineSequence: can't INCREMENT by 0");
+
+ if (max_value == (DefElem *) NULL) /* MAXVALUE */
+ if (new->increment_by > 0)
+ new->max_value = SEQ_MAXVALUE; /* ascending seq */
+ else
+ new->max_value = -1;/* descending seq */
else
- new->max_value = -1; /* descending seq */
- else
- new->max_value = get_param (max_value);
+ new->max_value = get_param(max_value);
- if ( min_value == (DefElem*) NULL ) /* MINVALUE */
- if ( new->increment_by > 0 )
- new->min_value = 1; /* ascending seq */
+ if (min_value == (DefElem *) NULL) /* MINVALUE */
+ if (new->increment_by > 0)
+ new->min_value = 1; /* ascending seq */
+ else
+ new->min_value = SEQ_MINVALUE; /* descending seq */
else
- new->min_value = SEQ_MINVALUE; /* descending seq */
- else
- new->min_value = get_param (min_value);
-
- if ( new->min_value >= new->max_value )
- elog (WARN, "DefineSequence: MINVALUE (%d) can't be >= MAXVALUE (%d)",
- new->min_value, new->max_value);
-
- if ( last_value == (DefElem*) NULL ) /* START WITH */
- if ( new->increment_by > 0 )
- new->last_value = new->min_value; /* ascending seq */
+ new->min_value = get_param(min_value);
+
+ if (new->min_value >= new->max_value)
+ elog(WARN, "DefineSequence: MINVALUE (%d) can't be >= MAXVALUE (%d)",
+ new->min_value, new->max_value);
+
+ if (last_value == (DefElem *) NULL) /* START WITH */
+ if (new->increment_by > 0)
+ new->last_value = new->min_value; /* ascending seq */
+ else
+ new->last_value = new->max_value; /* descending seq */
else
- new->last_value = new->max_value; /* descending seq */
- else
- new->last_value = get_param (last_value);
-
- if ( new->last_value < new->min_value )
- elog (WARN, "DefineSequence: START value (%d) can't be < MINVALUE (%d)",
- new->last_value, new->min_value);
- if ( new->last_value > new->max_value )
- elog (WARN, "DefineSequence: START value (%d) can't be > MAXVALUE (%d)",
- new->last_value, new->max_value);
-
- if ( cache_value == (DefElem*) NULL ) /* CACHE */
- new->cache_value = 1;
- else if ( ( new->cache_value = get_param (cache_value) ) <= 0 )
- elog (WARN, "DefineSequence: CACHE (%d) can't be <= 0",
- new->cache_value);
+ new->last_value = get_param(last_value);
+
+ if (new->last_value < new->min_value)
+ elog(WARN, "DefineSequence: START value (%d) can't be < MINVALUE (%d)",
+ new->last_value, new->min_value);
+ if (new->last_value > new->max_value)
+ elog(WARN, "DefineSequence: START value (%d) can't be > MAXVALUE (%d)",
+ new->last_value, new->max_value);
+
+ if (cache_value == (DefElem *) NULL) /* CACHE */
+ new->cache_value = 1;
+ else if ((new->cache_value = get_param(cache_value)) <= 0)
+ elog(WARN, "DefineSequence: CACHE (%d) can't be <= 0",
+ new->cache_value);
}
static int
-get_param (DefElem *def)
+get_param(DefElem * def)
{
- if ( def->arg == (Node*) NULL )
- elog (WARN, "DefineSequence: \"%s\" value unspecified", def->defname);
-
- if ( nodeTag (def->arg) == T_Integer )
- return (intVal (def->arg));
-
- elog (WARN, "DefineSequence: \"%s\" is to be integer", def->defname);
- return (-1);
+ if (def->arg == (Node *) NULL)
+ elog(WARN, "DefineSequence: \"%s\" value unspecified", def->defname);
+
+ if (nodeTag(def->arg) == T_Integer)
+ return (intVal(def->arg));
+
+ elog(WARN, "DefineSequence: \"%s\" is to be integer", def->defname);
+ return (-1);
}
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 2919df473fd..53ab1838cfe 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* trigger.c--
- * PostgreSQL TRIGGERs support code.
+ * PostgreSQL TRIGGERs support code.
*
*-------------------------------------------------------------------------
*/
@@ -32,581 +32,587 @@
#include "utils/syscache.h"
#endif
-TriggerData *CurrentTriggerData = NULL;
+TriggerData *CurrentTriggerData = NULL;
-void RelationBuildTriggers (Relation relation);
-void FreeTriggerDesc (Relation relation);
+void RelationBuildTriggers(Relation relation);
+void FreeTriggerDesc(Relation relation);
-static void DescribeTrigger (TriggerDesc *trigdesc, Trigger *trigger);
+static void DescribeTrigger(TriggerDesc * trigdesc, Trigger * trigger);
-extern void fmgr_info(Oid procedureId, func_ptr *function, int *nargs);
+extern void fmgr_info(Oid procedureId, func_ptr * function, int *nargs);
extern GlobalMemory CacheCxt;
void
-CreateTrigger (CreateTrigStmt *stmt)
+CreateTrigger(CreateTrigStmt * stmt)
{
- int16 tgtype;
- int16 tgattr[8] = {0};
- Datum values[Natts_pg_trigger];
- char nulls[Natts_pg_trigger];
- Relation rel;
- Relation tgrel;
- HeapScanDesc tgscan;
- ScanKeyData key;
- Relation relrdesc;
- HeapTuple tuple;
- ItemPointerData oldTID;
- Relation idescs[Num_pg_trigger_indices];
- Relation ridescs[Num_pg_class_indices];
- MemoryContext oldcxt;
- Oid fargtypes[8];
- int found = 0;
- int i;
-
- if ( IsSystemRelationName (stmt->relname) )
- elog(WARN, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
+ int16 tgtype;
+ int16 tgattr[8] = {0};
+ Datum values[Natts_pg_trigger];
+ char nulls[Natts_pg_trigger];
+ Relation rel;
+ Relation tgrel;
+ HeapScanDesc tgscan;
+ ScanKeyData key;
+ Relation relrdesc;
+ HeapTuple tuple;
+ ItemPointerData oldTID;
+ Relation idescs[Num_pg_trigger_indices];
+ Relation ridescs[Num_pg_class_indices];
+ MemoryContext oldcxt;
+ Oid fargtypes[8];
+ int found = 0;
+ int i;
+
+ if (IsSystemRelationName(stmt->relname))
+ elog(WARN, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
#ifndef NO_SECURITY
- if ( !pg_ownercheck (GetPgUserName (), stmt->relname, RELNAME))
- elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
+ elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
#endif
-
- rel = heap_openr (stmt->relname);
- if ( !RelationIsValid (rel) )
- elog (WARN, "CreateTrigger: there is no relation %s", stmt->relname);
-
- RelationSetLockForWrite (rel);
-
- TRIGGER_CLEAR_TYPE (tgtype);
- if ( stmt->before )
- TRIGGER_SETT_BEFORE (tgtype);
- if ( stmt->row )
- TRIGGER_SETT_ROW (tgtype);
- for (i = 0; i < 3 && stmt->actions[i]; i++)
- {
- switch ( stmt->actions[i] )
- {
- case 'i':
- if ( TRIGGER_FOR_INSERT (tgtype) )
- elog (WARN, "CreateTrigger: double INSERT event specified");
- TRIGGER_SETT_INSERT (tgtype);
- break;
- case 'd':
- if ( TRIGGER_FOR_DELETE (tgtype) )
- elog (WARN, "CreateTrigger: double DELETE event specified");
- TRIGGER_SETT_DELETE (tgtype);
- break;
- case 'u':
- if ( TRIGGER_FOR_UPDATE (tgtype) )
- elog (WARN, "CreateTrigger: double UPDATE event specified");
- TRIGGER_SETT_UPDATE (tgtype);
- break;
- default:
- elog (WARN, "CreateTrigger: unknown event specified");
- break;
- }
- }
-
- /* Scan pg_trigger */
- tgrel = heap_openr (TriggerRelationName);
- RelationSetLockForWrite (tgrel);
- ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
- tgscan = heap_beginscan (tgrel, 0, NowTimeQual, 1, &key);
- while (tuple = heap_getnext (tgscan, 0, (Buffer *)NULL), PointerIsValid(tuple))
- {
- Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
- if ( namestrcmp (&(pg_trigger->tgname), stmt->trigname) == 0 )
- elog (WARN, "CreateTrigger: trigger %s already defined on relation %s",
- stmt->trigname, stmt->relname);
- else
- found++;
- }
- heap_endscan (tgscan);
-
- memset (fargtypes, 0, 8 * sizeof(Oid));
- tuple = SearchSysCacheTuple (PRONAME,
- PointerGetDatum (stmt->funcname),
- 0, PointerGetDatum (fargtypes), 0);
- if ( !HeapTupleIsValid (tuple) ||
- ((Form_pg_proc)GETSTRUCT(tuple))->prorettype != 0 ||
- ((Form_pg_proc)GETSTRUCT(tuple))->pronargs != 0 )
- elog (WARN, "CreateTrigger: function %s () does not exist", stmt->funcname);
-
- if ( ((Form_pg_proc)GETSTRUCT(tuple))->prolang != ClanguageId )
- elog (WARN, "CreateTrigger: only C functions are supported");
-
- memset (nulls, ' ', Natts_pg_trigger * sizeof (char));
-
- values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum (rel->rd_id);
- values[Anum_pg_trigger_tgname - 1] = NameGetDatum (namein (stmt->trigname));
- values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum (tuple->t_oid);
- values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum (tgtype);
- if ( stmt->args )
- {
- List *le;
- char *args;
- int16 nargs = length (stmt->args);
- int len = 0;
-
- foreach (le, stmt->args)
- {
- char *ar = (char *) lfirst (le);
- len += strlen (ar) + 4;
- }
- args = (char *) palloc (len + 1);
- args[0] = 0;
- foreach (le, stmt->args)
- sprintf (args + strlen (args), "%s\\000", (char *)lfirst (le));
- values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum (nargs);
- values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum (byteain (args));
- }
- else
- {
- values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum (0);
- values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum (byteain (""));
- }
- values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum (tgattr);
-
- tuple = heap_formtuple (tgrel->rd_att, values, nulls);
- heap_insert (tgrel, tuple);
- CatalogOpenIndices (Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
- CatalogIndexInsert (idescs, Num_pg_trigger_indices, tgrel, tuple);
- CatalogCloseIndices (Num_pg_trigger_indices, idescs);
- pfree (tuple);
- RelationUnsetLockForWrite (tgrel);
- heap_close (tgrel);
-
- pfree (DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
- pfree (DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
-
- /* update pg_class */
- relrdesc = heap_openr (RelationRelationName);
- tuple = ClassNameIndexScan (relrdesc, stmt->relname);
- if ( !PointerIsValid (tuple) )
- {
+
+ rel = heap_openr(stmt->relname);
+ if (!RelationIsValid(rel))
+ elog(WARN, "CreateTrigger: there is no relation %s", stmt->relname);
+
+ RelationSetLockForWrite(rel);
+
+ TRIGGER_CLEAR_TYPE(tgtype);
+ if (stmt->before)
+ TRIGGER_SETT_BEFORE(tgtype);
+ if (stmt->row)
+ TRIGGER_SETT_ROW(tgtype);
+ for (i = 0; i < 3 && stmt->actions[i]; i++)
+ {
+ switch (stmt->actions[i])
+ {
+ case 'i':
+ if (TRIGGER_FOR_INSERT(tgtype))
+ elog(WARN, "CreateTrigger: double INSERT event specified");
+ TRIGGER_SETT_INSERT(tgtype);
+ break;
+ case 'd':
+ if (TRIGGER_FOR_DELETE(tgtype))
+ elog(WARN, "CreateTrigger: double DELETE event specified");
+ TRIGGER_SETT_DELETE(tgtype);
+ break;
+ case 'u':
+ if (TRIGGER_FOR_UPDATE(tgtype))
+ elog(WARN, "CreateTrigger: double UPDATE event specified");
+ TRIGGER_SETT_UPDATE(tgtype);
+ break;
+ default:
+ elog(WARN, "CreateTrigger: unknown event specified");
+ break;
+ }
+ }
+
+ /* Scan pg_trigger */
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForWrite(tgrel);
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+ tgscan = heap_beginscan(tgrel, 0, NowTimeQual, 1, &key);
+ while (tuple = heap_getnext(tgscan, 0, (Buffer *) NULL), PointerIsValid(tuple))
+ {
+ Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+
+ if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
+ elog(WARN, "CreateTrigger: trigger %s already defined on relation %s",
+ stmt->trigname, stmt->relname);
+ else
+ found++;
+ }
+ heap_endscan(tgscan);
+
+ memset(fargtypes, 0, 8 * sizeof(Oid));
+ tuple = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(stmt->funcname),
+ 0, PointerGetDatum(fargtypes), 0);
+ if (!HeapTupleIsValid(tuple) ||
+ ((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0 ||
+ ((Form_pg_proc) GETSTRUCT(tuple))->pronargs != 0)
+ elog(WARN, "CreateTrigger: function %s () does not exist", stmt->funcname);
+
+ if (((Form_pg_proc) GETSTRUCT(tuple))->prolang != ClanguageId)
+ elog(WARN, "CreateTrigger: only C functions are supported");
+
+ memset(nulls, ' ', Natts_pg_trigger * sizeof(char));
+
+ values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(rel->rd_id);
+ values[Anum_pg_trigger_tgname - 1] = NameGetDatum(namein(stmt->trigname));
+ values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(tuple->t_oid);
+ values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
+ if (stmt->args)
+ {
+ List *le;
+ char *args;
+ int16 nargs = length(stmt->args);
+ int len = 0;
+
+ foreach(le, stmt->args)
+ {
+ char *ar = (char *) lfirst(le);
+
+ len += strlen(ar) + 4;
+ }
+ args = (char *) palloc(len + 1);
+ args[0] = 0;
+ foreach(le, stmt->args)
+ sprintf(args + strlen(args), "%s\\000", (char *) lfirst(le));
+ values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
+ values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain(args));
+ }
+ else
+ {
+ values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
+ values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain(""));
+ }
+ values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
+
+ tuple = heap_formtuple(tgrel->rd_att, values, nulls);
+ heap_insert(tgrel, tuple);
+ CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
+ CatalogCloseIndices(Num_pg_trigger_indices, idescs);
+ pfree(tuple);
+ RelationUnsetLockForWrite(tgrel);
+ heap_close(tgrel);
+
+ pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
+ pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
+
+ /* update pg_class */
+ relrdesc = heap_openr(RelationRelationName);
+ tuple = ClassNameIndexScan(relrdesc, stmt->relname);
+ if (!PointerIsValid(tuple))
+ {
+ heap_close(relrdesc);
+ elog(WARN, "CreateTrigger: relation %s not found in pg_class", stmt->relname);
+ }
+ ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
+ RelationInvalidateHeapTuple(relrdesc, tuple);
+ oldTID = tuple->t_ctid;
+ heap_replace(relrdesc, &oldTID, tuple);
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
+ CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, tuple);
+ CatalogCloseIndices(Num_pg_class_indices, ridescs);
+ pfree(tuple);
heap_close(relrdesc);
- elog(WARN, "CreateTrigger: relation %s not found in pg_class", stmt->relname);
- }
- ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
- RelationInvalidateHeapTuple (relrdesc, tuple);
- oldTID = tuple->t_ctid;
- heap_replace (relrdesc, &oldTID, tuple);
- CatalogOpenIndices (Num_pg_class_indices, Name_pg_class_indices, ridescs);
- CatalogIndexInsert (ridescs, Num_pg_class_indices, relrdesc, tuple);
- CatalogCloseIndices (Num_pg_class_indices, ridescs);
- pfree(tuple);
- heap_close(relrdesc);
-
- CommandCounterIncrement ();
- oldcxt = MemoryContextSwitchTo ((MemoryContext)CacheCxt);
- FreeTriggerDesc (rel);
- rel->rd_rel->reltriggers = found + 1;
- RelationBuildTriggers (rel);
- MemoryContextSwitchTo (oldcxt);
- heap_close (rel);
- return;
+
+ CommandCounterIncrement();
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ FreeTriggerDesc(rel);
+ rel->rd_rel->reltriggers = found + 1;
+ RelationBuildTriggers(rel);
+ MemoryContextSwitchTo(oldcxt);
+ heap_close(rel);
+ return;
}
void
-DropTrigger (DropTrigStmt *stmt)
+DropTrigger(DropTrigStmt * stmt)
{
- Relation rel;
- Relation tgrel;
- HeapScanDesc tgscan;
- ScanKeyData key;
- Relation relrdesc;
- HeapTuple tuple;
- ItemPointerData oldTID;
- Relation ridescs[Num_pg_class_indices];
- MemoryContext oldcxt;
- int found = 0;
- int tgfound = 0;
-
+ Relation rel;
+ Relation tgrel;
+ HeapScanDesc tgscan;
+ ScanKeyData key;
+ Relation relrdesc;
+ HeapTuple tuple;
+ ItemPointerData oldTID;
+ Relation ridescs[Num_pg_class_indices];
+ MemoryContext oldcxt;
+ int found = 0;
+ int tgfound = 0;
+
#ifndef NO_SECURITY
- if ( !pg_ownercheck (GetPgUserName (), stmt->relname, RELNAME))
- elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
+ elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
#endif
-
- rel = heap_openr (stmt->relname);
- if ( !RelationIsValid (rel) )
- elog (WARN, "DropTrigger: there is no relation %s", stmt->relname);
-
- RelationSetLockForWrite (rel);
-
- tgrel = heap_openr (TriggerRelationName);
- RelationSetLockForWrite (tgrel);
- ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
- tgscan = heap_beginscan (tgrel, 0, NowTimeQual, 1, &key);
- while (tuple = heap_getnext (tgscan, 0, (Buffer *)NULL), PointerIsValid(tuple))
- {
- Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
- if ( namestrcmp (&(pg_trigger->tgname), stmt->trigname) == 0 )
- {
- heap_delete (tgrel, &tuple->t_ctid);
- tgfound++;
- }
- else
- found++;
- }
- if ( tgfound == 0 )
- elog (WARN, "DropTrigger: there is no trigger %s on relation %s",
- stmt->trigname, stmt->relname);
- if ( tgfound > 1 )
- elog (NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s",
- tgfound, stmt->trigname, stmt->relname);
- heap_endscan (tgscan);
- RelationUnsetLockForWrite (tgrel);
- heap_close (tgrel);
-
- /* update pg_class */
- relrdesc = heap_openr (RelationRelationName);
- tuple = ClassNameIndexScan (relrdesc, stmt->relname);
- if ( !PointerIsValid (tuple) )
- {
+
+ rel = heap_openr(stmt->relname);
+ if (!RelationIsValid(rel))
+ elog(WARN, "DropTrigger: there is no relation %s", stmt->relname);
+
+ RelationSetLockForWrite(rel);
+
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForWrite(tgrel);
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+ tgscan = heap_beginscan(tgrel, 0, NowTimeQual, 1, &key);
+ while (tuple = heap_getnext(tgscan, 0, (Buffer *) NULL), PointerIsValid(tuple))
+ {
+ Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+
+ if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
+ {
+ heap_delete(tgrel, &tuple->t_ctid);
+ tgfound++;
+ }
+ else
+ found++;
+ }
+ if (tgfound == 0)
+ elog(WARN, "DropTrigger: there is no trigger %s on relation %s",
+ stmt->trigname, stmt->relname);
+ if (tgfound > 1)
+ elog(NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s",
+ tgfound, stmt->trigname, stmt->relname);
+ heap_endscan(tgscan);
+ RelationUnsetLockForWrite(tgrel);
+ heap_close(tgrel);
+
+ /* update pg_class */
+ relrdesc = heap_openr(RelationRelationName);
+ tuple = ClassNameIndexScan(relrdesc, stmt->relname);
+ if (!PointerIsValid(tuple))
+ {
+ heap_close(relrdesc);
+ elog(WARN, "DropTrigger: relation %s not found in pg_class", stmt->relname);
+ }
+ ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
+ RelationInvalidateHeapTuple(relrdesc, tuple);
+ oldTID = tuple->t_ctid;
+ heap_replace(relrdesc, &oldTID, tuple);
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
+ CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, tuple);
+ CatalogCloseIndices(Num_pg_class_indices, ridescs);
+ pfree(tuple);
heap_close(relrdesc);
- elog(WARN, "DropTrigger: relation %s not found in pg_class", stmt->relname);
- }
- ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
- RelationInvalidateHeapTuple (relrdesc, tuple);
- oldTID = tuple->t_ctid;
- heap_replace (relrdesc, &oldTID, tuple);
- CatalogOpenIndices (Num_pg_class_indices, Name_pg_class_indices, ridescs);
- CatalogIndexInsert (ridescs, Num_pg_class_indices, relrdesc, tuple);
- CatalogCloseIndices (Num_pg_class_indices, ridescs);
- pfree(tuple);
- heap_close(relrdesc);
-
- CommandCounterIncrement ();
- oldcxt = MemoryContextSwitchTo ((MemoryContext)CacheCxt);
- FreeTriggerDesc (rel);
- rel->rd_rel->reltriggers = found;
- if ( found > 0 )
- RelationBuildTriggers (rel);
- MemoryContextSwitchTo (oldcxt);
- heap_close (rel);
- return;
+
+ CommandCounterIncrement();
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ FreeTriggerDesc(rel);
+ rel->rd_rel->reltriggers = found;
+ if (found > 0)
+ RelationBuildTriggers(rel);
+ MemoryContextSwitchTo(oldcxt);
+ heap_close(rel);
+ return;
}
-void
-RelationRemoveTriggers (Relation rel)
+void
+RelationRemoveTriggers(Relation rel)
{
- Relation tgrel;
- HeapScanDesc tgscan;
- ScanKeyData key;
- HeapTuple tup;
-
- tgrel = heap_openr (TriggerRelationName);
- RelationSetLockForWrite (tgrel);
- ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
-
- tgscan = heap_beginscan (tgrel, 0, NowTimeQual, 1, &key);
-
- while (tup = heap_getnext (tgscan, 0, (Buffer *)NULL), PointerIsValid(tup))
- heap_delete (tgrel, &tup->t_ctid);
-
- heap_endscan (tgscan);
- RelationUnsetLockForWrite (tgrel);
- heap_close (tgrel);
+ Relation tgrel;
+ HeapScanDesc tgscan;
+ ScanKeyData key;
+ HeapTuple tup;
+
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForWrite(tgrel);
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+
+ tgscan = heap_beginscan(tgrel, 0, NowTimeQual, 1, &key);
+
+ while (tup = heap_getnext(tgscan, 0, (Buffer *) NULL), PointerIsValid(tup))
+ heap_delete(tgrel, &tup->t_ctid);
+
+ heap_endscan(tgscan);
+ RelationUnsetLockForWrite(tgrel);
+ heap_close(tgrel);
}
void
-RelationBuildTriggers (Relation relation)
+RelationBuildTriggers(Relation relation)
{
- TriggerDesc *trigdesc = (TriggerDesc *) palloc (sizeof (TriggerDesc));
- int ntrigs = relation->rd_rel->reltriggers;
- Trigger *triggers = NULL;
- Trigger *build;
- Relation tgrel;
- Form_pg_trigger pg_trigger;
- Relation irel;
- ScanKeyData skey;
- HeapTuple tuple;
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- Buffer buffer;
- ItemPointer iptr;
- struct varlena *val;
- bool isnull;
- int found;
-
- memset (trigdesc, 0, sizeof (TriggerDesc));
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relation->rd_id));
-
- tgrel = heap_openr(TriggerRelationName);
- RelationSetLockForRead (tgrel);
- irel = index_openr(TriggerRelidIndex);
- sd = index_beginscan(irel, false, 1, &skey);
-
- for (found = 0; ; )
- {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (!indexRes)
- break;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(tgrel, NowTimeQual, iptr, &buffer);
- pfree(indexRes);
- if (!HeapTupleIsValid(tuple))
- continue;
- if ( found == ntrigs )
- elog (WARN, "RelationBuildTriggers: unexpected record found for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
-
- if ( triggers == NULL )
- triggers = (Trigger *) palloc (sizeof (Trigger));
- else
- triggers = (Trigger *) repalloc (triggers, (found + 1) * sizeof (Trigger));
- build = &(triggers[found]);
-
- build->tgname = nameout (&(pg_trigger->tgname));
- build->tgfoid = pg_trigger->tgfoid;
- build->tgfunc = NULL;
- build->tgtype = pg_trigger->tgtype;
- build->tgnargs = pg_trigger->tgnargs;
- memcpy (build->tgattr, &(pg_trigger->tgattr), 8 * sizeof (int16));
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_trigger_tgargs,
- tgrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
- if ( build->tgnargs > 0 )
- {
- char *p;
- int i;
-
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_trigger_tgargs,
- tgrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
- p = (char *) VARDATA (val);
- build->tgargs = (char**) palloc (build->tgnargs * sizeof (char*));
- for (i = 0; i < build->tgnargs; i++)
- {
- build->tgargs[i] = (char*) palloc (strlen (p) + 1);
- strcpy (build->tgargs[i], p);
- p += strlen (p) + 1;
- }
- }
- else
- build->tgargs = NULL;
-
- found++;
- ReleaseBuffer(buffer);
- }
-
- if ( found < ntrigs )
- elog (WARN, "RelationBuildTriggers: %d record not found for rel %.*s",
- ntrigs - found,
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- index_endscan (sd);
- pfree (sd);
- index_close (irel);
- RelationUnsetLockForRead (tgrel);
- heap_close (tgrel);
-
- /* Build trigdesc */
- trigdesc->triggers = triggers;
- for (found = 0; found < ntrigs; found++)
- {
- build = &(triggers[found]);
- DescribeTrigger (trigdesc, build);
- }
-
- relation->trigdesc = trigdesc;
-
+ TriggerDesc *trigdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
+ int ntrigs = relation->rd_rel->reltriggers;
+ Trigger *triggers = NULL;
+ Trigger *build;
+ Relation tgrel;
+ Form_pg_trigger pg_trigger;
+ Relation irel;
+ ScanKeyData skey;
+ HeapTuple tuple;
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ Buffer buffer;
+ ItemPointer iptr;
+ struct varlena *val;
+ bool isnull;
+ int found;
+
+ memset(trigdesc, 0, sizeof(TriggerDesc));
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relation->rd_id));
+
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForRead(tgrel);
+ irel = index_openr(TriggerRelidIndex);
+ sd = index_beginscan(irel, false, 1, &skey);
+
+ for (found = 0;;)
+ {
+ indexRes = index_getnext(sd, ForwardScanDirection);
+ if (!indexRes)
+ break;
+
+ iptr = &indexRes->heap_iptr;
+ tuple = heap_fetch(tgrel, NowTimeQual, iptr, &buffer);
+ pfree(indexRes);
+ if (!HeapTupleIsValid(tuple))
+ continue;
+ if (found == ntrigs)
+ elog(WARN, "RelationBuildTriggers: unexpected record found for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+
+ if (triggers == NULL)
+ triggers = (Trigger *) palloc(sizeof(Trigger));
+ else
+ triggers = (Trigger *) repalloc(triggers, (found + 1) * sizeof(Trigger));
+ build = &(triggers[found]);
+
+ build->tgname = nameout(&(pg_trigger->tgname));
+ build->tgfoid = pg_trigger->tgfoid;
+ build->tgfunc = NULL;
+ build->tgtype = pg_trigger->tgtype;
+ build->tgnargs = pg_trigger->tgnargs;
+ memcpy(build->tgattr, &(pg_trigger->tgattr), 8 * sizeof(int16));
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_trigger_tgargs,
+ tgrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ if (build->tgnargs > 0)
+ {
+ char *p;
+ int i;
+
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_trigger_tgargs,
+ tgrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ p = (char *) VARDATA(val);
+ build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));
+ for (i = 0; i < build->tgnargs; i++)
+ {
+ build->tgargs[i] = (char *) palloc(strlen(p) + 1);
+ strcpy(build->tgargs[i], p);
+ p += strlen(p) + 1;
+ }
+ }
+ else
+ build->tgargs = NULL;
+
+ found++;
+ ReleaseBuffer(buffer);
+ }
+
+ if (found < ntrigs)
+ elog(WARN, "RelationBuildTriggers: %d record not found for rel %.*s",
+ ntrigs - found,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ index_endscan(sd);
+ pfree(sd);
+ index_close(irel);
+ RelationUnsetLockForRead(tgrel);
+ heap_close(tgrel);
+
+ /* Build trigdesc */
+ trigdesc->triggers = triggers;
+ for (found = 0; found < ntrigs; found++)
+ {
+ build = &(triggers[found]);
+ DescribeTrigger(trigdesc, build);
+ }
+
+ relation->trigdesc = trigdesc;
+
}
-void
-FreeTriggerDesc (Relation relation)
+void
+FreeTriggerDesc(Relation relation)
{
- TriggerDesc *trigdesc = relation->trigdesc;
- Trigger ***t;
- Trigger *trigger;
- int i;
-
- if ( trigdesc == NULL )
- return;
-
- t = trigdesc->tg_before_statement;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
- t = trigdesc->tg_before_row;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
- t = trigdesc->tg_after_row;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
- t = trigdesc->tg_after_statement;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
-
- trigger = trigdesc->triggers;
- for (i = 0; i < relation->rd_rel->reltriggers; i++)
- {
- pfree (trigger->tgname);
- if ( trigger->tgnargs > 0 )
- {
- while ( --(trigger->tgnargs) >= 0 )
- pfree (trigger->tgargs[trigger->tgnargs]);
- pfree (trigger->tgargs);
- }
- trigger++;
- }
- pfree (trigdesc->triggers);
- pfree (trigdesc);
- relation->trigdesc = NULL;
- return;
+ TriggerDesc *trigdesc = relation->trigdesc;
+ Trigger ***t;
+ Trigger *trigger;
+ int i;
+
+ if (trigdesc == NULL)
+ return;
+
+ t = trigdesc->tg_before_statement;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+ t = trigdesc->tg_before_row;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+ t = trigdesc->tg_after_row;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+ t = trigdesc->tg_after_statement;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+
+ trigger = trigdesc->triggers;
+ for (i = 0; i < relation->rd_rel->reltriggers; i++)
+ {
+ pfree(trigger->tgname);
+ if (trigger->tgnargs > 0)
+ {
+ while (--(trigger->tgnargs) >= 0)
+ pfree(trigger->tgargs[trigger->tgnargs]);
+ pfree(trigger->tgargs);
+ }
+ trigger++;
+ }
+ pfree(trigdesc->triggers);
+ pfree(trigdesc);
+ relation->trigdesc = NULL;
+ return;
}
static void
-DescribeTrigger (TriggerDesc *trigdesc, Trigger *trigger)
+DescribeTrigger(TriggerDesc * trigdesc, Trigger * trigger)
{
- uint16 *n;
- Trigger ***t, ***tp;
-
- if ( TRIGGER_FOR_ROW (trigger->tgtype) ) /* Is ROW/STATEMENT trigger */
- {
- if ( TRIGGER_FOR_BEFORE (trigger->tgtype) )
- {
- n = trigdesc->n_before_row;
- t = trigdesc->tg_before_row;
- }
- else
- {
- n = trigdesc->n_after_row;
- t = trigdesc->tg_after_row;
- }
- }
- else /* STATEMENT (NI) */
- {
- if ( TRIGGER_FOR_BEFORE (trigger->tgtype) )
- {
- n = trigdesc->n_before_statement;
- t = trigdesc->tg_before_statement;
- }
- else
- {
- n = trigdesc->n_after_statement;
- t = trigdesc->tg_after_statement;
- }
- }
-
- if ( TRIGGER_FOR_INSERT (trigger->tgtype) )
- {
- tp = &(t[TRIGGER_EVENT_INSERT]);
- if ( *tp == NULL )
- *tp = (Trigger **) palloc (sizeof (Trigger *));
- else
- *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
- sizeof (Trigger *));
- (*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
- (n[TRIGGER_EVENT_INSERT])++;
- }
-
- if ( TRIGGER_FOR_DELETE (trigger->tgtype) )
- {
- tp = &(t[TRIGGER_EVENT_DELETE]);
- if ( *tp == NULL )
- *tp = (Trigger **) palloc (sizeof (Trigger *));
- else
- *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
- sizeof (Trigger *));
- (*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
- (n[TRIGGER_EVENT_DELETE])++;
- }
-
- if ( TRIGGER_FOR_UPDATE (trigger->tgtype) )
- {
- tp = &(t[TRIGGER_EVENT_UPDATE]);
- if ( *tp == NULL )
- *tp = (Trigger **) palloc (sizeof (Trigger *));
- else
- *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
- sizeof (Trigger *));
- (*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
- (n[TRIGGER_EVENT_UPDATE])++;
- }
-
+ uint16 *n;
+ Trigger ***t,
+ ***tp;
+
+ if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT
+ * trigger */
+ {
+ if (TRIGGER_FOR_BEFORE(trigger->tgtype))
+ {
+ n = trigdesc->n_before_row;
+ t = trigdesc->tg_before_row;
+ }
+ else
+ {
+ n = trigdesc->n_after_row;
+ t = trigdesc->tg_after_row;
+ }
+ }
+ else
+/* STATEMENT (NI) */
+ {
+ if (TRIGGER_FOR_BEFORE(trigger->tgtype))
+ {
+ n = trigdesc->n_before_statement;
+ t = trigdesc->tg_before_statement;
+ }
+ else
+ {
+ n = trigdesc->n_after_statement;
+ t = trigdesc->tg_after_statement;
+ }
+ }
+
+ if (TRIGGER_FOR_INSERT(trigger->tgtype))
+ {
+ tp = &(t[TRIGGER_EVENT_INSERT]);
+ if (*tp == NULL)
+ *tp = (Trigger **) palloc(sizeof(Trigger *));
+ else
+ *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
+ sizeof(Trigger *));
+ (*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
+ (n[TRIGGER_EVENT_INSERT])++;
+ }
+
+ if (TRIGGER_FOR_DELETE(trigger->tgtype))
+ {
+ tp = &(t[TRIGGER_EVENT_DELETE]);
+ if (*tp == NULL)
+ *tp = (Trigger **) palloc(sizeof(Trigger *));
+ else
+ *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
+ sizeof(Trigger *));
+ (*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
+ (n[TRIGGER_EVENT_DELETE])++;
+ }
+
+ if (TRIGGER_FOR_UPDATE(trigger->tgtype))
+ {
+ tp = &(t[TRIGGER_EVENT_UPDATE]);
+ if (*tp == NULL)
+ *tp = (Trigger **) palloc(sizeof(Trigger *));
+ else
+ *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
+ sizeof(Trigger *));
+ (*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
+ (n[TRIGGER_EVENT_UPDATE])++;
+ }
+
}
-HeapTuple
-ExecBRInsertTriggers (Relation rel, HeapTuple tuple)
+HeapTuple
+ExecBRInsertTriggers(Relation rel, HeapTuple tuple)
{
- int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
- Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
- HeapTuple newtuple = tuple;
- int nargs;
- int i;
-
- CurrentTriggerData = (TriggerData *) palloc (sizeof (TriggerData));
- CurrentTriggerData->tg_event = TRIGGER_EVENT_INSERT|TRIGGER_EVENT_ROW;
- CurrentTriggerData->tg_relation = rel;
- CurrentTriggerData->tg_newtuple = NULL;
- for (i = 0; i < ntrigs; i++)
- {
- CurrentTriggerData->tg_trigtuple = newtuple;
- CurrentTriggerData->tg_trigger = trigger[i];
- if ( trigger[i]->tgfunc == NULL )
- fmgr_info (trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- newtuple = (HeapTuple) ( (*(trigger[i]->tgfunc)) () );
- if ( newtuple == NULL )
- break;
- }
- pfree (CurrentTriggerData);
- CurrentTriggerData = NULL;
- return (newtuple);
+ int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
+ Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
+ HeapTuple newtuple = tuple;
+ int nargs;
+ int i;
+
+ CurrentTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
+ CurrentTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
+ CurrentTriggerData->tg_relation = rel;
+ CurrentTriggerData->tg_newtuple = NULL;
+ for (i = 0; i < ntrigs; i++)
+ {
+ CurrentTriggerData->tg_trigtuple = newtuple;
+ CurrentTriggerData->tg_trigger = trigger[i];
+ if (trigger[i]->tgfunc == NULL)
+ fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
+ newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ());
+ if (newtuple == NULL)
+ break;
+ }
+ pfree(CurrentTriggerData);
+ CurrentTriggerData = NULL;
+ return (newtuple);
}
void
-ExecARInsertTriggers (Relation rel, HeapTuple tuple)
+ExecARInsertTriggers(Relation rel, HeapTuple tuple)
{
-
- return;
+
+ return;
}
bool
-ExecBRDeleteTriggers (Relation rel, ItemPointer tupleid)
+ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid)
{
-
- return (true);
+
+ return (true);
}
void
-ExecARDeleteTriggers (Relation rel, ItemPointer tupleid)
+ExecARDeleteTriggers(Relation rel, ItemPointer tupleid)
{
-
- return;
+
+ return;
}
HeapTuple
-ExecBRUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
+ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple)
{
-
- return (tuple);
+
+ return (tuple);
}
void
-ExecARUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
+ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple)
{
-
- return;
+
+ return;
}
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 0c480581179..30690f0f32b 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* vacuum.c--
- * the postgres vacuum cleaner
+ * the postgres vacuum cleaner
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.42 1997/08/22 04:13:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.43 1997/09/07 04:41:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -48,2220 +48,2364 @@
#include <storage/bufpage.h>
#include "storage/shmem.h"
#ifndef HAVE_GETRUSAGE
-# include <rusagestub.h>
-#else
-# include <sys/time.h>
-# include <sys/resource.h>
-#endif
+#include <rusagestub.h>
+#else
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
#include <port-protos.h>
-bool VacuumRunning = false;
+bool VacuumRunning = false;
-static Portal vc_portal;
+static Portal vc_portal;
-static int MESSAGE_LEVEL; /* message level */
+static int MESSAGE_LEVEL; /* message level */
#define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
#define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
#define swapDatum(a,b) {Datum tmp; tmp=a; a=b; b=tmp;}
#define VacAttrStatsEqValid(stats) ( stats->f_cmpeq != NULL )
#define VacAttrStatsLtGtValid(stats) ( stats->f_cmplt != NULL && \
- stats->f_cmpgt != NULL && \
- RegProcedureIsValid(stats->outfunc) )
-
+ stats->f_cmpgt != NULL && \
+ RegProcedureIsValid(stats->outfunc) )
+
/* non-export function prototypes */
-static void vc_init(void);
-static void vc_shutdown(void);
-static void vc_vacuum(NameData *VacRelP, bool analyze, List *va_cols);
-static VRelList vc_getrels(NameData *VacRelP);
-static void vc_vacone (Oid relid, bool analyze, List *va_cols);
-static void vc_scanheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl);
-static void vc_rpfheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel);
-static void vc_vacheap (VRelStats *vacrelstats, Relation onerel, VPageList vpl);
-static void vc_vacpage (Page page, VPageDescr vpd, Relation archrel);
-static void vc_vaconeind (VPageList vpl, Relation indrel, int nhtups);
-static void vc_scanoneind (Relation indrel, int nhtups);
-static void vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple htup);
-static void vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_len);
-static void vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats *vacrelstats);
-static void vc_delhilowstats (Oid relid, int attcnt, int *attnums);
-static void vc_setpagelock(Relation rel, BlockNumber blkno);
-static VPageDescr vc_tidreapped (ItemPointer itemptr, VPageList vpl);
-static void vc_reappage (VPageList vpl, VPageDescr vpc);
-static void vc_vpinsert (VPageList vpl, VPageDescr vpnew);
-static void vc_free(VRelList vrl);
-static void vc_getindices (Oid relid, int *nindices, Relation **Irel);
-static void vc_clsindices (int nindices, Relation *Irel);
+static void vc_init(void);
+static void vc_shutdown(void);
+static void vc_vacuum(NameData * VacRelP, bool analyze, List * va_cols);
+static VRelList vc_getrels(NameData * VacRelP);
+static void vc_vacone(Oid relid, bool analyze, List * va_cols);
+static void vc_scanheap(VRelStats * vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl);
+static void vc_rpfheap(VRelStats * vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl, int nindices, Relation * Irel);
+static void vc_vacheap(VRelStats * vacrelstats, Relation onerel, VPageList vpl);
+static void vc_vacpage(Page page, VPageDescr vpd, Relation archrel);
+static void vc_vaconeind(VPageList vpl, Relation indrel, int nhtups);
+static void vc_scanoneind(Relation indrel, int nhtups);
+static void vc_attrstats(Relation onerel, VRelStats * vacrelstats, HeapTuple htup);
+static void vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum * bucket, int16 * bucket_len);
+static void vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats * vacrelstats);
+static void vc_delhilowstats(Oid relid, int attcnt, int *attnums);
+static void vc_setpagelock(Relation rel, BlockNumber blkno);
+static VPageDescr vc_tidreapped(ItemPointer itemptr, VPageList vpl);
+static void vc_reappage(VPageList vpl, VPageDescr vpc);
+static void vc_vpinsert(VPageList vpl, VPageDescr vpnew);
+static void vc_free(VRelList vrl);
+static void vc_getindices(Oid relid, int *nindices, Relation ** Irel);
+static void vc_clsindices(int nindices, Relation * Irel);
static Relation vc_getarchrel(Relation heaprel);
-static void vc_archive(Relation archrel, HeapTuple htup);
-static bool vc_isarchrel(char *rname);
-static void vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
-static char * vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *));
-static int vc_cmp_blk (char *left, char *right);
-static int vc_cmp_offno (char *left, char *right);
-static bool vc_enough_space (VPageDescr vpd, Size len);
+static void vc_archive(Relation archrel, HeapTuple htup);
+static bool vc_isarchrel(char *rname);
+static void vc_mkindesc(Relation onerel, int nindices, Relation * Irel, IndDesc ** Idesc);
+static char *vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, char *));
+static int vc_cmp_blk(char *left, char *right);
+static int vc_cmp_offno(char *left, char *right);
+static bool vc_enough_space(VPageDescr vpd, Size len);
void
-vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec)
+vacuum(char *vacrel, bool verbose, bool analyze, List * va_spec)
{
- char *pname;
- MemoryContext old;
- PortalVariableMemory pmem;
- NameData VacRel;
- List *le;
- List *va_cols = NIL;
-
- /*
- * Create a portal for safe memory across transctions. We need to
- * palloc the name space for it because our hash function expects
- * the name to be on a longword boundary. CreatePortal copies the
- * name to safe storage for us.
- */
- pname = (char *) palloc(strlen(VACPNAME) + 1);
- strcpy(pname, VACPNAME);
- vc_portal = CreatePortal(pname);
- pfree(pname);
-
- if (verbose)
- MESSAGE_LEVEL = NOTICE;
- else
- MESSAGE_LEVEL = DEBUG;
-
- /* vacrel gets de-allocated on transaction commit */
- if (vacrel)
- strcpy(VacRel.data,vacrel);
-
- pmem = PortalGetVariableMemory(vc_portal);
- old = MemoryContextSwitchTo((MemoryContext)pmem);
-
- Assert ( va_spec == NIL || analyze );
- foreach (le, va_spec)
- {
- char *col = (char*)lfirst(le);
- char *dest;
-
- dest = (char*) palloc (strlen (col) + 1);
- strcpy (dest, col);
- va_cols = lappend (va_cols, dest);
- }
- MemoryContextSwitchTo(old);
-
- /* initialize vacuum cleaner */
- vc_init();
-
- /* vacuum the database */
- if (vacrel)
- vc_vacuum (&VacRel, analyze, va_cols);
- else
- vc_vacuum (NULL, analyze, NIL);
-
- PortalDestroy (&vc_portal);
-
- /* clean up */
- vc_shutdown();
+ char *pname;
+ MemoryContext old;
+ PortalVariableMemory pmem;
+ NameData VacRel;
+ List *le;
+ List *va_cols = NIL;
+
+ /*
+ * Create a portal for safe memory across transctions. We need to
+ * palloc the name space for it because our hash function expects the
+ * name to be on a longword boundary. CreatePortal copies the name to
+ * safe storage for us.
+ */
+ pname = (char *) palloc(strlen(VACPNAME) + 1);
+ strcpy(pname, VACPNAME);
+ vc_portal = CreatePortal(pname);
+ pfree(pname);
+
+ if (verbose)
+ MESSAGE_LEVEL = NOTICE;
+ else
+ MESSAGE_LEVEL = DEBUG;
+
+ /* vacrel gets de-allocated on transaction commit */
+ if (vacrel)
+ strcpy(VacRel.data, vacrel);
+
+ pmem = PortalGetVariableMemory(vc_portal);
+ old = MemoryContextSwitchTo((MemoryContext) pmem);
+
+ Assert(va_spec == NIL || analyze);
+ foreach(le, va_spec)
+ {
+ char *col = (char *) lfirst(le);
+ char *dest;
+
+ dest = (char *) palloc(strlen(col) + 1);
+ strcpy(dest, col);
+ va_cols = lappend(va_cols, dest);
+ }
+ MemoryContextSwitchTo(old);
+
+ /* initialize vacuum cleaner */
+ vc_init();
+
+ /* vacuum the database */
+ if (vacrel)
+ vc_vacuum(&VacRel, analyze, va_cols);
+ else
+ vc_vacuum(NULL, analyze, NIL);
+
+ PortalDestroy(&vc_portal);
+
+ /* clean up */
+ vc_shutdown();
}
/*
- * vc_init(), vc_shutdown() -- start up and shut down the vacuum cleaner.
+ * vc_init(), vc_shutdown() -- start up and shut down the vacuum cleaner.
*
- * We run exactly one vacuum cleaner at a time. We use the file system
- * to guarantee an exclusive lock on vacuuming, since a single vacuum
- * cleaner instantiation crosses transaction boundaries, and we'd lose
- * postgres-style locks at the end of every transaction.
+ * We run exactly one vacuum cleaner at a time. We use the file system
+ * to guarantee an exclusive lock on vacuuming, since a single vacuum
+ * cleaner instantiation crosses transaction boundaries, and we'd lose
+ * postgres-style locks at the end of every transaction.
*
- * The strangeness with committing and starting transactions in the
- * init and shutdown routines is due to the fact that the vacuum cleaner
- * is invoked via a sql command, and so is already executing inside
- * a transaction. We need to leave ourselves in a predictable state
- * on entry and exit to the vacuum cleaner. We commit the transaction
- * started in PostgresMain() inside vc_init(), and start one in
- * vc_shutdown() to match the commit waiting for us back in
- * PostgresMain().
+ * The strangeness with committing and starting transactions in the
+ * init and shutdown routines is due to the fact that the vacuum cleaner
+ * is invoked via a sql command, and so is already executing inside
+ * a transaction. We need to leave ourselves in a predictable state
+ * on entry and exit to the vacuum cleaner. We commit the transaction
+ * started in PostgresMain() inside vc_init(), and start one in
+ * vc_shutdown() to match the commit waiting for us back in
+ * PostgresMain().
*/
static void
vc_init()
{
- int fd;
+ int fd;
- if ((fd = open("pg_vlock", O_CREAT|O_EXCL, 0600)) < 0)
- elog(WARN, "can't create lock file -- another vacuum cleaner running?");
+ if ((fd = open("pg_vlock", O_CREAT | O_EXCL, 0600)) < 0)
+ elog(WARN, "can't create lock file -- another vacuum cleaner running?");
- close(fd);
+ close(fd);
- /*
- * By here, exclusive open on the lock file succeeded. If we abort
- * for any reason during vacuuming, we need to remove the lock file.
- * This global variable is checked in the transaction manager on xact
- * abort, and the routine vc_abort() is called if necessary.
- */
+ /*
+ * By here, exclusive open on the lock file succeeded. If we abort
+ * for any reason during vacuuming, we need to remove the lock file.
+ * This global variable is checked in the transaction manager on xact
+ * abort, and the routine vc_abort() is called if necessary.
+ */
- VacuumRunning = true;
+ VacuumRunning = true;
- /* matches the StartTransaction in PostgresMain() */
- CommitTransactionCommand();
+ /* matches the StartTransaction in PostgresMain() */
+ CommitTransactionCommand();
}
static void
vc_shutdown()
{
- /* on entry, not in a transaction */
- if (unlink("pg_vlock") < 0)
- elog(WARN, "vacuum: can't destroy lock file!");
+ /* on entry, not in a transaction */
+ if (unlink("pg_vlock") < 0)
+ elog(WARN, "vacuum: can't destroy lock file!");
- /* okay, we're done */
- VacuumRunning = false;
+ /* okay, we're done */
+ VacuumRunning = false;
- /* matches the CommitTransaction in PostgresMain() */
- StartTransactionCommand();
+ /* matches the CommitTransaction in PostgresMain() */
+ StartTransactionCommand();
}
void
vc_abort()
{
- /* on abort, remove the vacuum cleaner lock file */
- unlink("pg_vlock");
+ /* on abort, remove the vacuum cleaner lock file */
+ unlink("pg_vlock");
- VacuumRunning = false;
+ VacuumRunning = false;
}
/*
- * vc_vacuum() -- vacuum the database.
+ * vc_vacuum() -- vacuum the database.
*
- * This routine builds a list of relations to vacuum, and then calls
- * code that vacuums them one at a time. We are careful to vacuum each
- * relation in a separate transaction in order to avoid holding too many
- * locks at one time.
+ * This routine builds a list of relations to vacuum, and then calls
+ * code that vacuums them one at a time. We are careful to vacuum each
+ * relation in a separate transaction in order to avoid holding too many
+ * locks at one time.
*/
static void
-vc_vacuum(NameData *VacRelP, bool analyze, List *va_cols)
+vc_vacuum(NameData * VacRelP, bool analyze, List * va_cols)
{
- VRelList vrl, cur;
+ VRelList vrl,
+ cur;
+
+ /* get list of relations */
+ vrl = vc_getrels(VacRelP);
- /* get list of relations */
- vrl = vc_getrels(VacRelP);
+ if (analyze && VacRelP == NULL && vrl != NULL)
+ vc_delhilowstats(InvalidOid, 0, NULL);
- if ( analyze && VacRelP == NULL && vrl != NULL )
- vc_delhilowstats (InvalidOid, 0, NULL);
-
- /* vacuum each heap relation */
- for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
- vc_vacone (cur->vrl_relid, analyze, va_cols);
+ /* vacuum each heap relation */
+ for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
+ vc_vacone(cur->vrl_relid, analyze, va_cols);
- vc_free(vrl);
+ vc_free(vrl);
}
-static VRelList
-vc_getrels(NameData *VacRelP)
+static VRelList
+vc_getrels(NameData * VacRelP)
{
- Relation pgclass;
- TupleDesc pgcdesc;
- HeapScanDesc pgcscan;
- HeapTuple pgctup;
- Buffer buf;
- PortalVariableMemory portalmem;
- MemoryContext old;
- VRelList vrl, cur;
- Datum d;
- char *rname;
- char rkind;
- int16 smgrno;
- bool n;
- ScanKeyData pgckey;
- bool found = false;
-
- StartTransactionCommand();
-
- if (VacRelP->data) {
- ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relname,
- NameEqualRegProcedure,
- PointerGetDatum(VacRelP->data));
- } else {
- ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relkind,
- CharacterEqualRegProcedure, CharGetDatum('r'));
- }
-
- portalmem = PortalGetVariableMemory(vc_portal);
- vrl = cur = (VRelList) NULL;
-
- pgclass = heap_openr(RelationRelationName);
- pgcdesc = RelationGetTupleDescriptor(pgclass);
-
- pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
-
- while (HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &buf))) {
-
- found = true;
-
- /*
- * We have to be careful not to vacuum the archive (since it
- * already contains vacuumed tuples), and not to vacuum
- * relations on write-once storage managers like the Sony
- * jukebox at Berkeley.
- */
+ Relation pgclass;
+ TupleDesc pgcdesc;
+ HeapScanDesc pgcscan;
+ HeapTuple pgctup;
+ Buffer buf;
+ PortalVariableMemory portalmem;
+ MemoryContext old;
+ VRelList vrl,
+ cur;
+ Datum d;
+ char *rname;
+ char rkind;
+ int16 smgrno;
+ bool n;
+ ScanKeyData pgckey;
+ bool found = false;
+
+ StartTransactionCommand();
+
+ if (VacRelP->data)
+ {
+ ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relname,
+ NameEqualRegProcedure,
+ PointerGetDatum(VacRelP->data));
+ }
+ else
+ {
+ ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relkind,
+ CharacterEqualRegProcedure, CharGetDatum('r'));
+ }
- d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relname,
- pgcdesc, &n);
- rname = (char*)d;
+ portalmem = PortalGetVariableMemory(vc_portal);
+ vrl = cur = (VRelList) NULL;
- /* skip archive relations */
- if (vc_isarchrel(rname)) {
- ReleaseBuffer(buf);
- continue;
- }
+ pgclass = heap_openr(RelationRelationName);
+ pgcdesc = RelationGetTupleDescriptor(pgclass);
+
+ pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
- /* don't vacuum large objects for now - something breaks when we do */
- if ( (strlen(rname) >= 5) && rname[0] == 'x' &&
- rname[1] == 'i' && rname[2] == 'n' &&
- (rname[3] == 'v' || rname[3] == 'x') &&
- rname[4] >= '0' && rname[4] <= '9')
+ while (HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &buf)))
{
- elog (NOTICE, "Rel %s: can't vacuum LargeObjects now",
- rname);
- ReleaseBuffer(buf);
- continue;
- }
- d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relsmgr,
- pgcdesc, &n);
- smgrno = DatumGetInt16(d);
+ found = true;
- /* skip write-once storage managers */
- if (smgriswo(smgrno)) {
- ReleaseBuffer(buf);
- continue;
- }
+ /*
+ * We have to be careful not to vacuum the archive (since it
+ * already contains vacuumed tuples), and not to vacuum relations
+ * on write-once storage managers like the Sony jukebox at
+ * Berkeley.
+ */
- d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relkind,
- pgcdesc, &n);
+ d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relname,
+ pgcdesc, &n);
+ rname = (char *) d;
- rkind = DatumGetChar(d);
+ /* skip archive relations */
+ if (vc_isarchrel(rname))
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
- /* skip system relations */
- if (rkind != 'r') {
- ReleaseBuffer(buf);
- elog(NOTICE, "Vacuum: can not process index and certain system tables" );
- continue;
- }
-
- /* get a relation list entry for this guy */
- old = MemoryContextSwitchTo((MemoryContext)portalmem);
- if (vrl == (VRelList) NULL) {
- vrl = cur = (VRelList) palloc(sizeof(VRelListData));
- } else {
- cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
- cur = cur->vrl_next;
- }
- MemoryContextSwitchTo(old);
+ /*
+ * don't vacuum large objects for now - something breaks when we
+ * do
+ */
+ if ((strlen(rname) >= 5) && rname[0] == 'x' &&
+ rname[1] == 'i' && rname[2] == 'n' &&
+ (rname[3] == 'v' || rname[3] == 'x') &&
+ rname[4] >= '0' && rname[4] <= '9')
+ {
+ elog(NOTICE, "Rel %s: can't vacuum LargeObjects now",
+ rname);
+ ReleaseBuffer(buf);
+ continue;
+ }
+
+ d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relsmgr,
+ pgcdesc, &n);
+ smgrno = DatumGetInt16(d);
+
+ /* skip write-once storage managers */
+ if (smgriswo(smgrno))
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
+
+ d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relkind,
+ pgcdesc, &n);
+
+ rkind = DatumGetChar(d);
+
+ /* skip system relations */
+ if (rkind != 'r')
+ {
+ ReleaseBuffer(buf);
+ elog(NOTICE, "Vacuum: can not process index and certain system tables");
+ continue;
+ }
- cur->vrl_relid = pgctup->t_oid;
- cur->vrl_next = (VRelList) NULL;
+ /* get a relation list entry for this guy */
+ old = MemoryContextSwitchTo((MemoryContext) portalmem);
+ if (vrl == (VRelList) NULL)
+ {
+ vrl = cur = (VRelList) palloc(sizeof(VRelListData));
+ }
+ else
+ {
+ cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
+ cur = cur->vrl_next;
+ }
+ MemoryContextSwitchTo(old);
- /* wei hates it if you forget to do this */
- ReleaseBuffer(buf);
- }
- if (found == false)
- elog(NOTICE, "Vacuum: table not found" );
+ cur->vrl_relid = pgctup->t_oid;
+ cur->vrl_next = (VRelList) NULL;
-
- heap_endscan(pgcscan);
- heap_close(pgclass);
+ /* wei hates it if you forget to do this */
+ ReleaseBuffer(buf);
+ }
+ if (found == false)
+ elog(NOTICE, "Vacuum: table not found");
+
+
+ heap_endscan(pgcscan);
+ heap_close(pgclass);
- CommitTransactionCommand();
+ CommitTransactionCommand();
- return (vrl);
+ return (vrl);
}
/*
- * vc_vacone() -- vacuum one heap relation
+ * vc_vacone() -- vacuum one heap relation
*
- * This routine vacuums a single heap, cleans out its indices, and
- * updates its statistics npages and ntups statistics.
+ * This routine vacuums a single heap, cleans out its indices, and
+ * updates its statistics npages and ntups statistics.
*
- * Doing one heap at a time incurs extra overhead, since we need to
- * check that the heap exists again just before we vacuum it. The
- * reason that we do this is so that vacuuming can be spread across
- * many small transactions. Otherwise, two-phase locking would require
- * us to lock the entire database during one pass of the vacuum cleaner.
+ * Doing one heap at a time incurs extra overhead, since we need to
+ * check that the heap exists again just before we vacuum it. The
+ * reason that we do this is so that vacuuming can be spread across
+ * many small transactions. Otherwise, two-phase locking would require
+ * us to lock the entire database during one pass of the vacuum cleaner.
*/
static void
-vc_vacone (Oid relid, bool analyze, List *va_cols)
+vc_vacone(Oid relid, bool analyze, List * va_cols)
{
- Relation pgclass;
- TupleDesc pgcdesc;
- HeapTuple pgctup, pgttup;
- Buffer pgcbuf;
- HeapScanDesc pgcscan;
- Relation onerel;
- ScanKeyData pgckey;
- VPageListData Vvpl; /* List of pages to vacuum and/or clean indices */
- VPageListData Fvpl; /* List of pages with space enough for re-using */
- VPageDescr *vpp;
- Relation *Irel;
- int32 nindices, i;
- VRelStats *vacrelstats;
-
- StartTransactionCommand();
-
- ScanKeyEntryInitialize(&pgckey, 0x0, ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- pgclass = heap_openr(RelationRelationName);
- pgcdesc = RelationGetTupleDescriptor(pgclass);
- pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
-
- /*
- * Race condition -- if the pg_class tuple has gone away since the
- * last time we saw it, we don't need to vacuum it.
- */
-
- if (!HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &pgcbuf))) {
+ Relation pgclass;
+ TupleDesc pgcdesc;
+ HeapTuple pgctup,
+ pgttup;
+ Buffer pgcbuf;
+ HeapScanDesc pgcscan;
+ Relation onerel;
+ ScanKeyData pgckey;
+ VPageListData Vvpl; /* List of pages to vacuum and/or clean
+ * indices */
+ VPageListData Fvpl; /* List of pages with space enough for
+ * re-using */
+ VPageDescr *vpp;
+ Relation *Irel;
+ int32 nindices,
+ i;
+ VRelStats *vacrelstats;
+
+ StartTransactionCommand();
+
+ ScanKeyEntryInitialize(&pgckey, 0x0, ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+
+ pgclass = heap_openr(RelationRelationName);
+ pgcdesc = RelationGetTupleDescriptor(pgclass);
+ pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
+
+ /*
+ * Race condition -- if the pg_class tuple has gone away since the
+ * last time we saw it, we don't need to vacuum it.
+ */
+
+ if (!HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &pgcbuf)))
+ {
+ heap_endscan(pgcscan);
+ heap_close(pgclass);
+ CommitTransactionCommand();
+ return;
+ }
+
+ /* now open the class and vacuum it */
+ onerel = heap_open(relid);
+
+ vacrelstats = (VRelStats *) palloc(sizeof(VRelStats));
+ vacrelstats->relid = relid;
+ vacrelstats->npages = vacrelstats->ntups = 0;
+ vacrelstats->hasindex = false;
+ if (analyze && !IsSystemRelationName((RelationGetRelationName(onerel))->data))
+ {
+ int attr_cnt,
+ *attnums = NULL;
+ AttributeTupleForm *attr;
+
+ attr_cnt = onerel->rd_att->natts;
+ attr = onerel->rd_att->attrs;
+
+ if (va_cols != NIL)
+ {
+ int tcnt = 0;
+ List *le;
+
+ if (length(va_cols) > attr_cnt)
+ elog(WARN, "vacuum: too many attributes specified for relation %s",
+ (RelationGetRelationName(onerel))->data);
+ attnums = (int *) palloc(attr_cnt * sizeof(int));
+ foreach(le, va_cols)
+ {
+ char *col = (char *) lfirst(le);
+
+ for (i = 0; i < attr_cnt; i++)
+ {
+ if (namestrcmp(&(attr[i]->attname), col) == 0)
+ break;
+ }
+ if (i < attr_cnt) /* found */
+ attnums[tcnt++] = i;
+ else
+ {
+ elog(WARN, "vacuum: there is no attribute %s in %s",
+ col, (RelationGetRelationName(onerel))->data);
+ }
+ }
+ attr_cnt = tcnt;
+ }
+
+ vacrelstats->vacattrstats =
+ (VacAttrStats *) palloc(attr_cnt * sizeof(VacAttrStats));
+
+ for (i = 0; i < attr_cnt; i++)
+ {
+ Operator func_operator;
+ OperatorTupleForm pgopform;
+ VacAttrStats *stats;
+
+ stats = &vacrelstats->vacattrstats[i];
+ stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
+ memmove(stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE);
+ stats->best = stats->guess1 = stats->guess2 = 0;
+ stats->max = stats->min = 0;
+ stats->best_len = stats->guess1_len = stats->guess2_len = 0;
+ stats->max_len = stats->min_len = 0;
+ stats->initialized = false;
+ stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
+ stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
+
+ func_operator = oper("=", stats->attr->atttypid, stats->attr->atttypid, true);
+ if (func_operator != NULL)
+ {
+ int nargs;
+
+ pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+ fmgr_info(pgopform->oprcode, &(stats->f_cmpeq), &nargs);
+ }
+ else
+ stats->f_cmpeq = NULL;
+
+ func_operator = oper("<", stats->attr->atttypid, stats->attr->atttypid, true);
+ if (func_operator != NULL)
+ {
+ int nargs;
+
+ pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+ fmgr_info(pgopform->oprcode, &(stats->f_cmplt), &nargs);
+ }
+ else
+ stats->f_cmplt = NULL;
+
+ func_operator = oper(">", stats->attr->atttypid, stats->attr->atttypid, true);
+ if (func_operator != NULL)
+ {
+ int nargs;
+
+ pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+ fmgr_info(pgopform->oprcode, &(stats->f_cmpgt), &nargs);
+ }
+ else
+ stats->f_cmpgt = NULL;
+
+ pgttup = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(stats->attr->atttypid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(pgttup))
+ stats->outfunc = ((TypeTupleForm) GETSTRUCT(pgttup))->typoutput;
+ else
+ stats->outfunc = InvalidOid;
+ }
+ vacrelstats->va_natts = attr_cnt;
+ vc_delhilowstats(relid, ((attnums) ? attr_cnt : 0), attnums);
+ if (attnums)
+ pfree(attnums);
+ }
+ else
+ {
+ vacrelstats->va_natts = 0;
+ vacrelstats->vacattrstats = (VacAttrStats *) NULL;
+ }
+
+ /* we require the relation to be locked until the indices are cleaned */
+ RelationSetLockForWrite(onerel);
+
+ /* scan it */
+ Vvpl.vpl_npages = Fvpl.vpl_npages = 0;
+ vc_scanheap(vacrelstats, onerel, &Vvpl, &Fvpl);
+
+ /* Now open indices */
+ Irel = (Relation *) NULL;
+ vc_getindices(vacrelstats->relid, &nindices, &Irel);
+
+ if (nindices > 0)
+ vacrelstats->hasindex = true;
+ else
+ vacrelstats->hasindex = false;
+
+ /* Clean/scan index relation(s) */
+ if (Irel != (Relation *) NULL)
+ {
+ if (Vvpl.vpl_npages > 0)
+ {
+ for (i = 0; i < nindices; i++)
+ vc_vaconeind(&Vvpl, Irel[i], vacrelstats->ntups);
+ }
+ else
+/* just scan indices to update statistic */
+ {
+ for (i = 0; i < nindices; i++)
+ vc_scanoneind(Irel[i], vacrelstats->ntups);
+ }
+ }
+
+ if (Fvpl.vpl_npages > 0) /* Try to shrink heap */
+ vc_rpfheap(vacrelstats, onerel, &Vvpl, &Fvpl, nindices, Irel);
+ else
+ {
+ if (Irel != (Relation *) NULL)
+ vc_clsindices(nindices, Irel);
+ if (Vvpl.vpl_npages > 0)/* Clean pages from Vvpl list */
+ vc_vacheap(vacrelstats, onerel, &Vvpl);
+ }
+
+ /* ok - free Vvpl list of reapped pages */
+ if (Vvpl.vpl_npages > 0)
+ {
+ vpp = Vvpl.vpl_pgdesc;
+ for (i = 0; i < Vvpl.vpl_npages; i++, vpp++)
+ pfree(*vpp);
+ pfree(Vvpl.vpl_pgdesc);
+ if (Fvpl.vpl_npages > 0)
+ pfree(Fvpl.vpl_pgdesc);
+ }
+
+ /* all done with this class */
+ heap_close(onerel);
heap_endscan(pgcscan);
heap_close(pgclass);
- CommitTransactionCommand();
- return;
- }
-
- /* now open the class and vacuum it */
- onerel = heap_open(relid);
-
- vacrelstats = (VRelStats *) palloc(sizeof(VRelStats));
- vacrelstats->relid = relid;
- vacrelstats->npages = vacrelstats->ntups = 0;
- vacrelstats->hasindex = false;
- if ( analyze && !IsSystemRelationName ((RelationGetRelationName (onerel))->data) )
- {
- int attr_cnt, *attnums = NULL;
- AttributeTupleForm *attr;
-
- attr_cnt = onerel->rd_att->natts;
- attr = onerel->rd_att->attrs;
-
- if ( va_cols != NIL )
- {
- int tcnt = 0;
- List *le;
-
- if ( length (va_cols) > attr_cnt )
- elog (WARN, "vacuum: too many attributes specified for relation %s",
- (RelationGetRelationName(onerel))->data);
- attnums = (int*) palloc (attr_cnt * sizeof (int));
- foreach (le, va_cols)
- {
- char *col = (char*) lfirst(le);
-
- for (i = 0; i < attr_cnt; i++)
- {
- if ( namestrcmp (&(attr[i]->attname), col) == 0 )
- break;
- }
- if ( i < attr_cnt ) /* found */
- attnums[tcnt++] = i;
- else
- {
- elog (WARN, "vacuum: there is no attribute %s in %s",
- col, (RelationGetRelationName(onerel))->data);
- }
- }
- attr_cnt = tcnt;
- }
-
- vacrelstats->vacattrstats =
- (VacAttrStats *) palloc (attr_cnt * sizeof(VacAttrStats));
-
- for (i = 0; i < attr_cnt; i++)
- {
- Operator func_operator;
- OperatorTupleForm pgopform;
- VacAttrStats *stats;
-
- stats = &vacrelstats->vacattrstats[i];
- stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
- memmove (stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE);
- stats->best = stats->guess1 = stats->guess2 = 0;
- stats->max = stats->min = 0;
- stats->best_len = stats->guess1_len = stats->guess2_len = 0;
- stats->max_len = stats->min_len = 0;
- stats->initialized = false;
- stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
- stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
-
- func_operator = oper("=",stats->attr->atttypid,stats->attr->atttypid,true);
- if (func_operator != NULL)
- {
- int nargs;
-
- pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
- fmgr_info (pgopform->oprcode, &(stats->f_cmpeq), &nargs);
- }
- else
- stats->f_cmpeq = NULL;
-
- func_operator = oper("<",stats->attr->atttypid,stats->attr->atttypid,true);
- if (func_operator != NULL)
- {
- int nargs;
-
- pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
- fmgr_info (pgopform->oprcode, &(stats->f_cmplt), &nargs);
- }
- else
- stats->f_cmplt = NULL;
-
- func_operator = oper(">",stats->attr->atttypid,stats->attr->atttypid,true);
- if (func_operator != NULL)
- {
- int nargs;
-
- pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
- fmgr_info (pgopform->oprcode, &(stats->f_cmpgt), &nargs);
- }
- else
- stats->f_cmpgt = NULL;
-
- pgttup = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(stats->attr->atttypid),
- 0,0,0);
- if (HeapTupleIsValid(pgttup))
- stats->outfunc = ((TypeTupleForm) GETSTRUCT(pgttup))->typoutput;
- else
- stats->outfunc = InvalidOid;
- }
- vacrelstats->va_natts = attr_cnt;
- vc_delhilowstats (relid, ((attnums) ? attr_cnt : 0), attnums);
- if ( attnums )
- pfree (attnums);
- }
- else
- {
- vacrelstats->va_natts = 0;
- vacrelstats->vacattrstats = (VacAttrStats *) NULL;
- }
-
- /* we require the relation to be locked until the indices are cleaned */
- RelationSetLockForWrite(onerel);
-
- /* scan it */
- Vvpl.vpl_npages = Fvpl.vpl_npages = 0;
- vc_scanheap(vacrelstats, onerel, &Vvpl, &Fvpl);
-
- /* Now open indices */
- Irel = (Relation *) NULL;
- vc_getindices(vacrelstats->relid, &nindices, &Irel);
-
- if ( nindices > 0 )
- vacrelstats->hasindex = true;
- else
- vacrelstats->hasindex = false;
- /* Clean/scan index relation(s) */
- if ( Irel != (Relation*) NULL )
- {
- if ( Vvpl.vpl_npages > 0 )
- {
- for (i = 0; i < nindices; i++)
- vc_vaconeind (&Vvpl, Irel[i], vacrelstats->ntups);
- }
- else /* just scan indices to update statistic */
- {
- for (i = 0; i < nindices; i++)
- vc_scanoneind (Irel[i], vacrelstats->ntups);
- }
- }
-
- if ( Fvpl.vpl_npages > 0 ) /* Try to shrink heap */
- vc_rpfheap (vacrelstats, onerel, &Vvpl, &Fvpl, nindices, Irel);
- else
- {
- if ( Irel != (Relation*) NULL )
- vc_clsindices (nindices, Irel);
- if ( Vvpl.vpl_npages > 0 ) /* Clean pages from Vvpl list */
- vc_vacheap (vacrelstats, onerel, &Vvpl);
- }
-
- /* ok - free Vvpl list of reapped pages */
- if ( Vvpl.vpl_npages > 0 )
- {
- vpp = Vvpl.vpl_pgdesc;
- for (i = 0; i < Vvpl.vpl_npages; i++, vpp++)
- pfree(*vpp);
- pfree (Vvpl.vpl_pgdesc);
- if ( Fvpl.vpl_npages > 0 )
- pfree (Fvpl.vpl_pgdesc);
- }
-
- /* all done with this class */
- heap_close(onerel);
- heap_endscan(pgcscan);
- heap_close(pgclass);
-
- /* update statistics in pg_class */
- vc_updstats(vacrelstats->relid, vacrelstats->npages, vacrelstats->ntups,
- vacrelstats->hasindex, vacrelstats);
-
- /* next command frees attribute stats */
-
- CommitTransactionCommand();
+ /* update statistics in pg_class */
+ vc_updstats(vacrelstats->relid, vacrelstats->npages, vacrelstats->ntups,
+ vacrelstats->hasindex, vacrelstats);
+
+ /* next command frees attribute stats */
+
+ CommitTransactionCommand();
}
/*
- * vc_scanheap() -- scan an open heap relation
+ * vc_scanheap() -- scan an open heap relation
*
- * This routine sets commit times, constructs Vvpl list of
- * empty/uninitialized pages and pages with dead tuples and
- * ~LP_USED line pointers, constructs Fvpl list of pages
- * appropriate for purposes of shrinking and maintains statistics
- * on the number of live tuples in a heap.
+ * This routine sets commit times, constructs Vvpl list of
+ * empty/uninitialized pages and pages with dead tuples and
+ * ~LP_USED line pointers, constructs Fvpl list of pages
+ * appropriate for purposes of shrinking and maintains statistics
+ * on the number of live tuples in a heap.
*/
static void
-vc_scanheap (VRelStats *vacrelstats, Relation onerel,
+vc_scanheap(VRelStats * vacrelstats, Relation onerel,
VPageList Vvpl, VPageList Fvpl)
{
- int nblocks, blkno;
- ItemId itemid;
- ItemPointer itemptr;
- HeapTuple htup;
- Buffer buf;
- Page page, tempPage = NULL;
- OffsetNumber offnum, maxoff;
- bool pgchanged, tupgone, dobufrel, notup;
- char *relname;
- VPageDescr vpc, vp;
- uint32 nvac, ntups, nunused, ncrash, nempg, nnepg, nchpg, nemend;
- Size frsize, frsusf;
- Size min_tlen = MAXTUPLEN;
- Size max_tlen = 0;
- int32 i/*, attr_cnt*/;
- struct rusage ru0, ru1;
- bool do_shrinking = true;
-
- getrusage(RUSAGE_SELF, &ru0);
-
- nvac = ntups = nunused = ncrash = nempg = nnepg = nchpg = nemend = 0;
- frsize = frsusf = 0;
-
- relname = (RelationGetRelationName(onerel))->data;
-
- nblocks = RelationGetNumberOfBlocks(onerel);
-
- vpc = (VPageDescr) palloc (sizeof(VPageDescrData) + MaxOffsetNumber*sizeof(OffsetNumber));
- vpc->vpd_nusd = 0;
-
- for (blkno = 0; blkno < nblocks; blkno++) {
- buf = ReadBuffer(onerel, blkno);
- page = BufferGetPage(buf);
- vpc->vpd_blkno = blkno;
- vpc->vpd_noff = 0;
-
- if (PageIsNew(page)) {
- elog (NOTICE, "Rel %s: Uninitialized page %u - fixing",
- relname, blkno);
- PageInit (page, BufferGetPageSize (buf), 0);
- vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
- frsize += (vpc->vpd_free - sizeof (ItemIdData));
- nnepg++;
- nemend++;
- vc_reappage (Vvpl, vpc);
- WriteBuffer(buf);
- continue;
- }
-
- if (PageIsEmpty(page)) {
- vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
- frsize += (vpc->vpd_free - sizeof (ItemIdData));
- nempg++;
- nemend++;
- vc_reappage (Vvpl, vpc);
- ReleaseBuffer(buf);
- continue;
- }
+ int nblocks,
+ blkno;
+ ItemId itemid;
+ ItemPointer itemptr;
+ HeapTuple htup;
+ Buffer buf;
+ Page page,
+ tempPage = NULL;
+ OffsetNumber offnum,
+ maxoff;
+ bool pgchanged,
+ tupgone,
+ dobufrel,
+ notup;
+ char *relname;
+ VPageDescr vpc,
+ vp;
+ uint32 nvac,
+ ntups,
+ nunused,
+ ncrash,
+ nempg,
+ nnepg,
+ nchpg,
+ nemend;
+ Size frsize,
+ frsusf;
+ Size min_tlen = MAXTUPLEN;
+ Size max_tlen = 0;
+ int32 i /* , attr_cnt */ ;
+ struct rusage ru0,
+ ru1;
+ bool do_shrinking = true;
+
+ getrusage(RUSAGE_SELF, &ru0);
+
+ nvac = ntups = nunused = ncrash = nempg = nnepg = nchpg = nemend = 0;
+ frsize = frsusf = 0;
+
+ relname = (RelationGetRelationName(onerel))->data;
+
+ nblocks = RelationGetNumberOfBlocks(onerel);
+
+ vpc = (VPageDescr) palloc(sizeof(VPageDescrData) + MaxOffsetNumber * sizeof(OffsetNumber));
+ vpc->vpd_nusd = 0;
+
+ for (blkno = 0; blkno < nblocks; blkno++)
+ {
+ buf = ReadBuffer(onerel, blkno);
+ page = BufferGetPage(buf);
+ vpc->vpd_blkno = blkno;
+ vpc->vpd_noff = 0;
- pgchanged = false;
- notup = true;
- maxoff = PageGetMaxOffsetNumber(page);
- for (offnum = FirstOffsetNumber;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum)) {
- itemid = PageGetItemId(page, offnum);
-
- /*
- * Collect un-used items too - it's possible to have
- * indices pointing here after crash.
- */
- if (!ItemIdIsUsed(itemid)) {
- vpc->vpd_voff[vpc->vpd_noff++] = offnum;
- nunused++;
- continue;
- }
-
- htup = (HeapTuple) PageGetItem(page, itemid);
- tupgone = false;
-
- if (!AbsoluteTimeIsBackwardCompatiblyValid(htup->t_tmin) &&
- TransactionIdIsValid((TransactionId)htup->t_xmin)) {
-
- if (TransactionIdDidAbort(htup->t_xmin)) {
- tupgone = true;
- } else if (TransactionIdDidCommit(htup->t_xmin)) {
- htup->t_tmin = TransactionIdGetCommitTime(htup->t_xmin);
- pgchanged = true;
- } else if ( !TransactionIdIsInProgress (htup->t_xmin) ) {
- /*
- * Not Aborted, Not Committed, Not in Progress -
- * so it from crashed process. - vadim 11/26/96
- */
- ncrash++;
- tupgone = true;
+ if (PageIsNew(page))
+ {
+ elog(NOTICE, "Rel %s: Uninitialized page %u - fixing",
+ relname, blkno);
+ PageInit(page, BufferGetPageSize(buf), 0);
+ vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+ frsize += (vpc->vpd_free - sizeof(ItemIdData));
+ nnepg++;
+ nemend++;
+ vc_reappage(Vvpl, vpc);
+ WriteBuffer(buf);
+ continue;
}
- else
+
+ if (PageIsEmpty(page))
{
- elog (NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation",
- relname, blkno, offnum, htup->t_xmin);
- do_shrinking = false;
+ vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+ frsize += (vpc->vpd_free - sizeof(ItemIdData));
+ nempg++;
+ nemend++;
+ vc_reappage(Vvpl, vpc);
+ ReleaseBuffer(buf);
+ continue;
}
- }
- if (TransactionIdIsValid((TransactionId)htup->t_xmax))
- {
- if (TransactionIdDidAbort(htup->t_xmax))
+ pgchanged = false;
+ notup = true;
+ maxoff = PageGetMaxOffsetNumber(page);
+ for (offnum = FirstOffsetNumber;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
{
- StoreInvalidTransactionId(&(htup->t_xmax));
- pgchanged = true;
+ itemid = PageGetItemId(page, offnum);
+
+ /*
+ * Collect un-used items too - it's possible to have indices
+ * pointing here after crash.
+ */
+ if (!ItemIdIsUsed(itemid))
+ {
+ vpc->vpd_voff[vpc->vpd_noff++] = offnum;
+ nunused++;
+ continue;
+ }
+
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ tupgone = false;
+
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(htup->t_tmin) &&
+ TransactionIdIsValid((TransactionId) htup->t_xmin))
+ {
+
+ if (TransactionIdDidAbort(htup->t_xmin))
+ {
+ tupgone = true;
+ }
+ else if (TransactionIdDidCommit(htup->t_xmin))
+ {
+ htup->t_tmin = TransactionIdGetCommitTime(htup->t_xmin);
+ pgchanged = true;
+ }
+ else if (!TransactionIdIsInProgress(htup->t_xmin))
+ {
+
+ /*
+ * Not Aborted, Not Committed, Not in Progress - so it
+ * from crashed process. - vadim 11/26/96
+ */
+ ncrash++;
+ tupgone = true;
+ }
+ else
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation",
+ relname, blkno, offnum, htup->t_xmin);
+ do_shrinking = false;
+ }
+ }
+
+ if (TransactionIdIsValid((TransactionId) htup->t_xmax))
+ {
+ if (TransactionIdDidAbort(htup->t_xmax))
+ {
+ StoreInvalidTransactionId(&(htup->t_xmax));
+ pgchanged = true;
+ }
+ else if (TransactionIdDidCommit(htup->t_xmax))
+ tupgone = true;
+ else if (!TransactionIdIsInProgress(htup->t_xmax))
+ {
+
+ /*
+ * Not Aborted, Not Committed, Not in Progress - so it
+ * from crashed process. - vadim 06/02/97
+ */
+ StoreInvalidTransactionId(&(htup->t_xmax));
+ pgchanged = true;
+ }
+ else
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: DeleteTransactionInProgress %u - can't shrink relation",
+ relname, blkno, offnum, htup->t_xmax);
+ do_shrinking = false;
+ }
+ }
+
+ /*
+ * Is it possible at all ? - vadim 11/26/96
+ */
+ if (!TransactionIdIsValid((TransactionId) htup->t_xmin))
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: INSERT_TRANSACTION_ID IS INVALID. \
+DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
+ relname, blkno, offnum,
+ TransactionIdIsValid((TransactionId) htup->t_xmax),
+ tupgone);
+ }
+
+ /*
+ * It's possibly! But from where it comes ? And should we fix
+ * it ? - vadim 11/28/96
+ */
+ itemptr = &(htup->t_ctid);
+ if (!ItemPointerIsValid(itemptr) ||
+ BlockIdGetBlockNumber(&(itemptr->ip_blkid)) != blkno)
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: TID IN TUPLEHEADER %u/%u IS NOT THE SAME. TUPGONE %d.",
+ relname, blkno, offnum,
+ BlockIdGetBlockNumber(&(itemptr->ip_blkid)),
+ itemptr->ip_posid, tupgone);
+ }
+
+ /*
+ * Other checks...
+ */
+ if (htup->t_len != itemid->lp_len)
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: TUPLE_LEN IN PAGEHEADER %u IS NOT THE SAME AS IN TUPLEHEADER %u. TUPGONE %d.",
+ relname, blkno, offnum,
+ itemid->lp_len, htup->t_len, tupgone);
+ }
+ if (!OidIsValid(htup->t_oid))
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
+ relname, blkno, offnum, tupgone);
+ }
+
+ if (tupgone)
+ {
+ ItemId lpp;
+
+ if (tempPage == (Page) NULL)
+ {
+ Size pageSize;
+
+ pageSize = PageGetPageSize(page);
+ tempPage = (Page) palloc(pageSize);
+ memmove(tempPage, page, pageSize);
+ }
+
+ lpp = &(((PageHeader) tempPage)->pd_linp[offnum - 1]);
+
+ /* mark it unused */
+ lpp->lp_flags &= ~LP_USED;
+
+ vpc->vpd_voff[vpc->vpd_noff++] = offnum;
+ nvac++;
+
+ }
+ else
+ {
+ ntups++;
+ notup = false;
+ if (htup->t_len < min_tlen)
+ min_tlen = htup->t_len;
+ if (htup->t_len > max_tlen)
+ max_tlen = htup->t_len;
+ vc_attrstats(onerel, vacrelstats, htup);
+ }
}
- else if (TransactionIdDidCommit(htup->t_xmax))
- tupgone = true;
- else if ( !TransactionIdIsInProgress (htup->t_xmax) ) {
- /*
- * Not Aborted, Not Committed, Not in Progress -
- * so it from crashed process. - vadim 06/02/97
- */
- StoreInvalidTransactionId(&(htup->t_xmax));
- pgchanged = true;
+
+ if (pgchanged)
+ {
+ WriteBuffer(buf);
+ dobufrel = false;
+ nchpg++;
}
else
- {
- elog (NOTICE, "Rel %s: TID %u/%u: DeleteTransactionInProgress %u - can't shrink relation",
- relname, blkno, offnum, htup->t_xmax);
- do_shrinking = false;
+ dobufrel = true;
+ if (tempPage != (Page) NULL)
+ { /* Some tuples are gone */
+ PageRepairFragmentation(tempPage);
+ vpc->vpd_free = ((PageHeader) tempPage)->pd_upper - ((PageHeader) tempPage)->pd_lower;
+ frsize += vpc->vpd_free;
+ vc_reappage(Vvpl, vpc);
+ pfree(tempPage);
+ tempPage = (Page) NULL;
}
- }
-
- /*
- * Is it possible at all ? - vadim 11/26/96
- */
- if ( !TransactionIdIsValid((TransactionId)htup->t_xmin) )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: INSERT_TRANSACTION_ID IS INVALID. \
-DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
- relname, blkno, offnum,
- TransactionIdIsValid((TransactionId)htup->t_xmax),
- tupgone);
- }
-
- /*
- * It's possibly! But from where it comes ?
- * And should we fix it ? - vadim 11/28/96
- */
- itemptr = &(htup->t_ctid);
- if ( !ItemPointerIsValid (itemptr) ||
- BlockIdGetBlockNumber(&(itemptr->ip_blkid)) != blkno )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: TID IN TUPLEHEADER %u/%u IS NOT THE SAME. TUPGONE %d.",
- relname, blkno, offnum,
- BlockIdGetBlockNumber(&(itemptr->ip_blkid)),
- itemptr->ip_posid, tupgone);
- }
-
- /*
- * Other checks...
- */
- if ( htup->t_len != itemid->lp_len )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: TUPLE_LEN IN PAGEHEADER %u IS NOT THE SAME AS IN TUPLEHEADER %u. TUPGONE %d.",
- relname, blkno, offnum,
- itemid->lp_len, htup->t_len, tupgone);
- }
- if ( !OidIsValid(htup->t_oid) )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
- relname, blkno, offnum, tupgone);
- }
-
- if (tupgone) {
- ItemId lpp;
-
- if ( tempPage == (Page) NULL )
- {
- Size pageSize;
-
- pageSize = PageGetPageSize(page);
- tempPage = (Page) palloc(pageSize);
- memmove (tempPage, page, pageSize);
+ else if (vpc->vpd_noff > 0)
+ { /* there are only ~LP_USED line pointers */
+ vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+ frsize += vpc->vpd_free;
+ vc_reappage(Vvpl, vpc);
}
-
- lpp = &(((PageHeader) tempPage)->pd_linp[offnum - 1]);
-
- /* mark it unused */
- lpp->lp_flags &= ~LP_USED;
-
- vpc->vpd_voff[vpc->vpd_noff++] = offnum;
- nvac++;
-
- } else {
- ntups++;
- notup = false;
- if ( htup->t_len < min_tlen )
- min_tlen = htup->t_len;
- if ( htup->t_len > max_tlen )
- max_tlen = htup->t_len;
- vc_attrstats(onerel, vacrelstats, htup);
- }
+ if (dobufrel)
+ ReleaseBuffer(buf);
+ if (notup)
+ nemend++;
+ else
+ nemend = 0;
}
- if (pgchanged) {
- WriteBuffer(buf);
- dobufrel = false;
- nchpg++;
- }
- else
- dobufrel = true;
- if ( tempPage != (Page) NULL )
- { /* Some tuples are gone */
- PageRepairFragmentation(tempPage);
- vpc->vpd_free = ((PageHeader)tempPage)->pd_upper - ((PageHeader)tempPage)->pd_lower;
- frsize += vpc->vpd_free;
- vc_reappage (Vvpl, vpc);
- pfree (tempPage);
- tempPage = (Page) NULL;
- }
- else if ( vpc->vpd_noff > 0 )
- { /* there are only ~LP_USED line pointers */
- vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
- frsize += vpc->vpd_free;
- vc_reappage (Vvpl, vpc);
- }
- if ( dobufrel )
- ReleaseBuffer(buf);
- if ( notup )
- nemend++;
- else
- nemend = 0;
- }
-
- pfree (vpc);
-
- /* save stats in the rel list for use later */
- vacrelstats->ntups = ntups;
- vacrelstats->npages = nblocks;
-/* vacrelstats->natts = attr_cnt;*/
- if ( ntups == 0 )
- min_tlen = max_tlen = 0;
- vacrelstats->min_tlen = min_tlen;
- vacrelstats->max_tlen = max_tlen;
-
- Vvpl->vpl_nemend = nemend;
- Fvpl->vpl_nemend = nemend;
-
- /*
- * Try to make Fvpl keeping in mind that we can't use free space
- * of "empty" end-pages and last page if it reapped.
- */
- if ( do_shrinking && Vvpl->vpl_npages - nemend > 0 )
- {
- int nusf; /* blocks usefull for re-using */
-
- nusf = Vvpl->vpl_npages - nemend;
- if ( (Vvpl->vpl_pgdesc[nusf-1])->vpd_blkno == nblocks - nemend - 1 )
- nusf--;
-
- for (i = 0; i < nusf; i++)
- {
- vp = Vvpl->vpl_pgdesc[i];
- if ( vc_enough_space (vp, min_tlen) )
- {
- vc_vpinsert (Fvpl, vp);
- frsusf += vp->vpd_free;
- }
+ pfree(vpc);
+
+ /* save stats in the rel list for use later */
+ vacrelstats->ntups = ntups;
+ vacrelstats->npages = nblocks;
+/* vacrelstats->natts = attr_cnt;*/
+ if (ntups == 0)
+ min_tlen = max_tlen = 0;
+ vacrelstats->min_tlen = min_tlen;
+ vacrelstats->max_tlen = max_tlen;
+
+ Vvpl->vpl_nemend = nemend;
+ Fvpl->vpl_nemend = nemend;
+
+ /*
+ * Try to make Fvpl keeping in mind that we can't use free space of
+ * "empty" end-pages and last page if it reapped.
+ */
+ if (do_shrinking && Vvpl->vpl_npages - nemend > 0)
+ {
+ int nusf; /* blocks usefull for re-using */
+
+ nusf = Vvpl->vpl_npages - nemend;
+ if ((Vvpl->vpl_pgdesc[nusf - 1])->vpd_blkno == nblocks - nemend - 1)
+ nusf--;
+
+ for (i = 0; i < nusf; i++)
+ {
+ vp = Vvpl->vpl_pgdesc[i];
+ if (vc_enough_space(vp, min_tlen))
+ {
+ vc_vpinsert(Fvpl, vp);
+ frsusf += vp->vpd_free;
+ }
+ }
}
- }
- getrusage(RUSAGE_SELF, &ru1);
-
- elog (MESSAGE_LEVEL, "Rel %s: Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
+ getrusage(RUSAGE_SELF, &ru1);
+
+ elog(MESSAGE_LEVEL, "Rel %s: Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. Elapsed %u/%u sec.",
- relname,
- nblocks, nchpg, Vvpl->vpl_npages, nempg, nnepg,
- ntups, nvac, ncrash, nunused, min_tlen, max_tlen,
- frsize, frsusf, nemend, Fvpl->vpl_npages,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+ relname,
+ nblocks, nchpg, Vvpl->vpl_npages, nempg, nnepg,
+ ntups, nvac, ncrash, nunused, min_tlen, max_tlen,
+ frsize, frsusf, nemend, Fvpl->vpl_npages,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
-} /* vc_scanheap */
+} /* vc_scanheap */
/*
- * vc_rpfheap() -- try to repaire relation' fragmentation
+ * vc_rpfheap() -- try to repaire relation' fragmentation
*
- * This routine marks dead tuples as unused and tries re-use dead space
- * by moving tuples (and inserting indices if needed). It constructs
- * Nvpl list of free-ed pages (moved tuples) and clean indices
- * for them after committing (in hack-manner - without losing locks
- * and freeing memory!) current transaction. It truncates relation
- * if some end-blocks are gone away.
+ * This routine marks dead tuples as unused and tries re-use dead space
+ * by moving tuples (and inserting indices if needed). It constructs
+ * Nvpl list of free-ed pages (moved tuples) and clean indices
+ * for them after committing (in hack-manner - without losing locks
+ * and freeing memory!) current transaction. It truncates relation
+ * if some end-blocks are gone away.
*/
static void
-vc_rpfheap (VRelStats *vacrelstats, Relation onerel,
- VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel)
+vc_rpfheap(VRelStats * vacrelstats, Relation onerel,
+ VPageList Vvpl, VPageList Fvpl, int nindices, Relation * Irel)
{
- TransactionId myXID;
- CommandId myCID;
- AbsoluteTime myCTM = 0;
- Buffer buf, ToBuf;
- int nblocks, blkno;
- Page page, ToPage = NULL;
- OffsetNumber offnum = 0, maxoff = 0, newoff, moff;
- ItemId itemid, newitemid;
- HeapTuple htup, newtup;
- TupleDesc tupdesc = NULL;
- Datum *idatum = NULL;
- char *inulls = NULL;
- InsertIndexResult iresult;
- VPageListData Nvpl;
- VPageDescr ToVpd = NULL, Fvplast, Vvplast, vpc, *vpp;
- int ToVpI = 0;
- IndDesc *Idesc, *idcur;
- int Fblklast, Vblklast, i;
- Size tlen;
- int nmoved, Fnpages, Vnpages;
- int nchkmvd, ntups;
- bool isempty, dowrite;
- Relation archrel;
- struct rusage ru0, ru1;
-
- getrusage(RUSAGE_SELF, &ru0);
-
- myXID = GetCurrentTransactionId();
- myCID = GetCurrentCommandId();
-
- if ( Irel != (Relation*) NULL ) /* preparation for index' inserts */
- {
- vc_mkindesc (onerel, nindices, Irel, &Idesc);
- tupdesc = RelationGetTupleDescriptor(onerel);
- idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof (*idatum));
- inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof (*inulls));
- }
-
- /* if the relation has an archive, open it */
- if (onerel->rd_rel->relarch != 'n')
- {
- archrel = vc_getarchrel(onerel);
- /* Archive tuples from "empty" end-pages */
- for ( vpp = Vvpl->vpl_pgdesc + Vvpl->vpl_npages - 1,
- i = Vvpl->vpl_nemend; i > 0; i--, vpp-- )
+ TransactionId myXID;
+ CommandId myCID;
+ AbsoluteTime myCTM = 0;
+ Buffer buf,
+ ToBuf;
+ int nblocks,
+ blkno;
+ Page page,
+ ToPage = NULL;
+ OffsetNumber offnum = 0,
+ maxoff = 0,
+ newoff,
+ moff;
+ ItemId itemid,
+ newitemid;
+ HeapTuple htup,
+ newtup;
+ TupleDesc tupdesc = NULL;
+ Datum *idatum = NULL;
+ char *inulls = NULL;
+ InsertIndexResult iresult;
+ VPageListData Nvpl;
+ VPageDescr ToVpd = NULL,
+ Fvplast,
+ Vvplast,
+ vpc,
+ *vpp;
+ int ToVpI = 0;
+ IndDesc *Idesc,
+ *idcur;
+ int Fblklast,
+ Vblklast,
+ i;
+ Size tlen;
+ int nmoved,
+ Fnpages,
+ Vnpages;
+ int nchkmvd,
+ ntups;
+ bool isempty,
+ dowrite;
+ Relation archrel;
+ struct rusage ru0,
+ ru1;
+
+ getrusage(RUSAGE_SELF, &ru0);
+
+ myXID = GetCurrentTransactionId();
+ myCID = GetCurrentCommandId();
+
+ if (Irel != (Relation *) NULL) /* preparation for index' inserts */
{
- if ( (*vpp)->vpd_noff > 0 )
- {
- buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
- page = BufferGetPage(buf);
- Assert ( !PageIsEmpty(page) );
- vc_vacpage (page, *vpp, archrel);
- WriteBuffer (buf);
- }
+ vc_mkindesc(onerel, nindices, Irel, &Idesc);
+ tupdesc = RelationGetTupleDescriptor(onerel);
+ idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof(*idatum));
+ inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof(*inulls));
}
- }
- else
- archrel = (Relation) NULL;
-
- Nvpl.vpl_npages = 0;
- Fnpages = Fvpl->vpl_npages;
- Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
- Fblklast = Fvplast->vpd_blkno;
- Assert ( Vvpl->vpl_npages > Vvpl->vpl_nemend );
- Vnpages = Vvpl->vpl_npages - Vvpl->vpl_nemend;
- Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
- Vblklast = Vvplast->vpd_blkno;
- Assert ( Vblklast >= Fblklast );
- ToBuf = InvalidBuffer;
- nmoved = 0;
-
- vpc = (VPageDescr) palloc (sizeof(VPageDescrData) + MaxOffsetNumber*sizeof(OffsetNumber));
- vpc->vpd_nusd = vpc->vpd_noff = 0;
-
- nblocks = vacrelstats->npages;
- for (blkno = nblocks - Vvpl->vpl_nemend - 1; ; blkno--)
- {
- /* if it's reapped page and it was used by me - quit */
- if ( blkno == Fblklast && Fvplast->vpd_nusd > 0 )
- break;
-
- buf = ReadBuffer(onerel, blkno);
- page = BufferGetPage(buf);
-
- vpc->vpd_noff = 0;
-
- isempty = PageIsEmpty(page);
-
- dowrite = false;
- if ( blkno == Vblklast ) /* it's reapped page */
+
+ /* if the relation has an archive, open it */
+ if (onerel->rd_rel->relarch != 'n')
{
- if ( Vvplast->vpd_noff > 0 ) /* there are dead tuples */
- { /* on this page - clean */
- Assert ( ! isempty );
- vc_vacpage (page, Vvplast, archrel);
- dowrite = true;
- }
- else
- {
- Assert ( isempty );
- }
- --Vnpages;
- Assert ( Vnpages > 0 );
- /* get prev reapped page from Vvpl */
- Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
- Vblklast = Vvplast->vpd_blkno;
- if ( blkno == Fblklast ) /* this page in Fvpl too */
- {
- --Fnpages;
- Assert ( Fnpages > 0 );
- Assert ( Fvplast->vpd_nusd == 0 );
- /* get prev reapped page from Fvpl */
- Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
- Fblklast = Fvplast->vpd_blkno;
- }
- Assert ( Fblklast <= Vblklast );
- if ( isempty )
- {
- ReleaseBuffer(buf);
- continue;
- }
+ archrel = vc_getarchrel(onerel);
+ /* Archive tuples from "empty" end-pages */
+ for (vpp = Vvpl->vpl_pgdesc + Vvpl->vpl_npages - 1,
+ i = Vvpl->vpl_nemend; i > 0; i--, vpp--)
+ {
+ if ((*vpp)->vpd_noff > 0)
+ {
+ buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
+ page = BufferGetPage(buf);
+ Assert(!PageIsEmpty(page));
+ vc_vacpage(page, *vpp, archrel);
+ WriteBuffer(buf);
+ }
+ }
}
else
+ archrel = (Relation) NULL;
+
+ Nvpl.vpl_npages = 0;
+ Fnpages = Fvpl->vpl_npages;
+ Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
+ Fblklast = Fvplast->vpd_blkno;
+ Assert(Vvpl->vpl_npages > Vvpl->vpl_nemend);
+ Vnpages = Vvpl->vpl_npages - Vvpl->vpl_nemend;
+ Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
+ Vblklast = Vvplast->vpd_blkno;
+ Assert(Vblklast >= Fblklast);
+ ToBuf = InvalidBuffer;
+ nmoved = 0;
+
+ vpc = (VPageDescr) palloc(sizeof(VPageDescrData) + MaxOffsetNumber * sizeof(OffsetNumber));
+ vpc->vpd_nusd = vpc->vpd_noff = 0;
+
+ nblocks = vacrelstats->npages;
+ for (blkno = nblocks - Vvpl->vpl_nemend - 1;; blkno--)
{
- Assert ( ! isempty );
- }
+ /* if it's reapped page and it was used by me - quit */
+ if (blkno == Fblklast && Fvplast->vpd_nusd > 0)
+ break;
- vpc->vpd_blkno = blkno;
- maxoff = PageGetMaxOffsetNumber(page);
- for (offnum = FirstOffsetNumber;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum))
- {
- itemid = PageGetItemId(page, offnum);
-
- if (!ItemIdIsUsed(itemid))
- continue;
-
- htup = (HeapTuple) PageGetItem(page, itemid);
- tlen = htup->t_len;
-
- /* try to find new page for this tuple */
- if ( ToBuf == InvalidBuffer ||
- ! vc_enough_space (ToVpd, tlen) )
- {
- if ( ToBuf != InvalidBuffer )
+ buf = ReadBuffer(onerel, blkno);
+ page = BufferGetPage(buf);
+
+ vpc->vpd_noff = 0;
+
+ isempty = PageIsEmpty(page);
+
+ dowrite = false;
+ if (blkno == Vblklast) /* it's reapped page */
{
- WriteBuffer(ToBuf);
- ToBuf = InvalidBuffer;
- /*
- * If no one tuple can't be added to this page -
- * remove page from Fvpl. - vadim 11/27/96
- */
- if ( !vc_enough_space (ToVpd, vacrelstats->min_tlen) )
- {
- if ( ToVpd != Fvplast )
- {
- Assert ( Fnpages > ToVpI + 1 );
- memmove (Fvpl->vpl_pgdesc + ToVpI,
- Fvpl->vpl_pgdesc + ToVpI + 1,
- sizeof (VPageDescr*) * (Fnpages - ToVpI - 1));
- }
- Assert ( Fnpages >= 1 );
- Fnpages--;
- if ( Fnpages == 0 )
- break;
- /* get prev reapped page from Fvpl */
- Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
- Fblklast = Fvplast->vpd_blkno;
- }
- }
- for (i=0; i < Fnpages; i++)
+ if (Vvplast->vpd_noff > 0) /* there are dead tuples */
+ { /* on this page - clean */
+ Assert(!isempty);
+ vc_vacpage(page, Vvplast, archrel);
+ dowrite = true;
+ }
+ else
+ {
+ Assert(isempty);
+ }
+ --Vnpages;
+ Assert(Vnpages > 0);
+ /* get prev reapped page from Vvpl */
+ Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
+ Vblklast = Vvplast->vpd_blkno;
+ if (blkno == Fblklast) /* this page in Fvpl too */
+ {
+ --Fnpages;
+ Assert(Fnpages > 0);
+ Assert(Fvplast->vpd_nusd == 0);
+ /* get prev reapped page from Fvpl */
+ Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
+ Fblklast = Fvplast->vpd_blkno;
+ }
+ Assert(Fblklast <= Vblklast);
+ if (isempty)
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
+ }
+ else
{
- if ( vc_enough_space (Fvpl->vpl_pgdesc[i], tlen) )
- break;
+ Assert(!isempty);
}
- if ( i == Fnpages )
- break; /* can't move item anywhere */
- ToVpI = i;
- ToVpd = Fvpl->vpl_pgdesc[ToVpI];
- ToBuf = ReadBuffer(onerel, ToVpd->vpd_blkno);
- ToPage = BufferGetPage(ToBuf);
- /* if this page was not used before - clean it */
- if ( ! PageIsEmpty(ToPage) && ToVpd->vpd_nusd == 0 )
- vc_vacpage (ToPage, ToVpd, archrel);
- }
-
- /* copy tuple */
- newtup = (HeapTuple) palloc (tlen);
- memmove((char *) newtup, (char *) htup, tlen);
-
- /* store transaction information */
- TransactionIdStore(myXID, &(newtup->t_xmin));
- newtup->t_cmin = myCID;
- StoreInvalidTransactionId(&(newtup->t_xmax));
- newtup->t_tmin = INVALID_ABSTIME;
- newtup->t_tmax = CURRENT_ABSTIME;
- ItemPointerSetInvalid(&newtup->t_chain);
-
- /* add tuple to the page */
- newoff = PageAddItem (ToPage, (Item)newtup, tlen,
- InvalidOffsetNumber, LP_USED);
- if ( newoff == InvalidOffsetNumber )
- {
- elog (WARN, "\
+
+ vpc->vpd_blkno = blkno;
+ maxoff = PageGetMaxOffsetNumber(page);
+ for (offnum = FirstOffsetNumber;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ itemid = PageGetItemId(page, offnum);
+
+ if (!ItemIdIsUsed(itemid))
+ continue;
+
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ tlen = htup->t_len;
+
+ /* try to find new page for this tuple */
+ if (ToBuf == InvalidBuffer ||
+ !vc_enough_space(ToVpd, tlen))
+ {
+ if (ToBuf != InvalidBuffer)
+ {
+ WriteBuffer(ToBuf);
+ ToBuf = InvalidBuffer;
+
+ /*
+ * If no one tuple can't be added to this page -
+ * remove page from Fvpl. - vadim 11/27/96
+ */
+ if (!vc_enough_space(ToVpd, vacrelstats->min_tlen))
+ {
+ if (ToVpd != Fvplast)
+ {
+ Assert(Fnpages > ToVpI + 1);
+ memmove(Fvpl->vpl_pgdesc + ToVpI,
+ Fvpl->vpl_pgdesc + ToVpI + 1,
+ sizeof(VPageDescr *) * (Fnpages - ToVpI - 1));
+ }
+ Assert(Fnpages >= 1);
+ Fnpages--;
+ if (Fnpages == 0)
+ break;
+ /* get prev reapped page from Fvpl */
+ Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
+ Fblklast = Fvplast->vpd_blkno;
+ }
+ }
+ for (i = 0; i < Fnpages; i++)
+ {
+ if (vc_enough_space(Fvpl->vpl_pgdesc[i], tlen))
+ break;
+ }
+ if (i == Fnpages)
+ break; /* can't move item anywhere */
+ ToVpI = i;
+ ToVpd = Fvpl->vpl_pgdesc[ToVpI];
+ ToBuf = ReadBuffer(onerel, ToVpd->vpd_blkno);
+ ToPage = BufferGetPage(ToBuf);
+ /* if this page was not used before - clean it */
+ if (!PageIsEmpty(ToPage) && ToVpd->vpd_nusd == 0)
+ vc_vacpage(ToPage, ToVpd, archrel);
+ }
+
+ /* copy tuple */
+ newtup = (HeapTuple) palloc(tlen);
+ memmove((char *) newtup, (char *) htup, tlen);
+
+ /* store transaction information */
+ TransactionIdStore(myXID, &(newtup->t_xmin));
+ newtup->t_cmin = myCID;
+ StoreInvalidTransactionId(&(newtup->t_xmax));
+ newtup->t_tmin = INVALID_ABSTIME;
+ newtup->t_tmax = CURRENT_ABSTIME;
+ ItemPointerSetInvalid(&newtup->t_chain);
+
+ /* add tuple to the page */
+ newoff = PageAddItem(ToPage, (Item) newtup, tlen,
+ InvalidOffsetNumber, LP_USED);
+ if (newoff == InvalidOffsetNumber)
+ {
+ elog(WARN, "\
failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
- tlen, ToVpd->vpd_blkno, ToVpd->vpd_free,
- ToVpd->vpd_nusd, ToVpd->vpd_noff);
- }
- newitemid = PageGetItemId(ToPage, newoff);
- pfree (newtup);
- newtup = (HeapTuple) PageGetItem(ToPage, newitemid);
- ItemPointerSet(&(newtup->t_ctid), ToVpd->vpd_blkno, newoff);
-
- /* now logically delete end-tuple */
- TransactionIdStore(myXID, &(htup->t_xmax));
- htup->t_cmax = myCID;
- memmove ((char*)&(htup->t_chain), (char*)&(newtup->t_ctid), sizeof (newtup->t_ctid));
-
- ToVpd->vpd_nusd++;
- nmoved++;
- ToVpd->vpd_free = ((PageHeader)ToPage)->pd_upper - ((PageHeader)ToPage)->pd_lower;
- vpc->vpd_voff[vpc->vpd_noff++] = offnum;
-
- /* insert index' tuples if needed */
- if ( Irel != (Relation*) NULL )
- {
- for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
+ tlen, ToVpd->vpd_blkno, ToVpd->vpd_free,
+ ToVpd->vpd_nusd, ToVpd->vpd_noff);
+ }
+ newitemid = PageGetItemId(ToPage, newoff);
+ pfree(newtup);
+ newtup = (HeapTuple) PageGetItem(ToPage, newitemid);
+ ItemPointerSet(&(newtup->t_ctid), ToVpd->vpd_blkno, newoff);
+
+ /* now logically delete end-tuple */
+ TransactionIdStore(myXID, &(htup->t_xmax));
+ htup->t_cmax = myCID;
+ memmove((char *) &(htup->t_chain), (char *) &(newtup->t_ctid), sizeof(newtup->t_ctid));
+
+ ToVpd->vpd_nusd++;
+ nmoved++;
+ ToVpd->vpd_free = ((PageHeader) ToPage)->pd_upper - ((PageHeader) ToPage)->pd_lower;
+ vpc->vpd_voff[vpc->vpd_noff++] = offnum;
+
+ /* insert index' tuples if needed */
+ if (Irel != (Relation *) NULL)
+ {
+ for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
+ {
+ FormIndexDatum(
+ idcur->natts,
+ (AttrNumber *) & (idcur->tform->indkey[0]),
+ newtup,
+ tupdesc,
+ InvalidBuffer,
+ idatum,
+ inulls,
+ idcur->finfoP);
+ iresult = index_insert(
+ Irel[i],
+ idatum,
+ inulls,
+ &(newtup->t_ctid),
+ onerel);
+ if (iresult)
+ pfree(iresult);
+ }
+ }
+
+ } /* walk along page */
+
+ if (vpc->vpd_noff > 0) /* some tuples were moved */
{
- FormIndexDatum (
- idcur->natts,
- (AttrNumber *)&(idcur->tform->indkey[0]),
- newtup,
- tupdesc,
- InvalidBuffer,
- idatum,
- inulls,
- idcur->finfoP);
- iresult = index_insert (
- Irel[i],
- idatum,
- inulls,
- &(newtup->t_ctid),
- onerel);
- if (iresult) pfree(iresult);
+ vc_reappage(&Nvpl, vpc);
+ WriteBuffer(buf);
}
- }
-
- } /* walk along page */
+ else if (dowrite)
+ WriteBuffer(buf);
+ else
+ ReleaseBuffer(buf);
- if ( vpc->vpd_noff > 0 ) /* some tuples were moved */
+ if (offnum <= maxoff)
+ break; /* some item(s) left */
+
+ } /* walk along relation */
+
+ blkno++; /* new number of blocks */
+
+ if (ToBuf != InvalidBuffer)
{
- vc_reappage (&Nvpl, vpc);
- WriteBuffer(buf);
+ Assert(nmoved > 0);
+ WriteBuffer(ToBuf);
}
- else if ( dowrite )
- WriteBuffer(buf);
- else
- ReleaseBuffer(buf);
-
- if ( offnum <= maxoff )
- break; /* some item(s) left */
-
- } /* walk along relation */
-
- blkno++; /* new number of blocks */
-
- if ( ToBuf != InvalidBuffer )
- {
- Assert (nmoved > 0);
- WriteBuffer(ToBuf);
- }
-
- if ( nmoved > 0 )
- {
- /*
- * We have to commit our tuple' movings before we'll truncate
- * relation, but we shouldn't lose our locks. And so - quick hack:
- * flush buffers and record status of current transaction
- * as committed, and continue. - vadim 11/13/96
- */
- FlushBufferPool(!TransactionFlushEnabled());
- TransactionIdCommit(myXID);
- FlushBufferPool(!TransactionFlushEnabled());
- myCTM = TransactionIdGetCommitTime(myXID);
- }
-
- /*
- * Clean uncleaned reapped pages from Vvpl list
- * and set commit' times for inserted tuples
- */
- nchkmvd = 0;
- for (i = 0, vpp = Vvpl->vpl_pgdesc; i < Vnpages; i++, vpp++)
- {
- Assert ( (*vpp)->vpd_blkno < blkno );
- buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
- page = BufferGetPage(buf);
- if ( (*vpp)->vpd_nusd == 0 ) /* this page was not used */
+
+ if (nmoved > 0)
{
- /* noff == 0 in empty pages only - such pages should be re-used */
- Assert ( (*vpp)->vpd_noff > 0 );
- vc_vacpage (page, *vpp, archrel);
+
+ /*
+ * We have to commit our tuple' movings before we'll truncate
+ * relation, but we shouldn't lose our locks. And so - quick hack:
+ * flush buffers and record status of current transaction as
+ * committed, and continue. - vadim 11/13/96
+ */
+ FlushBufferPool(!TransactionFlushEnabled());
+ TransactionIdCommit(myXID);
+ FlushBufferPool(!TransactionFlushEnabled());
+ myCTM = TransactionIdGetCommitTime(myXID);
}
- else /* this page was used */
+
+ /*
+ * Clean uncleaned reapped pages from Vvpl list and set commit' times
+ * for inserted tuples
+ */
+ nchkmvd = 0;
+ for (i = 0, vpp = Vvpl->vpl_pgdesc; i < Vnpages; i++, vpp++)
{
- ntups = 0;
- moff = PageGetMaxOffsetNumber(page);
- for (newoff = FirstOffsetNumber;
- newoff <= moff;
- newoff = OffsetNumberNext(newoff))
- {
- itemid = PageGetItemId(page, newoff);
- if (!ItemIdIsUsed(itemid))
- continue;
- htup = (HeapTuple) PageGetItem(page, itemid);
- if ( TransactionIdEquals((TransactionId)htup->t_xmin, myXID) )
- {
- htup->t_tmin = myCTM;
- ntups++;
- }
- }
- Assert ( (*vpp)->vpd_nusd == ntups );
- nchkmvd += ntups;
+ Assert((*vpp)->vpd_blkno < blkno);
+ buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
+ page = BufferGetPage(buf);
+ if ((*vpp)->vpd_nusd == 0) /* this page was not used */
+ {
+
+ /*
+ * noff == 0 in empty pages only - such pages should be
+ * re-used
+ */
+ Assert((*vpp)->vpd_noff > 0);
+ vc_vacpage(page, *vpp, archrel);
+ }
+ else
+/* this page was used */
+ {
+ ntups = 0;
+ moff = PageGetMaxOffsetNumber(page);
+ for (newoff = FirstOffsetNumber;
+ newoff <= moff;
+ newoff = OffsetNumberNext(newoff))
+ {
+ itemid = PageGetItemId(page, newoff);
+ if (!ItemIdIsUsed(itemid))
+ continue;
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ if (TransactionIdEquals((TransactionId) htup->t_xmin, myXID))
+ {
+ htup->t_tmin = myCTM;
+ ntups++;
+ }
+ }
+ Assert((*vpp)->vpd_nusd == ntups);
+ nchkmvd += ntups;
+ }
+ WriteBuffer(buf);
}
- WriteBuffer (buf);
- }
- Assert ( nmoved == nchkmvd );
+ Assert(nmoved == nchkmvd);
+
+ getrusage(RUSAGE_SELF, &ru1);
- getrusage(RUSAGE_SELF, &ru1);
-
- elog (MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. \
+ elog(MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. \
Elapsed %u/%u sec.",
- (RelationGetRelationName(onerel))->data,
- nblocks, blkno, nmoved,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
-
- if ( Nvpl.vpl_npages > 0 )
- {
- /* vacuum indices again if needed */
- if ( Irel != (Relation*) NULL )
+ (RelationGetRelationName(onerel))->data,
+ nblocks, blkno, nmoved,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+
+ if (Nvpl.vpl_npages > 0)
{
- VPageDescr *vpleft, *vpright, vpsave;
-
- /* re-sort Nvpl.vpl_pgdesc */
- for (vpleft = Nvpl.vpl_pgdesc,
- vpright = Nvpl.vpl_pgdesc + Nvpl.vpl_npages - 1;
- vpleft < vpright; vpleft++, vpright--)
- {
- vpsave = *vpleft; *vpleft = *vpright; *vpright = vpsave;
- }
- for (i = 0; i < nindices; i++)
- vc_vaconeind (&Nvpl, Irel[i], vacrelstats->ntups);
+ /* vacuum indices again if needed */
+ if (Irel != (Relation *) NULL)
+ {
+ VPageDescr *vpleft,
+ *vpright,
+ vpsave;
+
+ /* re-sort Nvpl.vpl_pgdesc */
+ for (vpleft = Nvpl.vpl_pgdesc,
+ vpright = Nvpl.vpl_pgdesc + Nvpl.vpl_npages - 1;
+ vpleft < vpright; vpleft++, vpright--)
+ {
+ vpsave = *vpleft;
+ *vpleft = *vpright;
+ *vpright = vpsave;
+ }
+ for (i = 0; i < nindices; i++)
+ vc_vaconeind(&Nvpl, Irel[i], vacrelstats->ntups);
+ }
+
+ /*
+ * clean moved tuples from last page in Nvpl list if some tuples
+ * left there
+ */
+ if (vpc->vpd_noff > 0 && offnum <= maxoff)
+ {
+ Assert(vpc->vpd_blkno == blkno - 1);
+ buf = ReadBuffer(onerel, vpc->vpd_blkno);
+ page = BufferGetPage(buf);
+ ntups = 0;
+ maxoff = offnum;
+ for (offnum = FirstOffsetNumber;
+ offnum < maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ itemid = PageGetItemId(page, offnum);
+ if (!ItemIdIsUsed(itemid))
+ continue;
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ Assert(TransactionIdEquals((TransactionId) htup->t_xmax, myXID));
+ itemid->lp_flags &= ~LP_USED;
+ ntups++;
+ }
+ Assert(vpc->vpd_noff == ntups);
+ PageRepairFragmentation(page);
+ WriteBuffer(buf);
+ }
+
+ /* now - free new list of reapped pages */
+ vpp = Nvpl.vpl_pgdesc;
+ for (i = 0; i < Nvpl.vpl_npages; i++, vpp++)
+ pfree(*vpp);
+ pfree(Nvpl.vpl_pgdesc);
}
- /*
- * clean moved tuples from last page in Nvpl list
- * if some tuples left there
- */
- if ( vpc->vpd_noff > 0 && offnum <= maxoff )
+ /* truncate relation */
+ if (blkno < nblocks)
{
- Assert (vpc->vpd_blkno == blkno - 1);
- buf = ReadBuffer(onerel, vpc->vpd_blkno);
- page = BufferGetPage (buf);
- ntups = 0;
- maxoff = offnum;
- for (offnum = FirstOffsetNumber;
- offnum < maxoff;
- offnum = OffsetNumberNext(offnum))
- {
- itemid = PageGetItemId(page, offnum);
- if (!ItemIdIsUsed(itemid))
- continue;
- htup = (HeapTuple) PageGetItem(page, itemid);
- Assert ( TransactionIdEquals((TransactionId)htup->t_xmax, myXID) );
- itemid->lp_flags &= ~LP_USED;
- ntups++;
- }
- Assert ( vpc->vpd_noff == ntups );
- PageRepairFragmentation(page);
- WriteBuffer (buf);
+ blkno = smgrtruncate(onerel->rd_rel->relsmgr, onerel, blkno);
+ Assert(blkno >= 0);
+ vacrelstats->npages = blkno; /* set new number of blocks */
+ }
+
+ if (archrel != (Relation) NULL)
+ heap_close(archrel);
+
+ if (Irel != (Relation *) NULL) /* pfree index' allocations */
+ {
+ pfree(Idesc);
+ pfree(idatum);
+ pfree(inulls);
+ vc_clsindices(nindices, Irel);
}
- /* now - free new list of reapped pages */
- vpp = Nvpl.vpl_pgdesc;
- for (i = 0; i < Nvpl.vpl_npages; i++, vpp++)
- pfree(*vpp);
- pfree (Nvpl.vpl_pgdesc);
- }
-
- /* truncate relation */
- if ( blkno < nblocks )
- {
- blkno = smgrtruncate (onerel->rd_rel->relsmgr, onerel, blkno);
- Assert ( blkno >= 0 );
- vacrelstats->npages = blkno; /* set new number of blocks */
- }
-
- if ( archrel != (Relation) NULL )
- heap_close(archrel);
-
- if ( Irel != (Relation*) NULL ) /* pfree index' allocations */
- {
- pfree (Idesc);
- pfree (idatum);
- pfree (inulls);
- vc_clsindices (nindices, Irel);
- }
-
- pfree (vpc);
-
-} /* vc_rpfheap */
+ pfree(vpc);
+
+} /* vc_rpfheap */
/*
- * vc_vacheap() -- free dead tuples
+ * vc_vacheap() -- free dead tuples
*
- * This routine marks dead tuples as unused and truncates relation
- * if there are "empty" end-blocks.
+ * This routine marks dead tuples as unused and truncates relation
+ * if there are "empty" end-blocks.
*/
static void
-vc_vacheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl)
+vc_vacheap(VRelStats * vacrelstats, Relation onerel, VPageList Vvpl)
{
- Buffer buf;
- Page page;
- VPageDescr *vpp;
- Relation archrel;
- int nblocks;
- int i;
-
- nblocks = Vvpl->vpl_npages;
- /* if the relation has an archive, open it */
- if (onerel->rd_rel->relarch != 'n')
- archrel = vc_getarchrel(onerel);
- else
- {
- archrel = (Relation) NULL;
- nblocks -= Vvpl->vpl_nemend; /* nothing to do with them */
- }
-
- for (i = 0, vpp = Vvpl->vpl_pgdesc; i < nblocks; i++, vpp++)
- {
- if ( (*vpp)->vpd_noff > 0 )
+ Buffer buf;
+ Page page;
+ VPageDescr *vpp;
+ Relation archrel;
+ int nblocks;
+ int i;
+
+ nblocks = Vvpl->vpl_npages;
+ /* if the relation has an archive, open it */
+ if (onerel->rd_rel->relarch != 'n')
+ archrel = vc_getarchrel(onerel);
+ else
{
- buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
- page = BufferGetPage (buf);
- vc_vacpage (page, *vpp, archrel);
- WriteBuffer (buf);
+ archrel = (Relation) NULL;
+ nblocks -= Vvpl->vpl_nemend; /* nothing to do with them */
+ }
+
+ for (i = 0, vpp = Vvpl->vpl_pgdesc; i < nblocks; i++, vpp++)
+ {
+ if ((*vpp)->vpd_noff > 0)
+ {
+ buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
+ page = BufferGetPage(buf);
+ vc_vacpage(page, *vpp, archrel);
+ WriteBuffer(buf);
+ }
}
- }
-
- /* truncate relation if there are some empty end-pages */
- if ( Vvpl->vpl_nemend > 0 )
- {
- Assert ( vacrelstats->npages >= Vvpl->vpl_nemend );
- nblocks = vacrelstats->npages - Vvpl->vpl_nemend;
- elog (MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u.",
- (RelationGetRelationName(onerel))->data,
- vacrelstats->npages, nblocks);
-
- /*
- * we have to flush "empty" end-pages (if changed, but who knows it)
- * before truncation
- */
- FlushBufferPool(!TransactionFlushEnabled());
- nblocks = smgrtruncate (onerel->rd_rel->relsmgr, onerel, nblocks);
- Assert ( nblocks >= 0 );
- vacrelstats->npages = nblocks; /* set new number of blocks */
- }
+ /* truncate relation if there are some empty end-pages */
+ if (Vvpl->vpl_nemend > 0)
+ {
+ Assert(vacrelstats->npages >= Vvpl->vpl_nemend);
+ nblocks = vacrelstats->npages - Vvpl->vpl_nemend;
+ elog(MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u.",
+ (RelationGetRelationName(onerel))->data,
+ vacrelstats->npages, nblocks);
+
+ /*
+ * we have to flush "empty" end-pages (if changed, but who knows
+ * it) before truncation
+ */
+ FlushBufferPool(!TransactionFlushEnabled());
+
+ nblocks = smgrtruncate(onerel->rd_rel->relsmgr, onerel, nblocks);
+ Assert(nblocks >= 0);
+ vacrelstats->npages = nblocks; /* set new number of blocks */
+ }
- if ( archrel != (Relation) NULL )
- heap_close(archrel);
+ if (archrel != (Relation) NULL)
+ heap_close(archrel);
-} /* vc_vacheap */
+} /* vc_vacheap */
/*
- * vc_vacpage() -- free (and archive if needed) dead tuples on a page
- * and repaire its fragmentation.
+ * vc_vacpage() -- free (and archive if needed) dead tuples on a page
+ * and repaire its fragmentation.
*/
static void
-vc_vacpage (Page page, VPageDescr vpd, Relation archrel)
+vc_vacpage(Page page, VPageDescr vpd, Relation archrel)
{
- ItemId itemid;
- HeapTuple htup;
- int i;
-
- Assert ( vpd->vpd_nusd == 0 );
- for (i=0; i < vpd->vpd_noff; i++)
- {
- itemid = &(((PageHeader) page)->pd_linp[vpd->vpd_voff[i] - 1]);
- if ( archrel != (Relation) NULL && ItemIdIsUsed(itemid) )
+ ItemId itemid;
+ HeapTuple htup;
+ int i;
+
+ Assert(vpd->vpd_nusd == 0);
+ for (i = 0; i < vpd->vpd_noff; i++)
{
- htup = (HeapTuple) PageGetItem (page, itemid);
- vc_archive (archrel, htup);
+ itemid = &(((PageHeader) page)->pd_linp[vpd->vpd_voff[i] - 1]);
+ if (archrel != (Relation) NULL && ItemIdIsUsed(itemid))
+ {
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ vc_archive(archrel, htup);
+ }
+ itemid->lp_flags &= ~LP_USED;
}
- itemid->lp_flags &= ~LP_USED;
- }
- PageRepairFragmentation(page);
+ PageRepairFragmentation(page);
-} /* vc_vacpage */
+} /* vc_vacpage */
/*
- * _vc_scanoneind() -- scan one index relation to update statistic.
+ * _vc_scanoneind() -- scan one index relation to update statistic.
*
*/
static void
-vc_scanoneind (Relation indrel, int nhtups)
+vc_scanoneind(Relation indrel, int nhtups)
{
- RetrieveIndexResult res;
- IndexScanDesc iscan;
- int nitups;
- int nipages;
- struct rusage ru0, ru1;
+ RetrieveIndexResult res;
+ IndexScanDesc iscan;
+ int nitups;
+ int nipages;
+ struct rusage ru0,
+ ru1;
- getrusage(RUSAGE_SELF, &ru0);
+ getrusage(RUSAGE_SELF, &ru0);
- /* walk through the entire index */
- iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
- nitups = 0;
+ /* walk through the entire index */
+ iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
+ nitups = 0;
- while ((res = index_getnext(iscan, ForwardScanDirection))
- != (RetrieveIndexResult) NULL)
- {
- nitups++;
- pfree(res);
- }
+ while ((res = index_getnext(iscan, ForwardScanDirection))
+ != (RetrieveIndexResult) NULL)
+ {
+ nitups++;
+ pfree(res);
+ }
- index_endscan(iscan);
+ index_endscan(iscan);
- /* now update statistics in pg_class */
- nipages = RelationGetNumberOfBlocks(indrel);
- vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
+ /* now update statistics in pg_class */
+ nipages = RelationGetNumberOfBlocks(indrel);
+ vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
- getrusage(RUSAGE_SELF, &ru1);
+ getrusage(RUSAGE_SELF, &ru1);
- elog (MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u. Elapsed %u/%u sec.",
- indrel->rd_rel->relname.data, nipages, nitups,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+ elog(MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u. Elapsed %u/%u sec.",
+ indrel->rd_rel->relname.data, nipages, nitups,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
- if ( nitups != nhtups )
- elog (NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
- indrel->rd_rel->relname.data, nitups, nhtups);
+ if (nitups != nhtups)
+ elog(NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
+ indrel->rd_rel->relname.data, nitups, nhtups);
-} /* vc_scanoneind */
+} /* vc_scanoneind */
/*
- * vc_vaconeind() -- vacuum one index relation.
+ * vc_vaconeind() -- vacuum one index relation.
*
- * Vpl is the VPageList of the heap we're currently vacuuming.
- * It's locked. Indrel is an index relation on the vacuumed heap.
- * We don't set locks on the index relation here, since the indexed
- * access methods support locking at different granularities.
- * We let them handle it.
+ * Vpl is the VPageList of the heap we're currently vacuuming.
+ * It's locked. Indrel is an index relation on the vacuumed heap.
+ * We don't set locks on the index relation here, since the indexed
+ * access methods support locking at different granularities.
+ * We let them handle it.
*
- * Finally, we arrange to update the index relation's statistics in
- * pg_class.
+ * Finally, we arrange to update the index relation's statistics in
+ * pg_class.
*/
static void
vc_vaconeind(VPageList vpl, Relation indrel, int nhtups)
{
- RetrieveIndexResult res;
- IndexScanDesc iscan;
- ItemPointer heapptr;
- int nvac;
- int nitups;
- int nipages;
- VPageDescr vp;
- struct rusage ru0, ru1;
-
- getrusage(RUSAGE_SELF, &ru0);
-
- /* walk through the entire index */
- iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
- nvac = 0;
- nitups = 0;
-
- while ((res = index_getnext(iscan, ForwardScanDirection))
- != (RetrieveIndexResult) NULL) {
- heapptr = &res->heap_iptr;
-
- if ( (vp = vc_tidreapped (heapptr, vpl)) != (VPageDescr) NULL)
+ RetrieveIndexResult res;
+ IndexScanDesc iscan;
+ ItemPointer heapptr;
+ int nvac;
+ int nitups;
+ int nipages;
+ VPageDescr vp;
+ struct rusage ru0,
+ ru1;
+
+ getrusage(RUSAGE_SELF, &ru0);
+
+ /* walk through the entire index */
+ iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
+ nvac = 0;
+ nitups = 0;
+
+ while ((res = index_getnext(iscan, ForwardScanDirection))
+ != (RetrieveIndexResult) NULL)
{
+ heapptr = &res->heap_iptr;
+
+ if ((vp = vc_tidreapped(heapptr, vpl)) != (VPageDescr) NULL)
+ {
#if 0
- elog(DEBUG, "<%x,%x> -> <%x,%x>",
- ItemPointerGetBlockNumber(&(res->index_iptr)),
- ItemPointerGetOffsetNumber(&(res->index_iptr)),
- ItemPointerGetBlockNumber(&(res->heap_iptr)),
- ItemPointerGetOffsetNumber(&(res->heap_iptr)));
+ elog(DEBUG, "<%x,%x> -> <%x,%x>",
+ ItemPointerGetBlockNumber(&(res->index_iptr)),
+ ItemPointerGetOffsetNumber(&(res->index_iptr)),
+ ItemPointerGetBlockNumber(&(res->heap_iptr)),
+ ItemPointerGetOffsetNumber(&(res->heap_iptr)));
#endif
- if ( vp->vpd_noff == 0 )
- { /* this is EmptyPage !!! */
- elog (NOTICE, "Ind %s: pointer to EmptyPage (blk %u off %u) - fixing",
- indrel->rd_rel->relname.data,
- vp->vpd_blkno, ItemPointerGetOffsetNumber(heapptr));
- }
- ++nvac;
- index_delete(indrel, &res->index_iptr);
- } else {
- nitups++;
- }
+ if (vp->vpd_noff == 0)
+ { /* this is EmptyPage !!! */
+ elog(NOTICE, "Ind %s: pointer to EmptyPage (blk %u off %u) - fixing",
+ indrel->rd_rel->relname.data,
+ vp->vpd_blkno, ItemPointerGetOffsetNumber(heapptr));
+ }
+ ++nvac;
+ index_delete(indrel, &res->index_iptr);
+ }
+ else
+ {
+ nitups++;
+ }
- /* be tidy */
- pfree(res);
- }
+ /* be tidy */
+ pfree(res);
+ }
- index_endscan(iscan);
+ index_endscan(iscan);
- /* now update statistics in pg_class */
- nipages = RelationGetNumberOfBlocks(indrel);
- vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
+ /* now update statistics in pg_class */
+ nipages = RelationGetNumberOfBlocks(indrel);
+ vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
- getrusage(RUSAGE_SELF, &ru1);
+ getrusage(RUSAGE_SELF, &ru1);
- elog (MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
- indrel->rd_rel->relname.data, nipages, nitups, nvac,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+ elog(MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
+ indrel->rd_rel->relname.data, nipages, nitups, nvac,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
- if ( nitups != nhtups )
- elog (NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
- indrel->rd_rel->relname.data, nitups, nhtups);
+ if (nitups != nhtups)
+ elog(NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
+ indrel->rd_rel->relname.data, nitups, nhtups);
-} /* vc_vaconeind */
+} /* vc_vaconeind */
/*
- * vc_tidreapped() -- is a particular tid reapped?
+ * vc_tidreapped() -- is a particular tid reapped?
*
- * vpl->VPageDescr_array is sorted in right order.
+ * vpl->VPageDescr_array is sorted in right order.
*/
-static VPageDescr
+static VPageDescr
vc_tidreapped(ItemPointer itemptr, VPageList vpl)
{
- OffsetNumber ioffno;
- OffsetNumber *voff;
- VPageDescr vp, *vpp;
- VPageDescrData vpd;
-
- vpd.vpd_blkno = ItemPointerGetBlockNumber(itemptr);
- ioffno = ItemPointerGetOffsetNumber(itemptr);
-
- vp = &vpd;
- vpp = (VPageDescr*) vc_find_eq ((char*)(vpl->vpl_pgdesc),
- vpl->vpl_npages, sizeof (VPageDescr), (char*)&vp,
- vc_cmp_blk);
-
- if ( vpp == (VPageDescr*) NULL )
- return ((VPageDescr)NULL);
- vp = *vpp;
-
- /* ok - we are on true page */
-
- if ( vp->vpd_noff == 0 ) { /* this is EmptyPage !!! */
- return (vp);
- }
-
- voff = (OffsetNumber*) vc_find_eq ((char*)(vp->vpd_voff),
- vp->vpd_noff, sizeof (OffsetNumber), (char*)&ioffno,
- vc_cmp_offno);
+ OffsetNumber ioffno;
+ OffsetNumber *voff;
+ VPageDescr vp,
+ *vpp;
+ VPageDescrData vpd;
- if ( voff == (OffsetNumber*) NULL )
- return ((VPageDescr)NULL);
+ vpd.vpd_blkno = ItemPointerGetBlockNumber(itemptr);
+ ioffno = ItemPointerGetOffsetNumber(itemptr);
- return (vp);
+ vp = &vpd;
+ vpp = (VPageDescr *) vc_find_eq((char *) (vpl->vpl_pgdesc),
+ vpl->vpl_npages, sizeof(VPageDescr), (char *) &vp,
+ vc_cmp_blk);
-} /* vc_tidreapped */
+ if (vpp == (VPageDescr *) NULL)
+ return ((VPageDescr) NULL);
+ vp = *vpp;
+
+ /* ok - we are on true page */
+
+ if (vp->vpd_noff == 0)
+ { /* this is EmptyPage !!! */
+ return (vp);
+ }
+
+ voff = (OffsetNumber *) vc_find_eq((char *) (vp->vpd_voff),
+ vp->vpd_noff, sizeof(OffsetNumber), (char *) &ioffno,
+ vc_cmp_offno);
+
+ if (voff == (OffsetNumber *) NULL)
+ return ((VPageDescr) NULL);
+
+ return (vp);
+
+} /* vc_tidreapped */
/*
- * vc_attrstats() -- compute column statistics used by the optimzer
+ * vc_attrstats() -- compute column statistics used by the optimzer
*
- * We compute the column min, max, null and non-null counts.
- * Plus we attempt to find the count of the value that occurs most
- * frequently in each column
- * These figures are used to compute the selectivity of the column
+ * We compute the column min, max, null and non-null counts.
+ * Plus we attempt to find the count of the value that occurs most
+ * frequently in each column
+ * These figures are used to compute the selectivity of the column
*
- * We use a three-bucked cache to get the most frequent item
- * The 'guess' buckets count hits. A cache miss causes guess1
- * to get the most hit 'guess' item in the most recent cycle, and
- * the new item goes into guess2. Whenever the total count of hits
- * of a 'guess' entry is larger than 'best', 'guess' becomes 'best'.
+ * We use a three-bucked cache to get the most frequent item
+ * The 'guess' buckets count hits. A cache miss causes guess1
+ * to get the most hit 'guess' item in the most recent cycle, and
+ * the new item goes into guess2. Whenever the total count of hits
+ * of a 'guess' entry is larger than 'best', 'guess' becomes 'best'.
*
- * This method works perfectly for columns with unique values, and columns
- * with only two unique values, plus nulls.
+ * This method works perfectly for columns with unique values, and columns
+ * with only two unique values, plus nulls.
*
- * It becomes less perfect as the number of unique values increases and
- * their distribution in the table becomes more random.
+ * It becomes less perfect as the number of unique values increases and
+ * their distribution in the table becomes more random.
*
*/
static void
-vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple htup)
+vc_attrstats(Relation onerel, VRelStats * vacrelstats, HeapTuple htup)
{
- int i, attr_cnt = vacrelstats->va_natts;
- VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
- TupleDesc tupDesc = onerel->rd_att;
- Datum value;
- bool isnull;
-
- for (i = 0; i < attr_cnt; i++) {
- VacAttrStats *stats = &vacattrstats[i];
- bool value_hit = true;
-
- value = (Datum) heap_getattr (htup, InvalidBuffer,
- stats->attr->attnum, tupDesc, &isnull);
-
- if (!VacAttrStatsEqValid(stats))
- continue;
-
- if (isnull)
- stats->null_cnt++;
- else {
- stats->nonnull_cnt++;
- if (stats->initialized == false) {
- vc_bucketcpy(stats->attr, value, &stats->best, &stats->best_len);
- /* best_cnt gets incremented later */
- vc_bucketcpy(stats->attr, value, &stats->guess1, &stats->guess1_len);
- stats->guess1_cnt = stats->guess1_hits = 1;
- vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
- stats->guess2_hits = 1;
- if (VacAttrStatsLtGtValid(stats)) {
- vc_bucketcpy(stats->attr, value, &stats->max , &stats->max_len);
- vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
+ int i,
+ attr_cnt = vacrelstats->va_natts;
+ VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
+ TupleDesc tupDesc = onerel->rd_att;
+ Datum value;
+ bool isnull;
+
+ for (i = 0; i < attr_cnt; i++)
+ {
+ VacAttrStats *stats = &vacattrstats[i];
+ bool value_hit = true;
+
+ value = (Datum) heap_getattr(htup, InvalidBuffer,
+ stats->attr->attnum, tupDesc, &isnull);
+
+ if (!VacAttrStatsEqValid(stats))
+ continue;
+
+ if (isnull)
+ stats->null_cnt++;
+ else
+ {
+ stats->nonnull_cnt++;
+ if (stats->initialized == false)
+ {
+ vc_bucketcpy(stats->attr, value, &stats->best, &stats->best_len);
+ /* best_cnt gets incremented later */
+ vc_bucketcpy(stats->attr, value, &stats->guess1, &stats->guess1_len);
+ stats->guess1_cnt = stats->guess1_hits = 1;
+ vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
+ stats->guess2_hits = 1;
+ if (VacAttrStatsLtGtValid(stats))
+ {
+ vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
+ vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
+ }
+ stats->initialized = true;
+ }
+ if (VacAttrStatsLtGtValid(stats))
+ {
+ if ((*(stats->f_cmplt)) (value, stats->min))
+ {
+ vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
+ stats->min_cnt = 0;
+ }
+ if ((*(stats->f_cmpgt)) (value, stats->max))
+ {
+ vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
+ stats->max_cnt = 0;
+ }
+ if ((*(stats->f_cmpeq)) (value, stats->min))
+ stats->min_cnt++;
+ else if ((*(stats->f_cmpeq)) (value, stats->max))
+ stats->max_cnt++;
+ }
+ if ((*(stats->f_cmpeq)) (value, stats->best))
+ stats->best_cnt++;
+ else if ((*(stats->f_cmpeq)) (value, stats->guess1))
+ {
+ stats->guess1_cnt++;
+ stats->guess1_hits++;
+ }
+ else if ((*(stats->f_cmpeq)) (value, stats->guess2))
+ stats->guess2_hits++;
+ else
+ value_hit = false;
+
+ if (stats->guess2_hits > stats->guess1_hits)
+ {
+ swapDatum(stats->guess1, stats->guess2);
+ swapInt(stats->guess1_len, stats->guess2_len);
+ stats->guess1_cnt = stats->guess2_hits;
+ swapLong(stats->guess1_hits, stats->guess2_hits);
+ }
+ if (stats->guess1_cnt > stats->best_cnt)
+ {
+ swapDatum(stats->best, stats->guess1);
+ swapInt(stats->best_len, stats->guess1_len);
+ swapLong(stats->best_cnt, stats->guess1_cnt);
+ stats->guess1_hits = 1;
+ stats->guess2_hits = 1;
+ }
+ if (!value_hit)
+ {
+ vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
+ stats->guess1_hits = 1;
+ stats->guess2_hits = 1;
+ }
}
- stats->initialized = true;
- }
- if (VacAttrStatsLtGtValid(stats)) {
- if ( (*(stats->f_cmplt)) (value,stats->min) ) {
- vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
- stats->min_cnt = 0;
- }
- if ( (*(stats->f_cmpgt)) (value,stats->max) ) {
- vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
- stats->max_cnt = 0;
- }
- if ( (*(stats->f_cmpeq)) (value,stats->min) )
- stats->min_cnt++;
- else if ( (*(stats->f_cmpeq)) (value,stats->max) )
- stats->max_cnt++;
- }
- if ( (*(stats->f_cmpeq)) (value,stats->best) )
- stats->best_cnt++;
- else if ( (*(stats->f_cmpeq)) (value,stats->guess1) ) {
- stats->guess1_cnt++;
- stats->guess1_hits++;
- }
- else if ( (*(stats->f_cmpeq)) (value,stats->guess2) )
- stats->guess2_hits++;
- else value_hit = false;
-
- if (stats->guess2_hits > stats->guess1_hits) {
- swapDatum(stats->guess1,stats->guess2);
- swapInt(stats->guess1_len,stats->guess2_len);
- stats->guess1_cnt = stats->guess2_hits;
- swapLong(stats->guess1_hits, stats->guess2_hits);
- }
- if (stats->guess1_cnt > stats->best_cnt) {
- swapDatum(stats->best,stats->guess1);
- swapInt(stats->best_len,stats->guess1_len);
- swapLong(stats->best_cnt,stats->guess1_cnt);
- stats->guess1_hits = 1;
- stats->guess2_hits = 1;
- }
- if (!value_hit) {
- vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
- stats->guess1_hits = 1;
- stats->guess2_hits = 1;
- }
}
- }
- return;
+ return;
}
/*
- * vc_bucketcpy() -- update pg_class statistics for one relation
+ * vc_bucketcpy() -- update pg_class statistics for one relation
*
*/
static void
-vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_len)
+vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum * bucket, int16 * bucket_len)
{
- if (attr->attbyval && attr->attlen != -1)
- *bucket = value;
- else {
- int len = (attr->attlen != -1 ? attr->attlen : VARSIZE(value));
-
- if (len > *bucket_len)
- {
- if (*bucket_len != 0)
- pfree(DatumGetPointer(*bucket));
- *bucket = PointerGetDatum(palloc(len));
- *bucket_len = len;
+ if (attr->attbyval && attr->attlen != -1)
+ *bucket = value;
+ else
+ {
+ int len = (attr->attlen != -1 ? attr->attlen : VARSIZE(value));
+
+ if (len > *bucket_len)
+ {
+ if (*bucket_len != 0)
+ pfree(DatumGetPointer(*bucket));
+ *bucket = PointerGetDatum(palloc(len));
+ *bucket_len = len;
+ }
+ memmove(DatumGetPointer(*bucket), DatumGetPointer(value), len);
}
- memmove(DatumGetPointer(*bucket), DatumGetPointer(value), len);
- }
}
/*
- * vc_updstats() -- update pg_class statistics for one relation
+ * vc_updstats() -- update pg_class statistics for one relation
*
- * This routine works for both index and heap relation entries in
- * pg_class. We violate no-overwrite semantics here by storing new
- * values for ntups, npages, and hasindex directly in the pg_class
- * tuple that's already on the page. The reason for this is that if
- * we updated these tuples in the usual way, then every tuple in pg_class
- * would be replaced every day. This would make planning and executing
- * historical queries very expensive.
+ * This routine works for both index and heap relation entries in
+ * pg_class. We violate no-overwrite semantics here by storing new
+ * values for ntups, npages, and hasindex directly in the pg_class
+ * tuple that's already on the page. The reason for this is that if
+ * we updated these tuples in the usual way, then every tuple in pg_class
+ * would be replaced every day. This would make planning and executing
+ * historical queries very expensive.
*/
static void
-vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats *vacrelstats)
+vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats * vacrelstats)
{
- Relation rd, ad, sd;
- HeapScanDesc rsdesc, asdesc;
- TupleDesc sdesc;
- HeapTuple rtup, atup, stup;
- Buffer rbuf, abuf;
- Form_pg_class pgcform;
- ScanKeyData rskey, askey;
- AttributeTupleForm attp;
-
- /*
- * update number of tuples and number of pages in pg_class
- */
- ScanKeyEntryInitialize(&rskey, 0x0, ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- rd = heap_openr(RelationRelationName);
- rsdesc = heap_beginscan(rd, false, NowTimeQual, 1, &rskey);
-
- if (!HeapTupleIsValid(rtup = heap_getnext(rsdesc, 0, &rbuf)))
- elog(WARN, "pg_class entry for relid %d vanished during vacuuming",
- relid);
-
- /* overwrite the existing statistics in the tuple */
- vc_setpagelock(rd, BufferGetBlockNumber(rbuf));
- pgcform = (Form_pg_class) GETSTRUCT(rtup);
- pgcform->reltuples = ntups;
- pgcform->relpages = npages;
- pgcform->relhasindex = hasindex;
-
- if ( vacrelstats != NULL && vacrelstats->va_natts > 0 )
- {
- VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
- int natts = vacrelstats->va_natts;
-
- ad = heap_openr(AttributeRelationName);
- sd = heap_openr(StatisticRelationName);
- ScanKeyEntryInitialize(&askey, 0, Anum_pg_attribute_attrelid,
- F_INT4EQ, relid);
-
- asdesc = heap_beginscan(ad, false, NowTimeQual, 1, &askey);
-
- while (HeapTupleIsValid(atup = heap_getnext(asdesc, 0, &abuf)))
+ Relation rd,
+ ad,
+ sd;
+ HeapScanDesc rsdesc,
+ asdesc;
+ TupleDesc sdesc;
+ HeapTuple rtup,
+ atup,
+ stup;
+ Buffer rbuf,
+ abuf;
+ Form_pg_class pgcform;
+ ScanKeyData rskey,
+ askey;
+ AttributeTupleForm attp;
+
+ /*
+ * update number of tuples and number of pages in pg_class
+ */
+ ScanKeyEntryInitialize(&rskey, 0x0, ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+
+ rd = heap_openr(RelationRelationName);
+ rsdesc = heap_beginscan(rd, false, NowTimeQual, 1, &rskey);
+
+ if (!HeapTupleIsValid(rtup = heap_getnext(rsdesc, 0, &rbuf)))
+ elog(WARN, "pg_class entry for relid %d vanished during vacuuming",
+ relid);
+
+ /* overwrite the existing statistics in the tuple */
+ vc_setpagelock(rd, BufferGetBlockNumber(rbuf));
+ pgcform = (Form_pg_class) GETSTRUCT(rtup);
+ pgcform->reltuples = ntups;
+ pgcform->relpages = npages;
+ pgcform->relhasindex = hasindex;
+
+ if (vacrelstats != NULL && vacrelstats->va_natts > 0)
{
- int i;
- float32data selratio; /* average ratio of rows selected for a random constant */
- VacAttrStats *stats;
- Datum values[ Natts_pg_statistic ];
- char nulls[ Natts_pg_statistic ];
-
- attp = (AttributeTupleForm) GETSTRUCT(atup);
- if ( attp->attnum <= 0) /* skip system attributes for now, */
- /* they are unique anyway */
- continue;
-
- for (i = 0; i < natts; i++)
- {
- if ( attp->attnum == vacattrstats[i].attr->attnum )
- break;
- }
- if ( i >= natts )
- continue;
- stats = &(vacattrstats[i]);
-
- /* overwrite the existing statistics in the tuple */
- if (VacAttrStatsEqValid(stats)) {
-
- vc_setpagelock(ad, BufferGetBlockNumber(abuf));
-
- if (stats->nonnull_cnt + stats->null_cnt == 0 ||
- (stats->null_cnt <= 1 && stats->best_cnt == 1))
- selratio = 0;
- else if (VacAttrStatsLtGtValid(stats) && stats->min_cnt + stats->max_cnt == stats->nonnull_cnt)
+ VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
+ int natts = vacrelstats->va_natts;
+
+ ad = heap_openr(AttributeRelationName);
+ sd = heap_openr(StatisticRelationName);
+ ScanKeyEntryInitialize(&askey, 0, Anum_pg_attribute_attrelid,
+ F_INT4EQ, relid);
+
+ asdesc = heap_beginscan(ad, false, NowTimeQual, 1, &askey);
+
+ while (HeapTupleIsValid(atup = heap_getnext(asdesc, 0, &abuf)))
{
- double min_cnt_d = stats->min_cnt,
- max_cnt_d = stats->max_cnt,
- null_cnt_d = stats->null_cnt,
- nonnullcnt_d = stats->nonnull_cnt; /* prevent overflow */
- selratio = (min_cnt_d*min_cnt_d+max_cnt_d*max_cnt_d+null_cnt_d*null_cnt_d)/
- (nonnullcnt_d+null_cnt_d)/(nonnullcnt_d+null_cnt_d);
+ int i;
+ float32data selratio; /* average ratio of rows selected
+ * for a random constant */
+ VacAttrStats *stats;
+ Datum values[Natts_pg_statistic];
+ char nulls[Natts_pg_statistic];
+
+ attp = (AttributeTupleForm) GETSTRUCT(atup);
+ if (attp->attnum <= 0) /* skip system attributes for now, */
+ /* they are unique anyway */
+ continue;
+
+ for (i = 0; i < natts; i++)
+ {
+ if (attp->attnum == vacattrstats[i].attr->attnum)
+ break;
+ }
+ if (i >= natts)
+ continue;
+ stats = &(vacattrstats[i]);
+
+ /* overwrite the existing statistics in the tuple */
+ if (VacAttrStatsEqValid(stats))
+ {
+
+ vc_setpagelock(ad, BufferGetBlockNumber(abuf));
+
+ if (stats->nonnull_cnt + stats->null_cnt == 0 ||
+ (stats->null_cnt <= 1 && stats->best_cnt == 1))
+ selratio = 0;
+ else if (VacAttrStatsLtGtValid(stats) && stats->min_cnt + stats->max_cnt == stats->nonnull_cnt)
+ {
+ double min_cnt_d = stats->min_cnt,
+ max_cnt_d = stats->max_cnt,
+ null_cnt_d = stats->null_cnt,
+ nonnullcnt_d = stats->nonnull_cnt; /* prevent overflow */
+
+ selratio = (min_cnt_d * min_cnt_d + max_cnt_d * max_cnt_d + null_cnt_d * null_cnt_d) /
+ (nonnullcnt_d + null_cnt_d) / (nonnullcnt_d + null_cnt_d);
+ }
+ else
+ {
+ double most = (double) (stats->best_cnt > stats->null_cnt ? stats->best_cnt : stats->null_cnt);
+ double total = ((double) stats->nonnull_cnt) + ((double) stats->null_cnt);
+
+ /*
+ * we assume count of other values are 20% of best
+ * count in table
+ */
+ selratio = (most * most + 0.20 * most * (total - most)) / total / total;
+ }
+ if (selratio > 1.0)
+ selratio = 1.0;
+ attp->attdisbursion = selratio;
+ WriteNoReleaseBuffer(abuf);
+
+ /* DO PG_STATISTIC INSERTS */
+
+ /*
+ * doing system relations, especially pg_statistic is a
+ * problem
+ */
+ if (VacAttrStatsLtGtValid(stats) && stats->initialized /* &&
+ * !IsSystemRelationName(
+ * pgcform->relname.data)
+ */ )
+ {
+ func_ptr out_function;
+ char *out_string;
+ int dummy;
+
+ for (i = 0; i < Natts_pg_statistic; ++i)
+ nulls[i] = ' ';
+
+ /* ----------------
+ * initialize values[]
+ * ----------------
+ */
+ i = 0;
+ values[i++] = (Datum) relid; /* 1 */
+ values[i++] = (Datum) attp->attnum; /* 2 */
+ values[i++] = (Datum) InvalidOid; /* 3 */
+ fmgr_info(stats->outfunc, &out_function, &dummy);
+ out_string = (*out_function) (stats->min, stats->attr->atttypid);
+ values[i++] = (Datum) fmgr(TextInRegProcedure, out_string);
+ pfree(out_string);
+ out_string = (char *) (*out_function) (stats->max, stats->attr->atttypid);
+ values[i++] = (Datum) fmgr(TextInRegProcedure, out_string);
+ pfree(out_string);
+
+ sdesc = sd->rd_att;
+
+ stup = heap_formtuple(sdesc, values, nulls);
+
+ /* ----------------
+ * insert the tuple in the relation and get the tuple's oid.
+ * ----------------
+ */
+ heap_insert(sd, stup);
+ pfree(DatumGetPointer(values[3]));
+ pfree(DatumGetPointer(values[4]));
+ pfree(stup);
+ }
+ }
}
- else {
- double most = (double)(stats->best_cnt > stats->null_cnt ? stats->best_cnt : stats->null_cnt);
- double total = ((double)stats->nonnull_cnt)+((double)stats->null_cnt);
- /* we assume count of other values are 20%
- of best count in table */
- selratio = (most*most + 0.20*most*(total-most))/total/total;
- }
- if (selratio > 1.0)
- selratio = 1.0;
- attp->attdisbursion = selratio;
- WriteNoReleaseBuffer(abuf);
-
- /* DO PG_STATISTIC INSERTS */
-
- /* doing system relations, especially pg_statistic is a problem */
- if (VacAttrStatsLtGtValid(stats) && stats->initialized /* &&
- !IsSystemRelationName(pgcform->relname.data)*/) {
- func_ptr out_function;
- char *out_string;
- int dummy;
-
- for (i = 0; i < Natts_pg_statistic; ++i) nulls[i] = ' ';
-
- /* ----------------
- * initialize values[]
- * ----------------
- */
- i = 0;
- values[i++] = (Datum) relid; /* 1 */
- values[i++] = (Datum) attp->attnum; /* 2 */
- values[i++] = (Datum) InvalidOid; /* 3 */
- fmgr_info(stats->outfunc, &out_function, &dummy);
- out_string = (*out_function)(stats->min, stats->attr->atttypid);
- values[i++] = (Datum) fmgr(TextInRegProcedure,out_string);
- pfree(out_string);
- out_string = (char *)(*out_function)(stats->max, stats->attr->atttypid);
- values[i++] = (Datum) fmgr(TextInRegProcedure,out_string);
- pfree(out_string);
-
- sdesc = sd->rd_att;
-
- stup = heap_formtuple(sdesc, values, nulls);
-
- /* ----------------
- * insert the tuple in the relation and get the tuple's oid.
- * ----------------
- */
- heap_insert(sd, stup);
- pfree(DatumGetPointer(values[3]));
- pfree(DatumGetPointer(values[4]));
- pfree(stup);
- }
- }
+ heap_endscan(asdesc);
+ heap_close(ad);
+ heap_close(sd);
}
- heap_endscan(asdesc);
- heap_close(ad);
- heap_close(sd);
- }
-
- /* XXX -- after write, should invalidate relcache in other backends */
- WriteNoReleaseBuffer(rbuf); /* heap_endscan release scan' buffers ? */
-
- /* invalidating system relations confuses the function cache
- of pg_operator and pg_opclass */
- if ( !IsSystemRelationName(pgcform->relname.data))
- RelationInvalidateHeapTuple(rd, rtup);
-
- /* that's all, folks */
- heap_endscan(rsdesc);
- heap_close(rd);
+
+ /* XXX -- after write, should invalidate relcache in other backends */
+ WriteNoReleaseBuffer(rbuf); /* heap_endscan release scan' buffers ? */
+
+ /*
+ * invalidating system relations confuses the function cache of
+ * pg_operator and pg_opclass
+ */
+ if (!IsSystemRelationName(pgcform->relname.data))
+ RelationInvalidateHeapTuple(rd, rtup);
+
+ /* that's all, folks */
+ heap_endscan(rsdesc);
+ heap_close(rd);
}
/*
- * vc_delhilowstats() -- delete pg_statistics rows
+ * vc_delhilowstats() -- delete pg_statistics rows
*
*/
static void
vc_delhilowstats(Oid relid, int attcnt, int *attnums)
{
- Relation pgstatistic;
- HeapScanDesc pgsscan;
- HeapTuple pgstup;
- ScanKeyData pgskey;
-
- pgstatistic = heap_openr(StatisticRelationName);
-
- if (relid != InvalidOid ) {
- ScanKeyEntryInitialize(&pgskey, 0x0, Anum_pg_statistic_starelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
- pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 1, &pgskey);
- }
- else
- pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 0, NULL);
-
- while (HeapTupleIsValid(pgstup = heap_getnext(pgsscan, 0, NULL)))
- {
- if ( attcnt > 0 )
- {
- Form_pg_statistic pgs = (Form_pg_statistic) GETSTRUCT (pgstup);
- int i;
-
- for (i = 0; i < attcnt; i++)
- {
- if ( pgs->staattnum == attnums[i] + 1 )
- break;
- }
- if ( i >= attcnt )
- continue; /* don't delete it */
- }
- heap_delete(pgstatistic, &pgstup->t_ctid);
- }
-
- heap_endscan(pgsscan);
- heap_close(pgstatistic);
+ Relation pgstatistic;
+ HeapScanDesc pgsscan;
+ HeapTuple pgstup;
+ ScanKeyData pgskey;
+
+ pgstatistic = heap_openr(StatisticRelationName);
+
+ if (relid != InvalidOid)
+ {
+ ScanKeyEntryInitialize(&pgskey, 0x0, Anum_pg_statistic_starelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+ pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 1, &pgskey);
+ }
+ else
+ pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 0, NULL);
+
+ while (HeapTupleIsValid(pgstup = heap_getnext(pgsscan, 0, NULL)))
+ {
+ if (attcnt > 0)
+ {
+ Form_pg_statistic pgs = (Form_pg_statistic) GETSTRUCT(pgstup);
+ int i;
+
+ for (i = 0; i < attcnt; i++)
+ {
+ if (pgs->staattnum == attnums[i] + 1)
+ break;
+ }
+ if (i >= attcnt)
+ continue; /* don't delete it */
+ }
+ heap_delete(pgstatistic, &pgstup->t_ctid);
+ }
+
+ heap_endscan(pgsscan);
+ heap_close(pgstatistic);
}
-static void vc_setpagelock(Relation rel, BlockNumber blkno)
+static void
+vc_setpagelock(Relation rel, BlockNumber blkno)
{
- ItemPointerData itm;
+ ItemPointerData itm;
- ItemPointerSet(&itm, blkno, 1);
+ ItemPointerSet(&itm, blkno, 1);
- RelationSetLockForWritePage(rel, &itm);
+ RelationSetLockForWritePage(rel, &itm);
}
/*
- * vc_reappage() -- save a page on the array of reapped pages.
+ * vc_reappage() -- save a page on the array of reapped pages.
*
- * As a side effect of the way that the vacuuming loop for a given
- * relation works, higher pages come after lower pages in the array
- * (and highest tid on a page is last).
+ * As a side effect of the way that the vacuuming loop for a given
+ * relation works, higher pages come after lower pages in the array
+ * (and highest tid on a page is last).
*/
-static void
+static void
vc_reappage(VPageList vpl, VPageDescr vpc)
{
- VPageDescr newvpd;
+ VPageDescr newvpd;
- /* allocate a VPageDescrData entry */
- newvpd = (VPageDescr) palloc(sizeof(VPageDescrData) + vpc->vpd_noff*sizeof(OffsetNumber));
+ /* allocate a VPageDescrData entry */
+ newvpd = (VPageDescr) palloc(sizeof(VPageDescrData) + vpc->vpd_noff * sizeof(OffsetNumber));
- /* fill it in */
- if ( vpc->vpd_noff > 0 )
- memmove (newvpd->vpd_voff, vpc->vpd_voff, vpc->vpd_noff*sizeof(OffsetNumber));
- newvpd->vpd_blkno = vpc->vpd_blkno;
- newvpd->vpd_free = vpc->vpd_free;
- newvpd->vpd_nusd = vpc->vpd_nusd;
- newvpd->vpd_noff = vpc->vpd_noff;
+ /* fill it in */
+ if (vpc->vpd_noff > 0)
+ memmove(newvpd->vpd_voff, vpc->vpd_voff, vpc->vpd_noff * sizeof(OffsetNumber));
+ newvpd->vpd_blkno = vpc->vpd_blkno;
+ newvpd->vpd_free = vpc->vpd_free;
+ newvpd->vpd_nusd = vpc->vpd_nusd;
+ newvpd->vpd_noff = vpc->vpd_noff;
- /* insert this page into vpl list */
- vc_vpinsert (vpl, newvpd);
-
-} /* vc_reappage */
+ /* insert this page into vpl list */
+ vc_vpinsert(vpl, newvpd);
+
+} /* vc_reappage */
static void
-vc_vpinsert (VPageList vpl, VPageDescr vpnew)
+vc_vpinsert(VPageList vpl, VPageDescr vpnew)
{
- /* allocate a VPageDescr entry if needed */
- if ( vpl->vpl_npages == 0 )
- vpl->vpl_pgdesc = (VPageDescr*) palloc(100*sizeof(VPageDescr));
- else if ( vpl->vpl_npages % 100 == 0 )
- vpl->vpl_pgdesc = (VPageDescr*) repalloc(vpl->vpl_pgdesc, (vpl->vpl_npages+100)*sizeof(VPageDescr));
- vpl->vpl_pgdesc[vpl->vpl_npages] = vpnew;
- (vpl->vpl_npages)++;
-
+ /* allocate a VPageDescr entry if needed */
+ if (vpl->vpl_npages == 0)
+ vpl->vpl_pgdesc = (VPageDescr *) palloc(100 * sizeof(VPageDescr));
+ else if (vpl->vpl_npages % 100 == 0)
+ vpl->vpl_pgdesc = (VPageDescr *) repalloc(vpl->vpl_pgdesc, (vpl->vpl_npages + 100) * sizeof(VPageDescr));
+ vpl->vpl_pgdesc[vpl->vpl_npages] = vpnew;
+ (vpl->vpl_npages)++;
+
}
static void
vc_free(VRelList vrl)
{
- VRelList p_vrl;
- MemoryContext old;
- PortalVariableMemory pmem;
+ VRelList p_vrl;
+ MemoryContext old;
+ PortalVariableMemory pmem;
- pmem = PortalGetVariableMemory(vc_portal);
- old = MemoryContextSwitchTo((MemoryContext)pmem);
+ pmem = PortalGetVariableMemory(vc_portal);
+ old = MemoryContextSwitchTo((MemoryContext) pmem);
- while (vrl != (VRelList) NULL) {
+ while (vrl != (VRelList) NULL)
+ {
- /* free rel list entry */
- p_vrl = vrl;
- vrl = vrl->vrl_next;
- pfree(p_vrl);
- }
+ /* free rel list entry */
+ p_vrl = vrl;
+ vrl = vrl->vrl_next;
+ pfree(p_vrl);
+ }
- MemoryContextSwitchTo(old);
+ MemoryContextSwitchTo(old);
}
/*
- * vc_getarchrel() -- open the archive relation for a heap relation
+ * vc_getarchrel() -- open the archive relation for a heap relation
*
- * The archive relation is named 'a,XXXXX' for the heap relation
- * whose relid is XXXXX.
+ * The archive relation is named 'a,XXXXX' for the heap relation
+ * whose relid is XXXXX.
*/
#define ARCHIVE_PREFIX "a,"
-static Relation
+static Relation
vc_getarchrel(Relation heaprel)
{
- Relation archrel;
- char *archrelname;
+ Relation archrel;
+ char *archrelname;
- archrelname = palloc(sizeof(ARCHIVE_PREFIX) + NAMEDATALEN); /* bogus */
- sprintf(archrelname, "%s%d", ARCHIVE_PREFIX, heaprel->rd_id);
+ archrelname = palloc(sizeof(ARCHIVE_PREFIX) + NAMEDATALEN); /* bogus */
+ sprintf(archrelname, "%s%d", ARCHIVE_PREFIX, heaprel->rd_id);
- archrel = heap_openr(archrelname);
+ archrel = heap_openr(archrelname);
- pfree(archrelname);
- return (archrel);
+ pfree(archrelname);
+ return (archrel);
}
/*
- * vc_archive() -- write a tuple to an archive relation
+ * vc_archive() -- write a tuple to an archive relation
*
- * In the future, this will invoke the archived accessd method. For
- * now, archive relations are on mag disk.
+ * In the future, this will invoke the archived accessd method. For
+ * now, archive relations are on mag disk.
*/
static void
vc_archive(Relation archrel, HeapTuple htup)
{
- doinsert(archrel, htup);
+ doinsert(archrel, htup);
}
-static bool
+static bool
vc_isarchrel(char *rname)
{
- if (strncmp(ARCHIVE_PREFIX, rname,strlen(ARCHIVE_PREFIX)) == 0)
- return (true);
+ if (strncmp(ARCHIVE_PREFIX, rname, strlen(ARCHIVE_PREFIX)) == 0)
+ return (true);
- return (false);
+ return (false);
}
-static char *
-vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *))
+static char *
+vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, char *))
{
- int res;
- int last = nelem - 1;
- int celm = nelem / 2;
- bool last_move, first_move;
-
- last_move = first_move = true;
- for ( ; ; )
- {
- if ( first_move == true )
+ int res;
+ int last = nelem - 1;
+ int celm = nelem / 2;
+ bool last_move,
+ first_move;
+
+ last_move = first_move = true;
+ for (;;)
{
- res = compar (bot, elm);
- if ( res > 0 )
- return (NULL);
- if ( res == 0 )
- return (bot);
- first_move = false;
- }
- if ( last_move == true )
- {
- res = compar (elm, bot + last*size);
- if ( res > 0 )
- return (NULL);
- if ( res == 0 )
- return (bot + last*size);
- last_move = false;
- }
- res = compar (elm, bot + celm*size);
- if ( res == 0 )
- return (bot + celm*size);
- if ( res < 0 )
- {
- if ( celm == 0 )
- return (NULL);
- last = celm - 1;
- celm = celm / 2;
- last_move = true;
- continue;
+ if (first_move == true)
+ {
+ res = compar(bot, elm);
+ if (res > 0)
+ return (NULL);
+ if (res == 0)
+ return (bot);
+ first_move = false;
+ }
+ if (last_move == true)
+ {
+ res = compar(elm, bot + last * size);
+ if (res > 0)
+ return (NULL);
+ if (res == 0)
+ return (bot + last * size);
+ last_move = false;
+ }
+ res = compar(elm, bot + celm * size);
+ if (res == 0)
+ return (bot + celm * size);
+ if (res < 0)
+ {
+ if (celm == 0)
+ return (NULL);
+ last = celm - 1;
+ celm = celm / 2;
+ last_move = true;
+ continue;
+ }
+
+ if (celm == last)
+ return (NULL);
+
+ last = last - celm - 1;
+ bot = bot + (celm + 1) * size;
+ celm = (last + 1) / 2;
+ first_move = true;
}
-
- if ( celm == last )
- return (NULL);
-
- last = last - celm - 1;
- bot = bot + (celm+1)*size;
- celm = (last + 1) / 2;
- first_move = true;
- }
-
-} /* vc_find_eq */
-
-static int
-vc_cmp_blk (char *left, char *right)
+
+} /* vc_find_eq */
+
+static int
+vc_cmp_blk(char *left, char *right)
{
- BlockNumber lblk, rblk;
+ BlockNumber lblk,
+ rblk;
- lblk = (*((VPageDescr*)left))->vpd_blkno;
- rblk = (*((VPageDescr*)right))->vpd_blkno;
+ lblk = (*((VPageDescr *) left))->vpd_blkno;
+ rblk = (*((VPageDescr *) right))->vpd_blkno;
- if ( lblk < rblk )
- return (-1);
- if ( lblk == rblk )
- return (0);
- return (1);
+ if (lblk < rblk)
+ return (-1);
+ if (lblk == rblk)
+ return (0);
+ return (1);
-} /* vc_cmp_blk */
+} /* vc_cmp_blk */
-static int
-vc_cmp_offno (char *left, char *right)
+static int
+vc_cmp_offno(char *left, char *right)
{
- if ( *(OffsetNumber*)left < *(OffsetNumber*)right )
- return (-1);
- if ( *(OffsetNumber*)left == *(OffsetNumber*)right )
- return (0);
- return (1);
+ if (*(OffsetNumber *) left < *(OffsetNumber *) right)
+ return (-1);
+ if (*(OffsetNumber *) left == *(OffsetNumber *) right)
+ return (0);
+ return (1);
-} /* vc_cmp_offno */
+} /* vc_cmp_offno */
static void
-vc_getindices (Oid relid, int *nindices, Relation **Irel)
+vc_getindices(Oid relid, int *nindices, Relation ** Irel)
{
- Relation pgindex;
- Relation irel;
- TupleDesc pgidesc;
- HeapTuple pgitup;
- HeapScanDesc pgiscan;
- Datum d;
- int i, k;
- bool n;
- ScanKeyData pgikey;
- Oid *ioid;
-
- *nindices = i = 0;
-
- ioid = (Oid *) palloc(10*sizeof(Oid));
-
- /* prepare a heap scan on the pg_index relation */
- pgindex = heap_openr(IndexRelationName);
- pgidesc = RelationGetTupleDescriptor(pgindex);
-
- ScanKeyEntryInitialize(&pgikey, 0x0, Anum_pg_index_indrelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- pgiscan = heap_beginscan(pgindex, false, NowTimeQual, 1, &pgikey);
-
- while (HeapTupleIsValid(pgitup = heap_getnext(pgiscan, 0, NULL))) {
- d = (Datum) heap_getattr(pgitup, InvalidBuffer, Anum_pg_index_indexrelid,
- pgidesc, &n);
- i++;
- if ( i % 10 == 0 )
- ioid = (Oid *) repalloc(ioid, (i+10)*sizeof(Oid));
- ioid[i-1] = DatumGetObjectId(d);
- }
-
- heap_endscan(pgiscan);
- heap_close(pgindex);
-
- if ( i == 0 ) { /* No one index found */
- pfree(ioid);
- return;
- }
-
- if ( Irel != (Relation **) NULL )
- *Irel = (Relation *) palloc(i * sizeof(Relation));
-
- for (k = 0; i > 0; )
- {
- irel = index_open(ioid[--i]);
- if ( irel != (Relation) NULL )
+ Relation pgindex;
+ Relation irel;
+ TupleDesc pgidesc;
+ HeapTuple pgitup;
+ HeapScanDesc pgiscan;
+ Datum d;
+ int i,
+ k;
+ bool n;
+ ScanKeyData pgikey;
+ Oid *ioid;
+
+ *nindices = i = 0;
+
+ ioid = (Oid *) palloc(10 * sizeof(Oid));
+
+ /* prepare a heap scan on the pg_index relation */
+ pgindex = heap_openr(IndexRelationName);
+ pgidesc = RelationGetTupleDescriptor(pgindex);
+
+ ScanKeyEntryInitialize(&pgikey, 0x0, Anum_pg_index_indrelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+
+ pgiscan = heap_beginscan(pgindex, false, NowTimeQual, 1, &pgikey);
+
+ while (HeapTupleIsValid(pgitup = heap_getnext(pgiscan, 0, NULL)))
{
- if ( Irel != (Relation **) NULL )
- (*Irel)[k] = irel;
- else
- index_close (irel);
- k++;
+ d = (Datum) heap_getattr(pgitup, InvalidBuffer, Anum_pg_index_indexrelid,
+ pgidesc, &n);
+ i++;
+ if (i % 10 == 0)
+ ioid = (Oid *) repalloc(ioid, (i + 10) * sizeof(Oid));
+ ioid[i - 1] = DatumGetObjectId(d);
}
- else
- elog (NOTICE, "CAN't OPEN INDEX %u - SKIP IT", ioid[i]);
- }
- *nindices = k;
- pfree(ioid);
- if ( Irel != (Relation **) NULL && *nindices == 0 )
- {
- pfree (*Irel);
- *Irel = (Relation *) NULL;
- }
+ heap_endscan(pgiscan);
+ heap_close(pgindex);
+
+ if (i == 0)
+ { /* No one index found */
+ pfree(ioid);
+ return;
+ }
+
+ if (Irel != (Relation **) NULL)
+ *Irel = (Relation *) palloc(i * sizeof(Relation));
+
+ for (k = 0; i > 0;)
+ {
+ irel = index_open(ioid[--i]);
+ if (irel != (Relation) NULL)
+ {
+ if (Irel != (Relation **) NULL)
+ (*Irel)[k] = irel;
+ else
+ index_close(irel);
+ k++;
+ }
+ else
+ elog(NOTICE, "CAN't OPEN INDEX %u - SKIP IT", ioid[i]);
+ }
+ *nindices = k;
+ pfree(ioid);
-} /* vc_getindices */
+ if (Irel != (Relation **) NULL && *nindices == 0)
+ {
+ pfree(*Irel);
+ *Irel = (Relation *) NULL;
+ }
+
+} /* vc_getindices */
static void
-vc_clsindices (int nindices, Relation *Irel)
+vc_clsindices(int nindices, Relation * Irel)
{
- if ( Irel == (Relation*) NULL )
- return;
+ if (Irel == (Relation *) NULL)
+ return;
- while (nindices--) {
- index_close (Irel[nindices]);
- }
- pfree (Irel);
+ while (nindices--)
+ {
+ index_close(Irel[nindices]);
+ }
+ pfree(Irel);
-} /* vc_clsindices */
+} /* vc_clsindices */
static void
-vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc)
+vc_mkindesc(Relation onerel, int nindices, Relation * Irel, IndDesc ** Idesc)
{
- IndDesc *idcur;
- HeapTuple pgIndexTup;
- AttrNumber *attnumP;
- int natts;
- int i;
-
- *Idesc = (IndDesc *) palloc (nindices * sizeof (IndDesc));
-
- for (i = 0, idcur = *Idesc; i < nindices; i++, idcur++) {
- pgIndexTup =
- SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(Irel[i]->rd_id),
- 0,0,0);
- Assert(pgIndexTup);
- idcur->tform = (IndexTupleForm)GETSTRUCT(pgIndexTup);
- for (attnumP = &(idcur->tform->indkey[0]), natts = 0;
- *attnumP != InvalidAttrNumber && natts != INDEX_MAX_KEYS;
- attnumP++, natts++);
- if (idcur->tform->indproc != InvalidOid) {
- idcur->finfoP = &(idcur->finfo);
- FIgetnArgs(idcur->finfoP) = natts;
- natts = 1;
- FIgetProcOid(idcur->finfoP) = idcur->tform->indproc;
- *(FIgetname(idcur->finfoP)) = '\0';
- } else
- idcur->finfoP = (FuncIndexInfo *) NULL;
-
- idcur->natts = natts;
- }
-
-} /* vc_mkindesc */
-
-
-static bool
-vc_enough_space (VPageDescr vpd, Size len)
+ IndDesc *idcur;
+ HeapTuple pgIndexTup;
+ AttrNumber *attnumP;
+ int natts;
+ int i;
+
+ *Idesc = (IndDesc *) palloc(nindices * sizeof(IndDesc));
+
+ for (i = 0, idcur = *Idesc; i < nindices; i++, idcur++)
+ {
+ pgIndexTup =
+ SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(Irel[i]->rd_id),
+ 0, 0, 0);
+ Assert(pgIndexTup);
+ idcur->tform = (IndexTupleForm) GETSTRUCT(pgIndexTup);
+ for (attnumP = &(idcur->tform->indkey[0]), natts = 0;
+ *attnumP != InvalidAttrNumber && natts != INDEX_MAX_KEYS;
+ attnumP++, natts++);
+ if (idcur->tform->indproc != InvalidOid)
+ {
+ idcur->finfoP = &(idcur->finfo);
+ FIgetnArgs(idcur->finfoP) = natts;
+ natts = 1;
+ FIgetProcOid(idcur->finfoP) = idcur->tform->indproc;
+ *(FIgetname(idcur->finfoP)) = '\0';
+ }
+ else
+ idcur->finfoP = (FuncIndexInfo *) NULL;
+
+ idcur->natts = natts;
+ }
+
+} /* vc_mkindesc */
+
+
+static bool
+vc_enough_space(VPageDescr vpd, Size len)
{
- len = DOUBLEALIGN(len);
-
- if ( len > vpd->vpd_free )
- return (false);
-
- if ( vpd->vpd_nusd < vpd->vpd_noff ) /* there are free itemid(s) */
- return (true); /* and len <= free_space */
-
- /* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */
- if ( len <= vpd->vpd_free - sizeof (ItemIdData) )
- return (true);
-
- return (false);
-
-} /* vc_enough_space */
+ len = DOUBLEALIGN(len);
+
+ if (len > vpd->vpd_free)
+ return (false);
+
+ if (vpd->vpd_nusd < vpd->vpd_noff) /* there are free itemid(s) */
+ return (true); /* and len <= free_space */
+
+ /* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */
+ if (len <= vpd->vpd_free - sizeof(ItemIdData))
+ return (true);
+
+ return (false);
+
+} /* vc_enough_space */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 3cd011ace25..99439de9ce3 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* view.c--
- * use rewrite rules to construct views
+ * use rewrite rules to construct views
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.8 1997/08/22 14:22:14 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.9 1997/09/07 04:41:06 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <postgres.h>
@@ -42,69 +42,74 @@
*---------------------------------------------------------------------
*/
static void
-DefineVirtualRelation(char *relname, List *tlist)
+DefineVirtualRelation(char *relname, List * tlist)
{
- CreateStmt createStmt;
- List *attrList, *t;
- TargetEntry *entry;
- Resdom *res;
- char *resname;
- char *restypename;
-
- /*
- * create a list with one entry per attribute of this relation.
- * Each entry is a two element list. The first element is the
- * name of the attribute (a string) and the second the name of the type
- * (NOTE: a string, not a type id!).
- */
- attrList = NIL;
- if (tlist!=NIL) {
- foreach (t, tlist ) {
- ColumnDef *def = makeNode(ColumnDef);
- TypeName *typename;
-
- /*
- * find the names of the attribute & its type
- */
- entry = lfirst(t);
- res = entry->resdom;
- resname = res->resname;
- restypename = tname(get_id_type(res->restype));
-
- typename = makeNode(TypeName);
-
- typename->name = pstrdup(restypename);
- def->colname = pstrdup(resname);
-
- def->typename = typename;
-
- def->is_not_null = false;
- def->defval = (char*) NULL;
-
- attrList = lappend(attrList, def);
+ CreateStmt createStmt;
+ List *attrList,
+ *t;
+ TargetEntry *entry;
+ Resdom *res;
+ char *resname;
+ char *restypename;
+
+ /*
+ * create a list with one entry per attribute of this relation. Each
+ * entry is a two element list. The first element is the name of the
+ * attribute (a string) and the second the name of the type (NOTE: a
+ * string, not a type id!).
+ */
+ attrList = NIL;
+ if (tlist != NIL)
+ {
+ foreach(t, tlist)
+ {
+ ColumnDef *def = makeNode(ColumnDef);
+ TypeName *typename;
+
+ /*
+ * find the names of the attribute & its type
+ */
+ entry = lfirst(t);
+ res = entry->resdom;
+ resname = res->resname;
+ restypename = tname(get_id_type(res->restype));
+
+ typename = makeNode(TypeName);
+
+ typename->name = pstrdup(restypename);
+ def->colname = pstrdup(resname);
+
+ def->typename = typename;
+
+ def->is_not_null = false;
+ def->defval = (char *) NULL;
+
+ attrList = lappend(attrList, def);
+ }
}
- } else {
- elog ( WARN, "attempted to define virtual relation with no attrs");
- }
-
- /*
- * now create the parametesr for keys/inheritance etc.
- * All of them are nil...
- */
- createStmt.relname = relname;
- createStmt.tableElts = attrList;
-/* createStmt.tableType = NULL;*/
- createStmt.inhRelnames = NIL;
- createStmt.archiveType = ARCH_NONE;
- createStmt.location = -1;
- createStmt.archiveLoc = -1;
- createStmt.constraints = NIL;
-
- /*
- * finally create the relation...
- */
- DefineRelation(&createStmt);
-}
+ else
+ {
+ elog(WARN, "attempted to define virtual relation with no attrs");
+ }
+
+ /*
+ * now create the parametesr for keys/inheritance etc. All of them are
+ * nil...
+ */
+ createStmt.relname = relname;
+ createStmt.tableElts = attrList;
+/* createStmt.tableType = NULL;*/
+ createStmt.inhRelnames = NIL;
+ createStmt.archiveType = ARCH_NONE;
+ createStmt.location = -1;
+ createStmt.archiveLoc = -1;
+ createStmt.constraints = NIL;
+
+ /*
+ * finally create the relation...
+ */
+ DefineRelation(&createStmt);
+}
/*------------------------------------------------------------------
* makeViewRetrieveRuleName
@@ -118,84 +123,87 @@ DefineVirtualRelation(char *relname, List *tlist)
* XXX it also means viewName cannot be 16 chars long! - ay 11/94
*------------------------------------------------------------------
*/
-char *
+char *
MakeRetrieveViewRuleName(char *viewName)
{
/*
- char buf[100];
+ char buf[100];
- memset(buf, 0, sizeof(buf));
- sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
- buf[15] = '\0';
- namestrcpy(rule_name, buf);
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
+ buf[15] = '\0';
+ namestrcpy(rule_name, buf);
*/
- char *buf;
- buf = palloc(strlen(viewName) + 5);
- sprintf(buf, "_RET%s",viewName);
- return buf;
+ char *buf;
+
+ buf = palloc(strlen(viewName) + 5);
+ sprintf(buf, "_RET%s", viewName);
+ return buf;
}
static RuleStmt *
-FormViewRetrieveRule(char *viewName, Query *viewParse)
+FormViewRetrieveRule(char *viewName, Query * viewParse)
{
- RuleStmt *rule;
- char *rname;
- Attr *attr;
-
- /*
- * Create a RuleStmt that corresponds to the suitable
- * rewrite rule args for DefineQueryRewrite();
- */
- rule = makeNode(RuleStmt);
- rname = MakeRetrieveViewRuleName(viewName);
-
- attr = makeNode(Attr);
- attr->relname = pstrdup(viewName);
-/* attr->refname = pstrdup(viewName);*/
- rule->rulename = pstrdup(rname);
- rule->whereClause = NULL;
- rule->event = CMD_SELECT;
- rule->object = attr;
- rule->instead = true;
- rule->actions = lcons(viewParse, NIL);
-
- return rule;
+ RuleStmt *rule;
+ char *rname;
+ Attr *attr;
+
+ /*
+ * Create a RuleStmt that corresponds to the suitable rewrite rule
+ * args for DefineQueryRewrite();
+ */
+ rule = makeNode(RuleStmt);
+ rname = MakeRetrieveViewRuleName(viewName);
+
+ attr = makeNode(Attr);
+ attr->relname = pstrdup(viewName);
+/* attr->refname = pstrdup(viewName);*/
+ rule->rulename = pstrdup(rname);
+ rule->whereClause = NULL;
+ rule->event = CMD_SELECT;
+ rule->object = attr;
+ rule->instead = true;
+ rule->actions = lcons(viewParse, NIL);
+
+ return rule;
}
static void
-DefineViewRules(char *viewName, Query *viewParse)
+DefineViewRules(char *viewName, Query * viewParse)
{
- RuleStmt *retrieve_rule = NULL;
+ RuleStmt *retrieve_rule = NULL;
+
#ifdef NOTYET
- RuleStmt *replace_rule = NULL;
- RuleStmt *append_rule = NULL;
- RuleStmt *delete_rule = NULL;
+ RuleStmt *replace_rule = NULL;
+ RuleStmt *append_rule = NULL;
+ RuleStmt *delete_rule = NULL;
+
#endif
-
- retrieve_rule =
- FormViewRetrieveRule(viewName, viewParse);
-
+
+ retrieve_rule =
+ FormViewRetrieveRule(viewName, viewParse);
+
#ifdef NOTYET
-
- replace_rule =
- FormViewReplaceRule(viewName, viewParse);
- append_rule =
- FormViewAppendRule(viewName, viewParse);
- delete_rule =
- FormViewDeleteRule(viewName, viewParse);
-
+
+ replace_rule =
+ FormViewReplaceRule(viewName, viewParse);
+ append_rule =
+ FormViewAppendRule(viewName, viewParse);
+ delete_rule =
+ FormViewDeleteRule(viewName, viewParse);
+
#endif
-
- DefineQueryRewrite(retrieve_rule);
+
+ DefineQueryRewrite(retrieve_rule);
#ifdef NOTYET
- DefineQueryRewrite(replace_rule);
- DefineQueryRewrite(append_rule);
- DefineQueryRewrite(delete_rule);
+ DefineQueryRewrite(replace_rule);
+ DefineQueryRewrite(append_rule);
+ DefineQueryRewrite(delete_rule);
#endif
-
-}
+
+}
/*---------------------------------------------------------------
* UpdateRangeTableOfViewParse
@@ -216,88 +224,84 @@ DefineViewRules(char *viewName, Query *viewParse)
*---------------------------------------------------------------
*/
static void
-UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
+UpdateRangeTableOfViewParse(char *viewName, Query * viewParse)
{
- List *old_rt;
- List *new_rt;
- RangeTblEntry *rt_entry1, *rt_entry2;
-
- /*
- * first offset all var nodes by 2
- */
- OffsetVarNodes((Node*)viewParse->targetList, 2);
- OffsetVarNodes(viewParse->qual, 2);
-
- /*
- * find the old range table...
- */
- old_rt = viewParse->rtable;
-
- /*
- * create the 2 new range table entries and form the new
- * range table...
- * CURRENT first, then NEW....
- */
- rt_entry1 =
- addRangeTableEntry(NULL, (char*)viewName, "*CURRENT*",
- FALSE, FALSE, NULL);
- rt_entry2 =
- addRangeTableEntry(NULL, (char*)viewName, "*NEW*",
- FALSE, FALSE, NULL);
- new_rt = lcons(rt_entry2, old_rt);
- new_rt = lcons(rt_entry1, new_rt);
-
- /*
- * Now the tricky part....
- * Update the range table in place... Be careful here, or
- * hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
- */
- viewParse->rtable = new_rt;
+ List *old_rt;
+ List *new_rt;
+ RangeTblEntry *rt_entry1,
+ *rt_entry2;
+
+ /*
+ * first offset all var nodes by 2
+ */
+ OffsetVarNodes((Node *) viewParse->targetList, 2);
+ OffsetVarNodes(viewParse->qual, 2);
+
+ /*
+ * find the old range table...
+ */
+ old_rt = viewParse->rtable;
+
+ /*
+ * create the 2 new range table entries and form the new range
+ * table... CURRENT first, then NEW....
+ */
+ rt_entry1 =
+ addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
+ FALSE, FALSE, NULL);
+ rt_entry2 =
+ addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
+ FALSE, FALSE, NULL);
+ new_rt = lcons(rt_entry2, old_rt);
+ new_rt = lcons(rt_entry1, new_rt);
+
+ /*
+ * Now the tricky part.... Update the range table in place... Be
+ * careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
+ */
+ viewParse->rtable = new_rt;
}
/*-------------------------------------------------------------------
* DefineView
*
- * - takes a "viewname", "parsetree" pair and then
- * 1) construct the "virtual" relation
- * 2) commit the command but NOT the transaction,
- * so that the relation exists
- * before the rules are defined.
- * 2) define the "n" rules specified in the PRS2 paper
- * over the "virtual" relation
+ * - takes a "viewname", "parsetree" pair and then
+ * 1) construct the "virtual" relation
+ * 2) commit the command but NOT the transaction,
+ * so that the relation exists
+ * before the rules are defined.
+ * 2) define the "n" rules specified in the PRS2 paper
+ * over the "virtual" relation
*-------------------------------------------------------------------
*/
void
-DefineView(char *viewName, Query *viewParse)
+DefineView(char *viewName, Query * viewParse)
{
- List *viewTlist;
-
- viewTlist = viewParse->targetList;
-
- /*
- * Create the "view" relation
- * NOTE: if it already exists, the xaxt will be aborted.
- */
- DefineVirtualRelation(viewName, viewTlist);
-
- /*
- * The relation we have just created is not visible
- * to any other commands running with the same transaction &
- * command id.
- * So, increment the command id counter (but do NOT pfree any
- * memory!!!!)
- */
- CommandCounterIncrement();
-
- /*
- * The range table of 'viewParse' does not contain entries
- * for the "CURRENT" and "NEW" relations.
- * So... add them!
- * NOTE: we make the update in place! After this call 'viewParse'
- * will never be what it used to be...
- */
- UpdateRangeTableOfViewParse(viewName, viewParse);
- DefineViewRules(viewName, viewParse);
+ List *viewTlist;
+
+ viewTlist = viewParse->targetList;
+
+ /*
+ * Create the "view" relation NOTE: if it already exists, the xaxt
+ * will be aborted.
+ */
+ DefineVirtualRelation(viewName, viewTlist);
+
+ /*
+ * The relation we have just created is not visible to any other
+ * commands running with the same transaction & command id. So,
+ * increment the command id counter (but do NOT pfree any memory!!!!)
+ */
+ CommandCounterIncrement();
+
+ /*
+ * The range table of 'viewParse' does not contain entries for the
+ * "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
+ * update in place! After this call 'viewParse' will never be what it
+ * used to be...
+ */
+ UpdateRangeTableOfViewParse(viewName, viewParse);
+ DefineViewRules(viewName, viewParse);
}
/*------------------------------------------------------------------
@@ -309,23 +313,22 @@ DefineView(char *viewName, Query *viewParse)
void
RemoveView(char *viewName)
{
- char* rname;
-
- /*
- * first remove all the "view" rules...
- * Currently we only have one!
- */
- rname = MakeRetrieveViewRuleName(viewName);
- RemoveRewriteRule(rname);
-
- /*
- * we don't really need that, but just in case...
- */
- CommandCounterIncrement();
-
- /*
- * now remove the relation.
- */
- heap_destroy(viewName);
- pfree(rname);
+ char *rname;
+
+ /*
+ * first remove all the "view" rules... Currently we only have one!
+ */
+ rname = MakeRetrieveViewRuleName(viewName);
+ RemoveRewriteRule(rname);
+
+ /*
+ * we don't really need that, but just in case...
+ */
+ CommandCounterIncrement();
+
+ /*
+ * now remove the relation.
+ */
+ heap_destroy(viewName);
+ pfree(rname);
}
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 84b33d4f1e1..401924485e0 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -1,32 +1,32 @@
/*-------------------------------------------------------------------------
*
* execAmi.c--
- * miscellanious executor access method routines
+ * miscellanious executor access method routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.5 1997/08/19 21:30:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execAmi.c,v 1.6 1997/09/07 04:41:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
+ * INTERFACE ROUTINES
*
- * ExecOpenScanR \ / amopen
- * ExecBeginScan \ / ambeginscan
- * ExecCloseR \ / amclose
- * ExecInsert \ executor interface / aminsert
- * ExecReScanNode / to access methods \ amrescan
- * ExecReScanR / \ amrescan
- * ExecMarkPos / \ ammarkpos
- * ExecRestrPos / \ amrestpos
+ * ExecOpenScanR \ / amopen
+ * ExecBeginScan \ / ambeginscan
+ * ExecCloseR \ / amclose
+ * ExecInsert \ executor interface / aminsert
+ * ExecReScanNode / to access methods \ amrescan
+ * ExecReScanR / \ amrescan
+ * ExecMarkPos / \ ammarkpos
+ * ExecRestrPos / \ amrestpos
*
- * ExecCreatR function to create temporary relations
+ * ExecCreatR function to create temporary relations
*
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include "postgres.h"
@@ -43,409 +43,430 @@
#include "access/heapam.h"
#include "catalog/heap.h"
-static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
- bool isindex, ScanDirection dir, TimeQual time_range);
+static Pointer
+ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
+ bool isindex, ScanDirection dir, TimeQual time_range);
static Relation ExecOpenR(Oid relationOid, bool isindex);
/* ----------------------------------------------------------------
- * ExecOpenScanR
+ * ExecOpenScanR
*
* old comments:
- * Parameters:
- * relation -- relation to be opened and scanned.
- * nkeys -- number of keys
- * skeys -- keys to restrict scanning
- * isindex -- if this is true, the relation is the relid of
- * an index relation, else it is an index into the
- * range table.
- * Returns the relation as(relDesc scanDesc)
- * If this structure is changed, need to modify the access macros
- * defined in execInt.h.
+ * Parameters:
+ * relation -- relation to be opened and scanned.
+ * nkeys -- number of keys
+ * skeys -- keys to restrict scanning
+ * isindex -- if this is true, the relation is the relid of
+ * an index relation, else it is an index into the
+ * range table.
+ * Returns the relation as(relDesc scanDesc)
+ * If this structure is changed, need to modify the access macros
+ * defined in execInt.h.
* ----------------------------------------------------------------
*/
void
ExecOpenScanR(Oid relOid,
- int nkeys,
- ScanKey skeys,
- bool isindex,
- ScanDirection dir,
- TimeQual timeRange,
- Relation *returnRelation, /* return */
- Pointer *returnScanDesc) /* return */
+ int nkeys,
+ ScanKey skeys,
+ bool isindex,
+ ScanDirection dir,
+ TimeQual timeRange,
+ Relation * returnRelation, /* return */
+ Pointer * returnScanDesc) /* return */
{
- Relation relation;
- Pointer scanDesc;
-
- /* ----------------
- * note: scanDesc returned by ExecBeginScan can be either
- * a HeapScanDesc or an IndexScanDesc so for now we
- * make it a Pointer. There should be a better scan
- * abstraction someday -cim 9/9/89
- * ----------------
- */
- relation = ExecOpenR(relOid, isindex);
- scanDesc = ExecBeginScan(relation,
- nkeys,
- skeys,
- isindex,
- dir,
- timeRange);
-
- if (returnRelation != NULL)
- *returnRelation = relation;
- if (scanDesc != NULL)
- *returnScanDesc = scanDesc;
+ Relation relation;
+ Pointer scanDesc;
+
+ /* ----------------
+ * note: scanDesc returned by ExecBeginScan can be either
+ * a HeapScanDesc or an IndexScanDesc so for now we
+ * make it a Pointer. There should be a better scan
+ * abstraction someday -cim 9/9/89
+ * ----------------
+ */
+ relation = ExecOpenR(relOid, isindex);
+ scanDesc = ExecBeginScan(relation,
+ nkeys,
+ skeys,
+ isindex,
+ dir,
+ timeRange);
+
+ if (returnRelation != NULL)
+ *returnRelation = relation;
+ if (scanDesc != NULL)
+ *returnScanDesc = scanDesc;
}
-
+
/* ----------------------------------------------------------------
- * ExecOpenR
+ * ExecOpenR
*
- * returns a relation descriptor given an object id.
+ * returns a relation descriptor given an object id.
* ----------------------------------------------------------------
*/
-static Relation
+static Relation
ExecOpenR(Oid relationOid, bool isindex)
{
- Relation relation;
- relation = (Relation) NULL;
-
- /* ----------------
- * open the relation with the correct call depending
- * on whether this is a heap relation or an index relation.
- * ----------------
- */
- if (isindex) {
- relation = index_open(relationOid);
- } else
- relation = heap_open(relationOid);
-
- if (relation == NULL)
- elog(DEBUG, "ExecOpenR: relation == NULL, heap_open failed.");
-
- return relation;
+ Relation relation;
+
+ relation = (Relation) NULL;
+
+ /* ----------------
+ * open the relation with the correct call depending
+ * on whether this is a heap relation or an index relation.
+ * ----------------
+ */
+ if (isindex)
+ {
+ relation = index_open(relationOid);
+ }
+ else
+ relation = heap_open(relationOid);
+
+ if (relation == NULL)
+ elog(DEBUG, "ExecOpenR: relation == NULL, heap_open failed.");
+
+ return relation;
}
-
+
/* ----------------------------------------------------------------
- * ExecBeginScan
+ * ExecBeginScan
*
- * beginscans a relation in current direction.
+ * beginscans a relation in current direction.
*
- * XXX fix parameters to AMbeginscan (and btbeginscan)
- * currently we need to pass a flag stating whether
- * or not the scan should begin at an endpoint of
- * the relation.. Right now we always pass false
- * -cim 9/14/89
+ * XXX fix parameters to AMbeginscan (and btbeginscan)
+ * currently we need to pass a flag stating whether
+ * or not the scan should begin at an endpoint of
+ * the relation.. Right now we always pass false
+ * -cim 9/14/89
* ----------------------------------------------------------------
*/
-static Pointer
+static Pointer
ExecBeginScan(Relation relation,
- int nkeys,
- ScanKey skeys,
- bool isindex,
- ScanDirection dir,
- TimeQual time_range)
+ int nkeys,
+ ScanKey skeys,
+ bool isindex,
+ ScanDirection dir,
+ TimeQual time_range)
{
- Pointer scanDesc;
-
- scanDesc = NULL;
-
- /* ----------------
- * open the appropriate type of scan.
- *
- * Note: ambeginscan()'s second arg is a boolean indicating
- * that the scan should be done in reverse.. That is,
- * if you pass it true, then the scan is backward.
- * ----------------
- */
- if (isindex) {
- scanDesc = (Pointer) index_beginscan(relation,
- false, /* see above comment */
- nkeys,
- skeys);
- } else {
- scanDesc = (Pointer) heap_beginscan(relation,
- ScanDirectionIsBackward(dir),
- time_range,
- nkeys,
- skeys);
- }
-
- if (scanDesc == NULL)
- elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
-
-
- return scanDesc;
+ Pointer scanDesc;
+
+ scanDesc = NULL;
+
+ /* ----------------
+ * open the appropriate type of scan.
+ *
+ * Note: ambeginscan()'s second arg is a boolean indicating
+ * that the scan should be done in reverse.. That is,
+ * if you pass it true, then the scan is backward.
+ * ----------------
+ */
+ if (isindex)
+ {
+ scanDesc = (Pointer) index_beginscan(relation,
+ false, /* see above comment */
+ nkeys,
+ skeys);
+ }
+ else
+ {
+ scanDesc = (Pointer) heap_beginscan(relation,
+ ScanDirectionIsBackward(dir),
+ time_range,
+ nkeys,
+ skeys);
+ }
+
+ if (scanDesc == NULL)
+ elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
+
+
+ return scanDesc;
}
-
+
/* ----------------------------------------------------------------
- * ExecCloseR
+ * ExecCloseR
*
- * closes the relation and scan descriptor for a scan or sort
- * node. Also closes index relations and scans for index scans.
+ * closes the relation and scan descriptor for a scan or sort
+ * node. Also closes index relations and scans for index scans.
*
* old comments
- * closes the relation indicated in 'relID'
+ * closes the relation indicated in 'relID'
* ----------------------------------------------------------------
*/
void
-ExecCloseR(Plan *node)
+ExecCloseR(Plan * node)
{
- CommonScanState *state;
- Relation relation;
- HeapScanDesc scanDesc;
-
- /* ----------------
- * shut down the heap scan and close the heap relation
- * ----------------
- */
- switch (nodeTag(node)) {
-
- case T_SeqScan:
- state = ((SeqScan *)node)->scanstate;
- break;
-
- case T_IndexScan:
- state = ((IndexScan *)node)->scan.scanstate;
- break;
-
- case T_Material:
- state = &(((Material *)node)->matstate->csstate);
- break;
-
- case T_Sort:
- state = &(((Sort *)node)->sortstate->csstate);
- break;
-
- case T_Agg:
- state = &(((Agg *)node)->aggstate->csstate);
- break;
-
- default:
- elog(DEBUG, "ExecCloseR: not a scan, material, or sort node!");
- return;
- }
-
- relation = state->css_currentRelation;
- scanDesc = state->css_currentScanDesc;
-
- if (scanDesc != NULL)
- heap_endscan(scanDesc);
-
- if (relation != NULL)
- heap_close(relation);
-
- /* ----------------
- * if this is an index scan then we have to take care
- * of the index relations as well..
- * ----------------
- */
- if (nodeTag(node) == T_IndexScan) {
- IndexScan *iscan= (IndexScan *)node;
- IndexScanState *indexstate;
- int numIndices;
- RelationPtr indexRelationDescs;
- IndexScanDescPtr indexScanDescs;
- int i;
-
- indexstate = iscan->indxstate;
- numIndices = indexstate->iss_NumIndices;
- indexRelationDescs = indexstate->iss_RelationDescs;
- indexScanDescs = indexstate->iss_ScanDescs;
-
- for (i = 0; i<numIndices; i++) {
- /* ----------------
- * shut down each of the scans and
- * close each of the index relations
- * ----------------
- */
- if (indexScanDescs[i] != NULL)
- index_endscan(indexScanDescs[i]);
-
- if (indexRelationDescs[i] != NULL)
- index_close(indexRelationDescs[i]);
+ CommonScanState *state;
+ Relation relation;
+ HeapScanDesc scanDesc;
+
+ /* ----------------
+ * shut down the heap scan and close the heap relation
+ * ----------------
+ */
+ switch (nodeTag(node))
+ {
+
+ case T_SeqScan:
+ state = ((SeqScan *) node)->scanstate;
+ break;
+
+ case T_IndexScan:
+ state = ((IndexScan *) node)->scan.scanstate;
+ break;
+
+ case T_Material:
+ state = &(((Material *) node)->matstate->csstate);
+ break;
+
+ case T_Sort:
+ state = &(((Sort *) node)->sortstate->csstate);
+ break;
+
+ case T_Agg:
+ state = &(((Agg *) node)->aggstate->csstate);
+ break;
+
+ default:
+ elog(DEBUG, "ExecCloseR: not a scan, material, or sort node!");
+ return;
+ }
+
+ relation = state->css_currentRelation;
+ scanDesc = state->css_currentScanDesc;
+
+ if (scanDesc != NULL)
+ heap_endscan(scanDesc);
+
+ if (relation != NULL)
+ heap_close(relation);
+
+ /* ----------------
+ * if this is an index scan then we have to take care
+ * of the index relations as well..
+ * ----------------
+ */
+ if (nodeTag(node) == T_IndexScan)
+ {
+ IndexScan *iscan = (IndexScan *) node;
+ IndexScanState *indexstate;
+ int numIndices;
+ RelationPtr indexRelationDescs;
+ IndexScanDescPtr indexScanDescs;
+ int i;
+
+ indexstate = iscan->indxstate;
+ numIndices = indexstate->iss_NumIndices;
+ indexRelationDescs = indexstate->iss_RelationDescs;
+ indexScanDescs = indexstate->iss_ScanDescs;
+
+ for (i = 0; i < numIndices; i++)
+ {
+ /* ----------------
+ * shut down each of the scans and
+ * close each of the index relations
+ * ----------------
+ */
+ if (indexScanDescs[i] != NULL)
+ index_endscan(indexScanDescs[i]);
+
+ if (indexRelationDescs[i] != NULL)
+ index_close(indexRelationDescs[i]);
+ }
}
- }
}
-
+
/* ----------------------------------------------------------------
- * ExecReScan
+ * ExecReScan
*
- * XXX this should be extended to cope with all the node types..
+ * XXX this should be extended to cope with all the node types..
*
- * takes the new expression context as an argument, so that
- * index scans needn't have their scan keys updated separately
- * - marcel 09/20/94
+ * takes the new expression context as an argument, so that
+ * index scans needn't have their scan keys updated separately
+ * - marcel 09/20/94
* ----------------------------------------------------------------
*/
void
-ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
+ExecReScan(Plan * node, ExprContext * exprCtxt, Plan * parent)
{
- switch(nodeTag(node)) {
- case T_SeqScan:
- ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
- return;
-
- case T_IndexScan:
- ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
- return;
+ switch (nodeTag(node))
+ {
+ case T_SeqScan:
+ ExecSeqReScan((SeqScan *) node, exprCtxt, parent);
+ return;
- case T_Material:
- /* the first call to ExecReScan should have no effect because
- * everything is initialized properly already. the following
- * calls will be handled by ExecSeqReScan() because the nodes
- * below the Material node have already been materialized into
- * a temp relation.
- */
- return;
+ case T_IndexScan:
+ ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
+ return;
- case T_Tee:
- ExecTeeReScan((Tee*) node, exprCtxt, parent);
- break;
+ case T_Material:
- default:
- elog(WARN, "ExecReScan: not a seqscan or indexscan node.");
- return;
- }
+ /*
+ * the first call to ExecReScan should have no effect because
+ * everything is initialized properly already. the following
+ * calls will be handled by ExecSeqReScan() because the nodes
+ * below the Material node have already been materialized into a
+ * temp relation.
+ */
+ return;
+
+ case T_Tee:
+ ExecTeeReScan((Tee *) node, exprCtxt, parent);
+ break;
+
+ default:
+ elog(WARN, "ExecReScan: not a seqscan or indexscan node.");
+ return;
+ }
}
-
+
/* ----------------------------------------------------------------
- * ExecReScanR
+ * ExecReScanR
*
- * XXX this does not do the right thing with indices yet.
+ * XXX this does not do the right thing with indices yet.
* ----------------------------------------------------------------
*/
HeapScanDesc
-ExecReScanR(Relation relDesc, /* LLL relDesc unused */
- HeapScanDesc scanDesc,
- ScanDirection direction,
- int nkeys, /* LLL nkeys unused */
- ScanKey skeys)
+ExecReScanR(Relation relDesc, /* LLL relDesc unused */
+ HeapScanDesc scanDesc,
+ ScanDirection direction,
+ int nkeys, /* LLL nkeys unused */
+ ScanKey skeys)
{
- if (scanDesc != NULL)
- heap_rescan(scanDesc, /* scan desc */
- ScanDirectionIsBackward(direction), /* backward flag */
- skeys); /* scan keys */
-
- return scanDesc;
+ if (scanDesc != NULL)
+ heap_rescan(scanDesc, /* scan desc */
+ ScanDirectionIsBackward(direction), /* backward flag */
+ skeys); /* scan keys */
+
+ return scanDesc;
}
-
+
/* ----------------------------------------------------------------
- * ExecMarkPos
+ * ExecMarkPos
*
- * Marks the current scan position.
+ * Marks the current scan position.
*
- * XXX Needs to be extended to include all the node types.
+ * XXX Needs to be extended to include all the node types.
* ----------------------------------------------------------------
*/
void
-ExecMarkPos(Plan *node)
+ExecMarkPos(Plan * node)
{
- switch(nodeTag(node)) {
- case T_SeqScan:
- ExecSeqMarkPos((SeqScan *) node);
- break;
-
- case T_IndexScan:
- ExecIndexMarkPos((IndexScan *) node);
- break;
-
- case T_Sort:
- ExecSortMarkPos((Sort *) node);
- break;
-
- default:
- /* elog(DEBUG, "ExecMarkPos: unsupported node type"); */
- break;
- }
- return;
+ switch (nodeTag(node))
+ {
+ case T_SeqScan:
+ ExecSeqMarkPos((SeqScan *) node);
+ break;
+
+ case T_IndexScan:
+ ExecIndexMarkPos((IndexScan *) node);
+ break;
+
+ case T_Sort:
+ ExecSortMarkPos((Sort *) node);
+ break;
+
+ default:
+ /* elog(DEBUG, "ExecMarkPos: unsupported node type"); */
+ break;
+ }
+ return;
}
-
+
/* ----------------------------------------------------------------
- * ExecRestrPos
+ * ExecRestrPos
*
- * restores the scan position previously saved with ExecMarkPos()
+ * restores the scan position previously saved with ExecMarkPos()
* ----------------------------------------------------------------
*/
void
-ExecRestrPos(Plan *node)
+ExecRestrPos(Plan * node)
{
- switch(nodeTag(node)) {
- case T_SeqScan:
- ExecSeqRestrPos((SeqScan *) node);
- return;
-
- case T_IndexScan:
- ExecIndexRestrPos((IndexScan *) node);
- return;
-
- case T_Sort:
- ExecSortRestrPos((Sort *) node);
- return;
+ switch (nodeTag(node))
+ {
+ case T_SeqScan:
+ ExecSeqRestrPos((SeqScan *) node);
+ return;
- default:
- /* elog(DEBUG, "ExecRestrPos: node type not supported"); */
- return;
- }
+ case T_IndexScan:
+ ExecIndexRestrPos((IndexScan *) node);
+ return;
+
+ case T_Sort:
+ ExecSortRestrPos((Sort *) node);
+ return;
+
+ default:
+ /* elog(DEBUG, "ExecRestrPos: node type not supported"); */
+ return;
+ }
}
-
+
/* ----------------------------------------------------------------
- * ExecCreatR
+ * ExecCreatR
*
* old comments
- * Creates a relation.
+ * Creates a relation.
*
- * Parameters:
- * attrType -- type information on the attributes.
- * accessMtd -- access methods used to access the created relation.
- * relation -- optional. Either an index to the range table or
- * negative number indicating a temporary relation.
- * A temporary relation is assume is this field is absent.
+ * Parameters:
+ * attrType -- type information on the attributes.
+ * accessMtd -- access methods used to access the created relation.
+ * relation -- optional. Either an index to the range table or
+ * negative number indicating a temporary relation.
+ * A temporary relation is assume is this field is absent.
* ----------------------------------------------------------------
*/
Relation
ExecCreatR(TupleDesc tupType,
- Oid relationOid)
+ Oid relationOid)
{
- Relation relDesc;
-
- EU3_printf("ExecCreatR: %s type=%d oid=%d\n",
- "entering: ", tupType, relationOid);
- CXT1_printf("ExecCreatR: context is %d\n", CurrentMemoryContext);
-
- relDesc = NULL;
-
- if (relationOid == _TEMP_RELATION_ID_ ) {
- /* ----------------
- * create a temporary relation
- * (currently the planner always puts a _TEMP_RELATION_ID
- * in the relation argument so we expect this to be the case although
- * it's possible that someday we'll get the name from
- * from the range table.. -cim 10/12/89)
- * ----------------
- */
+ Relation relDesc;
+
+ EU3_printf("ExecCreatR: %s type=%d oid=%d\n",
+ "entering: ", tupType, relationOid);
+ CXT1_printf("ExecCreatR: context is %d\n", CurrentMemoryContext);
+
+ relDesc = NULL;
+
+ if (relationOid == _TEMP_RELATION_ID_)
+ {
+ /* ----------------
+ * create a temporary relation
+ * (currently the planner always puts a _TEMP_RELATION_ID
+ * in the relation argument so we expect this to be the case although
+ * it's possible that someday we'll get the name from
+ * from the range table.. -cim 10/12/89)
+ * ----------------
+ */
/*
- sprintf(tempname, "temp_%d.%d", getpid(), tmpcnt++);
- EU1_printf("ExecCreatR: attempting to create %s\n", tempname);
+ sprintf(tempname, "temp_%d.%d", getpid(), tmpcnt++);
+ EU1_printf("ExecCreatR: attempting to create %s\n", tempname);
*/
- /* heap_creatr creates a name if the argument to heap_creatr is '\0 ' */
- relDesc = heap_creatr("",
- DEFAULT_SMGR,
- tupType);
- } else {
- /* ----------------
- * use a relation from the range table
- * ----------------
- */
- elog(DEBUG, "ExecCreatR: %s",
- "stuff using range table id's is not functional");
- }
-
- if (relDesc == NULL)
- elog(DEBUG, "ExecCreatR: failed to create relation.");
-
- EU1_printf("ExecCreatR: returning relDesc=%d\n", relDesc);
-
- return relDesc;
+
+ /*
+ * heap_creatr creates a name if the argument to heap_creatr is
+ * '\0 '
+ */
+ relDesc = heap_creatr("",
+ DEFAULT_SMGR,
+ tupType);
+ }
+ else
+ {
+ /* ----------------
+ * use a relation from the range table
+ * ----------------
+ */
+ elog(DEBUG, "ExecCreatR: %s",
+ "stuff using range table id's is not functional");
+ }
+
+ if (relDesc == NULL)
+ elog(DEBUG, "ExecCreatR: failed to create relation.");
+
+ EU1_printf("ExecCreatR: returning relDesc=%d\n", relDesc);
+
+ return relDesc;
}
-
diff --git a/src/backend/executor/execFlatten.c b/src/backend/executor/execFlatten.c
index c9bde2ff663..43d616712fa 100644
--- a/src/backend/executor/execFlatten.c
+++ b/src/backend/executor/execFlatten.c
@@ -1,29 +1,29 @@
/*-------------------------------------------------------------------------
*
* execFlatten.c--
- * This file handles the nodes associated with flattening sets in the
- * target list of queries containing functions returning sets.
+ * This file handles the nodes associated with flattening sets in the
+ * target list of queries containing functions returning sets.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/Attic/execFlatten.c,v 1.2 1997/08/19 21:30:56 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/Attic/execFlatten.c,v 1.3 1997/09/07 04:41:12 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* ExecEvalIter() -
- * Iterate through the all return tuples/base types from a function one
- * at time (i.e. one per ExecEvalIter call). Not really needed for
- * postquel functions, but for reasons of orthogonality, these nodes
- * exist above pq functions as well as c functions.
+ * Iterate through the all return tuples/base types from a function one
+ * at time (i.e. one per ExecEvalIter call). Not really needed for
+ * postquel functions, but for reasons of orthogonality, these nodes
+ * exist above pq functions as well as c functions.
*
* ExecEvalFjoin() -
- * Given N Iter nodes return a vector of all combinations of results
- * one at a time (i.e. one result vector per ExecEvalFjoin call). This
- * node does the actual flattening work.
+ * Given N Iter nodes return a vector of all combinations of results
+ * one at a time (i.e. one result vector per ExecEvalFjoin call). This
+ * node does the actual flattening work.
*/
#include "postgres.h"
#include "nodes/primnodes.h"
@@ -33,208 +33,216 @@
#include "executor/execFlatten.h"
#ifdef SETS_FIXED
-static bool FjoinBumpOuterNodes(TargetEntry *tlist, ExprContext *econtext,
- DatumPtr results, char *nulls);
+static bool
+FjoinBumpOuterNodes(TargetEntry * tlist, ExprContext * econtext,
+ DatumPtr results, char *nulls);
+
#endif
Datum
-ExecEvalIter(Iter *iterNode,
- ExprContext *econtext,
- bool *resultIsNull,
- bool *iterIsDone)
+ExecEvalIter(Iter * iterNode,
+ ExprContext * econtext,
+ bool * resultIsNull,
+ bool * iterIsDone)
{
- Node *expression;
-
- expression = iterNode->iterexpr;
-
- /*
- * Really Iter nodes are only needed for C functions, postquel function
- * by their nature return 1 result at a time. For now we are only worrying
- * about postquel functions, c functions will come later.
- */
- return ExecEvalExpr(expression, econtext, resultIsNull, iterIsDone);
+ Node *expression;
+
+ expression = iterNode->iterexpr;
+
+ /*
+ * Really Iter nodes are only needed for C functions, postquel
+ * function by their nature return 1 result at a time. For now we are
+ * only worrying about postquel functions, c functions will come
+ * later.
+ */
+ return ExecEvalExpr(expression, econtext, resultIsNull, iterIsDone);
}
void
-ExecEvalFjoin(TargetEntry *tlist,
- ExprContext *econtext,
- bool *isNullVect,
- bool *fj_isDone)
+ExecEvalFjoin(TargetEntry * tlist,
+ ExprContext * econtext,
+ bool * isNullVect,
+ bool * fj_isDone)
{
#ifdef SETS_FIXED
- bool isDone;
- int curNode;
- List *tlistP;
-
- Fjoin *fjNode = tlist->fjoin;
- DatumPtr resVect = fjNode->fj_results;
- BoolPtr alwaysDone = fjNode->fj_alwaysDone;
-
- if (fj_isDone) *fj_isDone = false;
- /*
- * For the next tuple produced by the plan, we need to re-initialize
- * the Fjoin node.
- */
- if (!fjNode->fj_initialized)
+ bool isDone;
+ int curNode;
+ List *tlistP;
+
+ Fjoin *fjNode = tlist->fjoin;
+ DatumPtr resVect = fjNode->fj_results;
+ BoolPtr alwaysDone = fjNode->fj_alwaysDone;
+
+ if (fj_isDone)
+ *fj_isDone = false;
+
+ /*
+ * For the next tuple produced by the plan, we need to re-initialize
+ * the Fjoin node.
+ */
+ if (!fjNode->fj_initialized)
{
- /*
- * Initialize all of the Outer nodes
- */
- curNode = 1;
- foreach(tlistP, lnext(tlist))
+
+ /*
+ * Initialize all of the Outer nodes
+ */
+ curNode = 1;
+ foreach(tlistP, lnext(tlist))
{
- TargetEntry *tle = lfirst(tlistP);
-
- resVect[curNode] = ExecEvalIter((Iter*)tle->expr,
- econtext,
- &isNullVect[curNode],
- &isDone);
- if (isDone)
- isNullVect[curNode] = alwaysDone[curNode] = true;
- else
- alwaysDone[curNode] = false;
-
- curNode++;
+ TargetEntry *tle = lfirst(tlistP);
+
+ resVect[curNode] = ExecEvalIter((Iter *) tle->expr,
+ econtext,
+ &isNullVect[curNode],
+ &isDone);
+ if (isDone)
+ isNullVect[curNode] = alwaysDone[curNode] = true;
+ else
+ alwaysDone[curNode] = false;
+
+ curNode++;
}
-
- /*
- * Initialize the inner node
- */
- resVect[0] = ExecEvalIter((Iter*)fjNode->fj_innerNode->expr,
- econtext,
- &isNullVect[0],
- &isDone);
- if (isDone)
- isNullVect[0] = alwaysDone[0] = true;
- else
- alwaysDone[0] = false;
-
- /*
- * Mark the Fjoin as initialized now.
- */
- fjNode->fj_initialized = TRUE;
-
- /*
- * If the inner node is always done, then we are done for now
- */
- if (isDone)
- return;
+
+ /*
+ * Initialize the inner node
+ */
+ resVect[0] = ExecEvalIter((Iter *) fjNode->fj_innerNode->expr,
+ econtext,
+ &isNullVect[0],
+ &isDone);
+ if (isDone)
+ isNullVect[0] = alwaysDone[0] = true;
+ else
+ alwaysDone[0] = false;
+
+ /*
+ * Mark the Fjoin as initialized now.
+ */
+ fjNode->fj_initialized = TRUE;
+
+ /*
+ * If the inner node is always done, then we are done for now
+ */
+ if (isDone)
+ return;
}
- else
+ else
{
- /*
- * If we're already initialized, all we need to do is get the
- * next inner result and pair it up with the existing outer node
- * result vector. Watch out for the degenerate case, where the
- * inner node never returns results.
- */
-
- /*
- * Fill in nulls for every function that is always done.
- */
- for (curNode=fjNode->fj_nNodes-1; curNode >= 0; curNode--)
- isNullVect[curNode] = alwaysDone[curNode];
-
- if (alwaysDone[0] == true)
+
+ /*
+ * If we're already initialized, all we need to do is get the next
+ * inner result and pair it up with the existing outer node result
+ * vector. Watch out for the degenerate case, where the inner
+ * node never returns results.
+ */
+
+ /*
+ * Fill in nulls for every function that is always done.
+ */
+ for (curNode = fjNode->fj_nNodes - 1; curNode >= 0; curNode--)
+ isNullVect[curNode] = alwaysDone[curNode];
+
+ if (alwaysDone[0] == true)
{
- *fj_isDone = FjoinBumpOuterNodes(tlist,
- econtext,
- resVect,
- isNullVect);
- return;
+ *fj_isDone = FjoinBumpOuterNodes(tlist,
+ econtext,
+ resVect,
+ isNullVect);
+ return;
}
- else
- resVect[0] = ExecEvalIter((Iter*)fjNode->fj_innerNode->expr,
- econtext,
- &isNullVect[0],
- &isDone);
+ else
+ resVect[0] = ExecEvalIter((Iter *) fjNode->fj_innerNode->expr,
+ econtext,
+ &isNullVect[0],
+ &isDone);
}
-
- /*
- * if the inner node is done
- */
- if (isDone)
+
+ /*
+ * if the inner node is done
+ */
+ if (isDone)
{
- *fj_isDone = FjoinBumpOuterNodes(tlist,
- econtext,
- resVect,
- isNullVect);
- if (*fj_isDone)
- return;
-
- resVect[0] = ExecEvalIter((Iter*)fjNode->fj_innerNode->expr,
- econtext,
- &isNullVect[0],
- &isDone);
-
+ *fj_isDone = FjoinBumpOuterNodes(tlist,
+ econtext,
+ resVect,
+ isNullVect);
+ if (*fj_isDone)
+ return;
+
+ resVect[0] = ExecEvalIter((Iter *) fjNode->fj_innerNode->expr,
+ econtext,
+ &isNullVect[0],
+ &isDone);
+
}
#endif
- return;
+ return;
}
#ifdef SETS_FIXED
-static bool
-FjoinBumpOuterNodes(TargetEntry *tlist,
- ExprContext *econtext,
- DatumPtr results,
- char *nulls)
+static bool
+FjoinBumpOuterNodes(TargetEntry * tlist,
+ ExprContext * econtext,
+ DatumPtr results,
+ char *nulls)
{
- bool funcIsDone = true;
- Fjoin *fjNode = tlist->fjoin;
- char *alwaysDone = fjNode->fj_alwaysDone;
- List *outerList = lnext(tlist);
- List *trailers = lnext(tlist);
- int trailNode = 1;
- int curNode = 1;
-
- /*
- * Run through list of functions until we get to one that isn't yet
- * done returning values. Watch out for funcs that are always done.
- */
- while ((funcIsDone == true) && (outerList != NIL))
+ bool funcIsDone = true;
+ Fjoin *fjNode = tlist->fjoin;
+ char *alwaysDone = fjNode->fj_alwaysDone;
+ List *outerList = lnext(tlist);
+ List *trailers = lnext(tlist);
+ int trailNode = 1;
+ int curNode = 1;
+
+ /*
+ * Run through list of functions until we get to one that isn't yet
+ * done returning values. Watch out for funcs that are always done.
+ */
+ while ((funcIsDone == true) && (outerList != NIL))
{
- TargetEntry *tle = lfirst(outerList);
-
- if (alwaysDone[curNode] == true)
- nulls[curNode] = 'n';
- else
- results[curNode] = ExecEvalIter((Iter)tle->expr,
- econtext,
- &nulls[curNode],
- &funcIsDone);
- curNode++;
- outerList = lnext(outerList);
+ TargetEntry *tle = lfirst(outerList);
+
+ if (alwaysDone[curNode] == true)
+ nulls[curNode] = 'n';
+ else
+ results[curNode] = ExecEvalIter((Iter) tle->expr,
+ econtext,
+ &nulls[curNode],
+ &funcIsDone);
+ curNode++;
+ outerList = lnext(outerList);
}
-
- /*
- * If every function is done, then we are done flattening.
- * Mark the Fjoin node unitialized, it is time to get the
- * next tuple from the plan and redo all of the flattening.
- */
- if (funcIsDone)
+
+ /*
+ * If every function is done, then we are done flattening. Mark the
+ * Fjoin node unitialized, it is time to get the next tuple from the
+ * plan and redo all of the flattening.
+ */
+ if (funcIsDone)
{
- set_fj_initialized(fjNode, false);
- return (true);
+ set_fj_initialized(fjNode, false);
+ return (true);
}
-
- /*
- * We found a function that wasn't done. Now re-run every function
- * before it. As usual watch out for functions that are always done.
- */
- trailNode = 1;
- while (trailNode != curNode-1)
+
+ /*
+ * We found a function that wasn't done. Now re-run every function
+ * before it. As usual watch out for functions that are always done.
+ */
+ trailNode = 1;
+ while (trailNode != curNode - 1)
{
- TargetEntry *tle = lfirst(trailers);
-
- if (alwaysDone[trailNode] != true)
- results[trailNode] = ExecEvalIter((Iter)tle->expr,
- econtext,
- &nulls[trailNode],
- &funcIsDone);
- trailNode++;
- trailers = lnext(trailers);
+ TargetEntry *tle = lfirst(trailers);
+
+ if (alwaysDone[trailNode] != true)
+ results[trailNode] = ExecEvalIter((Iter) tle->expr,
+ econtext,
+ &nulls[trailNode],
+ &funcIsDone);
+ trailNode++;
+ trailers = lnext(trailers);
}
- return false;
+ return false;
}
+
#endif
diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c
index 8779647a113..3ad41bd393f 100644
--- a/src/backend/executor/execJunk.c
+++ b/src/backend/executor/execJunk.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* junk.c--
- * Junk attribute support stuff....
+ * Junk attribute support stuff....
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.5 1997/08/26 23:31:37 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.6 1997/09/07 04:41:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,37 +20,37 @@
#include "access/heapam.h"
#include "executor/executor.h"
#include "nodes/relation.h"
-#include "optimizer/tlist.h" /* for MakeTLE */
+#include "optimizer/tlist.h" /* for MakeTLE */
/*-------------------------------------------------------------------------
- * XXX this stuff should be rewritten to take advantage
- * of ExecProject() and the ProjectionInfo node.
- * -cim 6/3/91
- *
+ * XXX this stuff should be rewritten to take advantage
+ * of ExecProject() and the ProjectionInfo node.
+ * -cim 6/3/91
+ *
* An attribute of a tuple living inside the executor, can be
* either a normal attribute or a "junk" attribute. "junk" attributes
* never make it out of the executor, i.e. they are never printed,
* returned or stored in disk. Their only purpose in life is to
* store some information useful only to the executor, mainly the values
* of some system attributes like "ctid" or rule locks.
- *
+ *
* The general idea is the following: A target list consists of a list of
* Resdom nodes & expression pairs. Each Resdom node has an attribute
* called 'resjunk'. If the value of this attribute is 1 then the
* corresponding attribute is a "junk" attribute.
- *
+ *
* When we initialize a plan we call 'ExecInitJunkFilter' to create
* and store the appropriate information in the 'es_junkFilter' attribute of
* EState.
- *
+ *
* We then execute the plan ignoring the "resjunk" attributes.
- *
+ *
* Finally, when at the top level we get back a tuple, we can call
* 'ExecGetJunkAttribute' to retrieve the value of the junk attributes we
* are interested in, and 'ExecRemoveJunk' to remove all the junk attributes
* from a tuple. This new "clean" tuple is then printed, replaced, deleted
* or inserted.
- *
+ *
*-------------------------------------------------------------------------
*/
@@ -60,174 +60,196 @@
* Initialize the Junk filter.
*-------------------------------------------------------------------------
*/
-JunkFilter *
-ExecInitJunkFilter(List *targetList)
+JunkFilter *
+ExecInitJunkFilter(List * targetList)
{
- JunkFilter *junkfilter;
- List *cleanTargetList;
- int len, cleanLength;
- TupleDesc tupType, cleanTupType;
- List *t;
- TargetEntry *tle;
- Resdom *resdom, *cleanResdom;
- int resjunk;
- AttrNumber cleanResno;
- AttrNumber *cleanMap;
- Size size;
- Node *expr;
-
- /* ---------------------
- * First find the "clean" target list, i.e. all the entries
- * in the original target list which have a zero 'resjunk'
- * NOTE: make copy of the Resdom nodes, because we have
- * to change the 'resno's...
- * ---------------------
- */
- cleanTargetList = NIL;
- cleanResno = 1;
-
- foreach (t, targetList) {
- TargetEntry *rtarget = lfirst(t);
- if (rtarget->resdom != NULL) {
- resdom = rtarget->resdom;
- expr = rtarget->expr;
- resjunk = resdom->resjunk;
- if (resjunk == 0) {
- /*
- * make a copy of the resdom node, changing its resno.
- */
- cleanResdom = (Resdom *) copyObject(resdom);
- cleanResdom->resno = cleanResno;
- cleanResno ++;
- /*
- * create a new target list entry
- */
- tle = makeNode(TargetEntry);
- tle->resdom = cleanResdom;
- tle->expr = expr;
- cleanTargetList = lappend(cleanTargetList, tle);
- }
- }
- else {
+ JunkFilter *junkfilter;
+ List *cleanTargetList;
+ int len,
+ cleanLength;
+ TupleDesc tupType,
+ cleanTupType;
+ List *t;
+ TargetEntry *tle;
+ Resdom *resdom,
+ *cleanResdom;
+ int resjunk;
+ AttrNumber cleanResno;
+ AttrNumber *cleanMap;
+ Size size;
+ Node *expr;
+
+ /* ---------------------
+ * First find the "clean" target list, i.e. all the entries
+ * in the original target list which have a zero 'resjunk'
+ * NOTE: make copy of the Resdom nodes, because we have
+ * to change the 'resno's...
+ * ---------------------
+ */
+ cleanTargetList = NIL;
+ cleanResno = 1;
+
+ foreach(t, targetList)
+ {
+ TargetEntry *rtarget = lfirst(t);
+
+ if (rtarget->resdom != NULL)
+ {
+ resdom = rtarget->resdom;
+ expr = rtarget->expr;
+ resjunk = resdom->resjunk;
+ if (resjunk == 0)
+ {
+
+ /*
+ * make a copy of the resdom node, changing its resno.
+ */
+ cleanResdom = (Resdom *) copyObject(resdom);
+ cleanResdom->resno = cleanResno;
+ cleanResno++;
+
+ /*
+ * create a new target list entry
+ */
+ tle = makeNode(TargetEntry);
+ tle->resdom = cleanResdom;
+ tle->expr = expr;
+ cleanTargetList = lappend(cleanTargetList, tle);
+ }
+ }
+ else
+ {
#ifdef SETS_FIXED
- List *fjListP;
- Fjoin *cleanFjoin;
- List *cleanFjList;
- List *fjList = lfirst(t);
- Fjoin *fjNode = (Fjoin *)tl_node(fjList);
-
- cleanFjoin = (Fjoin)copyObject((Node) fjNode);
- cleanFjList = lcons(cleanFjoin, NIL);
-
- resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
- expr = lsecond(get_fj_innerNode(fjNode));
- cleanResdom = (Resdom) copyObject((Node) resdom);
- set_resno(cleanResdom, cleanResno);
- cleanResno++;
- tle = (List) MakeTLE(cleanResdom, (Expr) expr);
- set_fj_innerNode(cleanFjoin, tle);
-
- foreach(fjListP, lnext(fjList)) {
- TargetEntry *tle = lfirst(fjListP);
-
- resdom = tle->resdom;
- expr = tle->expr;
- cleanResdom = (Resdom*) copyObject((Node) resdom);
- cleanResno++;
- cleanResdom->Resno = cleanResno;
- /*
- * create a new target list entry
- */
- tle = (List) MakeTLE(cleanResdom, (Expr) expr);
- cleanFjList = lappend(cleanFjList, tle);
- }
- lappend(cleanTargetList, cleanFjList);
+ List *fjListP;
+ Fjoin *cleanFjoin;
+ List *cleanFjList;
+ List *fjList = lfirst(t);
+ Fjoin *fjNode = (Fjoin *) tl_node(fjList);
+
+ cleanFjoin = (Fjoin) copyObject((Node) fjNode);
+ cleanFjList = lcons(cleanFjoin, NIL);
+
+ resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
+ expr = lsecond(get_fj_innerNode(fjNode));
+ cleanResdom = (Resdom) copyObject((Node) resdom);
+ set_resno(cleanResdom, cleanResno);
+ cleanResno++;
+ tle = (List) MakeTLE(cleanResdom, (Expr) expr);
+ set_fj_innerNode(cleanFjoin, tle);
+
+ foreach(fjListP, lnext(fjList))
+ {
+ TargetEntry *tle = lfirst(fjListP);
+
+ resdom = tle->resdom;
+ expr = tle->expr;
+ cleanResdom = (Resdom *) copyObject((Node) resdom);
+ cleanResno++;
+ cleanResdom->Resno = cleanResno;
+
+ /*
+ * create a new target list entry
+ */
+ tle = (List) MakeTLE(cleanResdom, (Expr) expr);
+ cleanFjList = lappend(cleanFjList, tle);
+ }
+ lappend(cleanTargetList, cleanFjList);
#endif
- }
- }
-
- /* ---------------------
- * Now calculate the tuple types for the original and the clean tuple
- *
- * XXX ExecTypeFromTL should be used sparingly. Don't we already
- * have the tupType corresponding to the targetlist we are passed?
- * -cim 5/31/91
- * ---------------------
- */
- tupType = (TupleDesc) ExecTypeFromTL(targetList);
- cleanTupType = (TupleDesc) ExecTypeFromTL(cleanTargetList);
-
- len = ExecTargetListLength(targetList);
- cleanLength = ExecTargetListLength(cleanTargetList);
-
- /* ---------------------
- * Now calculate the "map" between the original tuples attributes
- * and the "clean" tuple's attributes.
- *
- * The "map" is an array of "cleanLength" attribute numbers, i.e.
- * one entry for every attribute of the "clean" tuple.
- * The value of this entry is the attribute number of the corresponding
- * attribute of the "original" tuple.
- * ---------------------
- */
- if (cleanLength > 0) {
- size = cleanLength * sizeof(AttrNumber);
- cleanMap = (AttrNumber*) palloc(size);
- cleanResno = 1;
- foreach (t, targetList) {
- TargetEntry *tle = lfirst(t);
- if (tle->resdom != NULL) {
- resdom = tle->resdom;
- expr = tle->expr;
- resjunk = resdom->resjunk;
- if (resjunk == 0) {
- cleanMap[cleanResno-1] = resdom->resno;
- cleanResno ++;
}
- } else {
+ }
+
+ /* ---------------------
+ * Now calculate the tuple types for the original and the clean tuple
+ *
+ * XXX ExecTypeFromTL should be used sparingly. Don't we already
+ * have the tupType corresponding to the targetlist we are passed?
+ * -cim 5/31/91
+ * ---------------------
+ */
+ tupType = (TupleDesc) ExecTypeFromTL(targetList);
+ cleanTupType = (TupleDesc) ExecTypeFromTL(cleanTargetList);
+
+ len = ExecTargetListLength(targetList);
+ cleanLength = ExecTargetListLength(cleanTargetList);
+
+ /* ---------------------
+ * Now calculate the "map" between the original tuples attributes
+ * and the "clean" tuple's attributes.
+ *
+ * The "map" is an array of "cleanLength" attribute numbers, i.e.
+ * one entry for every attribute of the "clean" tuple.
+ * The value of this entry is the attribute number of the corresponding
+ * attribute of the "original" tuple.
+ * ---------------------
+ */
+ if (cleanLength > 0)
+ {
+ size = cleanLength * sizeof(AttrNumber);
+ cleanMap = (AttrNumber *) palloc(size);
+ cleanResno = 1;
+ foreach(t, targetList)
+ {
+ TargetEntry *tle = lfirst(t);
+
+ if (tle->resdom != NULL)
+ {
+ resdom = tle->resdom;
+ expr = tle->expr;
+ resjunk = resdom->resjunk;
+ if (resjunk == 0)
+ {
+ cleanMap[cleanResno - 1] = resdom->resno;
+ cleanResno++;
+ }
+ }
+ else
+ {
#ifdef SETS_FIXED
- List fjListP;
- List fjList = lfirst(t);
- Fjoin fjNode = (Fjoin)lfirst(fjList);
+ List fjListP;
+ List fjList = lfirst(t);
+ Fjoin fjNode = (Fjoin) lfirst(fjList);
- /* what the hell is this????? */
- resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
+ /* what the hell is this????? */
+ resdom = (Resdom) lfirst(get_fj_innerNode(fjNode));
#endif
- cleanMap[cleanResno-1] = tle->resdom->resno;
- cleanResno++;
+ cleanMap[cleanResno - 1] = tle->resdom->resno;
+ cleanResno++;
#ifdef SETS_FIXED
- foreach(fjListP, lnext(fjList)) {
- TargetEntry *tle = lfirst(fjListP);
+ foreach(fjListP, lnext(fjList))
+ {
+ TargetEntry *tle = lfirst(fjListP);
- resdom = tle->resdom;
- cleanMap[cleanResno-1] = resdom->resno;
- cleanResno++;
- }
+ resdom = tle->resdom;
+ cleanMap[cleanResno - 1] = resdom->resno;
+ cleanResno++;
+ }
#endif
- }
+ }
+ }
+ }
+ else
+ {
+ cleanMap = NULL;
}
- } else {
- cleanMap = NULL;
- }
-
- /* ---------------------
- * Finally create and initialize the JunkFilter.
- * ---------------------
- */
- junkfilter = makeNode(JunkFilter);
-
- junkfilter->jf_targetList = targetList;
- junkfilter->jf_length = len;
- junkfilter->jf_tupType = tupType;
- junkfilter->jf_cleanTargetList = cleanTargetList;
- junkfilter->jf_cleanLength = cleanLength;
- junkfilter->jf_cleanTupType = cleanTupType;
- junkfilter->jf_cleanMap = cleanMap;
-
- return(junkfilter);
-
+
+ /* ---------------------
+ * Finally create and initialize the JunkFilter.
+ * ---------------------
+ */
+ junkfilter = makeNode(JunkFilter);
+
+ junkfilter->jf_targetList = targetList;
+ junkfilter->jf_length = len;
+ junkfilter->jf_tupType = tupType;
+ junkfilter->jf_cleanTargetList = cleanTargetList;
+ junkfilter->jf_cleanLength = cleanLength;
+ junkfilter->jf_cleanTupType = cleanTupType;
+ junkfilter->jf_cleanMap = cleanMap;
+
+ return (junkfilter);
+
}
/*-------------------------------------------------------------------------
@@ -242,57 +264,61 @@ ExecInitJunkFilter(List *targetList)
*-------------------------------------------------------------------------
*/
bool
-ExecGetJunkAttribute(JunkFilter *junkfilter,
- TupleTableSlot *slot,
- char *attrName,
- Datum *value,
- bool *isNull)
+ExecGetJunkAttribute(JunkFilter * junkfilter,
+ TupleTableSlot * slot,
+ char *attrName,
+ Datum * value,
+ bool * isNull)
{
- List *targetList;
- List *t;
- Resdom *resdom;
- AttrNumber resno;
- char *resname;
- int resjunk;
- TupleDesc tupType;
- HeapTuple tuple;
-
- /* ---------------------
- * first look in the junkfilter's target list for
- * an attribute with the given name
- * ---------------------
- */
- resno = InvalidAttrNumber;
- targetList = junkfilter->jf_targetList;
-
- foreach (t, targetList) {
- TargetEntry *tle = lfirst(t);
- resdom = tle->resdom;
- resname = resdom->resname;
- resjunk = resdom->resjunk;
- if (resjunk != 0 && (strcmp(resname, attrName) == 0)) {
- /* We found it ! */
- resno = resdom->resno;
- break;
+ List *targetList;
+ List *t;
+ Resdom *resdom;
+ AttrNumber resno;
+ char *resname;
+ int resjunk;
+ TupleDesc tupType;
+ HeapTuple tuple;
+
+ /* ---------------------
+ * first look in the junkfilter's target list for
+ * an attribute with the given name
+ * ---------------------
+ */
+ resno = InvalidAttrNumber;
+ targetList = junkfilter->jf_targetList;
+
+ foreach(t, targetList)
+ {
+ TargetEntry *tle = lfirst(t);
+
+ resdom = tle->resdom;
+ resname = resdom->resname;
+ resjunk = resdom->resjunk;
+ if (resjunk != 0 && (strcmp(resname, attrName) == 0))
+ {
+ /* We found it ! */
+ resno = resdom->resno;
+ break;
+ }
+ }
+
+ if (resno == InvalidAttrNumber)
+ {
+ /* Ooops! We couldn't find this attribute... */
+ return (false);
}
- }
-
- if (resno == InvalidAttrNumber) {
- /* Ooops! We couldn't find this attribute... */
- return(false);
- }
-
- /* ---------------------
- * Now extract the attribute value from the tuple.
- * ---------------------
- */
- tuple = slot->val;
- tupType = (TupleDesc) junkfilter->jf_tupType;
-
- *value = (Datum)
- heap_getattr(tuple, InvalidBuffer, resno, tupType, isNull);
-
- return true;
+
+ /* ---------------------
+ * Now extract the attribute value from the tuple.
+ * ---------------------
+ */
+ tuple = slot->val;
+ tupType = (TupleDesc) junkfilter->jf_tupType;
+
+ *value = (Datum)
+ heap_getattr(tuple, InvalidBuffer, resno, tupType, isNull);
+
+ return true;
}
/*-------------------------------------------------------------------------
@@ -302,94 +328,98 @@ ExecGetJunkAttribute(JunkFilter *junkfilter,
*-------------------------------------------------------------------------
*/
HeapTuple
-ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
+ExecRemoveJunk(JunkFilter * junkfilter, TupleTableSlot * slot)
{
- HeapTuple tuple;
- HeapTuple cleanTuple;
- AttrNumber *cleanMap;
- TupleDesc cleanTupType;
- TupleDesc tupType;
- int cleanLength;
- bool isNull;
- int i;
- Size size;
- Datum *values;
- char *nulls;
- Datum values_array[64];
- char nulls_array[64];
-
- /* ----------------
- * get info from the slot and the junk filter
- * ----------------
- */
- tuple = slot->val;
-
- tupType = (TupleDesc) junkfilter->jf_tupType;
- cleanTupType = (TupleDesc) junkfilter->jf_cleanTupType;
- cleanLength = junkfilter->jf_cleanLength;
- cleanMap = junkfilter->jf_cleanMap;
-
- /* ---------------------
- * Handle the trivial case first.
- * ---------------------
- */
- if (cleanLength == 0)
- return (HeapTuple) NULL;
-
- /* ---------------------
- * Create the arrays that will hold the attribute values
- * and the null information for the new "clean" tuple.
- *
- * Note: we use memory on the stack to optimize things when
- * we are dealing with a small number of tuples.
- * for large tuples we just use palloc.
- * ---------------------
- */
- if (cleanLength > 64) {
- size = cleanLength * sizeof(Datum);
- values = (Datum *) palloc(size);
-
- size = cleanLength * sizeof(char);
- nulls = (char *) palloc(size);
- } else {
- values = values_array;
- nulls = nulls_array;
- }
-
- /* ---------------------
- * Exctract one by one all the values of the "clean" tuple.
- * ---------------------
- */
- for (i=0; i<cleanLength; i++) {
- Datum d = (Datum)
- heap_getattr(tuple, InvalidBuffer, cleanMap[i], tupType, &isNull);
-
- values[i] = d;
-
- if (isNull)
- nulls[i] = 'n';
+ HeapTuple tuple;
+ HeapTuple cleanTuple;
+ AttrNumber *cleanMap;
+ TupleDesc cleanTupType;
+ TupleDesc tupType;
+ int cleanLength;
+ bool isNull;
+ int i;
+ Size size;
+ Datum *values;
+ char *nulls;
+ Datum values_array[64];
+ char nulls_array[64];
+
+ /* ----------------
+ * get info from the slot and the junk filter
+ * ----------------
+ */
+ tuple = slot->val;
+
+ tupType = (TupleDesc) junkfilter->jf_tupType;
+ cleanTupType = (TupleDesc) junkfilter->jf_cleanTupType;
+ cleanLength = junkfilter->jf_cleanLength;
+ cleanMap = junkfilter->jf_cleanMap;
+
+ /* ---------------------
+ * Handle the trivial case first.
+ * ---------------------
+ */
+ if (cleanLength == 0)
+ return (HeapTuple) NULL;
+
+ /* ---------------------
+ * Create the arrays that will hold the attribute values
+ * and the null information for the new "clean" tuple.
+ *
+ * Note: we use memory on the stack to optimize things when
+ * we are dealing with a small number of tuples.
+ * for large tuples we just use palloc.
+ * ---------------------
+ */
+ if (cleanLength > 64)
+ {
+ size = cleanLength * sizeof(Datum);
+ values = (Datum *) palloc(size);
+
+ size = cleanLength * sizeof(char);
+ nulls = (char *) palloc(size);
+ }
else
- nulls[i] = ' ';
- }
-
- /* ---------------------
- * Now form the new tuple.
- * ---------------------
- */
- cleanTuple = heap_formtuple(cleanTupType,
- values,
- nulls);
-
- /* ---------------------
- * We are done. Free any space allocated for 'values' and 'nulls'
- * and return the new tuple.
- * ---------------------
- */
- if (cleanLength > 64) {
- pfree(values);
- pfree(nulls);
- }
-
- return(cleanTuple);
-}
+ {
+ values = values_array;
+ nulls = nulls_array;
+ }
+
+ /* ---------------------
+ * Exctract one by one all the values of the "clean" tuple.
+ * ---------------------
+ */
+ for (i = 0; i < cleanLength; i++)
+ {
+ Datum d = (Datum)
+ heap_getattr(tuple, InvalidBuffer, cleanMap[i], tupType, &isNull);
+ values[i] = d;
+
+ if (isNull)
+ nulls[i] = 'n';
+ else
+ nulls[i] = ' ';
+ }
+
+ /* ---------------------
+ * Now form the new tuple.
+ * ---------------------
+ */
+ cleanTuple = heap_formtuple(cleanTupType,
+ values,
+ nulls);
+
+ /* ---------------------
+ * We are done. Free any space allocated for 'values' and 'nulls'
+ * and return the new tuple.
+ * ---------------------
+ */
+ if (cleanLength > 64)
+ {
+ pfree(values);
+ pfree(nulls);
+ }
+
+ return (cleanTuple);
+}
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 48bf84ba095..2bf0edaf35e 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1,32 +1,32 @@
/*-------------------------------------------------------------------------
*
* execMain.c--
- * top level executor interface routines
+ * top level executor interface routines
*
* INTERFACE ROUTINES
- * ExecutorStart()
- * ExecutorRun()
- * ExecutorEnd()
+ * ExecutorStart()
+ * ExecutorRun()
+ * ExecutorEnd()
*
- * The old ExecutorMain() has been replaced by ExecutorStart(),
- * ExecutorRun() and ExecutorEnd()
+ * The old ExecutorMain() has been replaced by ExecutorStart(),
+ * ExecutorRun() and ExecutorEnd()
+ *
+ * These three procedures are the external interfaces to the executor.
+ * In each case, the query descriptor and the execution state is required
+ * as arguments
+ *
+ * ExecutorStart() must be called at the beginning of any execution of any
+ * query plan and ExecutorEnd() should always be called at the end of
+ * execution of a plan.
+ *
+ * ExecutorRun accepts 'feature' and 'count' arguments that specify whether
+ * the plan is to be executed forwards, backwards, and for how many tuples.
*
- * These three procedures are the external interfaces to the executor.
- * In each case, the query descriptor and the execution state is required
- * as arguments
- *
- * ExecutorStart() must be called at the beginning of any execution of any
- * query plan and ExecutorEnd() should always be called at the end of
- * execution of a plan.
- *
- * ExecutorRun accepts 'feature' and 'count' arguments that specify whether
- * the plan is to be executed forwards, backwards, and for how many tuples.
- *
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.22 1997/09/04 13:22:36 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.23 1997/09/07 04:41:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,7 +42,7 @@
#include "utils/palloc.h"
#include "utils/acl.h"
#include "utils/syscache.h"
-#include "parser/parsetree.h" /* rt_fetch() */
+#include "parser/parsetree.h" /* rt_fetch() */
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
@@ -56,28 +56,35 @@
/* decls for local routines only used within this module */
-static void ExecCheckPerms(CmdType operation, int resultRelation, List *rangeTable,
- Query *parseTree);
-static TupleDesc InitPlan(CmdType operation, Query *parseTree,
- Plan *plan, EState *estate);
-static void EndPlan(Plan *plan, EState *estate);
-static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
- Query *parseTree, CmdType operation,
- int numberTuples, ScanDirection direction,
- void (*printfunc)());
-static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc)(),
- EState *estate);
-static void ExecAppend(TupleTableSlot *slot,ItemPointer tupleid,
- EState *estate);
-static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
- EState *estate);
-static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
- EState *estate, Query *parseTree);
+static void
+ExecCheckPerms(CmdType operation, int resultRelation, List * rangeTable,
+ Query * parseTree);
+static TupleDesc
+InitPlan(CmdType operation, Query * parseTree,
+ Plan * plan, EState * estate);
+static void EndPlan(Plan * plan, EState * estate);
+static TupleTableSlot *
+ExecutePlan(EState * estate, Plan * plan,
+ Query * parseTree, CmdType operation,
+ int numberTuples, ScanDirection direction,
+ void (*printfunc) ());
+static void ExecRetrieve(TupleTableSlot * slot, void (*printfunc) (),
+ EState * estate);
+static void
+ExecAppend(TupleTableSlot * slot, ItemPointer tupleid,
+ EState * estate);
+static void
+ExecDelete(TupleTableSlot * slot, ItemPointer tupleid,
+ EState * estate);
+static void
+ExecReplace(TupleTableSlot * slot, ItemPointer tupleid,
+ EState * estate, Query * parseTree);
/* end of local decls */
#ifdef QUERY_LIMIT
-static int queryLimit = ALL_TUPLES;
+static int queryLimit = ALL_TUPLES;
+
#undef ALL_TUPLES
#define ALL_TUPLES queryLimit
@@ -85,574 +92,605 @@ static int queryLimit = ALL_TUPLES;
int
ExecutorLimit(int limit)
{
- return queryLimit = limit;
+ return queryLimit = limit;
}
+
#endif
#endif
/* ----------------------------------------------------------------
- * ExecutorStart
- *
- * This routine must be called at the beginning of any execution of any
- * query plan
- *
- * returns (AttrInfo*) which describes the attributes of the tuples to
- * be returned by the query.
+ * ExecutorStart
+ *
+ * This routine must be called at the beginning of any execution of any
+ * query plan
+ *
+ * returns (AttrInfo*) which describes the attributes of the tuples to
+ * be returned by the query.
*
* ----------------------------------------------------------------
*/
TupleDesc
-ExecutorStart(QueryDesc *queryDesc, EState *estate)
+ExecutorStart(QueryDesc * queryDesc, EState * estate)
{
- TupleDesc result;
-
- /* sanity checks */
- Assert(queryDesc!=NULL);
-
- result = InitPlan(queryDesc->operation,
- queryDesc->parsetree,
- queryDesc->plantree,
- estate);
-
- /* reset buffer refcount. the current refcounts
- * are saved and will be restored when ExecutorEnd is called
- *
- * this makes sure that when ExecutorRun's are
- * called recursively as for postquel functions,
- * the buffers pinned by one ExecutorRun will not be
- * unpinned by another ExecutorRun.
- */
- BufferRefCountReset(estate->es_refcount);
-
- return result;
+ TupleDesc result;
+
+ /* sanity checks */
+ Assert(queryDesc != NULL);
+
+ result = InitPlan(queryDesc->operation,
+ queryDesc->parsetree,
+ queryDesc->plantree,
+ estate);
+
+ /*
+ * reset buffer refcount. the current refcounts are saved and will be
+ * restored when ExecutorEnd is called
+ *
+ * this makes sure that when ExecutorRun's are called recursively as for
+ * postquel functions, the buffers pinned by one ExecutorRun will not
+ * be unpinned by another ExecutorRun.
+ */
+ BufferRefCountReset(estate->es_refcount);
+
+ return result;
}
/* ----------------------------------------------------------------
- * ExecutorRun
- *
- * This is the main routine of the executor module. It accepts
- * the query descriptor from the traffic cop and executes the
- * query plan.
- *
- * ExecutorStart must have been called already.
+ * ExecutorRun
+ *
+ * This is the main routine of the executor module. It accepts
+ * the query descriptor from the traffic cop and executes the
+ * query plan.
+ *
+ * ExecutorStart must have been called already.
*
- * the different features supported are:
- * EXEC_RUN: retrieve all tuples in the forward direction
- * EXEC_FOR: retrieve 'count' number of tuples in the forward dir
- * EXEC_BACK: retrieve 'count' number of tuples in the backward dir
- * EXEC_RETONE: return one tuple but don't 'retrieve' it
- * used in postquel function processing
+ * the different features supported are:
+ * EXEC_RUN: retrieve all tuples in the forward direction
+ * EXEC_FOR: retrieve 'count' number of tuples in the forward dir
+ * EXEC_BACK: retrieve 'count' number of tuples in the backward dir
+ * EXEC_RETONE: return one tuple but don't 'retrieve' it
+ * used in postquel function processing
*
*
* ----------------------------------------------------------------
*/
-TupleTableSlot*
-ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
+TupleTableSlot *
+ExecutorRun(QueryDesc * queryDesc, EState * estate, int feature, int count)
{
- CmdType operation;
- Query *parseTree;
- Plan *plan;
- TupleTableSlot *result;
- CommandDest dest;
- void (*destination)();
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(queryDesc!=NULL);
-
- /* ----------------
- * extract information from the query descriptor
- * and the query feature.
- * ----------------
- */
- operation = queryDesc->operation;
- parseTree = queryDesc->parsetree;
- plan = queryDesc->plantree;
- dest = queryDesc->dest;
- destination = (void (*)()) DestToFunction(dest);
- estate->es_processed = 0;
- estate->es_lastoid = InvalidOid;
+ CmdType operation;
+ Query *parseTree;
+ Plan *plan;
+ TupleTableSlot *result;
+ CommandDest dest;
+ void (*destination) ();
-#if 0
- /*
- * It doesn't work in common case (i.g. if function has a aggregate).
- * Now we store parameter values before ExecutorStart. - vadim 01/22/97
- */
-#ifdef INDEXSCAN_PATCH
- /*
- * If the plan is an index scan and some of the scan key are
- * function arguments rescan the indices after the parameter
- * values have been stored in the execution state. DZ - 27-8-1996
- */
- if ((nodeTag(plan) == T_IndexScan) &&
- (((IndexScan *)plan)->indxstate->iss_RuntimeKeyInfo != NULL)) {
- ExprContext *econtext;
- econtext = ((IndexScan *)plan)->scan.scanstate->cstate.cs_ExprContext;
- ExecIndexReScan((IndexScan *)plan, econtext, plan);
- }
-#endif
-#endif
-
- switch(feature) {
-
- case EXEC_RUN:
- result = ExecutePlan(estate,
- plan,
- parseTree,
- operation,
- ALL_TUPLES,
- ForwardScanDirection,
- destination);
- break;
- case EXEC_FOR:
- result = ExecutePlan(estate,
- plan,
- parseTree,
- operation,
- count,
- ForwardScanDirection,
- destination);
- break;
-
/* ----------------
- * retrieve next n "backward" tuples
+ * sanity checks
* ----------------
*/
- case EXEC_BACK:
- result = ExecutePlan(estate,
- plan,
- parseTree,
- operation,
- count,
- BackwardScanDirection,
- destination);
- break;
-
+ Assert(queryDesc != NULL);
+
/* ----------------
- * return one tuple but don't "retrieve" it.
- * (this is used by the rule manager..) -cim 9/14/89
+ * extract information from the query descriptor
+ * and the query feature.
* ----------------
*/
- case EXEC_RETONE:
- result = ExecutePlan(estate,
- plan,
- parseTree,
- operation,
- ONE_TUPLE,
- ForwardScanDirection,
- destination);
- break;
- default:
- result = NULL;
- elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
- break;
- }
+ operation = queryDesc->operation;
+ parseTree = queryDesc->parsetree;
+ plan = queryDesc->plantree;
+ dest = queryDesc->dest;
+ destination = (void (*) ()) DestToFunction(dest);
+ estate->es_processed = 0;
+ estate->es_lastoid = InvalidOid;
+
+#if 0
+
+ /*
+ * It doesn't work in common case (i.g. if function has a aggregate).
+ * Now we store parameter values before ExecutorStart. - vadim
+ * 01/22/97
+ */
+#ifdef INDEXSCAN_PATCH
+
+ /*
+ * If the plan is an index scan and some of the scan key are function
+ * arguments rescan the indices after the parameter values have been
+ * stored in the execution state. DZ - 27-8-1996
+ */
+ if ((nodeTag(plan) == T_IndexScan) &&
+ (((IndexScan *) plan)->indxstate->iss_RuntimeKeyInfo != NULL))
+ {
+ ExprContext *econtext;
+
+ econtext = ((IndexScan *) plan)->scan.scanstate->cstate.cs_ExprContext;
+ ExecIndexReScan((IndexScan *) plan, econtext, plan);
+ }
+#endif
+#endif
+
+ switch (feature)
+ {
+
+ case EXEC_RUN:
+ result = ExecutePlan(estate,
+ plan,
+ parseTree,
+ operation,
+ ALL_TUPLES,
+ ForwardScanDirection,
+ destination);
+ break;
+ case EXEC_FOR:
+ result = ExecutePlan(estate,
+ plan,
+ parseTree,
+ operation,
+ count,
+ ForwardScanDirection,
+ destination);
+ break;
- return result;
+ /* ----------------
+ * retrieve next n "backward" tuples
+ * ----------------
+ */
+ case EXEC_BACK:
+ result = ExecutePlan(estate,
+ plan,
+ parseTree,
+ operation,
+ count,
+ BackwardScanDirection,
+ destination);
+ break;
+
+ /* ----------------
+ * return one tuple but don't "retrieve" it.
+ * (this is used by the rule manager..) -cim 9/14/89
+ * ----------------
+ */
+ case EXEC_RETONE:
+ result = ExecutePlan(estate,
+ plan,
+ parseTree,
+ operation,
+ ONE_TUPLE,
+ ForwardScanDirection,
+ destination);
+ break;
+ default:
+ result = NULL;
+ elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
+ break;
+ }
+
+ return result;
}
/* ----------------------------------------------------------------
- * ExecutorEnd
- *
- * This routine must be called at the end of any execution of any
- * query plan
- *
- * returns (AttrInfo*) which describes the attributes of the tuples to
- * be returned by the query.
+ * ExecutorEnd
+ *
+ * This routine must be called at the end of any execution of any
+ * query plan
+ *
+ * returns (AttrInfo*) which describes the attributes of the tuples to
+ * be returned by the query.
*
* ----------------------------------------------------------------
*/
void
-ExecutorEnd(QueryDesc *queryDesc, EState *estate)
+ExecutorEnd(QueryDesc * queryDesc, EState * estate)
{
- /* sanity checks */
- Assert(queryDesc!=NULL);
+ /* sanity checks */
+ Assert(queryDesc != NULL);
- EndPlan(queryDesc->plantree, estate);
+ EndPlan(queryDesc->plantree, estate);
- /* restore saved refcounts. */
- BufferRefCountRestore(estate->es_refcount);
+ /* restore saved refcounts. */
+ BufferRefCountRestore(estate->es_refcount);
}
/* ===============================================================
* ===============================================================
- static routines follow
+ static routines follow
* ===============================================================
* ===============================================================
*/
static void
ExecCheckPerms(CmdType operation,
- int resultRelation,
- List *rangeTable,
- Query *parseTree)
+ int resultRelation,
+ List * rangeTable,
+ Query * parseTree)
{
- int i = 1;
- Oid relid;
- HeapTuple htp;
- List *lp;
- List *qvars, *tvars;
- int32 ok = 1, aclcheck_result = -1;
- char *opstr;
- NameData rname;
- char *userName;
-
-#define CHECK(MODE) pg_aclcheck(rname.data, userName, MODE)
-
- userName = GetPgUserName();
-
- foreach (lp, rangeTable) {
- RangeTblEntry *rte = lfirst(lp);
-
- relid = rte->relid;
- htp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relid),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "ExecCheckPerms: bogus RT relid: %d",
- relid);
- strNcpy(rname.data,
- ((Form_pg_class) GETSTRUCT(htp))->relname.data,
- NAMEDATALEN-1);
- if (i == resultRelation) { /* this is the result relation */
- qvars = pull_varnos(parseTree->qual);
- tvars = pull_varnos((Node*)parseTree->targetList);
- if (intMember(resultRelation, qvars) ||
- intMember(resultRelation, tvars)) {
- /* result relation is scanned */
- ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
- opstr = "read";
+ int i = 1;
+ Oid relid;
+ HeapTuple htp;
+ List *lp;
+ List *qvars,
+ *tvars;
+ int32 ok = 1,
+ aclcheck_result = -1;
+ char *opstr;
+ NameData rname;
+ char *userName;
+
+#define CHECK(MODE) pg_aclcheck(rname.data, userName, MODE)
+
+ userName = GetPgUserName();
+
+ foreach(lp, rangeTable)
+ {
+ RangeTblEntry *rte = lfirst(lp);
+
+ relid = rte->relid;
+ htp = SearchSysCacheTuple(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "ExecCheckPerms: bogus RT relid: %d",
+ relid);
+ strNcpy(rname.data,
+ ((Form_pg_class) GETSTRUCT(htp))->relname.data,
+ NAMEDATALEN - 1);
+ if (i == resultRelation)
+ { /* this is the result relation */
+ qvars = pull_varnos(parseTree->qual);
+ tvars = pull_varnos((Node *) parseTree->targetList);
+ if (intMember(resultRelation, qvars) ||
+ intMember(resultRelation, tvars))
+ {
+ /* result relation is scanned */
+ ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
+ opstr = "read";
+ if (!ok)
+ break;
+ }
+ switch (operation)
+ {
+ case CMD_INSERT:
+ ok = ((aclcheck_result = CHECK(ACL_AP)) == ACLCHECK_OK) ||
+ ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
+ opstr = "append";
+ break;
+ case CMD_NOTIFY: /* what does this mean?? -- jw, 1/6/94 */
+ case CMD_DELETE:
+ case CMD_UPDATE:
+ ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
+ opstr = "write";
+ break;
+ default:
+ elog(WARN, "ExecCheckPerms: bogus operation %d",
+ operation);
+ }
+ }
+ else
+ {
+ /* XXX NOTIFY?? */
+ ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
+ opstr = "read";
+ }
if (!ok)
- break;
- }
- switch (operation) {
- case CMD_INSERT:
- ok = ((aclcheck_result = CHECK(ACL_AP)) == ACLCHECK_OK) ||
- ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
- opstr = "append";
- break;
- case CMD_NOTIFY: /* what does this mean?? -- jw, 1/6/94 */
- case CMD_DELETE:
- case CMD_UPDATE:
- ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
- opstr = "write";
- break;
- default:
- elog(WARN, "ExecCheckPerms: bogus operation %d",
- operation);
- }
- } else {
- /* XXX NOTIFY?? */
- ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
- opstr = "read";
+ break;
+ ++i;
}
if (!ok)
- break;
- ++i;
- }
- if (!ok) {
- elog(WARN, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
- }
+ {
+ elog(WARN, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
+ }
}
/* ----------------------------------------------------------------
- * InitPlan
- *
- * Initializes the query plan: open files, allocate storage
- * and start up the rule manager
+ * InitPlan
+ *
+ * Initializes the query plan: open files, allocate storage
+ * and start up the rule manager
* ----------------------------------------------------------------
*/
-static TupleDesc
-InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
-{
- List *rangeTable;
- int resultRelation;
- Relation intoRelationDesc;
-
- TupleDesc tupType;
- List *targetList;
- int len;
-
- /* ----------------
- * get information from query descriptor
- * ----------------
- */
- rangeTable = parseTree->rtable;
- resultRelation = parseTree->resultRelation;
-
- /* ----------------
- * initialize the node's execution state
- * ----------------
- */
- estate->es_range_table = rangeTable;
-
- /* ----------------
- * initialize the BaseId counter so node base_id's
- * are assigned correctly. Someday baseid's will have to
- * be stored someplace other than estate because they
- * should be unique per query planned.
- * ----------------
- */
- estate->es_BaseId = 1;
-
- /* ----------------
- * initialize result relation stuff
- * ----------------
- */
-
- if (resultRelation != 0 && operation != CMD_SELECT) {
- /* ----------------
- * if we have a result relation, open it and
+static TupleDesc
+InitPlan(CmdType operation, Query * parseTree, Plan * plan, EState * estate)
+{
+ List *rangeTable;
+ int resultRelation;
+ Relation intoRelationDesc;
+
+ TupleDesc tupType;
+ List *targetList;
+ int len;
- * initialize the result relation info stuff.
+ /* ----------------
+ * get information from query descriptor
* ----------------
*/
- RelationInfo *resultRelationInfo;
- Index resultRelationIndex;
- RangeTblEntry *rtentry;
- Oid resultRelationOid;
- Relation resultRelationDesc;
-
- resultRelationIndex = resultRelation;
- rtentry = rt_fetch(resultRelationIndex, rangeTable);
- resultRelationOid = rtentry->relid;
- resultRelationDesc = heap_open(resultRelationOid);
-
- if ( resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE )
- elog (WARN, "You can't change sequence relation %s",
- resultRelationDesc->rd_rel->relname.data);
-
- /* Write-lock the result relation right away: if the relation
- is used in a subsequent scan, we won't have to elevate the
- read-lock set by heap_beginscan to a write-lock (needed by
- heap_insert, heap_delete and heap_replace).
- This will hopefully prevent some deadlocks. - 01/24/94 */
- RelationSetLockForWrite(resultRelationDesc);
-
- resultRelationInfo = makeNode(RelationInfo);
- resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
- resultRelationInfo->ri_RelationDesc = resultRelationDesc;
- resultRelationInfo->ri_NumIndices = 0;
- resultRelationInfo->ri_IndexRelationDescs = NULL;
- resultRelationInfo->ri_IndexRelationInfo = NULL;
+ rangeTable = parseTree->rtable;
+ resultRelation = parseTree->resultRelation;
/* ----------------
- * open indices on result relation and save descriptors
- * in the result relation information..
+ * initialize the node's execution state
* ----------------
*/
- ExecOpenIndices(resultRelationOid, resultRelationInfo);
-
- estate->es_result_relation_info = resultRelationInfo;
- } else {
+ estate->es_range_table = rangeTable;
+
/* ----------------
- * if no result relation, then set state appropriately
+ * initialize the BaseId counter so node base_id's
+ * are assigned correctly. Someday baseid's will have to
+ * be stored someplace other than estate because they
+ * should be unique per query planned.
* ----------------
*/
- estate->es_result_relation_info = NULL;
- }
+ estate->es_BaseId = 1;
-#ifndef NO_SECURITY
- ExecCheckPerms(operation, resultRelation, rangeTable, parseTree);
-#endif
+ /* ----------------
+ * initialize result relation stuff
+ * ----------------
+ */
- /* ----------------
- * initialize the executor "tuple" table.
- * ----------------
- */
- {
- int nSlots = ExecCountSlotsNode(plan);
- TupleTable tupleTable = ExecCreateTupleTable(nSlots+10); /* why add ten? - jolly */
-
- estate->es_tupleTable = tupleTable;
- }
-
- /* ----------------
- * initialize the private state information for
- * all the nodes in the query tree. This opens
- * files, allocates storage and leaves us ready
- * to start processing tuples..
- * ----------------
- */
- ExecInitNode(plan, estate, NULL);
-
- /* ----------------
- * get the tuple descriptor describing the type
- * of tuples to return.. (this is especially important
- * if we are creating a relation with "retrieve into")
- * ----------------
- */
- tupType = ExecGetTupType(plan); /* tuple descriptor */
- targetList = plan->targetlist;
- len = ExecTargetListLength(targetList); /* number of attributes */
-
- /* ----------------
- * now that we have the target list, initialize the junk filter
- * if this is a REPLACE or a DELETE query.
- * We also init the junk filter if this is an append query
- * (there might be some rule lock info there...)
- * NOTE: in the future we might want to initialize the junk
- * filter for all queries.
- * ----------------
- */
- if (operation == CMD_UPDATE || operation == CMD_DELETE ||
- operation == CMD_INSERT) {
-
- JunkFilter *j = (JunkFilter*) ExecInitJunkFilter(targetList);
- estate->es_junkFilter = j;
- } else
- estate->es_junkFilter = NULL;
-
- /* ----------------
- * initialize the "into" relation
- * ----------------
- */
- intoRelationDesc = (Relation) NULL;
-
- if (operation == CMD_SELECT) {
- char *intoName;
- char archiveMode;
- Oid intoRelationId;
- TupleDesc tupdesc;
-
- if (!parseTree->isPortal) {
- /*
- * a select into table
- */
- if (parseTree->into != NULL) {
+ if (resultRelation != 0 && operation != CMD_SELECT)
+ {
/* ----------------
- * create the "into" relation
- *
- * note: there is currently no way for the user to
- * specify the desired archive mode of the
- * "into" relation...
+ * if we have a result relation, open it and
+
+ * initialize the result relation info stuff.
* ----------------
*/
- intoName = parseTree->into;
- archiveMode = 'n';
-
+ RelationInfo *resultRelationInfo;
+ Index resultRelationIndex;
+ RangeTblEntry *rtentry;
+ Oid resultRelationOid;
+ Relation resultRelationDesc;
+
+ resultRelationIndex = resultRelation;
+ rtentry = rt_fetch(resultRelationIndex, rangeTable);
+ resultRelationOid = rtentry->relid;
+ resultRelationDesc = heap_open(resultRelationOid);
+
+ if (resultRelationDesc->rd_rel->relkind == RELKIND_SEQUENCE)
+ elog(WARN, "You can't change sequence relation %s",
+ resultRelationDesc->rd_rel->relname.data);
+
/*
- * have to copy tupType to get rid of constraints
+ * Write-lock the result relation right away: if the relation is
+ * used in a subsequent scan, we won't have to elevate the
+ * read-lock set by heap_beginscan to a write-lock (needed by
+ * heap_insert, heap_delete and heap_replace). This will hopefully
+ * prevent some deadlocks. - 01/24/94
*/
- tupdesc = CreateTupleDescCopy (tupType);
-
- /* fixup to prevent zero-length columns in create */
- setVarAttrLenForCreateTable(tupdesc, targetList, rangeTable);
-
- intoRelationId = heap_create(intoName,
- intoName, /* not used */
- archiveMode,
- DEFAULT_SMGR,
- tupdesc);
-#ifdef NOT_USED /* it's copy ... */
- resetVarAttrLenForCreateTable(tupdesc);
-#endif
- FreeTupleDesc (tupdesc);
+ RelationSetLockForWrite(resultRelationDesc);
+
+ resultRelationInfo = makeNode(RelationInfo);
+ resultRelationInfo->ri_RangeTableIndex = resultRelationIndex;
+ resultRelationInfo->ri_RelationDesc = resultRelationDesc;
+ resultRelationInfo->ri_NumIndices = 0;
+ resultRelationInfo->ri_IndexRelationDescs = NULL;
+ resultRelationInfo->ri_IndexRelationInfo = NULL;
/* ----------------
- * XXX rather than having to call setheapoverride(true)
- * and then back to false, we should change the
- * arguments to heap_open() instead..
+ * open indices on result relation and save descriptors
+ * in the result relation information..
* ----------------
*/
- setheapoverride(true);
-
- intoRelationDesc = heap_open(intoRelationId);
-
- setheapoverride(false);
- }
+ ExecOpenIndices(resultRelationOid, resultRelationInfo);
+
+ estate->es_result_relation_info = resultRelationInfo;
}
- }
+ else
+ {
+ /* ----------------
+ * if no result relation, then set state appropriately
+ * ----------------
+ */
+ estate->es_result_relation_info = NULL;
+ }
+
+#ifndef NO_SECURITY
+ ExecCheckPerms(operation, resultRelation, rangeTable, parseTree);
+#endif
+
+ /* ----------------
+ * initialize the executor "tuple" table.
+ * ----------------
+ */
+ {
+ int nSlots = ExecCountSlotsNode(plan);
+ TupleTable tupleTable = ExecCreateTupleTable(nSlots + 10); /* why add ten? - jolly */
- estate->es_into_relation_descriptor = intoRelationDesc;
+ estate->es_tupleTable = tupleTable;
+ }
- /* ----------------
- * return the type information..
- * ----------------
- */
+ /* ----------------
+ * initialize the private state information for
+ * all the nodes in the query tree. This opens
+ * files, allocates storage and leaves us ready
+ * to start processing tuples..
+ * ----------------
+ */
+ ExecInitNode(plan, estate, NULL);
+
+ /* ----------------
+ * get the tuple descriptor describing the type
+ * of tuples to return.. (this is especially important
+ * if we are creating a relation with "retrieve into")
+ * ----------------
+ */
+ tupType = ExecGetTupType(plan); /* tuple descriptor */
+ targetList = plan->targetlist;
+ len = ExecTargetListLength(targetList); /* number of attributes */
+
+ /* ----------------
+ * now that we have the target list, initialize the junk filter
+ * if this is a REPLACE or a DELETE query.
+ * We also init the junk filter if this is an append query
+ * (there might be some rule lock info there...)
+ * NOTE: in the future we might want to initialize the junk
+ * filter for all queries.
+ * ----------------
+ */
+ if (operation == CMD_UPDATE || operation == CMD_DELETE ||
+ operation == CMD_INSERT)
+ {
+
+ JunkFilter *j = (JunkFilter *) ExecInitJunkFilter(targetList);
+
+ estate->es_junkFilter = j;
+ }
+ else
+ estate->es_junkFilter = NULL;
+
+ /* ----------------
+ * initialize the "into" relation
+ * ----------------
+ */
+ intoRelationDesc = (Relation) NULL;
+
+ if (operation == CMD_SELECT)
+ {
+ char *intoName;
+ char archiveMode;
+ Oid intoRelationId;
+ TupleDesc tupdesc;
+
+ if (!parseTree->isPortal)
+ {
+
+ /*
+ * a select into table
+ */
+ if (parseTree->into != NULL)
+ {
+ /* ----------------
+ * create the "into" relation
+ *
+ * note: there is currently no way for the user to
+ * specify the desired archive mode of the
+ * "into" relation...
+ * ----------------
+ */
+ intoName = parseTree->into;
+ archiveMode = 'n';
+
+ /*
+ * have to copy tupType to get rid of constraints
+ */
+ tupdesc = CreateTupleDescCopy(tupType);
+
+ /* fixup to prevent zero-length columns in create */
+ setVarAttrLenForCreateTable(tupdesc, targetList, rangeTable);
+
+ intoRelationId = heap_create(intoName,
+ intoName, /* not used */
+ archiveMode,
+ DEFAULT_SMGR,
+ tupdesc);
+#ifdef NOT_USED /* it's copy ... */
+ resetVarAttrLenForCreateTable(tupdesc);
+#endif
+ FreeTupleDesc(tupdesc);
+
+ /* ----------------
+ * XXX rather than having to call setheapoverride(true)
+ * and then back to false, we should change the
+ * arguments to heap_open() instead..
+ * ----------------
+ */
+ setheapoverride(true);
+
+ intoRelationDesc = heap_open(intoRelationId);
+
+ setheapoverride(false);
+ }
+ }
+ }
+
+ estate->es_into_relation_descriptor = intoRelationDesc;
+
+ /* ----------------
+ * return the type information..
+ * ----------------
+ */
/*
- attinfo = (AttrInfo *)palloc(sizeof(AttrInfo));
- attinfo->numAttr = len;
- attinfo->attrs = tupType->attrs;
+ attinfo = (AttrInfo *)palloc(sizeof(AttrInfo));
+ attinfo->numAttr = len;
+ attinfo->attrs = tupType->attrs;
*/
- return tupType;
+ return tupType;
}
/* ----------------------------------------------------------------
- * EndPlan
- *
- * Cleans up the query plan -- closes files and free up storages
+ * EndPlan
+ *
+ * Cleans up the query plan -- closes files and free up storages
* ----------------------------------------------------------------
*/
static void
-EndPlan(Plan *plan, EState *estate)
+EndPlan(Plan * plan, EState * estate)
{
- RelationInfo *resultRelationInfo;
- Relation intoRelationDesc;
-
- /* ----------------
- * get information from state
- * ----------------
- */
- resultRelationInfo = estate->es_result_relation_info;
- intoRelationDesc = estate->es_into_relation_descriptor;
-
- /* ----------------
- * shut down the query
- * ----------------
- */
- ExecEndNode(plan, plan);
-
- /* ----------------
- * destroy the executor "tuple" table.
- * ----------------
- */
- {
- TupleTable tupleTable = (TupleTable) estate->es_tupleTable;
- ExecDestroyTupleTable(tupleTable,true); /* was missing last arg */
- estate->es_tupleTable = NULL;
- }
-
- /* ----------------
- * close the result relations if necessary
- * ----------------
- */
- if (resultRelationInfo != NULL) {
- Relation resultRelationDesc;
-
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
- heap_close(resultRelationDesc);
-
+ RelationInfo *resultRelationInfo;
+ Relation intoRelationDesc;
+
/* ----------------
- * close indices on the result relation
+ * get information from state
* ----------------
*/
- ExecCloseIndices(resultRelationInfo);
- }
-
- /* ----------------
- * close the "into" relation if necessary
- * ----------------
- */
- if (intoRelationDesc != NULL) {
- heap_close(intoRelationDesc);
- }
+ resultRelationInfo = estate->es_result_relation_info;
+ intoRelationDesc = estate->es_into_relation_descriptor;
+
+ /* ----------------
+ * shut down the query
+ * ----------------
+ */
+ ExecEndNode(plan, plan);
+
+ /* ----------------
+ * destroy the executor "tuple" table.
+ * ----------------
+ */
+ {
+ TupleTable tupleTable = (TupleTable) estate->es_tupleTable;
+
+ ExecDestroyTupleTable(tupleTable, true); /* was missing last arg */
+ estate->es_tupleTable = NULL;
+ }
+
+ /* ----------------
+ * close the result relations if necessary
+ * ----------------
+ */
+ if (resultRelationInfo != NULL)
+ {
+ Relation resultRelationDesc;
+
+ resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+ heap_close(resultRelationDesc);
+
+ /* ----------------
+ * close indices on the result relation
+ * ----------------
+ */
+ ExecCloseIndices(resultRelationInfo);
+ }
+
+ /* ----------------
+ * close the "into" relation if necessary
+ * ----------------
+ */
+ if (intoRelationDesc != NULL)
+ {
+ heap_close(intoRelationDesc);
+ }
}
/* ----------------------------------------------------------------
- * ExecutePlan
- *
- * processes the query plan to retrieve 'tupleCount' tuples in the
- * direction specified.
- * Retrieves all tuples if tupleCount is 0
+ * ExecutePlan
+ *
+ * processes the query plan to retrieve 'tupleCount' tuples in the
+ * direction specified.
+ * Retrieves all tuples if tupleCount is 0
+ *
+ * result is either a slot containing a tuple in the case
+ * of a RETRIEVE or NULL otherwise.
*
- * result is either a slot containing a tuple in the case
- * of a RETRIEVE or NULL otherwise.
- *
* ----------------------------------------------------------------
*/
@@ -660,688 +698,704 @@ EndPlan(Plan *plan, EState *estate)
user can see it*/
static TupleTableSlot *
-ExecutePlan(EState *estate,
- Plan *plan,
- Query *parseTree,
- CmdType operation,
- int numberTuples,
- ScanDirection direction,
- void (*printfunc)())
+ExecutePlan(EState * estate,
+ Plan * plan,
+ Query * parseTree,
+ CmdType operation,
+ int numberTuples,
+ ScanDirection direction,
+ void (*printfunc) ())
{
- JunkFilter *junkfilter;
-
- TupleTableSlot *slot;
- ItemPointer tupleid = NULL;
- ItemPointerData tuple_ctid;
- int current_tuple_count;
- TupleTableSlot *result;
-
- /* ----------------
- * initialize local variables
- * ----------------
- */
- slot = NULL;
- current_tuple_count = 0;
- result = NULL;
-
- /* ----------------
- * Set the direction.
- * ----------------
- */
- estate->es_direction = direction;
-
- /* ----------------
- * Loop until we've processed the proper number
- * of tuples from the plan..
- * ----------------
- */
-
- for(;;) {
- if (operation != CMD_NOTIFY) {
- /* ----------------
- * Execute the plan and obtain a tuple
- * ----------------
- */
- /* at the top level, the parent of a plan (2nd arg) is itself */
- slot = ExecProcNode(plan,plan);
-
- /* ----------------
- * if the tuple is null, then we assume
- * there is nothing more to process so
- * we just return null...
- * ----------------
- */
- if (TupIsNull(slot)) {
- result = NULL;
- break;
- }
- }
-
+ JunkFilter *junkfilter;
+
+ TupleTableSlot *slot;
+ ItemPointer tupleid = NULL;
+ ItemPointerData tuple_ctid;
+ int current_tuple_count;
+ TupleTableSlot *result;
+
/* ----------------
- * if we have a junk filter, then project a new
- * tuple with the junk removed.
- *
- * Store this new "clean" tuple in the place of the
- * original tuple.
- *
- * Also, extract all the junk ifnormation we need.
+ * initialize local variables
* ----------------
*/
- if ((junkfilter = estate->es_junkFilter) != (JunkFilter*)NULL) {
- Datum datum;
-/* NameData attrName; */
- HeapTuple newTuple;
- bool isNull;
-
- /* ---------------
- * extract the 'ctid' junk attribute.
- * ---------------
- */
- if (operation == CMD_UPDATE || operation == CMD_DELETE) {
- if (! ExecGetJunkAttribute(junkfilter,
- slot,
- "ctid",
- &datum,
- &isNull))
- elog(WARN,"ExecutePlan: NO (junk) `ctid' was found!");
-
- if (isNull)
- elog(WARN,"ExecutePlan: (junk) `ctid' is NULL!");
-
- tupleid = (ItemPointer) DatumGetPointer(datum);
- tuple_ctid = *tupleid; /* make sure we don't free the ctid!! */
- tupleid = &tuple_ctid;
- }
-
- /* ---------------
- * Finally create a new "clean" tuple with all junk attributes
- * removed
- * ---------------
- */
- newTuple = ExecRemoveJunk(junkfilter, slot);
-
- slot = ExecStoreTuple(newTuple, /* tuple to store */
- slot, /* destination slot */
- InvalidBuffer,/* this tuple has no buffer */
- true); /* tuple should be pfreed */
- } /* if (junkfilter... */
-
+ slot = NULL;
+ current_tuple_count = 0;
+ result = NULL;
+
/* ----------------
- * now that we have a tuple, do the appropriate thing
- * with it.. either return it to the user, add
- * it to a relation someplace, delete it from a
- * relation, or modify some of it's attributes.
+ * Set the direction.
* ----------------
*/
-
- switch(operation) {
- case CMD_SELECT:
- ExecRetrieve(slot, /* slot containing tuple */
- printfunc, /* print function */
- estate); /* */
- result = slot;
- break;
-
- case CMD_INSERT:
- ExecAppend(slot, tupleid, estate);
- result = NULL;
- break;
-
- case CMD_DELETE:
- ExecDelete(slot, tupleid, estate);
- result = NULL;
- break;
-
- case CMD_UPDATE:
- ExecReplace(slot, tupleid, estate, parseTree);
- result = NULL;
- break;
-
- /* Total hack. I'm ignoring any accessor functions for
- Relation, RelationTupleForm, NameData.
- Assuming that NameData.data has offset 0.
- */
- case CMD_NOTIFY: {
- RelationInfo *rInfo = estate->es_result_relation_info;
- Relation rDesc = rInfo->ri_RelationDesc;
- Async_Notify(rDesc->rd_rel->relname.data);
- result = NULL;
- current_tuple_count = 0;
- numberTuples = 1;
- elog(DEBUG, "ExecNotify %s",&rDesc->rd_rel->relname);
- }
- break;
-
- default:
- elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
- result = NULL;
- break;
+ estate->es_direction = direction;
+
+ /* ----------------
+ * Loop until we've processed the proper number
+ * of tuples from the plan..
+ * ----------------
+ */
+
+ for (;;)
+ {
+ if (operation != CMD_NOTIFY)
+ {
+ /* ----------------
+ * Execute the plan and obtain a tuple
+ * ----------------
+ */
+ /* at the top level, the parent of a plan (2nd arg) is itself */
+ slot = ExecProcNode(plan, plan);
+
+ /* ----------------
+ * if the tuple is null, then we assume
+ * there is nothing more to process so
+ * we just return null...
+ * ----------------
+ */
+ if (TupIsNull(slot))
+ {
+ result = NULL;
+ break;
+ }
+ }
+
+ /* ----------------
+ * if we have a junk filter, then project a new
+ * tuple with the junk removed.
+ *
+ * Store this new "clean" tuple in the place of the
+ * original tuple.
+ *
+ * Also, extract all the junk ifnormation we need.
+ * ----------------
+ */
+ if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)
+ {
+ Datum datum;
+
+/* NameData attrName; */
+ HeapTuple newTuple;
+ bool isNull;
+
+ /* ---------------
+ * extract the 'ctid' junk attribute.
+ * ---------------
+ */
+ if (operation == CMD_UPDATE || operation == CMD_DELETE)
+ {
+ if (!ExecGetJunkAttribute(junkfilter,
+ slot,
+ "ctid",
+ &datum,
+ &isNull))
+ elog(WARN, "ExecutePlan: NO (junk) `ctid' was found!");
+
+ if (isNull)
+ elog(WARN, "ExecutePlan: (junk) `ctid' is NULL!");
+
+ tupleid = (ItemPointer) DatumGetPointer(datum);
+ tuple_ctid = *tupleid; /* make sure we don't free the
+ * ctid!! */
+ tupleid = &tuple_ctid;
+ }
+
+ /* ---------------
+ * Finally create a new "clean" tuple with all junk attributes
+ * removed
+ * ---------------
+ */
+ newTuple = ExecRemoveJunk(junkfilter, slot);
+
+ slot = ExecStoreTuple(newTuple, /* tuple to store */
+ slot, /* destination slot */
+ InvalidBuffer, /* this tuple has no
+ * buffer */
+ true); /* tuple should be pfreed */
+ } /* if (junkfilter... */
+
+ /* ----------------
+ * now that we have a tuple, do the appropriate thing
+ * with it.. either return it to the user, add
+ * it to a relation someplace, delete it from a
+ * relation, or modify some of it's attributes.
+ * ----------------
+ */
+
+ switch (operation)
+ {
+ case CMD_SELECT:
+ ExecRetrieve(slot, /* slot containing tuple */
+ printfunc, /* print function */
+ estate); /* */
+ result = slot;
+ break;
+
+ case CMD_INSERT:
+ ExecAppend(slot, tupleid, estate);
+ result = NULL;
+ break;
+
+ case CMD_DELETE:
+ ExecDelete(slot, tupleid, estate);
+ result = NULL;
+ break;
+
+ case CMD_UPDATE:
+ ExecReplace(slot, tupleid, estate, parseTree);
+ result = NULL;
+ break;
+
+ /*
+ * Total hack. I'm ignoring any accessor functions for
+ * Relation, RelationTupleForm, NameData. Assuming that
+ * NameData.data has offset 0.
+ */
+ case CMD_NOTIFY:
+ {
+ RelationInfo *rInfo = estate->es_result_relation_info;
+ Relation rDesc = rInfo->ri_RelationDesc;
+
+ Async_Notify(rDesc->rd_rel->relname.data);
+ result = NULL;
+ current_tuple_count = 0;
+ numberTuples = 1;
+ elog(DEBUG, "ExecNotify %s", &rDesc->rd_rel->relname);
+ }
+ break;
+
+ default:
+ elog(DEBUG, "ExecutePlan: unknown operation in queryDesc");
+ result = NULL;
+ break;
+ }
+ /* ----------------
+ * check our tuple count.. if we've returned the
+ * proper number then return, else loop again and
+ * process more tuples..
+ * ----------------
+ */
+ current_tuple_count += 1;
+ if (numberTuples == current_tuple_count)
+ break;
}
+
/* ----------------
- * check our tuple count.. if we've returned the
- * proper number then return, else loop again and
- * process more tuples..
+ * here, result is either a slot containing a tuple in the case
+ * of a RETRIEVE or NULL otherwise.
* ----------------
*/
- current_tuple_count += 1;
- if (numberTuples == current_tuple_count)
- break;
- }
-
- /* ----------------
- * here, result is either a slot containing a tuple in the case
- * of a RETRIEVE or NULL otherwise.
- * ----------------
- */
- return result;
+ return result;
}
/* ----------------------------------------------------------------
- * ExecRetrieve
+ * ExecRetrieve
*
- * RETRIEVEs are easy.. we just pass the tuple to the appropriate
- * print function. The only complexity is when we do a
- * "retrieve into", in which case we insert the tuple into
- * the appropriate relation (note: this is a newly created relation
- * so we don't need to worry about indices or locks.)
+ * RETRIEVEs are easy.. we just pass the tuple to the appropriate
+ * print function. The only complexity is when we do a
+ * "retrieve into", in which case we insert the tuple into
+ * the appropriate relation (note: this is a newly created relation
+ * so we don't need to worry about indices or locks.)
* ----------------------------------------------------------------
*/
static void
-ExecRetrieve(TupleTableSlot *slot,
- void (*printfunc)(),
- EState *estate)
+ExecRetrieve(TupleTableSlot * slot,
+ void (*printfunc) (),
+ EState * estate)
{
- HeapTuple tuple;
- TupleDesc attrtype;
-
- /* ----------------
- * get the heap tuple out of the tuple table slot
- * ----------------
- */
- tuple = slot->val;
- attrtype = slot->ttc_tupleDescriptor;
-
- /* ----------------
- * insert the tuple into the "into relation"
- * ----------------
- */
- if ( estate->es_into_relation_descriptor != NULL )
- {
- heap_insert (estate->es_into_relation_descriptor, tuple);
- IncrAppended();
- }
-
- /* ----------------
- * send the tuple to the front end (or the screen)
- * ----------------
- */
- (*printfunc)(tuple, attrtype);
- IncrRetrieved();
- (estate->es_processed)++;
+ HeapTuple tuple;
+ TupleDesc attrtype;
+
+ /* ----------------
+ * get the heap tuple out of the tuple table slot
+ * ----------------
+ */
+ tuple = slot->val;
+ attrtype = slot->ttc_tupleDescriptor;
+
+ /* ----------------
+ * insert the tuple into the "into relation"
+ * ----------------
+ */
+ if (estate->es_into_relation_descriptor != NULL)
+ {
+ heap_insert(estate->es_into_relation_descriptor, tuple);
+ IncrAppended();
+ }
+
+ /* ----------------
+ * send the tuple to the front end (or the screen)
+ * ----------------
+ */
+ (*printfunc) (tuple, attrtype);
+ IncrRetrieved();
+ (estate->es_processed)++;
}
/* ----------------------------------------------------------------
- * ExecAppend
+ * ExecAppend
*
- * APPENDs are trickier.. we have to insert the tuple into
- * the base relation and insert appropriate tuples into the
- * index relations.
+ * APPENDs are trickier.. we have to insert the tuple into
+ * the base relation and insert appropriate tuples into the
+ * index relations.
* ----------------------------------------------------------------
*/
static void
-ExecAppend(TupleTableSlot *slot,
- ItemPointer tupleid,
- EState *estate)
+ExecAppend(TupleTableSlot * slot,
+ ItemPointer tupleid,
+ EState * estate)
{
- HeapTuple tuple;
- RelationInfo *resultRelationInfo;
- Relation resultRelationDesc;
- int numIndices;
- Oid newId;
-
- /* ----------------
- * get the heap tuple out of the tuple table slot
- * ----------------
- */
- tuple = slot->val;
-
- /* ----------------
- * get information on the result relation
- * ----------------
- */
- resultRelationInfo = estate->es_result_relation_info;
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
-
- /* ----------------
- * have to add code to preform unique checking here.
- * cim -12/1/89
- * ----------------
- */
-
- /* BEFORE ROW INSERT Triggers */
- if ( resultRelationDesc->trigdesc &&
- resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0 )
- {
- HeapTuple newtuple;
-
- newtuple = ExecBRInsertTriggers (resultRelationDesc, tuple);
-
- if ( newtuple == NULL ) /* "do nothing" */
- return;
-
- if ( newtuple != tuple ) /* modified by Trigger(s) */
- {
- Assert ( slot->ttc_shouldFree );
- pfree (tuple);
- slot->val = tuple = newtuple;
- }
- }
-
- /* ----------------
- * Check the constraints of a tuple
- * ----------------
- */
-
- if ( resultRelationDesc->rd_att->constr )
- {
- HeapTuple newtuple;
-
- newtuple = ExecConstraints ("ExecAppend", resultRelationDesc, tuple);
-
- if ( newtuple != tuple ) /* modified by DEFAULT */
- {
- Assert ( slot->ttc_shouldFree );
- pfree (tuple);
- slot->val = tuple = newtuple;
- }
- }
-
- /* ----------------
- * insert the tuple
- * ----------------
- */
- newId = heap_insert(resultRelationDesc, /* relation desc */
- tuple); /* heap tuple */
- IncrAppended();
-
- /* ----------------
- * process indices
- *
- * Note: heap_insert adds a new tuple to a relation. As a side
- * effect, the tupleid of the new tuple is placed in the new
- * tuple's t_ctid field.
- * ----------------
- */
- numIndices = resultRelationInfo->ri_NumIndices;
- if (numIndices > 0) {
- ExecInsertIndexTuples(slot, &(tuple->t_ctid), estate, false);
- }
- (estate->es_processed)++;
- estate->es_lastoid = newId;
-
- /* AFTER ROW INSERT Triggers */
- if ( resultRelationDesc->trigdesc &&
- resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 )
- ExecARInsertTriggers (resultRelationDesc, tuple);
+ HeapTuple tuple;
+ RelationInfo *resultRelationInfo;
+ Relation resultRelationDesc;
+ int numIndices;
+ Oid newId;
+
+ /* ----------------
+ * get the heap tuple out of the tuple table slot
+ * ----------------
+ */
+ tuple = slot->val;
+
+ /* ----------------
+ * get information on the result relation
+ * ----------------
+ */
+ resultRelationInfo = estate->es_result_relation_info;
+ resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+
+ /* ----------------
+ * have to add code to preform unique checking here.
+ * cim -12/1/89
+ * ----------------
+ */
+
+ /* BEFORE ROW INSERT Triggers */
+ if (resultRelationDesc->trigdesc &&
+ resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecBRInsertTriggers(resultRelationDesc, tuple);
+
+ if (newtuple == NULL) /* "do nothing" */
+ return;
+
+ if (newtuple != tuple) /* modified by Trigger(s) */
+ {
+ Assert(slot->ttc_shouldFree);
+ pfree(tuple);
+ slot->val = tuple = newtuple;
+ }
+ }
+
+ /* ----------------
+ * Check the constraints of a tuple
+ * ----------------
+ */
+
+ if (resultRelationDesc->rd_att->constr)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecConstraints("ExecAppend", resultRelationDesc, tuple);
+
+ if (newtuple != tuple) /* modified by DEFAULT */
+ {
+ Assert(slot->ttc_shouldFree);
+ pfree(tuple);
+ slot->val = tuple = newtuple;
+ }
+ }
+
+ /* ----------------
+ * insert the tuple
+ * ----------------
+ */
+ newId = heap_insert(resultRelationDesc, /* relation desc */
+ tuple); /* heap tuple */
+ IncrAppended();
+
+ /* ----------------
+ * process indices
+ *
+ * Note: heap_insert adds a new tuple to a relation. As a side
+ * effect, the tupleid of the new tuple is placed in the new
+ * tuple's t_ctid field.
+ * ----------------
+ */
+ numIndices = resultRelationInfo->ri_NumIndices;
+ if (numIndices > 0)
+ {
+ ExecInsertIndexTuples(slot, &(tuple->t_ctid), estate, false);
+ }
+ (estate->es_processed)++;
+ estate->es_lastoid = newId;
+
+ /* AFTER ROW INSERT Triggers */
+ if (resultRelationDesc->trigdesc &&
+ resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
+ ExecARInsertTriggers(resultRelationDesc, tuple);
}
/* ----------------------------------------------------------------
- * ExecDelete
+ * ExecDelete
*
- * DELETE is like append, we delete the tuple and its
- * index tuples.
+ * DELETE is like append, we delete the tuple and its
+ * index tuples.
* ----------------------------------------------------------------
*/
static void
-ExecDelete(TupleTableSlot *slot,
- ItemPointer tupleid,
- EState *estate)
+ExecDelete(TupleTableSlot * slot,
+ ItemPointer tupleid,
+ EState * estate)
{
- RelationInfo *resultRelationInfo;
- Relation resultRelationDesc;
-
- /* ----------------
- * get the result relation information
- * ----------------
- */
- resultRelationInfo = estate->es_result_relation_info;
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
-
- /* BEFORE ROW DELETE Triggers */
- if ( resultRelationDesc->trigdesc &&
- resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0 )
- {
- bool dodelete;
-
- dodelete = ExecBRDeleteTriggers (resultRelationDesc, tupleid);
-
- if ( !dodelete ) /* "do nothing" */
- return;
- }
-
- /* ----------------
- * delete the tuple
- * ----------------
- */
- if ( heap_delete(resultRelationDesc, /* relation desc */
- tupleid) ) /* item pointer to tuple */
- return;
-
- IncrDeleted();
- (estate->es_processed)++;
-
- /* ----------------
- * Note: Normally one would think that we have to
- * delete index tuples associated with the
- * heap tuple now..
- *
- * ... but in POSTGRES, we have no need to do this
- * because the vacuum daemon automatically
- * opens an index scan and deletes index tuples
- * when it finds deleted heap tuples. -cim 9/27/89
- * ----------------
- */
-
- /* AFTER ROW DELETE Triggers */
- if ( resultRelationDesc->trigdesc &&
- resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0 )
- ExecARDeleteTriggers (resultRelationDesc, tupleid);
+ RelationInfo *resultRelationInfo;
+ Relation resultRelationDesc;
+
+ /* ----------------
+ * get the result relation information
+ * ----------------
+ */
+ resultRelationInfo = estate->es_result_relation_info;
+ resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+
+ /* BEFORE ROW DELETE Triggers */
+ if (resultRelationDesc->trigdesc &&
+ resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
+ {
+ bool dodelete;
+
+ dodelete = ExecBRDeleteTriggers(resultRelationDesc, tupleid);
+
+ if (!dodelete) /* "do nothing" */
+ return;
+ }
+
+ /* ----------------
+ * delete the tuple
+ * ----------------
+ */
+ if (heap_delete(resultRelationDesc, /* relation desc */
+ tupleid)) /* item pointer to tuple */
+ return;
+
+ IncrDeleted();
+ (estate->es_processed)++;
+
+ /* ----------------
+ * Note: Normally one would think that we have to
+ * delete index tuples associated with the
+ * heap tuple now..
+ *
+ * ... but in POSTGRES, we have no need to do this
+ * because the vacuum daemon automatically
+ * opens an index scan and deletes index tuples
+ * when it finds deleted heap tuples. -cim 9/27/89
+ * ----------------
+ */
+
+ /* AFTER ROW DELETE Triggers */
+ if (resultRelationDesc->trigdesc &&
+ resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
+ ExecARDeleteTriggers(resultRelationDesc, tupleid);
}
/* ----------------------------------------------------------------
- * ExecReplace
+ * ExecReplace
*
- * note: we can't run replace queries with transactions
- * off because replaces are actually appends and our
- * scan will mistakenly loop forever, replacing the tuple
- * it just appended.. This should be fixed but until it
- * is, we don't want to get stuck in an infinite loop
- * which corrupts your database..
+ * note: we can't run replace queries with transactions
+ * off because replaces are actually appends and our
+ * scan will mistakenly loop forever, replacing the tuple
+ * it just appended.. This should be fixed but until it
+ * is, we don't want to get stuck in an infinite loop
+ * which corrupts your database..
* ----------------------------------------------------------------
*/
static void
-ExecReplace(TupleTableSlot *slot,
- ItemPointer tupleid,
- EState *estate,
- Query *parseTree)
+ExecReplace(TupleTableSlot * slot,
+ ItemPointer tupleid,
+ EState * estate,
+ Query * parseTree)
{
- HeapTuple tuple;
- RelationInfo *resultRelationInfo;
- Relation resultRelationDesc;
- int numIndices;
-
- /* ----------------
- * abort the operation if not running transactions
- * ----------------
- */
- if (IsBootstrapProcessingMode()) {
- elog(DEBUG, "ExecReplace: replace can't run without transactions");
- return;
- }
-
- /* ----------------
- * get the heap tuple out of the tuple table slot
- * ----------------
- */
- tuple = slot->val;
-
- /* ----------------
- * get the result relation information
- * ----------------
- */
- resultRelationInfo = estate->es_result_relation_info;
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
-
- /* ----------------
- * have to add code to preform unique checking here.
- * in the event of unique tuples, this becomes a deletion
- * of the original tuple affected by the replace.
- * cim -12/1/89
- * ----------------
- */
-
- /* BEFORE ROW UPDATE Triggers */
- if ( resultRelationDesc->trigdesc &&
- resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0 )
- {
- HeapTuple newtuple;
-
- newtuple = ExecBRUpdateTriggers (resultRelationDesc, tupleid, tuple);
-
- if ( newtuple == NULL ) /* "do nothing" */
- return;
-
- if ( newtuple != tuple ) /* modified by Trigger(s) */
- {
- Assert ( slot->ttc_shouldFree );
- pfree (tuple);
- slot->val = tuple = newtuple;
- }
- }
-
- /* ----------------
- * Check the constraints of a tuple
- * ----------------
- */
-
- if ( resultRelationDesc->rd_att->constr )
- {
- HeapTuple newtuple;
-
- newtuple = ExecConstraints ("ExecReplace", resultRelationDesc, tuple);
-
- if ( newtuple != tuple ) /* modified by DEFAULT */
- {
- Assert ( slot->ttc_shouldFree );
- pfree (tuple);
- slot->val = tuple = newtuple;
- }
- }
-
- /* ----------------
- * replace the heap tuple
- *
- * Don't want to continue if our heap_replace didn't actually
- * do a replace. This would be the case if heap_replace
- * detected a non-functional update. -kw 12/30/93
- * ----------------
- */
- if (heap_replace(resultRelationDesc, /* relation desc */
- tupleid, /* item ptr of tuple to replace */
- tuple)) { /* replacement heap tuple */
- return;
- }
-
- IncrReplaced();
- (estate->es_processed)++;
-
- /* ----------------
- * Note: instead of having to update the old index tuples
- * associated with the heap tuple, all we do is form
- * and insert new index tuples.. This is because
- * replaces are actually deletes and inserts and
- * index tuple deletion is done automagically by
- * the vaccuum deamon.. All we do is insert new
- * index tuples. -cim 9/27/89
- * ----------------
- */
-
- /* ----------------
- * process indices
- *
- * heap_replace updates a tuple in the base relation by invalidating
- * it and then appending a new tuple to the relation. As a side
- * effect, the tupleid of the new tuple is placed in the new
- * tuple's t_ctid field. So we now insert index tuples using
- * the new tupleid stored there.
- * ----------------
- */
-
- numIndices = resultRelationInfo->ri_NumIndices;
- if (numIndices > 0) {
- ExecInsertIndexTuples(slot, &(tuple->t_ctid), estate, true);
- }
-
- /* AFTER ROW UPDATE Triggers */
- if ( resultRelationDesc->trigdesc &&
- resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 )
- ExecARUpdateTriggers (resultRelationDesc, tupleid, tuple);
+ HeapTuple tuple;
+ RelationInfo *resultRelationInfo;
+ Relation resultRelationDesc;
+ int numIndices;
+
+ /* ----------------
+ * abort the operation if not running transactions
+ * ----------------
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ elog(DEBUG, "ExecReplace: replace can't run without transactions");
+ return;
+ }
+
+ /* ----------------
+ * get the heap tuple out of the tuple table slot
+ * ----------------
+ */
+ tuple = slot->val;
+
+ /* ----------------
+ * get the result relation information
+ * ----------------
+ */
+ resultRelationInfo = estate->es_result_relation_info;
+ resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+
+ /* ----------------
+ * have to add code to preform unique checking here.
+ * in the event of unique tuples, this becomes a deletion
+ * of the original tuple affected by the replace.
+ * cim -12/1/89
+ * ----------------
+ */
+
+ /* BEFORE ROW UPDATE Triggers */
+ if (resultRelationDesc->trigdesc &&
+ resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecBRUpdateTriggers(resultRelationDesc, tupleid, tuple);
+
+ if (newtuple == NULL) /* "do nothing" */
+ return;
+
+ if (newtuple != tuple) /* modified by Trigger(s) */
+ {
+ Assert(slot->ttc_shouldFree);
+ pfree(tuple);
+ slot->val = tuple = newtuple;
+ }
+ }
+
+ /* ----------------
+ * Check the constraints of a tuple
+ * ----------------
+ */
+
+ if (resultRelationDesc->rd_att->constr)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecConstraints("ExecReplace", resultRelationDesc, tuple);
+
+ if (newtuple != tuple) /* modified by DEFAULT */
+ {
+ Assert(slot->ttc_shouldFree);
+ pfree(tuple);
+ slot->val = tuple = newtuple;
+ }
+ }
+
+ /* ----------------
+ * replace the heap tuple
+ *
+ * Don't want to continue if our heap_replace didn't actually
+ * do a replace. This would be the case if heap_replace
+ * detected a non-functional update. -kw 12/30/93
+ * ----------------
+ */
+ if (heap_replace(resultRelationDesc, /* relation desc */
+ tupleid, /* item ptr of tuple to replace */
+ tuple))
+ { /* replacement heap tuple */
+ return;
+ }
+
+ IncrReplaced();
+ (estate->es_processed)++;
+
+ /* ----------------
+ * Note: instead of having to update the old index tuples
+ * associated with the heap tuple, all we do is form
+ * and insert new index tuples.. This is because
+ * replaces are actually deletes and inserts and
+ * index tuple deletion is done automagically by
+ * the vaccuum deamon.. All we do is insert new
+ * index tuples. -cim 9/27/89
+ * ----------------
+ */
+
+ /* ----------------
+ * process indices
+ *
+ * heap_replace updates a tuple in the base relation by invalidating
+ * it and then appending a new tuple to the relation. As a side
+ * effect, the tupleid of the new tuple is placed in the new
+ * tuple's t_ctid field. So we now insert index tuples using
+ * the new tupleid stored there.
+ * ----------------
+ */
+
+ numIndices = resultRelationInfo->ri_NumIndices;
+ if (numIndices > 0)
+ {
+ ExecInsertIndexTuples(slot, &(tuple->t_ctid), estate, true);
+ }
+
+ /* AFTER ROW UPDATE Triggers */
+ if (resultRelationDesc->trigdesc &&
+ resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0)
+ ExecARUpdateTriggers(resultRelationDesc, tupleid, tuple);
}
-static HeapTuple
-ExecAttrDefault (Relation rel, HeapTuple tuple)
+static HeapTuple
+ExecAttrDefault(Relation rel, HeapTuple tuple)
{
- int ndef = rel->rd_att->constr->num_defval;
- AttrDefault *attrdef = rel->rd_att->constr->defval;
- ExprContext *econtext = makeNode (ExprContext);
- HeapTuple newtuple;
- Node *expr;
- bool isnull;
- bool isdone;
- Datum val;
- Datum *replValue = NULL;
- char *replNull = NULL;
- char *repl = NULL;
- int i;
-
- econtext->ecxt_scantuple = NULL; /* scan tuple slot */
- econtext->ecxt_innertuple = NULL; /* inner tuple slot */
- econtext->ecxt_outertuple = NULL; /* outer tuple slot */
- econtext->ecxt_relation = NULL; /* relation */
- econtext->ecxt_relid = 0; /* relid */
- econtext->ecxt_param_list_info = NULL; /* param list info */
- econtext->ecxt_range_table = NULL; /* range table */
- for (i = 0; i < ndef; i++)
- {
- if ( !heap_attisnull (tuple, attrdef[i].adnum) )
- continue;
- expr = (Node*) stringToNode (attrdef[i].adbin);
-
- val = ExecEvalExpr (expr, econtext, &isnull, &isdone);
-
- pfree (expr);
-
- if ( isnull )
- continue;
-
- if ( repl == NULL )
- {
- repl = (char*) palloc (rel->rd_att->natts * sizeof (char));
- replNull = (char*) palloc (rel->rd_att->natts * sizeof (char));
- replValue = (Datum*) palloc (rel->rd_att->natts * sizeof (Datum));
- memset (repl, ' ', rel->rd_att->natts * sizeof (char));
- }
-
- repl[attrdef[i].adnum - 1] = 'r';
- replNull[attrdef[i].adnum - 1] = ' ';
- replValue[attrdef[i].adnum - 1] = val;
-
- }
-
- pfree (econtext);
-
- if ( repl == NULL )
- return (tuple);
-
- newtuple = heap_modifytuple (tuple, InvalidBuffer, rel, replValue, replNull, repl);
-
- pfree (repl);
- pfree (replNull);
- pfree (replValue);
-
- return (newtuple);
-
+ int ndef = rel->rd_att->constr->num_defval;
+ AttrDefault *attrdef = rel->rd_att->constr->defval;
+ ExprContext *econtext = makeNode(ExprContext);
+ HeapTuple newtuple;
+ Node *expr;
+ bool isnull;
+ bool isdone;
+ Datum val;
+ Datum *replValue = NULL;
+ char *replNull = NULL;
+ char *repl = NULL;
+ int i;
+
+ econtext->ecxt_scantuple = NULL; /* scan tuple slot */
+ econtext->ecxt_innertuple = NULL; /* inner tuple slot */
+ econtext->ecxt_outertuple = NULL; /* outer tuple slot */
+ econtext->ecxt_relation = NULL; /* relation */
+ econtext->ecxt_relid = 0; /* relid */
+ econtext->ecxt_param_list_info = NULL; /* param list info */
+ econtext->ecxt_range_table = NULL; /* range table */
+ for (i = 0; i < ndef; i++)
+ {
+ if (!heap_attisnull(tuple, attrdef[i].adnum))
+ continue;
+ expr = (Node *) stringToNode(attrdef[i].adbin);
+
+ val = ExecEvalExpr(expr, econtext, &isnull, &isdone);
+
+ pfree(expr);
+
+ if (isnull)
+ continue;
+
+ if (repl == NULL)
+ {
+ repl = (char *) palloc(rel->rd_att->natts * sizeof(char));
+ replNull = (char *) palloc(rel->rd_att->natts * sizeof(char));
+ replValue = (Datum *) palloc(rel->rd_att->natts * sizeof(Datum));
+ memset(repl, ' ', rel->rd_att->natts * sizeof(char));
+ }
+
+ repl[attrdef[i].adnum - 1] = 'r';
+ replNull[attrdef[i].adnum - 1] = ' ';
+ replValue[attrdef[i].adnum - 1] = val;
+
+ }
+
+ pfree(econtext);
+
+ if (repl == NULL)
+ return (tuple);
+
+ newtuple = heap_modifytuple(tuple, InvalidBuffer, rel, replValue, replNull, repl);
+
+ pfree(repl);
+ pfree(replNull);
+ pfree(replValue);
+
+ return (newtuple);
+
}
-static char *
-ExecRelCheck (Relation rel, HeapTuple tuple)
+static char *
+ExecRelCheck(Relation rel, HeapTuple tuple)
{
- int ncheck = rel->rd_att->constr->num_check;
- ConstrCheck *check = rel->rd_att->constr->check;
- ExprContext *econtext = makeNode (ExprContext);
- TupleTableSlot *slot = makeNode (TupleTableSlot);
- RangeTblEntry *rte = makeNode (RangeTblEntry);
- List *rtlist;
- List *qual;
- bool res;
- int i;
-
- slot->val = tuple;
- slot->ttc_shouldFree = false;
- slot->ttc_descIsNew = true;
- slot->ttc_tupleDescriptor = rel->rd_att;
- slot->ttc_buffer = InvalidBuffer;
- slot->ttc_whichplan = -1;
- rte->relname = nameout (&(rel->rd_rel->relname));
- rte->timeRange = NULL;
- rte->refname = rte->relname;
- rte->relid = rel->rd_id;
- rte->inh = false;
- rte->archive = false;
- rte->inFromCl = true;
- rte->timeQual = NULL;
- rtlist = lcons (rte, NIL);
- econtext->ecxt_scantuple = slot; /* scan tuple slot */
- econtext->ecxt_innertuple = NULL; /* inner tuple slot */
- econtext->ecxt_outertuple = NULL; /* outer tuple slot */
- econtext->ecxt_relation = rel; /* relation */
- econtext->ecxt_relid = 0; /* relid */
- econtext->ecxt_param_list_info = NULL; /* param list info */
- econtext->ecxt_range_table = rtlist; /* range table */
-
- for (i = 0; i < ncheck; i++)
- {
- qual = (List*) stringToNode (check[i].ccbin);
-
- res = ExecQual (qual, econtext);
-
- pfree (qual);
-
- if ( !res )
- return (check[i].ccname);
- }
-
- pfree (slot);
- pfree (rte->relname);
- pfree (rte);
- pfree (rtlist);
- pfree (econtext);
-
- return ((char *) NULL);
-
+ int ncheck = rel->rd_att->constr->num_check;
+ ConstrCheck *check = rel->rd_att->constr->check;
+ ExprContext *econtext = makeNode(ExprContext);
+ TupleTableSlot *slot = makeNode(TupleTableSlot);
+ RangeTblEntry *rte = makeNode(RangeTblEntry);
+ List *rtlist;
+ List *qual;
+ bool res;
+ int i;
+
+ slot->val = tuple;
+ slot->ttc_shouldFree = false;
+ slot->ttc_descIsNew = true;
+ slot->ttc_tupleDescriptor = rel->rd_att;
+ slot->ttc_buffer = InvalidBuffer;
+ slot->ttc_whichplan = -1;
+ rte->relname = nameout(&(rel->rd_rel->relname));
+ rte->timeRange = NULL;
+ rte->refname = rte->relname;
+ rte->relid = rel->rd_id;
+ rte->inh = false;
+ rte->archive = false;
+ rte->inFromCl = true;
+ rte->timeQual = NULL;
+ rtlist = lcons(rte, NIL);
+ econtext->ecxt_scantuple = slot; /* scan tuple slot */
+ econtext->ecxt_innertuple = NULL; /* inner tuple slot */
+ econtext->ecxt_outertuple = NULL; /* outer tuple slot */
+ econtext->ecxt_relation = rel; /* relation */
+ econtext->ecxt_relid = 0; /* relid */
+ econtext->ecxt_param_list_info = NULL; /* param list info */
+ econtext->ecxt_range_table = rtlist; /* range table */
+
+ for (i = 0; i < ncheck; i++)
+ {
+ qual = (List *) stringToNode(check[i].ccbin);
+
+ res = ExecQual(qual, econtext);
+
+ pfree(qual);
+
+ if (!res)
+ return (check[i].ccname);
+ }
+
+ pfree(slot);
+ pfree(rte->relname);
+ pfree(rte);
+ pfree(rtlist);
+ pfree(econtext);
+
+ return ((char *) NULL);
+
}
HeapTuple
-ExecConstraints (char *caller, Relation rel, HeapTuple tuple)
+ExecConstraints(char *caller, Relation rel, HeapTuple tuple)
{
- HeapTuple newtuple = tuple;
-
- Assert ( rel->rd_att->constr );
-
- if ( rel->rd_att->constr->num_defval > 0 )
- newtuple = tuple = ExecAttrDefault (rel, tuple);
-
- if ( rel->rd_att->constr->has_not_null )
- {
- int attrChk;
-
- for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
+ HeapTuple newtuple = tuple;
+
+ Assert(rel->rd_att->constr);
+
+ if (rel->rd_att->constr->num_defval > 0)
+ newtuple = tuple = ExecAttrDefault(rel, tuple);
+
+ if (rel->rd_att->constr->has_not_null)
{
- if (rel->rd_att->attrs[attrChk-1]->attnotnull && heap_attisnull (tuple,attrChk))
- elog(WARN,"%s: Fail to add null value in not null attribute %s",
- caller, rel->rd_att->attrs[attrChk-1]->attname.data);
- }
- }
-
- if ( rel->rd_att->constr->num_check > 0 )
- {
- char *failed;
-
- if ( ( failed = ExecRelCheck (rel, tuple) ) != NULL )
- elog(WARN,"%s: rejected due to CHECK constraint %s", caller, failed);
- }
-
- return (newtuple);
+ int attrChk;
+
+ for (attrChk = 1; attrChk <= rel->rd_att->natts; attrChk++)
+ {
+ if (rel->rd_att->attrs[attrChk - 1]->attnotnull && heap_attisnull(tuple, attrChk))
+ elog(WARN, "%s: Fail to add null value in not null attribute %s",
+ caller, rel->rd_att->attrs[attrChk - 1]->attname.data);
+ }
+ }
+
+ if (rel->rd_att->constr->num_check > 0)
+ {
+ char *failed;
+
+ if ((failed = ExecRelCheck(rel, tuple)) != NULL)
+ elog(WARN, "%s: rejected due to CHECK constraint %s", caller, failed);
+ }
+
+ return (newtuple);
}
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index f9e18d948f0..89caefd162e 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -1,75 +1,75 @@
/*-------------------------------------------------------------------------
*
* execProcnode.c--
- * contains dispatch functions which call the appropriate "initialize",
- * "get a tuple", and "cleanup" routines for the given node type.
- * If the node has children, then it will presumably call ExecInitNode,
- * ExecProcNode, or ExecEndNode on it's subnodes and do the appropriate
- * processing..
+ * contains dispatch functions which call the appropriate "initialize",
+ * "get a tuple", and "cleanup" routines for the given node type.
+ * If the node has children, then it will presumably call ExecInitNode,
+ * ExecProcNode, or ExecEndNode on it's subnodes and do the appropriate
+ * processing..
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.2 1996/10/31 10:11:27 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.3 1997/09/07 04:41:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * ExecInitNode - initialize a plan node and it's subplans
- * ExecProcNode - get a tuple by executing the plan node
- * ExecEndNode - shut down a plan node and it's subplans
+ * INTERFACE ROUTINES
+ * ExecInitNode - initialize a plan node and it's subplans
+ * ExecProcNode - get a tuple by executing the plan node
+ * ExecEndNode - shut down a plan node and it's subplans
*
- * NOTES
- * This used to be three files. It is now all combined into
- * one file so that it is easier to keep ExecInitNode, ExecProcNode,
- * and ExecEndNode in sync when new nodes are added.
- *
- * EXAMPLE
- * suppose we want the age of the manager of the shoe department and
- * the number of employees in that department. so we have the query:
+ * NOTES
+ * This used to be three files. It is now all combined into
+ * one file so that it is easier to keep ExecInitNode, ExecProcNode,
+ * and ExecEndNode in sync when new nodes are added.
*
- * retrieve (DEPT.no_emps, EMP.age)
- * where EMP.name = DEPT.mgr and
- * DEPT.name = "shoe"
- *
- * Suppose the planner gives us the following plan:
- *
- * Nest Loop (DEPT.mgr = EMP.name)
- * / \
- * / \
- * Seq Scan Seq Scan
- * DEPT EMP
- * (name = "shoe")
- *
- * ExecStart() is called first.
- * It calls InitPlan() which calls ExecInitNode() on
- * the root of the plan -- the nest loop node.
+ * EXAMPLE
+ * suppose we want the age of the manager of the shoe department and
+ * the number of employees in that department. so we have the query:
*
- * * ExecInitNode() notices that it is looking at a nest loop and
- * as the code below demonstrates, it calls ExecInitNestLoop().
- * Eventually this calls ExecInitNode() on the right and left subplans
- * and so forth until the entire plan is initialized.
- *
- * * Then when ExecRun() is called, it calls ExecutePlan() which
- * calls ExecProcNode() repeatedly on the top node of the plan.
- * Each time this happens, ExecProcNode() will end up calling
- * ExecNestLoop(), which calls ExecProcNode() on its subplans.
- * Each of these subplans is a sequential scan so ExecSeqScan() is
- * called. The slots returned by ExecSeqScan() may contain
- * tuples which contain the attributes ExecNestLoop() uses to
- * form the tuples it returns.
+ * retrieve (DEPT.no_emps, EMP.age)
+ * where EMP.name = DEPT.mgr and
+ * DEPT.name = "shoe"
*
- * * Eventually ExecSeqScan() stops returning tuples and the nest
- * loop join ends. Lastly, ExecEnd() calls ExecEndNode() which
- * calls ExecEndNestLoop() which in turn calls ExecEndNode() on
- * its subplans which result in ExecEndSeqScan().
+ * Suppose the planner gives us the following plan:
*
- * This should show how the executor works by having
- * ExecInitNode(), ExecProcNode() and ExecEndNode() dispatch
- * their work to the appopriate node support routines which may
- * in turn call these routines themselves on their subplans.
+ * Nest Loop (DEPT.mgr = EMP.name)
+ * / \
+ * / \
+ * Seq Scan Seq Scan
+ * DEPT EMP
+ * (name = "shoe")
+ *
+ * ExecStart() is called first.
+ * It calls InitPlan() which calls ExecInitNode() on
+ * the root of the plan -- the nest loop node.
+ *
+ * * ExecInitNode() notices that it is looking at a nest loop and
+ * as the code below demonstrates, it calls ExecInitNestLoop().
+ * Eventually this calls ExecInitNode() on the right and left subplans
+ * and so forth until the entire plan is initialized.
+ *
+ * * Then when ExecRun() is called, it calls ExecutePlan() which
+ * calls ExecProcNode() repeatedly on the top node of the plan.
+ * Each time this happens, ExecProcNode() will end up calling
+ * ExecNestLoop(), which calls ExecProcNode() on its subplans.
+ * Each of these subplans is a sequential scan so ExecSeqScan() is
+ * called. The slots returned by ExecSeqScan() may contain
+ * tuples which contain the attributes ExecNestLoop() uses to
+ * form the tuples it returns.
+ *
+ * * Eventually ExecSeqScan() stops returning tuples and the nest
+ * loop join ends. Lastly, ExecEnd() calls ExecEndNode() which
+ * calls ExecEndNestLoop() which in turn calls ExecEndNode() on
+ * its subplans which result in ExecEndSeqScan().
+ *
+ * This should show how the executor works by having
+ * ExecInitNode(), ExecProcNode() and ExecEndNode() dispatch
+ * their work to the appopriate node support routines which may
+ * in turn call these routines themselves on their subplans.
*
*/
#include "postgres.h"
@@ -91,389 +91,393 @@
#include "executor/nodeTee.h"
/* ------------------------------------------------------------------------
- * ExecInitNode
- *
- * Recursively initializes all the nodes in the plan rooted
- * at 'node'.
- *
- * Initial States:
- * 'node' is the plan produced by the query planner
- *
- * returns TRUE/FALSE on whether the plan was successfully initialized
+ * ExecInitNode
+ *
+ * Recursively initializes all the nodes in the plan rooted
+ * at 'node'.
+ *
+ * Initial States:
+ * 'node' is the plan produced by the query planner
+ *
+ * returns TRUE/FALSE on whether the plan was successfully initialized
* ------------------------------------------------------------------------
*/
bool
-ExecInitNode(Plan *node, EState *estate, Plan *parent)
+ExecInitNode(Plan * node, EState * estate, Plan * parent)
{
- bool result;
-
- /* ----------------
- * do nothing when we get to the end
- * of a leaf on tree.
- * ----------------
- */
- if (node == NULL)
- return FALSE;
-
- switch(nodeTag(node)) {
- /* ----------------
- * control nodes
- * ----------------
- */
- case T_Result:
- result = ExecInitResult((Result *)node, estate, parent);
- break;
-
- case T_Append:
- result = ExecInitAppend((Append *)node, estate, parent);
- break;
-
- /* ----------------
- * scan nodes
- * ----------------
- */
- case T_SeqScan:
- result = ExecInitSeqScan((SeqScan *)node, estate, parent);
- break;
-
- case T_IndexScan:
- result = ExecInitIndexScan((IndexScan *)node, estate, parent);
- break;
-
- /* ----------------
- * join nodes
- * ----------------
- */
- case T_NestLoop:
- result = ExecInitNestLoop((NestLoop *)node, estate, parent);
- break;
-
- case T_MergeJoin:
- result = ExecInitMergeJoin((MergeJoin *)node, estate, parent);
- break;
-
+ bool result;
+
/* ----------------
- * materialization nodes
+ * do nothing when we get to the end
+ * of a leaf on tree.
* ----------------
*/
- case T_Material:
- result = ExecInitMaterial((Material *)node, estate, parent);
- break;
-
- case T_Sort:
- result = ExecInitSort((Sort *)node, estate, parent);
- break;
-
- case T_Unique:
- result = ExecInitUnique((Unique *)node, estate, parent);
- break;
-
- case T_Group:
- result = ExecInitGroup((Group *)node, estate, parent);
- break;
-
- case T_Agg:
- result = ExecInitAgg((Agg *)node, estate, parent);
- break;
-
- case T_Hash:
- result = ExecInitHash((Hash *)node, estate, parent);
- break;
-
- case T_HashJoin:
- result = ExecInitHashJoin((HashJoin *)node, estate, parent);
- break;
-
- case T_Tee:
- result = ExecInitTee((Tee*)node, estate, parent);
- break;
-
- default:
- elog(DEBUG, "ExecInitNode: node not yet supported: %d",
- nodeTag(node));
- result = FALSE;
- }
-
- return result;
+ if (node == NULL)
+ return FALSE;
+
+ switch (nodeTag(node))
+ {
+ /* ----------------
+ * control nodes
+ * ----------------
+ */
+ case T_Result:
+ result = ExecInitResult((Result *) node, estate, parent);
+ break;
+
+ case T_Append:
+ result = ExecInitAppend((Append *) node, estate, parent);
+ break;
+
+ /* ----------------
+ * scan nodes
+ * ----------------
+ */
+ case T_SeqScan:
+ result = ExecInitSeqScan((SeqScan *) node, estate, parent);
+ break;
+
+ case T_IndexScan:
+ result = ExecInitIndexScan((IndexScan *) node, estate, parent);
+ break;
+
+ /* ----------------
+ * join nodes
+ * ----------------
+ */
+ case T_NestLoop:
+ result = ExecInitNestLoop((NestLoop *) node, estate, parent);
+ break;
+
+ case T_MergeJoin:
+ result = ExecInitMergeJoin((MergeJoin *) node, estate, parent);
+ break;
+
+ /* ----------------
+ * materialization nodes
+ * ----------------
+ */
+ case T_Material:
+ result = ExecInitMaterial((Material *) node, estate, parent);
+ break;
+
+ case T_Sort:
+ result = ExecInitSort((Sort *) node, estate, parent);
+ break;
+
+ case T_Unique:
+ result = ExecInitUnique((Unique *) node, estate, parent);
+ break;
+
+ case T_Group:
+ result = ExecInitGroup((Group *) node, estate, parent);
+ break;
+
+ case T_Agg:
+ result = ExecInitAgg((Agg *) node, estate, parent);
+ break;
+
+ case T_Hash:
+ result = ExecInitHash((Hash *) node, estate, parent);
+ break;
+
+ case T_HashJoin:
+ result = ExecInitHashJoin((HashJoin *) node, estate, parent);
+ break;
+
+ case T_Tee:
+ result = ExecInitTee((Tee *) node, estate, parent);
+ break;
+
+ default:
+ elog(DEBUG, "ExecInitNode: node not yet supported: %d",
+ nodeTag(node));
+ result = FALSE;
+ }
+
+ return result;
}
/* ----------------------------------------------------------------
- * ExecProcNode
- *
- * Initial States:
- * the query tree must be initialized once by calling ExecInit.
+ * ExecProcNode
+ *
+ * Initial States:
+ * the query tree must be initialized once by calling ExecInit.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecProcNode(Plan *node, Plan *parent)
+ExecProcNode(Plan * node, Plan * parent)
{
- TupleTableSlot *result;
-
- /* ----------------
- * deal with NULL nodes..
- * ----------------
- */
- if (node == NULL)
- return NULL;
-
- switch(nodeTag(node)) {
- /* ----------------
- * control nodes
- * ----------------
- */
- case T_Result:
- result = ExecResult((Result *)node);
- break;
-
- case T_Append:
- result = ExecProcAppend((Append *)node);
- break;
-
- /* ----------------
- * scan nodes
- * ----------------
- */
- case T_SeqScan:
- result = ExecSeqScan((SeqScan *)node);
- break;
-
- case T_IndexScan:
- result = ExecIndexScan((IndexScan *)node);
- break;
-
- /* ----------------
- * join nodes
- * ----------------
- */
- case T_NestLoop:
- result = ExecNestLoop((NestLoop *)node, parent);
- break;
-
- case T_MergeJoin:
- result = ExecMergeJoin((MergeJoin *)node);
- break;
-
+ TupleTableSlot *result;
+
/* ----------------
- * materialization nodes
+ * deal with NULL nodes..
* ----------------
*/
- case T_Material:
- result = ExecMaterial((Material *)node);
- break;
-
- case T_Sort:
- result = ExecSort((Sort *)node);
- break;
-
- case T_Unique:
- result = ExecUnique((Unique *)node);
- break;
-
- case T_Group:
- result = ExecGroup((Group *)node);
- break;
-
- case T_Agg:
- result = ExecAgg((Agg *)node);
- break;
-
- case T_Hash:
- result = ExecHash((Hash *)node);
- break;
-
- case T_HashJoin:
- result = ExecHashJoin((HashJoin *)node);
- break;
-
- case T_Tee:
- result = ExecTee((Tee*)node, parent);
- break;
-
- default:
- elog(DEBUG, "ExecProcNode: node not yet supported: %d",
- nodeTag(node));
- result = FALSE;
- }
-
- return result;
+ if (node == NULL)
+ return NULL;
+
+ switch (nodeTag(node))
+ {
+ /* ----------------
+ * control nodes
+ * ----------------
+ */
+ case T_Result:
+ result = ExecResult((Result *) node);
+ break;
+
+ case T_Append:
+ result = ExecProcAppend((Append *) node);
+ break;
+
+ /* ----------------
+ * scan nodes
+ * ----------------
+ */
+ case T_SeqScan:
+ result = ExecSeqScan((SeqScan *) node);
+ break;
+
+ case T_IndexScan:
+ result = ExecIndexScan((IndexScan *) node);
+ break;
+
+ /* ----------------
+ * join nodes
+ * ----------------
+ */
+ case T_NestLoop:
+ result = ExecNestLoop((NestLoop *) node, parent);
+ break;
+
+ case T_MergeJoin:
+ result = ExecMergeJoin((MergeJoin *) node);
+ break;
+
+ /* ----------------
+ * materialization nodes
+ * ----------------
+ */
+ case T_Material:
+ result = ExecMaterial((Material *) node);
+ break;
+
+ case T_Sort:
+ result = ExecSort((Sort *) node);
+ break;
+
+ case T_Unique:
+ result = ExecUnique((Unique *) node);
+ break;
+
+ case T_Group:
+ result = ExecGroup((Group *) node);
+ break;
+
+ case T_Agg:
+ result = ExecAgg((Agg *) node);
+ break;
+
+ case T_Hash:
+ result = ExecHash((Hash *) node);
+ break;
+
+ case T_HashJoin:
+ result = ExecHashJoin((HashJoin *) node);
+ break;
+
+ case T_Tee:
+ result = ExecTee((Tee *) node, parent);
+ break;
+
+ default:
+ elog(DEBUG, "ExecProcNode: node not yet supported: %d",
+ nodeTag(node));
+ result = FALSE;
+ }
+
+ return result;
}
int
-ExecCountSlotsNode(Plan *node)
+ExecCountSlotsNode(Plan * node)
{
- if (node == (Plan *)NULL)
- return 0;
-
- switch(nodeTag(node)) {
- /* ----------------
- * control nodes
- * ----------------
- */
- case T_Result:
- return ExecCountSlotsResult((Result *)node);
-
- case T_Append:
- return ExecCountSlotsAppend((Append *)node);
-
- /* ----------------
- * scan nodes
- * ----------------
- */
- case T_SeqScan:
- return ExecCountSlotsSeqScan((SeqScan *)node);
+ if (node == (Plan *) NULL)
+ return 0;
- case T_IndexScan:
- return ExecCountSlotsIndexScan((IndexScan *)node);
-
- /* ----------------
- * join nodes
- * ----------------
- */
- case T_NestLoop:
- return ExecCountSlotsNestLoop((NestLoop *)node);
-
- case T_MergeJoin:
- return ExecCountSlotsMergeJoin((MergeJoin *)node);
-
- /* ----------------
- * materialization nodes
- * ----------------
- */
- case T_Material:
- return ExecCountSlotsMaterial((Material *)node);
-
- case T_Sort:
- return ExecCountSlotsSort((Sort *)node);
-
- case T_Unique:
- return ExecCountSlotsUnique((Unique *)node);
-
- case T_Group:
- return ExecCountSlotsGroup((Group *)node);
-
- case T_Agg:
- return ExecCountSlotsAgg((Agg *)node);
-
- case T_Hash:
- return ExecCountSlotsHash((Hash *)node);
-
- case T_HashJoin:
- return ExecCountSlotsHashJoin((HashJoin *)node);
-
- case T_Tee:
- return ExecCountSlotsTee((Tee*)node);
-
- default:
- elog(WARN, "ExecCountSlotsNode: node not yet supported: %d",
- nodeTag(node));
- break;
- }
- return 0;
+ switch (nodeTag(node))
+ {
+ /* ----------------
+ * control nodes
+ * ----------------
+ */
+ case T_Result:
+ return ExecCountSlotsResult((Result *) node);
+
+ case T_Append:
+ return ExecCountSlotsAppend((Append *) node);
+
+ /* ----------------
+ * scan nodes
+ * ----------------
+ */
+ case T_SeqScan:
+ return ExecCountSlotsSeqScan((SeqScan *) node);
+
+ case T_IndexScan:
+ return ExecCountSlotsIndexScan((IndexScan *) node);
+
+ /* ----------------
+ * join nodes
+ * ----------------
+ */
+ case T_NestLoop:
+ return ExecCountSlotsNestLoop((NestLoop *) node);
+
+ case T_MergeJoin:
+ return ExecCountSlotsMergeJoin((MergeJoin *) node);
+
+ /* ----------------
+ * materialization nodes
+ * ----------------
+ */
+ case T_Material:
+ return ExecCountSlotsMaterial((Material *) node);
+
+ case T_Sort:
+ return ExecCountSlotsSort((Sort *) node);
+
+ case T_Unique:
+ return ExecCountSlotsUnique((Unique *) node);
+
+ case T_Group:
+ return ExecCountSlotsGroup((Group *) node);
+
+ case T_Agg:
+ return ExecCountSlotsAgg((Agg *) node);
+
+ case T_Hash:
+ return ExecCountSlotsHash((Hash *) node);
+
+ case T_HashJoin:
+ return ExecCountSlotsHashJoin((HashJoin *) node);
+
+ case T_Tee:
+ return ExecCountSlotsTee((Tee *) node);
+
+ default:
+ elog(WARN, "ExecCountSlotsNode: node not yet supported: %d",
+ nodeTag(node));
+ break;
+ }
+ return 0;
}
-/* ----------------------------------------------------------------
- * ExecEndNode
- *
- * Recursively cleans up all the nodes in the plan rooted
- * at 'node'.
+/* ----------------------------------------------------------------
+ * ExecEndNode
*
- * After this operation, the query plan will not be able to
- * processed any further. This should be called only after
- * the query plan has been fully executed.
- * ----------------------------------------------------------------
+ * Recursively cleans up all the nodes in the plan rooted
+ * at 'node'.
+ *
+ * After this operation, the query plan will not be able to
+ * processed any further. This should be called only after
+ * the query plan has been fully executed.
+ * ----------------------------------------------------------------
*/
void
-ExecEndNode(Plan *node, Plan *parent)
+ExecEndNode(Plan * node, Plan * parent)
{
- /* ----------------
- * do nothing when we get to the end
- * of a leaf on tree.
- * ----------------
- */
- if (node == NULL)
- return;
-
- switch(nodeTag(node)) {
- /* ----------------
- * control nodes
- * ----------------
- */
- case T_Result:
- ExecEndResult((Result *)node);
- break;
-
- case T_Append:
- ExecEndAppend((Append *)node);
- break;
-
- /* ----------------
- * scan nodes
- * ----------------
- */
- case T_SeqScan:
- ExecEndSeqScan((SeqScan *)node);
- break;
-
- case T_IndexScan:
- ExecEndIndexScan((IndexScan *)node);
- break;
-
/* ----------------
- * join nodes
+ * do nothing when we get to the end
+ * of a leaf on tree.
* ----------------
*/
- case T_NestLoop:
- ExecEndNestLoop((NestLoop *)node);
- break;
-
- case T_MergeJoin:
- ExecEndMergeJoin((MergeJoin *)node);
- break;
-
- /* ----------------
- * materialization nodes
- * ----------------
- */
- case T_Material:
- ExecEndMaterial((Material *)node);
- break;
-
- case T_Sort:
- ExecEndSort((Sort *)node);
- break;
-
- case T_Unique:
- ExecEndUnique((Unique *)node);
- break;
-
- case T_Group:
- ExecEndGroup((Group *)node);
- break;
-
- case T_Agg:
- ExecEndAgg((Agg *)node);
- break;
-
- /* ----------------
- * XXX add hooks to these
- * ----------------
- */
- case T_Hash:
- ExecEndHash((Hash *) node);
- break;
-
- case T_HashJoin:
- ExecEndHashJoin((HashJoin *) node);
- break;
-
- case T_Tee:
- ExecEndTee((Tee*) node, parent);
- break;
-
- default:
- elog(DEBUG, "ExecEndNode: node not yet supported",
- nodeTag(node));
- break;
- }
+ if (node == NULL)
+ return;
+
+ switch (nodeTag(node))
+ {
+ /* ----------------
+ * control nodes
+ * ----------------
+ */
+ case T_Result:
+ ExecEndResult((Result *) node);
+ break;
+
+ case T_Append:
+ ExecEndAppend((Append *) node);
+ break;
+
+ /* ----------------
+ * scan nodes
+ * ----------------
+ */
+ case T_SeqScan:
+ ExecEndSeqScan((SeqScan *) node);
+ break;
+
+ case T_IndexScan:
+ ExecEndIndexScan((IndexScan *) node);
+ break;
+
+ /* ----------------
+ * join nodes
+ * ----------------
+ */
+ case T_NestLoop:
+ ExecEndNestLoop((NestLoop *) node);
+ break;
+
+ case T_MergeJoin:
+ ExecEndMergeJoin((MergeJoin *) node);
+ break;
+
+ /* ----------------
+ * materialization nodes
+ * ----------------
+ */
+ case T_Material:
+ ExecEndMaterial((Material *) node);
+ break;
+
+ case T_Sort:
+ ExecEndSort((Sort *) node);
+ break;
+
+ case T_Unique:
+ ExecEndUnique((Unique *) node);
+ break;
+
+ case T_Group:
+ ExecEndGroup((Group *) node);
+ break;
+
+ case T_Agg:
+ ExecEndAgg((Agg *) node);
+ break;
+
+ /* ----------------
+ * XXX add hooks to these
+ * ----------------
+ */
+ case T_Hash:
+ ExecEndHash((Hash *) node);
+ break;
+
+ case T_HashJoin:
+ ExecEndHashJoin((HashJoin *) node);
+ break;
+
+ case T_Tee:
+ ExecEndTee((Tee *) node, parent);
+ break;
+
+ default:
+ elog(DEBUG, "ExecEndNode: node not yet supported",
+ nodeTag(node));
+ break;
+ }
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 536b0068342..7b8cb18ef25 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -1,32 +1,32 @@
/*-------------------------------------------------------------------------
*
* execQual.c--
- * Routines to evaluate qualification and targetlist expressions
+ * Routines to evaluate qualification and targetlist expressions
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.12 1997/08/19 21:31:03 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.13 1997/09/07 04:41:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * ExecEvalExpr - evaluate an expression and return a datum
- * ExecQual - return true/false if qualification is satisified
- * ExecTargetList - form a new tuple by projecting the given tuple
+ * INTERFACE ROUTINES
+ * ExecEvalExpr - evaluate an expression and return a datum
+ * ExecQual - return true/false if qualification is satisified
+ * ExecTargetList - form a new tuple by projecting the given tuple
*
- * NOTES
- * ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster
- * will speed up the entire system. Unfortunately they are currently
- * implemented recursively.. Eliminating the recursion is bound to
- * improve the speed of the executor.
+ * NOTES
+ * ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster
+ * will speed up the entire system. Unfortunately they are currently
+ * implemented recursively.. Eliminating the recursion is bound to
+ * improve the speed of the executor.
*
- * ExecTargetList() is used to make tuple projections. Rather then
- * trying to speed it up, the execution plan should be pre-processed
- * to facilitate attribute sharing between nodes wherever possible,
- * instead of doing needless copying. -cim 5/31/91
+ * ExecTargetList() is used to make tuple projections. Rather then
+ * trying to speed it up, the execution plan should be pre-processed
+ * to facilitate attribute sharing between nodes wherever possible,
+ * instead of doing needless copying. -cim 5/31/91
*
*/
#include <string.h>
@@ -56,7 +56,7 @@
#include "utils/mcxt.h"
/* ----------------
- * externs and constants
+ * externs and constants
* ----------------
*/
@@ -65,1492 +65,1577 @@
* Currently only used by ExecHashGetBucket and set only by ExecMakeVarConst
* and by ExecEvalArrayRef.
*/
-bool execConstByVal;
-int execConstLen;
+bool execConstByVal;
+int execConstLen;
/* static functions decls */
-static Datum ExecEvalAggreg(Aggreg *agg, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
- bool *isNull, bool *isDone);
-static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext,
- bool *isNull, bool *isDone);
-static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext,
- List *argList, Datum argV[], bool *argIsDone);
-static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext,
- bool *isNull);
-static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
-static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
-static Datum ExecMakeFunctionResult(Node *node, List *arguments,
- ExprContext *econtext, bool *isNull, bool *isDone);
-static bool ExecQualClause(Node *clause, ExprContext *econtext);
+static Datum ExecEvalAggreg(Aggreg * agg, ExprContext * econtext, bool * isNull);
+static Datum
+ExecEvalArrayRef(ArrayRef * arrayRef, ExprContext * econtext,
+ bool * isNull, bool * isDone);
+static Datum ExecEvalAnd(Expr * andExpr, ExprContext * econtext, bool * isNull);
+static Datum
+ExecEvalFunc(Expr * funcClause, ExprContext * econtext,
+ bool * isNull, bool * isDone);
+static void
+ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext * econtext,
+ List * argList, Datum argV[], bool * argIsDone);
+static Datum ExecEvalNot(Expr * notclause, ExprContext * econtext, bool * isNull);
+static Datum
+ExecEvalOper(Expr * opClause, ExprContext * econtext,
+ bool * isNull);
+static Datum ExecEvalOr(Expr * orExpr, ExprContext * econtext, bool * isNull);
+static Datum ExecEvalVar(Var * variable, ExprContext * econtext, bool * isNull);
+static Datum
+ExecMakeFunctionResult(Node * node, List * arguments,
+ ExprContext * econtext, bool * isNull, bool * isDone);
+static bool ExecQualClause(Node * clause, ExprContext * econtext);
/* --------------------------------
- * ExecEvalArrayRef
+ * ExecEvalArrayRef
*
- * This function takes an ArrayRef and returns a Const Node if it
- * is an array reference or returns the changed Array Node if it is
- * an array assignment.
+ * This function takes an ArrayRef and returns a Const Node if it
+ * is an array reference or returns the changed Array Node if it is
+ * an array assignment.
*
* --------------------------------
*/
-static Datum
-ExecEvalArrayRef(ArrayRef *arrayRef,
- ExprContext *econtext,
- bool *isNull,
- bool *isDone)
+static Datum
+ExecEvalArrayRef(ArrayRef * arrayRef,
+ ExprContext * econtext,
+ bool * isNull,
+ bool * isDone)
{
- bool dummy;
- int i = 0, j = 0;
- ArrayType *array_scanner;
- List *upperIndexpr, *lowerIndexpr;
- Node *assgnexpr;
- List *elt;
- IntArray upper, lower;
- int *lIndex;
- char *dataPtr;
-
- *isNull = false;
- array_scanner = (ArrayType*)ExecEvalExpr(arrayRef->refexpr,
- econtext,
- isNull,
- isDone);
- if (*isNull) return (Datum)NULL;
-
- upperIndexpr = arrayRef->refupperindexpr;
-
- foreach (elt, upperIndexpr) {
- upper.indx[i++] = (int32)ExecEvalExpr((Node*)lfirst(elt),
- econtext,
- isNull,
- &dummy);
- if (*isNull) return (Datum)NULL;
- }
-
- lowerIndexpr = arrayRef->reflowerindexpr;
- lIndex = NULL;
- if (lowerIndexpr != NIL) {
- foreach (elt, lowerIndexpr) {
- lower.indx[j++] = (int32)ExecEvalExpr((Node*)lfirst(elt),
- econtext,
- isNull,
- &dummy);
- if (*isNull) return (Datum)NULL;
+ bool dummy;
+ int i = 0,
+ j = 0;
+ ArrayType *array_scanner;
+ List *upperIndexpr,
+ *lowerIndexpr;
+ Node *assgnexpr;
+ List *elt;
+ IntArray upper,
+ lower;
+ int *lIndex;
+ char *dataPtr;
+
+ *isNull = false;
+ array_scanner = (ArrayType *) ExecEvalExpr(arrayRef->refexpr,
+ econtext,
+ isNull,
+ isDone);
+ if (*isNull)
+ return (Datum) NULL;
+
+ upperIndexpr = arrayRef->refupperindexpr;
+
+ foreach(elt, upperIndexpr)
+ {
+ upper.indx[i++] = (int32) ExecEvalExpr((Node *) lfirst(elt),
+ econtext,
+ isNull,
+ &dummy);
+ if (*isNull)
+ return (Datum) NULL;
+ }
+
+ lowerIndexpr = arrayRef->reflowerindexpr;
+ lIndex = NULL;
+ if (lowerIndexpr != NIL)
+ {
+ foreach(elt, lowerIndexpr)
+ {
+ lower.indx[j++] = (int32) ExecEvalExpr((Node *) lfirst(elt),
+ econtext,
+ isNull,
+ &dummy);
+ if (*isNull)
+ return (Datum) NULL;
+ }
+ if (i != j)
+ elog(WARN,
+ "ExecEvalArrayRef: upper and lower indices mismatch");
+ lIndex = lower.indx;
}
- if (i != j)
- elog(WARN,
- "ExecEvalArrayRef: upper and lower indices mismatch");
- lIndex = lower.indx;
- }
-
- assgnexpr = arrayRef->refassgnexpr;
- if (assgnexpr != NULL) {
- dataPtr = (char*)ExecEvalExpr((Node *)
- assgnexpr, econtext,
- isNull, &dummy);
- if (*isNull) return (Datum)NULL;
- execConstByVal = arrayRef->refelembyval;
- execConstLen = arrayRef->refelemlength;
+
+ assgnexpr = arrayRef->refassgnexpr;
+ if (assgnexpr != NULL)
+ {
+ dataPtr = (char *) ExecEvalExpr((Node *)
+ assgnexpr, econtext,
+ isNull, &dummy);
+ if (*isNull)
+ return (Datum) NULL;
+ execConstByVal = arrayRef->refelembyval;
+ execConstLen = arrayRef->refelemlength;
+ if (lIndex == NULL)
+ return (Datum) array_set(array_scanner, i, upper.indx, dataPtr,
+ arrayRef->refelembyval,
+ arrayRef->refelemlength,
+ arrayRef->refattrlength, isNull);
+ return (Datum) array_assgn(array_scanner, i, upper.indx,
+ lower.indx,
+ (ArrayType *) dataPtr,
+ arrayRef->refelembyval,
+ arrayRef->refelemlength, isNull);
+ }
+ execConstByVal = arrayRef->refelembyval;
+ execConstLen = arrayRef->refelemlength;
if (lIndex == NULL)
- return (Datum) array_set(array_scanner, i, upper.indx, dataPtr,
- arrayRef->refelembyval,
- arrayRef->refelemlength,
- arrayRef->refattrlength, isNull);
- return (Datum) array_assgn(array_scanner, i, upper.indx,
- lower.indx,
- (ArrayType*)dataPtr,
- arrayRef->refelembyval,
- arrayRef->refelemlength, isNull);
- }
- execConstByVal = arrayRef->refelembyval;
- execConstLen = arrayRef->refelemlength;
- if (lIndex == NULL)
- return (Datum) array_ref(array_scanner, i, upper.indx,
- arrayRef->refelembyval,
- arrayRef->refelemlength,
- arrayRef->refattrlength, isNull);
- return (Datum) array_clip(array_scanner, i, upper.indx, lower.indx,
- arrayRef->refelembyval,
- arrayRef->refelemlength, isNull);
+ return (Datum) array_ref(array_scanner, i, upper.indx,
+ arrayRef->refelembyval,
+ arrayRef->refelemlength,
+ arrayRef->refattrlength, isNull);
+ return (Datum) array_clip(array_scanner, i, upper.indx, lower.indx,
+ arrayRef->refelembyval,
+ arrayRef->refelemlength, isNull);
}
/* ----------------------------------------------------------------
- * ExecEvalAggreg
- *
- * Returns a Datum whose value is the value of the precomputed
- * aggregate found in the given expression context.
+ * ExecEvalAggreg
+ *
+ * Returns a Datum whose value is the value of the precomputed
+ * aggregate found in the given expression context.
* ----------------------------------------------------------------
*/
-static Datum
-ExecEvalAggreg(Aggreg *agg, ExprContext *econtext, bool *isNull)
+static Datum
+ExecEvalAggreg(Aggreg * agg, ExprContext * econtext, bool * isNull)
{
-
- *isNull = econtext->ecxt_nulls[agg->aggno];
- return econtext->ecxt_values[agg->aggno];
+
+ *isNull = econtext->ecxt_nulls[agg->aggno];
+ return econtext->ecxt_values[agg->aggno];
}
/* ----------------------------------------------------------------
- * ExecEvalVar
- *
- * Returns a Datum whose value is the value of a range
- * variable with respect to given expression context.
+ * ExecEvalVar
+ *
+ * Returns a Datum whose value is the value of a range
+ * variable with respect to given expression context.
+ *
+ *
+ * As an entry condition, we expect that the the datatype the
+ * plan expects to get (as told by our "variable" argument) is in
+ * fact the datatype of the attribute the plan says to fetch (as
+ * seen in the current context, identified by our "econtext"
+ * argument).
+ *
+ * If we fetch a Type A attribute and Caller treats it as if it
+ * were Type B, there will be undefined results (e.g. crash).
+ * One way these might mismatch now is that we're accessing a
+ * catalog class and the type information in the pg_attribute
+ * class does not match the hardcoded pg_attribute information
+ * (in pg_attribute.h) for the class in question.
*
+ * We have an Assert to make sure this entry condition is met.
*
- * As an entry condition, we expect that the the datatype the
- * plan expects to get (as told by our "variable" argument) is in
- * fact the datatype of the attribute the plan says to fetch (as
- * seen in the current context, identified by our "econtext"
- * argument).
- *
- * If we fetch a Type A attribute and Caller treats it as if it
- * were Type B, there will be undefined results (e.g. crash).
- * One way these might mismatch now is that we're accessing a
- * catalog class and the type information in the pg_attribute
- * class does not match the hardcoded pg_attribute information
- * (in pg_attribute.h) for the class in question.
- *
- * We have an Assert to make sure this entry condition is met.
- *
* ---------------------------------------------------------------- */
-static Datum
-ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
+static Datum
+ExecEvalVar(Var * variable, ExprContext * econtext, bool * isNull)
{
- Datum result;
- TupleTableSlot *slot;
- AttrNumber attnum;
- HeapTuple heapTuple;
- TupleDesc tuple_type;
- Buffer buffer;
- bool byval;
- int16 len;
-
- /* ----------------
- * get the slot we want
- * ----------------
- */
- switch(variable->varno) {
- case INNER: /* get the tuple from the inner node */
- slot = econtext->ecxt_innertuple;
- break;
-
- case OUTER: /* get the tuple from the outer node */
- slot = econtext->ecxt_outertuple;
- break;
-
- default: /* get the tuple from the relation being scanned */
- slot = econtext->ecxt_scantuple;
- break;
- }
-
- /* ----------------
- * extract tuple information from the slot
- * ----------------
- */
- heapTuple = slot->val;
- tuple_type = slot->ttc_tupleDescriptor;
- buffer = slot->ttc_buffer;
-
- attnum = variable->varattno;
-
- /* (See prolog for explanation of this Assert) */
- Assert(attnum <= 0 ||
- (attnum - 1 <= tuple_type->natts - 1 &&
- tuple_type->attrs[attnum-1] != NULL &&
- variable->vartype == tuple_type->attrs[attnum-1]->atttypid))
-
- /*
- * If the attribute number is invalid, then we are supposed to
- * return the entire tuple, we give back a whole slot so that
- * callers know what the tuple looks like.
- */
- if (attnum == InvalidAttrNumber)
+ Datum result;
+ TupleTableSlot *slot;
+ AttrNumber attnum;
+ HeapTuple heapTuple;
+ TupleDesc tuple_type;
+ Buffer buffer;
+ bool byval;
+ int16 len;
+
+ /* ----------------
+ * get the slot we want
+ * ----------------
+ */
+ switch (variable->varno)
+ {
+ case INNER: /* get the tuple from the inner node */
+ slot = econtext->ecxt_innertuple;
+ break;
+
+ case OUTER: /* get the tuple from the outer node */
+ slot = econtext->ecxt_outertuple;
+ break;
+
+ default: /* get the tuple from the relation being
+ * scanned */
+ slot = econtext->ecxt_scantuple;
+ break;
+ }
+
+ /* ----------------
+ * extract tuple information from the slot
+ * ----------------
+ */
+ heapTuple = slot->val;
+ tuple_type = slot->ttc_tupleDescriptor;
+ buffer = slot->ttc_buffer;
+
+ attnum = variable->varattno;
+
+ /* (See prolog for explanation of this Assert) */
+ Assert(attnum <= 0 ||
+ (attnum - 1 <= tuple_type->natts - 1 &&
+ tuple_type->attrs[attnum - 1] != NULL &&
+ variable->vartype == tuple_type->attrs[attnum - 1]->atttypid))
+
+ /*
+ * If the attribute number is invalid, then we are supposed to return
+ * the entire tuple, we give back a whole slot so that callers know
+ * what the tuple looks like.
+ */
+ if (attnum == InvalidAttrNumber)
{
- TupleTableSlot *tempSlot;
- TupleDesc td;
- HeapTuple tup;
-
- tempSlot = makeNode(TupleTableSlot);
- tempSlot->ttc_shouldFree = false;
- tempSlot->ttc_descIsNew = true;
- tempSlot->ttc_tupleDescriptor = (TupleDesc)NULL,
- tempSlot->ttc_buffer = InvalidBuffer;
- tempSlot->ttc_whichplan = -1;
-
- tup = heap_copytuple(slot->val);
- td = CreateTupleDescCopy(slot->ttc_tupleDescriptor);
-
- ExecSetSlotDescriptor(tempSlot, td);
-
- ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
- return (Datum) tempSlot;
+ TupleTableSlot *tempSlot;
+ TupleDesc td;
+ HeapTuple tup;
+
+ tempSlot = makeNode(TupleTableSlot);
+ tempSlot->ttc_shouldFree = false;
+ tempSlot->ttc_descIsNew = true;
+ tempSlot->ttc_tupleDescriptor = (TupleDesc) NULL,
+ tempSlot->ttc_buffer = InvalidBuffer;
+ tempSlot->ttc_whichplan = -1;
+
+ tup = heap_copytuple(slot->val);
+ td = CreateTupleDescCopy(slot->ttc_tupleDescriptor);
+
+ ExecSetSlotDescriptor(tempSlot, td);
+
+ ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
+ return (Datum) tempSlot;
}
-
- result = (Datum)
- heap_getattr(heapTuple, /* tuple containing attribute */
- buffer, /* buffer associated with tuple */
- attnum, /* attribute number of desired attribute */
- tuple_type, /* tuple descriptor of tuple */
- isNull); /* return: is attribute null? */
-
- /* ----------------
- * return null if att is null
- * ----------------
- */
- if (*isNull)
- return (Datum) NULL;
-
- /* ----------------
- * get length and type information..
- * ??? what should we do about variable length attributes
- * - variable length attributes have their length stored
- * in the first 4 bytes of the memory pointed to by the
- * returned value.. If we can determine that the type
- * is a variable length type, we can do the right thing.
- * -cim 9/15/89
- * ----------------
- */
- if (attnum < 0) {
+
+ result = (Datum)
+ heap_getattr(heapTuple, /* tuple containing attribute */
+ buffer, /* buffer associated with tuple */
+ attnum, /* attribute number of desired attribute */
+ tuple_type,/* tuple descriptor of tuple */
+ isNull); /* return: is attribute null? */
+
/* ----------------
- * If this is a pseudo-att, we get the type and fake the length.
- * There ought to be a routine to return the real lengths, so
- * we'll mark this one ... XXX -mao
+ * return null if att is null
* ----------------
*/
- len = heap_sysattrlen(attnum); /* XXX see -mao above */
- byval = heap_sysattrbyval(attnum); /* XXX see -mao above */
- } else {
- len = tuple_type->attrs[ attnum-1 ]->attlen;
- byval = tuple_type->attrs[ attnum-1 ]->attbyval ? true : false ;
- }
-
- execConstByVal = byval;
- execConstLen = len;
-
- return result;
+ if (*isNull)
+ return (Datum) NULL;
+
+ /* ----------------
+ * get length and type information..
+ * ??? what should we do about variable length attributes
+ * - variable length attributes have their length stored
+ * in the first 4 bytes of the memory pointed to by the
+ * returned value.. If we can determine that the type
+ * is a variable length type, we can do the right thing.
+ * -cim 9/15/89
+ * ----------------
+ */
+ if (attnum < 0)
+ {
+ /* ----------------
+ * If this is a pseudo-att, we get the type and fake the length.
+ * There ought to be a routine to return the real lengths, so
+ * we'll mark this one ... XXX -mao
+ * ----------------
+ */
+ len = heap_sysattrlen(attnum); /* XXX see -mao above */
+ byval = heap_sysattrbyval(attnum); /* XXX see -mao above */
+ }
+ else
+ {
+ len = tuple_type->attrs[attnum - 1]->attlen;
+ byval = tuple_type->attrs[attnum - 1]->attbyval ? true : false;
+ }
+
+ execConstByVal = byval;
+ execConstLen = len;
+
+ return result;
}
/* ----------------------------------------------------------------
- * ExecEvalParam
+ * ExecEvalParam
*
- * Returns the value of a parameter. A param node contains
- * something like ($.name) and the expression context contains
- * the current parameter bindings (name = "sam") (age = 34)...
- * so our job is to replace the param node with the datum
- * containing the appropriate information ("sam").
+ * Returns the value of a parameter. A param node contains
+ * something like ($.name) and the expression context contains
+ * the current parameter bindings (name = "sam") (age = 34)...
+ * so our job is to replace the param node with the datum
+ * containing the appropriate information ("sam").
*
- * Q: if we have a parameter ($.foo) without a binding, i.e.
- * there is no (foo = xxx) in the parameter list info,
- * is this a fatal error or should this be a "not available"
- * (in which case we shoud return a Const node with the
- * isnull flag) ? -cim 10/13/89
+ * Q: if we have a parameter ($.foo) without a binding, i.e.
+ * there is no (foo = xxx) in the parameter list info,
+ * is this a fatal error or should this be a "not available"
+ * (in which case we shoud return a Const node with the
+ * isnull flag) ? -cim 10/13/89
*
- * Minor modification: Param nodes now have an extra field,
- * `paramkind' which specifies the type of parameter
- * (see params.h). So while searching the paramList for
- * a paramname/value pair, we have also to check for `kind'.
- *
- * NOTE: The last entry in `paramList' is always an
- * entry with kind == PARAM_INVALID.
+ * Minor modification: Param nodes now have an extra field,
+ * `paramkind' which specifies the type of parameter
+ * (see params.h). So while searching the paramList for
+ * a paramname/value pair, we have also to check for `kind'.
+ *
+ * NOTE: The last entry in `paramList' is always an
+ * entry with kind == PARAM_INVALID.
* ----------------------------------------------------------------
*/
Datum
-ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
+ExecEvalParam(Param * expression, ExprContext * econtext, bool * isNull)
{
-
- char *thisParameterName;
- int thisParameterKind;
- AttrNumber thisParameterId;
- int matchFound;
- ParamListInfo paramList;
-
- thisParameterName = expression->paramname;
- thisParameterKind = expression->paramkind;
- thisParameterId = expression->paramid;
- paramList = econtext->ecxt_param_list_info;
-
- *isNull = false;
- /*
- * search the list with the parameter info to find a matching name.
- * An entry with an InvalidName denotes the last element in the array.
- */
- matchFound = 0;
- if (paramList != NULL) {
+
+ char *thisParameterName;
+ int thisParameterKind;
+ AttrNumber thisParameterId;
+ int matchFound;
+ ParamListInfo paramList;
+
+ thisParameterName = expression->paramname;
+ thisParameterKind = expression->paramkind;
+ thisParameterId = expression->paramid;
+ paramList = econtext->ecxt_param_list_info;
+
+ *isNull = false;
+
/*
- * search for an entry in 'paramList' that matches
- * the `expression'.
+ * search the list with the parameter info to find a matching name. An
+ * entry with an InvalidName denotes the last element in the array.
*/
- while(paramList->kind != PARAM_INVALID && !matchFound) {
- switch (thisParameterKind) {
- case PARAM_NAMED:
- if (thisParameterKind == paramList->kind &&
- strcmp(paramList->name, thisParameterName) == 0){
- matchFound = 1;
- }
- break;
- case PARAM_NUM:
- if (thisParameterKind == paramList->kind &&
- paramList->id == thisParameterId) {
- matchFound = 1;
- }
- break;
- case PARAM_OLD:
- case PARAM_NEW:
- if (thisParameterKind == paramList->kind &&
- paramList->id == thisParameterId)
- {
- matchFound = 1;
- /*
- * sanity check
- */
- if (strcmp(paramList->name, thisParameterName) != 0){
- elog(WARN,
- "ExecEvalParam: new/old params with same id & diff names");
+ matchFound = 0;
+ if (paramList != NULL)
+ {
+
+ /*
+ * search for an entry in 'paramList' that matches the
+ * `expression'.
+ */
+ while (paramList->kind != PARAM_INVALID && !matchFound)
+ {
+ switch (thisParameterKind)
+ {
+ case PARAM_NAMED:
+ if (thisParameterKind == paramList->kind &&
+ strcmp(paramList->name, thisParameterName) == 0)
+ {
+ matchFound = 1;
+ }
+ break;
+ case PARAM_NUM:
+ if (thisParameterKind == paramList->kind &&
+ paramList->id == thisParameterId)
+ {
+ matchFound = 1;
+ }
+ break;
+ case PARAM_OLD:
+ case PARAM_NEW:
+ if (thisParameterKind == paramList->kind &&
+ paramList->id == thisParameterId)
+ {
+ matchFound = 1;
+
+ /*
+ * sanity check
+ */
+ if (strcmp(paramList->name, thisParameterName) != 0)
+ {
+ elog(WARN,
+ "ExecEvalParam: new/old params with same id & diff names");
+ }
+ }
+ break;
+ default:
+
+ /*
+ * oops! this is not supposed to happen!
+ */
+ elog(WARN, "ExecEvalParam: invalid paramkind %d",
+ thisParameterKind);
}
- }
- break;
- default:
+ if (!matchFound)
+ {
+ paramList++;
+ }
+ } /* while */
+ } /* if */
+
+ if (!matchFound)
+ {
+
/*
- * oops! this is not supposed to happen!
+ * ooops! we couldn't find this parameter in the parameter list.
+ * Signal an error
*/
- elog(WARN, "ExecEvalParam: invalid paramkind %d",
- thisParameterKind);
- }
- if (! matchFound) {
- paramList++;
- }
- } /*while*/
- } /*if*/
-
- if (!matchFound) {
+ elog(WARN, "ExecEvalParam: Unknown value for parameter %s",
+ thisParameterName);
+ }
+
/*
- * ooops! we couldn't find this parameter
- * in the parameter list. Signal an error
+ * return the value.
*/
- elog(WARN, "ExecEvalParam: Unknown value for parameter %s",
- thisParameterName);
- }
-
- /*
- * return the value.
- */
- if (paramList->isnull)
+ if (paramList->isnull)
{
- *isNull = true;
- return (Datum)NULL;
+ *isNull = true;
+ return (Datum) NULL;
}
-
- if (expression->param_tlist != NIL)
+
+ if (expression->param_tlist != NIL)
{
- HeapTuple tup;
- Datum value;
- List *tlist = expression->param_tlist;
- TargetEntry *tle = (TargetEntry *)lfirst(tlist);
- TupleTableSlot *slot = (TupleTableSlot *)paramList->value;
-
- tup = slot->val;
- value = ProjectAttribute(slot->ttc_tupleDescriptor,
- tle, tup, isNull);
- return value;
+ HeapTuple tup;
+ Datum value;
+ List *tlist = expression->param_tlist;
+ TargetEntry *tle = (TargetEntry *) lfirst(tlist);
+ TupleTableSlot *slot = (TupleTableSlot *) paramList->value;
+
+ tup = slot->val;
+ value = ProjectAttribute(slot->ttc_tupleDescriptor,
+ tle, tup, isNull);
+ return value;
}
- return(paramList->value);
+ return (paramList->value);
}
/* ----------------------------------------------------------------
- * ExecEvalOper / ExecEvalFunc support routines
+ * ExecEvalOper / ExecEvalFunc support routines
* ----------------------------------------------------------------
*/
/* ----------------
- * GetAttributeByName
- * GetAttributeByNum
+ * GetAttributeByName
+ * GetAttributeByNum
*
- * These are functions which return the value of the
- * named attribute out of the tuple from the arg slot. User defined
- * C functions which take a tuple as an argument are expected
- * to use this. Ex: overpaid(EMP) might call GetAttributeByNum().
+ * These are functions which return the value of the
+ * named attribute out of the tuple from the arg slot. User defined
+ * C functions which take a tuple as an argument are expected
+ * to use this. Ex: overpaid(EMP) might call GetAttributeByNum().
* ----------------
*/
#ifdef NOT_USED
-static char *
-GetAttributeByNum(TupleTableSlot *slot,
- AttrNumber attrno,
- bool *isNull)
+static char *
+GetAttributeByNum(TupleTableSlot * slot,
+ AttrNumber attrno,
+ bool * isNull)
{
- Datum retval;
-
- if (!AttributeNumberIsValid(attrno))
- elog(WARN, "GetAttributeByNum: Invalid attribute number");
-
- if (!AttrNumberIsForUserDefinedAttr(attrno))
- elog(WARN, "GetAttributeByNum: cannot access system attributes here");
-
- if (isNull == (bool *)NULL)
- elog(WARN, "GetAttributeByNum: a NULL isNull flag was passed");
-
- if (TupIsNull(slot))
+ Datum retval;
+
+ if (!AttributeNumberIsValid(attrno))
+ elog(WARN, "GetAttributeByNum: Invalid attribute number");
+
+ if (!AttrNumberIsForUserDefinedAttr(attrno))
+ elog(WARN, "GetAttributeByNum: cannot access system attributes here");
+
+ if (isNull == (bool *) NULL)
+ elog(WARN, "GetAttributeByNum: a NULL isNull flag was passed");
+
+ if (TupIsNull(slot))
{
- *isNull = true;
- return (char *) NULL;
+ *isNull = true;
+ return (char *) NULL;
}
-
- retval = (Datum)
- heap_getattr(slot->val,
- slot->ttc_buffer,
- attrno,
- slot->ttc_tupleDescriptor,
- isNull);
- if (*isNull)
- return (char *) NULL;
- return (char *) retval;
+
+ retval = (Datum)
+ heap_getattr(slot->val,
+ slot->ttc_buffer,
+ attrno,
+ slot->ttc_tupleDescriptor,
+ isNull);
+ if (*isNull)
+ return (char *) NULL;
+ return (char *) retval;
}
+
#endif
/* XXX char16 name for catalogs */
#ifdef NOT_USED
-char *
-att_by_num(TupleTableSlot *slot,
- AttrNumber attrno,
- bool *isNull)
+char *
+att_by_num(TupleTableSlot * slot,
+ AttrNumber attrno,
+ bool * isNull)
{
- return(GetAttributeByNum(slot, attrno, isNull));
+ return (GetAttributeByNum(slot, attrno, isNull));
}
+
#endif
-char *
-GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull)
+char *
+GetAttributeByName(TupleTableSlot * slot, char *attname, bool * isNull)
{
- AttrNumber attrno;
- TupleDesc tupdesc;
- HeapTuple tuple;
- Datum retval;
- int natts;
- int i;
-
- if (attname == NULL)
- elog(WARN, "GetAttributeByName: Invalid attribute name");
-
- if (isNull == (bool *)NULL)
- elog(WARN, "GetAttributeByName: a NULL isNull flag was passed");
-
- if (TupIsNull(slot))
+ AttrNumber attrno;
+ TupleDesc tupdesc;
+ HeapTuple tuple;
+ Datum retval;
+ int natts;
+ int i;
+
+ if (attname == NULL)
+ elog(WARN, "GetAttributeByName: Invalid attribute name");
+
+ if (isNull == (bool *) NULL)
+ elog(WARN, "GetAttributeByName: a NULL isNull flag was passed");
+
+ if (TupIsNull(slot))
{
- *isNull = true;
- return (char *) NULL;
+ *isNull = true;
+ return (char *) NULL;
}
-
- tupdesc = slot->ttc_tupleDescriptor;
- tuple = slot->val;
-
- natts = tuple->t_natts;
-
- attrno = InvalidAttrNumber;
- for (i=0;i<tupdesc->natts;i++) {
- if (namestrcmp(&(tupdesc->attrs[i]->attname), attname) == 0) {
- attrno = tupdesc->attrs[i]->attnum;
- break;
+
+ tupdesc = slot->ttc_tupleDescriptor;
+ tuple = slot->val;
+
+ natts = tuple->t_natts;
+
+ attrno = InvalidAttrNumber;
+ for (i = 0; i < tupdesc->natts; i++)
+ {
+ if (namestrcmp(&(tupdesc->attrs[i]->attname), attname) == 0)
+ {
+ attrno = tupdesc->attrs[i]->attnum;
+ break;
+ }
}
- }
-
- if (attrno == InvalidAttrNumber)
- elog(WARN, "GetAttributeByName: attribute %s not found", attname);
-
- retval = (Datum)
- heap_getattr(slot->val,
- slot->ttc_buffer,
- attrno,
- tupdesc,
- isNull);
- if (*isNull)
- return (char *) NULL;
- return (char *) retval;
+
+ if (attrno == InvalidAttrNumber)
+ elog(WARN, "GetAttributeByName: attribute %s not found", attname);
+
+ retval = (Datum)
+ heap_getattr(slot->val,
+ slot->ttc_buffer,
+ attrno,
+ tupdesc,
+ isNull);
+ if (*isNull)
+ return (char *) NULL;
+ return (char *) retval;
}
/* XXX char16 name for catalogs */
#ifdef NOT_USED
-char *
-att_by_name(TupleTableSlot *slot, char *attname, bool *isNull)
+char *
+att_by_name(TupleTableSlot * slot, char *attname, bool * isNull)
{
- return(GetAttributeByName(slot, attname, isNull));
+ return (GetAttributeByName(slot, attname, isNull));
}
+
#endif
static void
ExecEvalFuncArgs(FunctionCachePtr fcache,
- ExprContext *econtext,
- List *argList,
- Datum argV[],
- bool *argIsDone)
+ ExprContext * econtext,
+ List * argList,
+ Datum argV[],
+ bool * argIsDone)
{
- int i;
- bool argIsNull, *nullVect;
- List *arg;
-
- nullVect = fcache->nullVect;
-
- i = 0;
- foreach (arg, argList) {
- /* ----------------
- * evaluate the expression, in general functions cannot take
- * sets as arguments but we make an exception in the case of
- * nested dot expressions. We have to watch out for this case
- * here.
- * ----------------
- */
- argV[i] = (Datum)
- ExecEvalExpr((Node *) lfirst(arg),
- econtext,
- &argIsNull,
- argIsDone);
- if (! (*argIsDone))
- {
- Assert(i == 0);
- fcache->setArg = (char *)argV[0];
- fcache->hasSetArg = true;
- }
- if (argIsNull)
- nullVect[i] = true;
- else
- nullVect[i] = false;
- i++;
- }
+ int i;
+ bool argIsNull,
+ *nullVect;
+ List *arg;
+
+ nullVect = fcache->nullVect;
+
+ i = 0;
+ foreach(arg, argList)
+ {
+ /* ----------------
+ * evaluate the expression, in general functions cannot take
+ * sets as arguments but we make an exception in the case of
+ * nested dot expressions. We have to watch out for this case
+ * here.
+ * ----------------
+ */
+ argV[i] = (Datum)
+ ExecEvalExpr((Node *) lfirst(arg),
+ econtext,
+ &argIsNull,
+ argIsDone);
+ if (!(*argIsDone))
+ {
+ Assert(i == 0);
+ fcache->setArg = (char *) argV[0];
+ fcache->hasSetArg = true;
+ }
+ if (argIsNull)
+ nullVect[i] = true;
+ else
+ nullVect[i] = false;
+ i++;
+ }
}
/* ----------------
- * ExecMakeFunctionResult
+ * ExecMakeFunctionResult
* ----------------
*/
-static Datum
-ExecMakeFunctionResult(Node *node,
- List *arguments,
- ExprContext *econtext,
- bool *isNull,
- bool *isDone)
+static Datum
+ExecMakeFunctionResult(Node * node,
+ List * arguments,
+ ExprContext * econtext,
+ bool * isNull,
+ bool * isDone)
{
- Datum argv[MAXFMGRARGS];
- FunctionCachePtr fcache;
- Func *funcNode = NULL;
- Oper *operNode = NULL;
- bool funcisset = false;
-
- /*
- * This is kind of ugly, Func nodes now have targetlists so that
- * we know when and what to project out from postquel function results.
- * This means we have to pass the func node all the way down instead
- * of using only the fcache struct as before. ExecMakeFunctionResult
- * becomes a little bit more of a dual personality as a result.
- */
- if (IsA(node,Func))
+ Datum argv[MAXFMGRARGS];
+ FunctionCachePtr fcache;
+ Func *funcNode = NULL;
+ Oper *operNode = NULL;
+ bool funcisset = false;
+
+ /*
+ * This is kind of ugly, Func nodes now have targetlists so that we
+ * know when and what to project out from postquel function results.
+ * This means we have to pass the func node all the way down instead
+ * of using only the fcache struct as before. ExecMakeFunctionResult
+ * becomes a little bit more of a dual personality as a result.
+ */
+ if (IsA(node, Func))
{
- funcNode = (Func *)node;
- fcache = funcNode->func_fcache;
+ funcNode = (Func *) node;
+ fcache = funcNode->func_fcache;
}
- else
+ else
{
- operNode = (Oper *)node;
- fcache = operNode->op_fcache;
+ operNode = (Oper *) node;
+ fcache = operNode->op_fcache;
}
-
- /* ----------------
- * arguments is a list of expressions to evaluate
- * before passing to the function manager.
- * We collect the results of evaluating the expressions
- * into a datum array (argv) and pass this array to arrayFmgr()
- * ----------------
- */
- if (fcache->nargs != 0) {
- bool argDone;
-
- if (fcache->nargs > MAXFMGRARGS)
- elog(WARN, "ExecMakeFunctionResult: too many arguments");
-
- /*
- * If the setArg in the fcache is set we have an argument
- * returning a set of tuples (i.e. a nested dot expression). We
- * don't want to evaluate the arguments again until the function
- * is done. hasSetArg will always be false until we eval the args
- * for the first time. We should set this in the parser.
+
+ /* ----------------
+ * arguments is a list of expressions to evaluate
+ * before passing to the function manager.
+ * We collect the results of evaluating the expressions
+ * into a datum array (argv) and pass this array to arrayFmgr()
+ * ----------------
*/
- if ((fcache->hasSetArg) && fcache->setArg != NULL)
- {
- argv[0] = (Datum)fcache->setArg;
- argDone = false;
- }
- else
- ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
-
- if ((fcache->hasSetArg) && (argDone)) {
- if (isDone) *isDone = true;
- return (Datum)NULL;
- }
- }
-
- /* If this function is really a set, we have to diddle with things.
- * If the function has already been called at least once, then the
- * setArg field of the fcache holds
- * the OID of this set in pg_proc. (This is not quite legit, since
- * the setArg field is really for functions which take sets of tuples
- * as input - set functions take no inputs at all. But it's a nice
- * place to stash this value, for now.)
- *
- * If this is the first call of the set's function, then
- * the call to ExecEvalFuncArgs above just returned the OID of
- * the pg_proc tuple which defines this set. So replace the existing
- * funcid in the funcnode with the set's OID. Also, we want a new
- * fcache which points to the right function, so get that, now that
- * we have the right OID. Also zero out the argv, since the real
- * set doesn't take any arguments.
- */
- if (((Func *)node)->funcid == SetEvalRegProcedure) {
- funcisset = true;
- if (fcache->setArg) {
- argv[0] = 0;
-
- ((Func *)node)->funcid = (Oid) PointerGetDatum(fcache->setArg);
-
- } else {
- ((Func *)node)->funcid = (Oid) argv[0];
- setFcache(node, argv[0], NIL,econtext);
- fcache = ((Func *)node)->func_fcache;
- fcache->setArg = (char*)argv[0];
- argv[0] = (Datum)0;
+ if (fcache->nargs != 0)
+ {
+ bool argDone;
+
+ if (fcache->nargs > MAXFMGRARGS)
+ elog(WARN, "ExecMakeFunctionResult: too many arguments");
+
+ /*
+ * If the setArg in the fcache is set we have an argument
+ * returning a set of tuples (i.e. a nested dot expression). We
+ * don't want to evaluate the arguments again until the function
+ * is done. hasSetArg will always be false until we eval the args
+ * for the first time. We should set this in the parser.
+ */
+ if ((fcache->hasSetArg) && fcache->setArg != NULL)
+ {
+ argv[0] = (Datum) fcache->setArg;
+ argDone = false;
+ }
+ else
+ ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
+
+ if ((fcache->hasSetArg) && (argDone))
+ {
+ if (isDone)
+ *isDone = true;
+ return (Datum) NULL;
+ }
}
- }
-
- /* ----------------
- * now return the value gotten by calling the function manager,
- * passing the function the evaluated parameter values.
- * ----------------
- */
- if (fcache->language == SQLlanguageId) {
- Datum result;
-
- Assert(funcNode);
- result = postquel_function (funcNode, (char **) argv, isNull, isDone);
+
/*
- * finagle the situation where we are iterating through all results
- * in a nested dot function (whose argument function returns a set
- * of tuples) and the current function finally finishes. We need to
- * get the next argument in the set and run the function all over
- * again. This is getting unclean.
+ * If this function is really a set, we have to diddle with things. If
+ * the function has already been called at least once, then the setArg
+ * field of the fcache holds the OID of this set in pg_proc. (This is
+ * not quite legit, since the setArg field is really for functions
+ * which take sets of tuples as input - set functions take no inputs
+ * at all. But it's a nice place to stash this value, for now.)
+ *
+ * If this is the first call of the set's function, then the call to
+ * ExecEvalFuncArgs above just returned the OID of the pg_proc tuple
+ * which defines this set. So replace the existing funcid in the
+ * funcnode with the set's OID. Also, we want a new fcache which
+ * points to the right function, so get that, now that we have the
+ * right OID. Also zero out the argv, since the real set doesn't take
+ * any arguments.
*/
- if ((*isDone) && (fcache->hasSetArg)) {
- bool argDone;
-
- ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
-
- if (argDone) {
- fcache->setArg = (char *)NULL;
- *isDone = true;
- result = (Datum)NULL;
- }
- else
- result = postquel_function(funcNode,
- (char **) argv,
- isNull,
- isDone);
+ if (((Func *) node)->funcid == SetEvalRegProcedure)
+ {
+ funcisset = true;
+ if (fcache->setArg)
+ {
+ argv[0] = 0;
+
+ ((Func *) node)->funcid = (Oid) PointerGetDatum(fcache->setArg);
+
+ }
+ else
+ {
+ ((Func *) node)->funcid = (Oid) argv[0];
+ setFcache(node, argv[0], NIL, econtext);
+ fcache = ((Func *) node)->func_fcache;
+ fcache->setArg = (char *) argv[0];
+ argv[0] = (Datum) 0;
+ }
}
- if (funcisset) {
- /* reset the funcid so that next call to this routine will
- * still recognize this func as a set.
- * Note that for now we assume that the set function in
- * pg_proc must be a Postquel function - the funcid is
- * not reset below for C functions.
- */
- ((Func *)node)->funcid = SetEvalRegProcedure;
- /* If we're done with the results of this function, get rid
- * of its func cache.
- */
- if (*isDone) {
- ((Func *)node)->func_fcache = NULL;
- }
+
+ /* ----------------
+ * now return the value gotten by calling the function manager,
+ * passing the function the evaluated parameter values.
+ * ----------------
+ */
+ if (fcache->language == SQLlanguageId)
+ {
+ Datum result;
+
+ Assert(funcNode);
+ result = postquel_function(funcNode, (char **) argv, isNull, isDone);
+
+ /*
+ * finagle the situation where we are iterating through all
+ * results in a nested dot function (whose argument function
+ * returns a set of tuples) and the current function finally
+ * finishes. We need to get the next argument in the set and run
+ * the function all over again. This is getting unclean.
+ */
+ if ((*isDone) && (fcache->hasSetArg))
+ {
+ bool argDone;
+
+ ExecEvalFuncArgs(fcache, econtext, arguments, argv, &argDone);
+
+ if (argDone)
+ {
+ fcache->setArg = (char *) NULL;
+ *isDone = true;
+ result = (Datum) NULL;
+ }
+ else
+ result = postquel_function(funcNode,
+ (char **) argv,
+ isNull,
+ isDone);
+ }
+ if (funcisset)
+ {
+
+ /*
+ * reset the funcid so that next call to this routine will
+ * still recognize this func as a set. Note that for now we
+ * assume that the set function in pg_proc must be a Postquel
+ * function - the funcid is not reset below for C functions.
+ */
+ ((Func *) node)->funcid = SetEvalRegProcedure;
+
+ /*
+ * If we're done with the results of this function, get rid of
+ * its func cache.
+ */
+ if (*isDone)
+ {
+ ((Func *) node)->func_fcache = NULL;
+ }
+ }
+ return result;
}
- return result;
- }
- else
+ else
{
- int i;
-
- if (isDone) *isDone = true;
- for (i = 0; i < fcache->nargs; i++)
- if (fcache->nullVect[i] == true) *isNull = true;
-
- return((Datum) fmgr_c(fcache->func, fcache->foid, fcache->nargs,
- (FmgrValues *) argv, isNull));
+ int i;
+
+ if (isDone)
+ *isDone = true;
+ for (i = 0; i < fcache->nargs; i++)
+ if (fcache->nullVect[i] == true)
+ *isNull = true;
+
+ return ((Datum) fmgr_c(fcache->func, fcache->foid, fcache->nargs,
+ (FmgrValues *) argv, isNull));
}
}
/* ----------------------------------------------------------------
- * ExecEvalOper
- * ExecEvalFunc
- *
- * Evaluate the functional result of a list of arguments by calling the
- * function manager. Note that in the case of operator expressions, the
- * optimizer had better have already replaced the operator OID with the
- * appropriate function OID or we're hosed.
+ * ExecEvalOper
+ * ExecEvalFunc
+ *
+ * Evaluate the functional result of a list of arguments by calling the
+ * function manager. Note that in the case of operator expressions, the
+ * optimizer had better have already replaced the operator OID with the
+ * appropriate function OID or we're hosed.
*
* old comments
- * Presumably the function manager will not take null arguments, so we
- * check for null arguments before sending the arguments to (fmgr).
- *
- * Returns the value of the functional expression.
+ * Presumably the function manager will not take null arguments, so we
+ * check for null arguments before sending the arguments to (fmgr).
+ *
+ * Returns the value of the functional expression.
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
- * ExecEvalOper
+ * ExecEvalOper
* ----------------------------------------------------------------
*/
-static Datum
-ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull)
+static Datum
+ExecEvalOper(Expr * opClause, ExprContext * econtext, bool * isNull)
{
- Oper *op;
- List *argList;
- FunctionCachePtr fcache;
- bool isDone;
-
- /* ----------------
- * an opclause is a list (op args). (I think)
- *
- * we extract the oid of the function associated with
- * the op and then pass the work onto ExecMakeFunctionResult
- * which evaluates the arguments and returns the result of
- * calling the function on the evaluated arguments.
- * ----------------
- */
- op = (Oper *) opClause->oper;
- argList = opClause->args;
-
- /*
- * get the fcache from the Oper node.
- * If it is NULL, then initialize it
- */
- fcache = op->op_fcache;
- if (fcache == NULL) {
- setFcache((Node*)op, op->opid, argList, econtext);
- fcache = op->op_fcache;
- }
-
- /* -----------
- * call ExecMakeFunctionResult() with a dummy isDone that we ignore.
- * We don't have operator whose arguments are sets.
- * -----------
- */
- return
- ExecMakeFunctionResult((Node *)op, argList, econtext, isNull, &isDone);
+ Oper *op;
+ List *argList;
+ FunctionCachePtr fcache;
+ bool isDone;
+
+ /* ----------------
+ * an opclause is a list (op args). (I think)
+ *
+ * we extract the oid of the function associated with
+ * the op and then pass the work onto ExecMakeFunctionResult
+ * which evaluates the arguments and returns the result of
+ * calling the function on the evaluated arguments.
+ * ----------------
+ */
+ op = (Oper *) opClause->oper;
+ argList = opClause->args;
+
+ /*
+ * get the fcache from the Oper node. If it is NULL, then initialize
+ * it
+ */
+ fcache = op->op_fcache;
+ if (fcache == NULL)
+ {
+ setFcache((Node *) op, op->opid, argList, econtext);
+ fcache = op->op_fcache;
+ }
+
+ /* -----------
+ * call ExecMakeFunctionResult() with a dummy isDone that we ignore.
+ * We don't have operator whose arguments are sets.
+ * -----------
+ */
+ return
+ ExecMakeFunctionResult((Node *) op, argList, econtext, isNull, &isDone);
}
/* ----------------------------------------------------------------
- * ExecEvalFunc
+ * ExecEvalFunc
* ----------------------------------------------------------------
*/
-static Datum
-ExecEvalFunc(Expr *funcClause,
- ExprContext *econtext,
- bool *isNull,
- bool *isDone)
+static Datum
+ExecEvalFunc(Expr * funcClause,
+ ExprContext * econtext,
+ bool * isNull,
+ bool * isDone)
{
- Func *func;
- List *argList;
- FunctionCachePtr fcache;
-
- /* ----------------
- * an funcclause is a list (func args). (I think)
- *
- * we extract the oid of the function associated with
- * the func node and then pass the work onto ExecMakeFunctionResult
- * which evaluates the arguments and returns the result of
- * calling the function on the evaluated arguments.
- *
- * this is nearly identical to the ExecEvalOper code.
- * ----------------
- */
- func = (Func *)funcClause->oper;
- argList = funcClause->args;
-
- /*
- * get the fcache from the Func node.
- * If it is NULL, then initialize it
- */
- fcache = func->func_fcache;
- if (fcache == NULL) {
- setFcache((Node*)func, func->funcid, argList, econtext);
- fcache = func->func_fcache;
- }
-
- return
- ExecMakeFunctionResult((Node*)func, argList, econtext, isNull, isDone);
+ Func *func;
+ List *argList;
+ FunctionCachePtr fcache;
+
+ /* ----------------
+ * an funcclause is a list (func args). (I think)
+ *
+ * we extract the oid of the function associated with
+ * the func node and then pass the work onto ExecMakeFunctionResult
+ * which evaluates the arguments and returns the result of
+ * calling the function on the evaluated arguments.
+ *
+ * this is nearly identical to the ExecEvalOper code.
+ * ----------------
+ */
+ func = (Func *) funcClause->oper;
+ argList = funcClause->args;
+
+ /*
+ * get the fcache from the Func node. If it is NULL, then initialize
+ * it
+ */
+ fcache = func->func_fcache;
+ if (fcache == NULL)
+ {
+ setFcache((Node *) func, func->funcid, argList, econtext);
+ fcache = func->func_fcache;
+ }
+
+ return
+ ExecMakeFunctionResult((Node *) func, argList, econtext, isNull, isDone);
}
/* ----------------------------------------------------------------
- * ExecEvalNot
- * ExecEvalOr
- * ExecEvalAnd
- *
- * Evaluate boolean expressions. Evaluation of 'or' is
- * short-circuited when the first true (or null) value is found.
+ * ExecEvalNot
+ * ExecEvalOr
+ * ExecEvalAnd
*
- * The query planner reformulates clause expressions in the
- * qualification to conjunctive normal form. If we ever get
- * an AND to evaluate, we can be sure that it's not a top-level
- * clause in the qualification, but appears lower (as a function
- * argument, for example), or in the target list. Not that you
- * need to know this, mind you...
+ * Evaluate boolean expressions. Evaluation of 'or' is
+ * short-circuited when the first true (or null) value is found.
+ *
+ * The query planner reformulates clause expressions in the
+ * qualification to conjunctive normal form. If we ever get
+ * an AND to evaluate, we can be sure that it's not a top-level
+ * clause in the qualification, but appears lower (as a function
+ * argument, for example), or in the target list. Not that you
+ * need to know this, mind you...
* ----------------------------------------------------------------
*/
-static Datum
-ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
+static Datum
+ExecEvalNot(Expr * notclause, ExprContext * econtext, bool * isNull)
{
- Datum expr_value;
- Node *clause;
- bool isDone;
-
- clause = lfirst(notclause->args);
-
- /* ----------------
- * We don't iterate over sets in the quals, so pass in an isDone
- * flag, but ignore it.
- * ----------------
- */
- expr_value = ExecEvalExpr(clause, econtext, isNull, &isDone);
-
- /* ----------------
- * if the expression evaluates to null, then we just
- * cascade the null back to whoever called us.
- * ----------------
- */
- if (*isNull)
- return expr_value;
-
- /* ----------------
- * evaluation of 'not' is simple.. expr is false, then
- * return 'true' and vice versa.
- * ----------------
- */
- if (DatumGetInt32(expr_value) == 0)
- return (Datum) true;
-
- return (Datum) false;
-}
+ Datum expr_value;
+ Node *clause;
+ bool isDone;
+
+ clause = lfirst(notclause->args);
-/* ----------------------------------------------------------------
- * ExecEvalOr
- * ----------------------------------------------------------------
- */
-static Datum
-ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull)
-{
- List *clauses;
- List *clause;
- bool isDone;
- bool IsNull;
- Datum const_value = 0;
-
- IsNull = false;
- clauses = orExpr->args;
-
- /* ----------------
- * we use three valued logic functions here...
- * we evaluate each of the clauses in turn,
- * as soon as one is true we return that
- * value. If none is true and none of the
- * clauses evaluate to NULL we return
- * the value of the last clause evaluated (which
- * should be false) with *isNull set to false else
- * if none is true and at least one clause evaluated
- * to NULL we set *isNull flag to true -
- * ----------------
- */
- foreach (clause, clauses) {
-
/* ----------------
- * We don't iterate over sets in the quals, so pass in an isDone
- * flag, but ignore it.
+ * We don't iterate over sets in the quals, so pass in an isDone
+ * flag, but ignore it.
* ----------------
*/
- const_value = ExecEvalExpr((Node *) lfirst(clause),
- econtext,
- isNull,
- &isDone);
-
+ expr_value = ExecEvalExpr(clause, econtext, isNull, &isDone);
+
/* ----------------
- * if the expression evaluates to null, then we
- * remember it in the local IsNull flag, if none of the
- * clauses are true then we need to set *isNull
- * to true again.
+ * if the expression evaluates to null, then we just
+ * cascade the null back to whoever called us.
* ----------------
*/
if (*isNull)
- IsNull = *isNull;
-
+ return expr_value;
+
/* ----------------
- * if we have a true result, then we return it.
+ * evaluation of 'not' is simple.. expr is false, then
+ * return 'true' and vice versa.
* ----------------
*/
- if (DatumGetInt32(const_value) != 0)
- return const_value;
- }
-
- /* IsNull is true if at least one clause evaluated to NULL */
- *isNull = IsNull;
- return const_value;
+ if (DatumGetInt32(expr_value) == 0)
+ return (Datum) true;
+
+ return (Datum) false;
}
/* ----------------------------------------------------------------
- * ExecEvalAnd
+ * ExecEvalOr
* ----------------------------------------------------------------
*/
-static Datum
-ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
+static Datum
+ExecEvalOr(Expr * orExpr, ExprContext * econtext, bool * isNull)
{
- List *clauses;
- List *clause;
- Datum const_value = 0;
- bool isDone;
- bool IsNull;
-
- IsNull = false;
-
- clauses = andExpr->args;
-
- /* ----------------
- * we evaluate each of the clauses in turn,
- * as soon as one is false we return that
- * value. If none are false or NULL then we return
- * the value of the last clause evaluated, which
- * should be true.
- * ----------------
- */
- foreach (clause, clauses) {
-
- /* ----------------
- * We don't iterate over sets in the quals, so pass in an isDone
- * flag, but ignore it.
- * ----------------
- */
- const_value = ExecEvalExpr((Node *) lfirst(clause),
- econtext,
- isNull,
- &isDone);
-
+ List *clauses;
+ List *clause;
+ bool isDone;
+ bool IsNull;
+ Datum const_value = 0;
+
+ IsNull = false;
+ clauses = orExpr->args;
+
/* ----------------
- * if the expression evaluates to null, then we
- * remember it in IsNull, if none of the clauses after
- * this evaluates to false we will have to set *isNull
- * to true again.
+ * we use three valued logic functions here...
+ * we evaluate each of the clauses in turn,
+ * as soon as one is true we return that
+ * value. If none is true and none of the
+ * clauses evaluate to NULL we return
+ * the value of the last clause evaluated (which
+ * should be false) with *isNull set to false else
+ * if none is true and at least one clause evaluated
+ * to NULL we set *isNull flag to true -
* ----------------
*/
- if (*isNull)
- IsNull = *isNull;
-
+ foreach(clause, clauses)
+ {
+
+ /* ----------------
+ * We don't iterate over sets in the quals, so pass in an isDone
+ * flag, but ignore it.
+ * ----------------
+ */
+ const_value = ExecEvalExpr((Node *) lfirst(clause),
+ econtext,
+ isNull,
+ &isDone);
+
+ /* ----------------
+ * if the expression evaluates to null, then we
+ * remember it in the local IsNull flag, if none of the
+ * clauses are true then we need to set *isNull
+ * to true again.
+ * ----------------
+ */
+ if (*isNull)
+ IsNull = *isNull;
+
+ /* ----------------
+ * if we have a true result, then we return it.
+ * ----------------
+ */
+ if (DatumGetInt32(const_value) != 0)
+ return const_value;
+ }
+
+ /* IsNull is true if at least one clause evaluated to NULL */
+ *isNull = IsNull;
+ return const_value;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalAnd
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalAnd(Expr * andExpr, ExprContext * econtext, bool * isNull)
+{
+ List *clauses;
+ List *clause;
+ Datum const_value = 0;
+ bool isDone;
+ bool IsNull;
+
+ IsNull = false;
+
+ clauses = andExpr->args;
+
/* ----------------
- * if we have a false result, then we return it, since the
- * conjunction must be false.
+ * we evaluate each of the clauses in turn,
+ * as soon as one is false we return that
+ * value. If none are false or NULL then we return
+ * the value of the last clause evaluated, which
+ * should be true.
* ----------------
*/
- if (DatumGetInt32(const_value) == 0)
- return const_value;
- }
-
- *isNull = IsNull;
- return const_value;
+ foreach(clause, clauses)
+ {
+
+ /* ----------------
+ * We don't iterate over sets in the quals, so pass in an isDone
+ * flag, but ignore it.
+ * ----------------
+ */
+ const_value = ExecEvalExpr((Node *) lfirst(clause),
+ econtext,
+ isNull,
+ &isDone);
+
+ /* ----------------
+ * if the expression evaluates to null, then we
+ * remember it in IsNull, if none of the clauses after
+ * this evaluates to false we will have to set *isNull
+ * to true again.
+ * ----------------
+ */
+ if (*isNull)
+ IsNull = *isNull;
+
+ /* ----------------
+ * if we have a false result, then we return it, since the
+ * conjunction must be false.
+ * ----------------
+ */
+ if (DatumGetInt32(const_value) == 0)
+ return const_value;
+ }
+
+ *isNull = IsNull;
+ return const_value;
}
-/* ----------------------------------------------------------------
- * ExecEvalExpr
- *
- * Recursively evaluate a targetlist or qualification expression.
+/* ----------------------------------------------------------------
+ * ExecEvalExpr
+ *
+ * Recursively evaluate a targetlist or qualification expression.
*
- * This routine is an inner loop routine and should be as fast
- * as possible.
+ * This routine is an inner loop routine and should be as fast
+ * as possible.
*
- * Node comparison functions were replaced by macros for speed and to plug
- * memory leaks incurred by using the planner's Lispy stuff for
- * comparisons. Order of evaluation of node comparisons IS IMPORTANT;
- * the macros do no checks. Order of evaluation:
- *
- * o an isnull check, largely to avoid coredumps since greg doubts this
- * routine is called with a null ptr anyway in proper operation, but is
- * not completely sure...
- * o ExactNodeType checks.
- * o clause checks or other checks where we look at the lfirst of something.
+ * Node comparison functions were replaced by macros for speed and to plug
+ * memory leaks incurred by using the planner's Lispy stuff for
+ * comparisons. Order of evaluation of node comparisons IS IMPORTANT;
+ * the macros do no checks. Order of evaluation:
+ *
+ * o an isnull check, largely to avoid coredumps since greg doubts this
+ * routine is called with a null ptr anyway in proper operation, but is
+ * not completely sure...
+ * o ExactNodeType checks.
+ * o clause checks or other checks where we look at the lfirst of something.
* ----------------------------------------------------------------
*/
Datum
-ExecEvalExpr(Node *expression,
- ExprContext *econtext,
- bool *isNull,
- bool *isDone)
+ExecEvalExpr(Node * expression,
+ ExprContext * econtext,
+ bool * isNull,
+ bool * isDone)
{
- Datum retDatum = 0;
-
- *isNull = false;
-
- /*
- * Some callers don't care about is done and only want 1 result. They
- * indicate this by passing NULL
- */
- if (isDone)
- *isDone = true;
-
- /* ----------------
- * here we dispatch the work to the appropriate type
- * of function given the type of our expression.
- * ----------------
- */
- if (expression == NULL) {
- *isNull = true;
- return (Datum) true;
- }
-
- switch(nodeTag(expression)) {
- case T_Var:
- retDatum = (Datum) ExecEvalVar((Var *) expression, econtext, isNull);
- break;
- case T_Const: {
- Const *con = (Const *)expression;
-
- if (con->constisnull)
- *isNull = true;
- retDatum = con->constvalue;
- break;
- }
- case T_Param:
- retDatum = (Datum)ExecEvalParam((Param *)expression, econtext, isNull);
- break;
- case T_Iter:
- retDatum = (Datum) ExecEvalIter((Iter *) expression,
- econtext,
- isNull,
- isDone);
- break;
- case T_Aggreg:
- retDatum = (Datum) ExecEvalAggreg((Aggreg *)expression,
- econtext,
- isNull);
- break;
- case T_ArrayRef:
- retDatum = (Datum) ExecEvalArrayRef((ArrayRef *) expression,
- econtext,
- isNull,
- isDone);
- break;
- case T_Expr: {
- Expr *expr = (Expr *)expression;
- switch (expr->opType) {
- case OP_EXPR:
- retDatum = (Datum) ExecEvalOper(expr, econtext, isNull);
- break;
- case FUNC_EXPR:
- retDatum = (Datum) ExecEvalFunc(expr, econtext, isNull, isDone);
- break;
- case OR_EXPR:
- retDatum = (Datum) ExecEvalOr(expr, econtext, isNull);
- break;
- case AND_EXPR:
- retDatum = (Datum) ExecEvalAnd(expr, econtext, isNull);
- break;
- case NOT_EXPR:
- retDatum = (Datum) ExecEvalNot(expr, econtext, isNull);
- break;
+ Datum retDatum = 0;
+
+ *isNull = false;
+
+ /*
+ * Some callers don't care about is done and only want 1 result. They
+ * indicate this by passing NULL
+ */
+ if (isDone)
+ *isDone = true;
+
+ /* ----------------
+ * here we dispatch the work to the appropriate type
+ * of function given the type of our expression.
+ * ----------------
+ */
+ if (expression == NULL)
+ {
+ *isNull = true;
+ return (Datum) true;
+ }
+
+ switch (nodeTag(expression))
+ {
+ case T_Var:
+ retDatum = (Datum) ExecEvalVar((Var *) expression, econtext, isNull);
+ break;
+ case T_Const:
+ {
+ Const *con = (Const *) expression;
+
+ if (con->constisnull)
+ *isNull = true;
+ retDatum = con->constvalue;
+ break;
+ }
+ case T_Param:
+ retDatum = (Datum) ExecEvalParam((Param *) expression, econtext, isNull);
+ break;
+ case T_Iter:
+ retDatum = (Datum) ExecEvalIter((Iter *) expression,
+ econtext,
+ isNull,
+ isDone);
+ break;
+ case T_Aggreg:
+ retDatum = (Datum) ExecEvalAggreg((Aggreg *) expression,
+ econtext,
+ isNull);
+ break;
+ case T_ArrayRef:
+ retDatum = (Datum) ExecEvalArrayRef((ArrayRef *) expression,
+ econtext,
+ isNull,
+ isDone);
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) expression;
+
+ switch (expr->opType)
+ {
+ case OP_EXPR:
+ retDatum = (Datum) ExecEvalOper(expr, econtext, isNull);
+ break;
+ case FUNC_EXPR:
+ retDatum = (Datum) ExecEvalFunc(expr, econtext, isNull, isDone);
+ break;
+ case OR_EXPR:
+ retDatum = (Datum) ExecEvalOr(expr, econtext, isNull);
+ break;
+ case AND_EXPR:
+ retDatum = (Datum) ExecEvalAnd(expr, econtext, isNull);
+ break;
+ case NOT_EXPR:
+ retDatum = (Datum) ExecEvalNot(expr, econtext, isNull);
+ break;
+ default:
+ elog(WARN, "ExecEvalExpr: unknown expression type");
+ break;
+ }
+ break;
+ }
default:
- elog(WARN, "ExecEvalExpr: unknown expression type");
- break;
+ elog(WARN, "ExecEvalExpr: unknown expression type");
+ break;
}
- break;
- }
- default:
- elog(WARN, "ExecEvalExpr: unknown expression type");
- break;
- }
-
- return retDatum;
+
+ return retDatum;
}
/* ----------------------------------------------------------------
- * ExecQual / ExecTargetList
+ * ExecQual / ExecTargetList
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
- * ExecQualClause
+ * ExecQualClause
*
- * this is a workhorse for ExecQual. ExecQual has to deal
- * with a list of qualifications, so it passes each qualification
- * in the list to this function one at a time. ExecQualClause
- * returns true when the qualification *fails* and false if
- * the qualification succeeded (meaning we have to test the
- * rest of the qualification)
+ * this is a workhorse for ExecQual. ExecQual has to deal
+ * with a list of qualifications, so it passes each qualification
+ * in the list to this function one at a time. ExecQualClause
+ * returns true when the qualification *fails* and false if
+ * the qualification succeeded (meaning we have to test the
+ * rest of the qualification)
* ----------------------------------------------------------------
*/
-static bool
-ExecQualClause(Node *clause, ExprContext *econtext)
+static bool
+ExecQualClause(Node * clause, ExprContext * econtext)
{
- Datum expr_value;
- bool isNull;
- bool isDone;
-
- /* when there is a null clause, consider the qualification to be true */
- if (clause == NULL)
- return true;
-
- /*
- * pass isDone, but ignore it. We don't iterate over multiple
- * returns in the qualifications.
- */
- expr_value = (Datum)
- ExecEvalExpr(clause, econtext, &isNull, &isDone);
-
- /* ----------------
- * this is interesting behaviour here. When a clause evaluates
- * to null, then we consider this as passing the qualification.
- * it seems kind of like, if the qual is NULL, then there's no
- * qual..
- * ----------------
- */
- if (isNull)
- return true;
-
- /* ----------------
- * remember, we return true when the qualification fails..
- * ----------------
- */
- if (DatumGetInt32(expr_value) == 0)
- return true;
-
- return false;
+ Datum expr_value;
+ bool isNull;
+ bool isDone;
+
+ /* when there is a null clause, consider the qualification to be true */
+ if (clause == NULL)
+ return true;
+
+ /*
+ * pass isDone, but ignore it. We don't iterate over multiple returns
+ * in the qualifications.
+ */
+ expr_value = (Datum)
+ ExecEvalExpr(clause, econtext, &isNull, &isDone);
+
+ /* ----------------
+ * this is interesting behaviour here. When a clause evaluates
+ * to null, then we consider this as passing the qualification.
+ * it seems kind of like, if the qual is NULL, then there's no
+ * qual..
+ * ----------------
+ */
+ if (isNull)
+ return true;
+
+ /* ----------------
+ * remember, we return true when the qualification fails..
+ * ----------------
+ */
+ if (DatumGetInt32(expr_value) == 0)
+ return true;
+
+ return false;
}
/* ----------------------------------------------------------------
- * ExecQual
- *
- * Evaluates a conjunctive boolean expression and returns t
- * iff none of the subexpressions are false (or null).
+ * ExecQual
+ *
+ * Evaluates a conjunctive boolean expression and returns t
+ * iff none of the subexpressions are false (or null).
* ----------------------------------------------------------------
*/
bool
-ExecQual(List *qual, ExprContext *econtext)
+ExecQual(List * qual, ExprContext * econtext)
{
- List *clause;
- bool result;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
- EV_printf("ExecQual: qual is ");
- EV_nodeDisplay(qual);
- EV_printf("\n");
-
- IncrProcessed();
-
- /* ----------------
- * return true immediately if no qual
- * ----------------
- */
- if (qual == NIL)
- return true;
-
- /* ----------------
- * a "qual" is a list of clauses. To evaluate the
- * qual, we evaluate each of the clauses in the list.
- *
- * ExecQualClause returns true when we know the qualification
- * *failed* so we just pass each clause in qual to it until
- * we know the qual failed or there are no more clauses.
- * ----------------
- */
- result = false;
- foreach (clause, qual) {
- result = ExecQualClause((Node *)lfirst(clause), econtext);
+ List *clause;
+ bool result;
+
+ /* ----------------
+ * debugging stuff
+ * ----------------
+ */
+ EV_printf("ExecQual: qual is ");
+ EV_nodeDisplay(qual);
+ EV_printf("\n");
+
+ IncrProcessed();
+
+ /* ----------------
+ * return true immediately if no qual
+ * ----------------
+ */
+ if (qual == NIL)
+ return true;
+
+ /* ----------------
+ * a "qual" is a list of clauses. To evaluate the
+ * qual, we evaluate each of the clauses in the list.
+ *
+ * ExecQualClause returns true when we know the qualification
+ * *failed* so we just pass each clause in qual to it until
+ * we know the qual failed or there are no more clauses.
+ * ----------------
+ */
+ result = false;
+ foreach(clause, qual)
+ {
+ result = ExecQualClause((Node *) lfirst(clause), econtext);
+ if (result == true)
+ break;
+ }
+
+ /* ----------------
+ * if result is true, then it means a clause failed so we
+ * return false. if result is false then it means no clause
+ * failed so we return true.
+ * ----------------
+ */
if (result == true)
- break;
- }
-
- /* ----------------
- * if result is true, then it means a clause failed so we
- * return false. if result is false then it means no clause
- * failed so we return true.
- * ----------------
- */
- if (result == true)
- return false;
-
- return true;
+ return false;
+
+ return true;
}
int
-ExecTargetListLength(List *targetlist)
+ExecTargetListLength(List * targetlist)
{
- int len;
- List *tl;
- TargetEntry *curTle;
-
- len = 0;
- foreach (tl, targetlist) {
- curTle = lfirst(tl);
-
- if (curTle->resdom != NULL)
- len++;
- else
- len += curTle->fjoin->fj_nNodes;
- }
- return len;
+ int len;
+ List *tl;
+ TargetEntry *curTle;
+
+ len = 0;
+ foreach(tl, targetlist)
+ {
+ curTle = lfirst(tl);
+
+ if (curTle->resdom != NULL)
+ len++;
+ else
+ len += curTle->fjoin->fj_nNodes;
+ }
+ return len;
}
/* ----------------------------------------------------------------
- * ExecTargetList
- *
- * Evaluates a targetlist with respect to the current
- * expression context and return a tuple.
+ * ExecTargetList
+ *
+ * Evaluates a targetlist with respect to the current
+ * expression context and return a tuple.
* ----------------------------------------------------------------
*/
-static HeapTuple
-ExecTargetList(List *targetlist,
- int nodomains,
- TupleDesc targettype,
- Datum *values,
- ExprContext *econtext,
- bool *isDone)
+static HeapTuple
+ExecTargetList(List * targetlist,
+ int nodomains,
+ TupleDesc targettype,
+ Datum * values,
+ ExprContext * econtext,
+ bool * isDone)
{
- char nulls_array[64];
- bool fjNullArray[64];
- bool *fjIsNull;
- char *null_head;
- List *tl;
- TargetEntry *tle;
- Node *expr;
- Resdom *resdom;
- AttrNumber resind;
- Datum constvalue;
- HeapTuple newTuple;
- bool isNull;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
- EV_printf("ExecTargetList: tl is ");
- EV_nodeDisplay(targetlist);
- EV_printf("\n");
-
- /* ----------------
- * Return a dummy tuple if the targetlist is empty .
- * the dummy tuple is necessary to differentiate
- * between passing and failing the qualification.
- * ----------------
- */
- if (targetlist == NIL) {
+ char nulls_array[64];
+ bool fjNullArray[64];
+ bool *fjIsNull;
+ char *null_head;
+ List *tl;
+ TargetEntry *tle;
+ Node *expr;
+ Resdom *resdom;
+ AttrNumber resind;
+ Datum constvalue;
+ HeapTuple newTuple;
+ bool isNull;
+
/* ----------------
- * I now think that the only time this makes
- * any sence is when we run a delete query. Then
- * we need to return something other than nil
- * so we know to delete the tuple associated
- * with the saved tupleid.. see what ExecutePlan
- * does with the returned tuple.. -cim 9/21/89
- *
- * It could also happen in queries like:
- * retrieve (foo.all) where bar.a = 3
- *
- * is this a new phenomenon? it might cause bogus behavior
- * if we try to free this tuple later!! I put a hook in
- * ExecProject to watch out for this case -mer 24 Aug 1992
+ * debugging stuff
* ----------------
*/
- CXT1_printf("ExecTargetList: context is %d\n", CurrentMemoryContext);
- *isDone = true;
- return (HeapTuple) true;
- }
-
- /* ----------------
- * allocate an array of char's to hold the "null" information
- * only if we have a really large targetlist. otherwise we use
- * the stack.
- * ----------------
- */
- if (nodomains > 64) {
- null_head = (char *) palloc(nodomains+1);
- fjIsNull = (bool *) palloc(nodomains+1);
- } else {
- null_head = &nulls_array[0];
- fjIsNull = &fjNullArray[0];
- }
-
- /* ----------------
- * evaluate all the expressions in the target list
- * ----------------
- */
- EV_printf("ExecTargetList: setting target list values\n");
-
- *isDone = true;
- foreach (tl, targetlist) {
+ EV_printf("ExecTargetList: tl is ");
+ EV_nodeDisplay(targetlist);
+ EV_printf("\n");
+
/* ----------------
- * remember, a target list is a list of lists:
- *
- * ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
- *
- * tl is a pointer to successive cdr's of the targetlist
- * tle is a pointer to the target list entry in tl
+ * Return a dummy tuple if the targetlist is empty .
+ * the dummy tuple is necessary to differentiate
+ * between passing and failing the qualification.
+ * ----------------
+ */
+ if (targetlist == NIL)
+ {
+ /* ----------------
+ * I now think that the only time this makes
+ * any sence is when we run a delete query. Then
+ * we need to return something other than nil
+ * so we know to delete the tuple associated
+ * with the saved tupleid.. see what ExecutePlan
+ * does with the returned tuple.. -cim 9/21/89
+ *
+ * It could also happen in queries like:
+ * retrieve (foo.all) where bar.a = 3
+ *
+ * is this a new phenomenon? it might cause bogus behavior
+ * if we try to free this tuple later!! I put a hook in
+ * ExecProject to watch out for this case -mer 24 Aug 1992
+ * ----------------
+ */
+ CXT1_printf("ExecTargetList: context is %d\n", CurrentMemoryContext);
+ *isDone = true;
+ return (HeapTuple) true;
+ }
+
+ /* ----------------
+ * allocate an array of char's to hold the "null" information
+ * only if we have a really large targetlist. otherwise we use
+ * the stack.
* ----------------
*/
- tle = lfirst(tl);
-
- if (tle->resdom != NULL) {
- expr = tle->expr;
- resdom = tle->resdom;
- resind = resdom->resno - 1;
- constvalue = (Datum) ExecEvalExpr(expr,
- econtext,
- &isNull,
- isDone);
-
- if ((IsA(expr,Iter)) && (*isDone))
- return (HeapTuple)NULL;
-
- values[resind] = constvalue;
-
- if (!isNull)
- null_head[resind] = ' ';
- else
- null_head[resind] = 'n';
- }else {
- int curNode;
- Resdom *fjRes;
- List *fjTlist = (List *)tle->expr;
- Fjoin *fjNode = tle->fjoin;
- int nNodes = fjNode->fj_nNodes;
- DatumPtr results = fjNode->fj_results;
-
- ExecEvalFjoin(tle, econtext, fjIsNull, isDone);
- if (*isDone)
- return (HeapTuple)NULL;
-
- /*
- * get the result from the inner node
- */
- fjRes = (Resdom *)fjNode->fj_innerNode;
- resind = fjRes->resno - 1;
- if (fjIsNull[0])
- null_head[resind] = 'n';
- else {
- null_head[resind] = ' ';
- values[resind] = results[0];
- }
-
- /*
- * Get results from all of the outer nodes
- */
- for (curNode = 1;
- curNode < nNodes;
- curNode++, fjTlist = lnext(fjTlist))
+ if (nodomains > 64)
+ {
+ null_head = (char *) palloc(nodomains + 1);
+ fjIsNull = (bool *) palloc(nodomains + 1);
+ }
+ else
+ {
+ null_head = &nulls_array[0];
+ fjIsNull = &fjNullArray[0];
+ }
+
+ /* ----------------
+ * evaluate all the expressions in the target list
+ * ----------------
+ */
+ EV_printf("ExecTargetList: setting target list values\n");
+
+ *isDone = true;
+ foreach(tl, targetlist)
+ {
+ /* ----------------
+ * remember, a target list is a list of lists:
+ *
+ * ((<resdom | fjoin> expr) (<resdom | fjoin> expr) ...)
+ *
+ * tl is a pointer to successive cdr's of the targetlist
+ * tle is a pointer to the target list entry in tl
+ * ----------------
+ */
+ tle = lfirst(tl);
+
+ if (tle->resdom != NULL)
+ {
+ expr = tle->expr;
+ resdom = tle->resdom;
+ resind = resdom->resno - 1;
+ constvalue = (Datum) ExecEvalExpr(expr,
+ econtext,
+ &isNull,
+ isDone);
+
+ if ((IsA(expr, Iter)) && (*isDone))
+ return (HeapTuple) NULL;
+
+ values[resind] = constvalue;
+
+ if (!isNull)
+ null_head[resind] = ' ';
+ else
+ null_head[resind] = 'n';
+ }
+ else
{
-#if 0 /* what is this?? */
- Node *outernode = lfirst(fjTlist);
- fjRes = (Resdom *)outernode->iterexpr;
-#endif
- resind = fjRes->resno - 1;
- if (fjIsNull[curNode]) {
- null_head[resind] = 'n';
- }else {
- null_head[resind] = ' ';
- values[resind] = results[curNode];
- }
+ int curNode;
+ Resdom *fjRes;
+ List *fjTlist = (List *) tle->expr;
+ Fjoin *fjNode = tle->fjoin;
+ int nNodes = fjNode->fj_nNodes;
+ DatumPtr results = fjNode->fj_results;
+
+ ExecEvalFjoin(tle, econtext, fjIsNull, isDone);
+ if (*isDone)
+ return (HeapTuple) NULL;
+
+ /*
+ * get the result from the inner node
+ */
+ fjRes = (Resdom *) fjNode->fj_innerNode;
+ resind = fjRes->resno - 1;
+ if (fjIsNull[0])
+ null_head[resind] = 'n';
+ else
+ {
+ null_head[resind] = ' ';
+ values[resind] = results[0];
+ }
+
+ /*
+ * Get results from all of the outer nodes
+ */
+ for (curNode = 1;
+ curNode < nNodes;
+ curNode++, fjTlist = lnext(fjTlist))
+ {
+#if 0 /* what is this?? */
+ Node *outernode = lfirst(fjTlist);
+
+ fjRes = (Resdom *) outernode->iterexpr;
+#endif
+ resind = fjRes->resno - 1;
+ if (fjIsNull[curNode])
+ {
+ null_head[resind] = 'n';
+ }
+ else
+ {
+ null_head[resind] = ' ';
+ values[resind] = results[curNode];
+ }
+ }
}
}
- }
-
- /* ----------------
- * form the new result tuple (in the "normal" context)
- * ----------------
- */
- newTuple = (HeapTuple)
- heap_formtuple(targettype, values, null_head);
-
- /* ----------------
- * free the nulls array if we allocated one..
- * ----------------
- */
- if (nodomains > 64) pfree(null_head);
-
- return
- newTuple;
+
+ /* ----------------
+ * form the new result tuple (in the "normal" context)
+ * ----------------
+ */
+ newTuple = (HeapTuple)
+ heap_formtuple(targettype, values, null_head);
+
+ /* ----------------
+ * free the nulls array if we allocated one..
+ * ----------------
+ */
+ if (nodomains > 64)
+ pfree(null_head);
+
+ return
+ newTuple;
}
/* ----------------------------------------------------------------
- * ExecProject
- *
- * projects a tuple based in projection info and stores
- * it in the specified tuple table slot.
+ * ExecProject
+ *
+ * projects a tuple based in projection info and stores
+ * it in the specified tuple table slot.
*
- * Note: someday soon the executor can be extended to eliminate
- * redundant projections by storing pointers to datums
- * in the tuple table and then passing these around when
- * possible. this should make things much quicker.
- * -cim 6/3/91
+ * Note: someday soon the executor can be extended to eliminate
+ * redundant projections by storing pointers to datums
+ * in the tuple table and then passing these around when
+ * possible. this should make things much quicker.
+ * -cim 6/3/91
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecProject(ProjectionInfo *projInfo, bool *isDone)
+ExecProject(ProjectionInfo * projInfo, bool * isDone)
{
- TupleTableSlot *slot;
- List *targetlist;
- int len;
- TupleDesc tupType;
- Datum *tupValue;
- ExprContext *econtext;
- HeapTuple newTuple;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- if (projInfo == NULL)
- return (TupleTableSlot *) NULL;
-
- /* ----------------
- * get the projection info we want
- * ----------------
- */
- slot = projInfo->pi_slot;
- targetlist = projInfo->pi_targetlist;
- len = projInfo->pi_len;
- tupType = slot->ttc_tupleDescriptor;
-
- tupValue = projInfo->pi_tupValue;
- econtext = projInfo->pi_exprContext;
-
- if (targetlist == NIL) {
- *isDone = true;
- return (TupleTableSlot *) NULL;
- }
-
- /* ----------------
- * form a new (result) tuple
- * ----------------
- */
- newTuple = ExecTargetList(targetlist,
- len,
- tupType,
- tupValue,
- econtext,
- isDone);
-
- /* ----------------
- * store the tuple in the projection slot and return the slot.
- *
- * If there's no projection target list we don't want to pfree
- * the bogus tuple that ExecTargetList passes back to us.
- * -mer 24 Aug 1992
- * ----------------
- */
- return (TupleTableSlot *)
- ExecStoreTuple(newTuple, /* tuple to store */
- slot, /* slot to store in */
- InvalidBuffer, /* tuple has no buffer */
- true);
-}
+ TupleTableSlot *slot;
+ List *targetlist;
+ int len;
+ TupleDesc tupType;
+ Datum *tupValue;
+ ExprContext *econtext;
+ HeapTuple newTuple;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ if (projInfo == NULL)
+ return (TupleTableSlot *) NULL;
+ /* ----------------
+ * get the projection info we want
+ * ----------------
+ */
+ slot = projInfo->pi_slot;
+ targetlist = projInfo->pi_targetlist;
+ len = projInfo->pi_len;
+ tupType = slot->ttc_tupleDescriptor;
+
+ tupValue = projInfo->pi_tupValue;
+ econtext = projInfo->pi_exprContext;
+
+ if (targetlist == NIL)
+ {
+ *isDone = true;
+ return (TupleTableSlot *) NULL;
+ }
+
+ /* ----------------
+ * form a new (result) tuple
+ * ----------------
+ */
+ newTuple = ExecTargetList(targetlist,
+ len,
+ tupType,
+ tupValue,
+ econtext,
+ isDone);
+
+ /* ----------------
+ * store the tuple in the projection slot and return the slot.
+ *
+ * If there's no projection target list we don't want to pfree
+ * the bogus tuple that ExecTargetList passes back to us.
+ * -mer 24 Aug 1992
+ * ----------------
+ */
+ return (TupleTableSlot *)
+ ExecStoreTuple(newTuple,/* tuple to store */
+ slot, /* slot to store in */
+ InvalidBuffer, /* tuple has no buffer */
+ true);
+}
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index 8e69f491731..6ea50bb2a93 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* execScan.c--
- * This code provides support for generalized relation scans. ExecScan
- * is passed a node and a pointer to a function to "do the right thing"
- * and return a tuple from the relation. ExecScan then does the tedious
- * stuff - checking the qualification and projecting the tuple
- * appropriately.
+ * This code provides support for generalized relation scans. ExecScan
+ * is passed a node and a pointer to a function to "do the right thing"
+ * and return a tuple from the relation. ExecScan then does the tedious
+ * stuff - checking the qualification and projecting the tuple
+ * appropriately.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.3 1997/07/28 00:53:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.4 1997/09/07 04:41:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,117 +23,123 @@
#include "executor/executor.h"
/* ----------------------------------------------------------------
- * ExecScan
- *
- * Scans the relation using the 'access method' indicated and
- * returns the next qualifying tuple in the direction specified
- * in the global variable ExecDirection.
- * The access method returns the next tuple and execScan() is
- * responisble for checking the tuple returned against the qual-clause.
- *
- * Conditions:
- * -- the "cursor" maintained by the AMI is positioned at the tuple
- * returned previously.
- *
- * Initial States:
- * -- the relation indicated is opened for scanning so that the
- * "cursor" is positioned before the first qualifying tuple.
+ * ExecScan
*
- * May need to put startmmgr and endmmgr in here.
+ * Scans the relation using the 'access method' indicated and
+ * returns the next qualifying tuple in the direction specified
+ * in the global variable ExecDirection.
+ * The access method returns the next tuple and execScan() is
+ * responisble for checking the tuple returned against the qual-clause.
+ *
+ * Conditions:
+ * -- the "cursor" maintained by the AMI is positioned at the tuple
+ * returned previously.
+ *
+ * Initial States:
+ * -- the relation indicated is opened for scanning so that the
+ * "cursor" is positioned before the first qualifying tuple.
+ *
+ * May need to put startmmgr and endmmgr in here.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecScan(Scan *node,
- TupleTableSlot* (*accessMtd)()) /* function returning a tuple */
+ExecScan(Scan * node,
+ TupleTableSlot * (*accessMtd) ()) /* function returning a
+ * tuple */
{
- CommonScanState *scanstate;
- EState *estate;
- List *qual;
- bool isDone;
-
- TupleTableSlot *slot;
- TupleTableSlot *resultSlot;
- HeapTuple newTuple;
-
- ExprContext *econtext;
- ProjectionInfo *projInfo;
-
-
- /* ----------------
- * initialize misc variables
- * ----------------
- */
- newTuple = NULL;
- slot = NULL;
-
- estate = node->plan.state;
- scanstate = node->scanstate;
-
- /* ----------------
- * get the expression context
- * ----------------
- */
- econtext = scanstate->cstate.cs_ExprContext;
-
- /* ----------------
- * initialize fields in ExprContext which don't change
- * in the course of the scan..
- * ----------------
- */
- qual = node->plan.qual;
- econtext->ecxt_relation = scanstate->css_currentRelation;
- econtext->ecxt_relid = node->scanrelid;
-
- if (scanstate->cstate.cs_TupFromTlist) {
- projInfo = scanstate->cstate.cs_ProjInfo;
- resultSlot = ExecProject(projInfo, &isDone);
- if (!isDone)
- return resultSlot;
- }
- /*
- * get a tuple from the access method
- * loop until we obtain a tuple which passes the qualification.
- */
- for(;;) {
- slot = (TupleTableSlot *) (*accessMtd)(node);
+ CommonScanState *scanstate;
+ EState *estate;
+ List *qual;
+ bool isDone;
+
+ TupleTableSlot *slot;
+ TupleTableSlot *resultSlot;
+ HeapTuple newTuple;
+
+ ExprContext *econtext;
+ ProjectionInfo *projInfo;
+
/* ----------------
- * if the slot returned by the accessMtd contains
- * NULL, then it means there is nothing more to scan
- * so we just return the empty slot.
+ * initialize misc variables
* ----------------
*/
- if (TupIsNull(slot)) return slot;
-
+ newTuple = NULL;
+ slot = NULL;
+
+ estate = node->plan.state;
+ scanstate = node->scanstate;
+
/* ----------------
- * place the current tuple into the expr context
+ * get the expression context
* ----------------
*/
- econtext->ecxt_scantuple = slot;
-
+ econtext = scanstate->cstate.cs_ExprContext;
+
/* ----------------
- * check that the current tuple satisfies the qual-clause
- * if our qualification succeeds then we
- * leave the loop.
+ * initialize fields in ExprContext which don't change
+ * in the course of the scan..
* ----------------
*/
+ qual = node->plan.qual;
+ econtext->ecxt_relation = scanstate->css_currentRelation;
+ econtext->ecxt_relid = node->scanrelid;
+
+ if (scanstate->cstate.cs_TupFromTlist)
+ {
+ projInfo = scanstate->cstate.cs_ProjInfo;
+ resultSlot = ExecProject(projInfo, &isDone);
+ if (!isDone)
+ return resultSlot;
+ }
+
+ /*
+ * get a tuple from the access method loop until we obtain a tuple
+ * which passes the qualification.
+ */
+ for (;;)
+ {
+ slot = (TupleTableSlot *) (*accessMtd) (node);
+
+ /* ----------------
+ * if the slot returned by the accessMtd contains
+ * NULL, then it means there is nothing more to scan
+ * so we just return the empty slot.
+ * ----------------
+ */
+ if (TupIsNull(slot))
+ return slot;
+
+ /* ----------------
+ * place the current tuple into the expr context
+ * ----------------
+ */
+ econtext->ecxt_scantuple = slot;
+
+ /* ----------------
+ * check that the current tuple satisfies the qual-clause
+ * if our qualification succeeds then we
+ * leave the loop.
+ * ----------------
+ */
+
+ /*
+ * add a check for non-nil qual here to avoid a function call to
+ * ExecQual() when the qual is nil
+ */
+ if (!qual || ExecQual(qual, econtext) == true)
+ break;
+ }
- /* add a check for non-nil qual here to avoid a
- function call to ExecQual() when the qual is nil */
- if (!qual || ExecQual(qual, econtext) == true)
- break;
- }
-
- /* ----------------
- * form a projection tuple, store it in the result tuple
- * slot and return it.
- * ----------------
- */
- projInfo = scanstate->cstate.cs_ProjInfo;
+ /* ----------------
+ * form a projection tuple, store it in the result tuple
+ * slot and return it.
+ * ----------------
+ */
+ projInfo = scanstate->cstate.cs_ProjInfo;
- resultSlot = ExecProject(projInfo, &isDone);
- scanstate->cstate.cs_TupFromTlist = !isDone;
+ resultSlot = ExecProject(projInfo, &isDone);
+ scanstate->cstate.cs_TupFromTlist = !isDone;
- return resultSlot;
+ return resultSlot;
}
-
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 0d5e7fda9fb..287f75699af 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -1,119 +1,119 @@
/*-------------------------------------------------------------------------
*
* execTuples.c--
- * Routines dealing with the executor tuple tables. These are used to
- * ensure that the executor frees copies of tuples (made by
- * ExecTargetList) properly.
+ * Routines dealing with the executor tuple tables. These are used to
+ * ensure that the executor frees copies of tuples (made by
+ * ExecTargetList) properly.
+ *
+ * Routines dealing with the type information for tuples. Currently,
+ * the type information for a tuple is an array of FormData_pg_attribute.
+ * This information is needed by routines manipulating tuples
+ * (getattribute, formtuple, etc.).
*
- * Routines dealing with the type information for tuples. Currently,
- * the type information for a tuple is an array of FormData_pg_attribute.
- * This information is needed by routines manipulating tuples
- * (getattribute, formtuple, etc.).
- *
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.6 1997/08/19 21:31:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.7 1997/09/07 04:41:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
*
- * TABLE CREATE/DELETE
- * ExecCreateTupleTable - create a new tuple table
- * ExecDestroyTupleTable - destroy a table
+ * TABLE CREATE/DELETE
+ * ExecCreateTupleTable - create a new tuple table
+ * ExecDestroyTupleTable - destroy a table
*
- * SLOT RESERVERATION
- * ExecAllocTableSlot - find an available slot in the table
+ * SLOT RESERVERATION
+ * ExecAllocTableSlot - find an available slot in the table
*
- * SLOT ACCESSORS
- * ExecStoreTuple - store a tuple in the table
- * ExecFetchTuple - fetch a tuple from the table
- * ExecClearTuple - clear contents of a table slot
- * ExecSlotPolicy - return slot's tuple pfree policy
- * ExecSetSlotPolicy - diddle the slot policy
- * ExecSlotDescriptor - type of tuple in a slot
- * ExecSetSlotDescriptor - set a slot's tuple descriptor
- * ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
- * ExecSetNewSlotDescriptor - set a desc and the is-new-flag all at once
- * ExecSlotBuffer - return buffer of tuple in slot
- * ExecSetSlotBuffer - set the buffer for tuple in slot
- * ExecIncrSlotBufferRefcnt - bump the refcnt of the slot buffer
+ * SLOT ACCESSORS
+ * ExecStoreTuple - store a tuple in the table
+ * ExecFetchTuple - fetch a tuple from the table
+ * ExecClearTuple - clear contents of a table slot
+ * ExecSlotPolicy - return slot's tuple pfree policy
+ * ExecSetSlotPolicy - diddle the slot policy
+ * ExecSlotDescriptor - type of tuple in a slot
+ * ExecSetSlotDescriptor - set a slot's tuple descriptor
+ * ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
+ * ExecSetNewSlotDescriptor - set a desc and the is-new-flag all at once
+ * ExecSlotBuffer - return buffer of tuple in slot
+ * ExecSetSlotBuffer - set the buffer for tuple in slot
+ * ExecIncrSlotBufferRefcnt - bump the refcnt of the slot buffer
*
- * SLOT STATUS PREDICATES
- * TupIsNull - true when slot contains no tuple
- * ExecSlotDescriptorIsNew - true if we're now storing a different
- * type of tuple in a slot
+ * SLOT STATUS PREDICATES
+ * TupIsNull - true when slot contains no tuple
+ * ExecSlotDescriptorIsNew - true if we're now storing a different
+ * type of tuple in a slot
*
- * CONVENIENCE INITIALIZATION ROUTINES
- * ExecInitResultTupleSlot \ convience routines to initialize
- * ExecInitScanTupleSlot \ the various tuple slots for nodes
- * ExecInitMarkedTupleSlot / which store copies of tuples.
- * ExecInitOuterTupleSlot /
- * ExecInitHashTupleSlot /
+ * CONVENIENCE INITIALIZATION ROUTINES
+ * ExecInitResultTupleSlot \ convience routines to initialize
+ * ExecInitScanTupleSlot \ the various tuple slots for nodes
+ * ExecInitMarkedTupleSlot / which store copies of tuples.
+ * ExecInitOuterTupleSlot /
+ * ExecInitHashTupleSlot /
*
- * old routines:
- * ExecGetTupType - get type of tuple returned by this node
- * ExecTypeFromTL - form a TupleDesc from a target list
+ * old routines:
+ * ExecGetTupType - get type of tuple returned by this node
+ * ExecTypeFromTL - form a TupleDesc from a target list
*
- * EXAMPLE OF HOW TABLE ROUTINES WORK
- * Suppose we have a query such as retrieve (EMP.name) and we have
- * a single SeqScan node in the query plan.
+ * EXAMPLE OF HOW TABLE ROUTINES WORK
+ * Suppose we have a query such as retrieve (EMP.name) and we have
+ * a single SeqScan node in the query plan.
*
- * At ExecStart()
- * ----------------
- * - InitPlan() calls ExecCreateTupleTable() to create the tuple
- * table which will hold tuples processed by the executor.
+ * At ExecStart()
+ * ----------------
+ * - InitPlan() calls ExecCreateTupleTable() to create the tuple
+ * table which will hold tuples processed by the executor.
*
- * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
- * ExecInitResultTupleSlot() to reserve places in the tuple
- * table for the tuples returned by the access methods and the
- * tuples resulting from preforming target list projections.
+ * - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
+ * ExecInitResultTupleSlot() to reserve places in the tuple
+ * table for the tuples returned by the access methods and the
+ * tuples resulting from preforming target list projections.
*
- * During ExecRun()
- * ----------------
- * - SeqNext() calls ExecStoreTuple() to place the tuple returned
- * by the access methods into the scan tuple slot.
+ * During ExecRun()
+ * ----------------
+ * - SeqNext() calls ExecStoreTuple() to place the tuple returned
+ * by the access methods into the scan tuple slot.
*
- * - ExecSeqScan() calls ExecStoreTuple() to take the result
- * tuple from ExecTargetList() and place it into the result tuple
- * slot.
+ * - ExecSeqScan() calls ExecStoreTuple() to take the result
+ * tuple from ExecTargetList() and place it into the result tuple
+ * slot.
*
- * - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
- * the slot passed to it by calling ExecFetchTuple(). this tuple
- * is then returned.
+ * - ExecutePlan() calls ExecRetrieve() which gets the tuple out of
+ * the slot passed to it by calling ExecFetchTuple(). this tuple
+ * is then returned.
*
- * At ExecEnd()
- * ----------------
- * - EndPlan() calls ExecDestroyTupleTable() to clean up any remaining
- * tuples left over from executing the query.
+ * At ExecEnd()
+ * ----------------
+ * - EndPlan() calls ExecDestroyTupleTable() to clean up any remaining
+ * tuples left over from executing the query.
*
- * The important thing to watch in the executor code is how pointers
- * to the slots containing tuples are passed instead of the tuples
- * themselves. This facilitates the communication of related information
- * (such as whether or not a tuple should be pfreed, what buffer contains
- * this tuple, the tuple's tuple descriptor, etc). Note that much of
- * this information is also kept in the ExprContext of each node.
- * Soon the executor will be redesigned and ExprContext's will contain
- * only slot pointers. -cim 3/14/91
+ * The important thing to watch in the executor code is how pointers
+ * to the slots containing tuples are passed instead of the tuples
+ * themselves. This facilitates the communication of related information
+ * (such as whether or not a tuple should be pfreed, what buffer contains
+ * this tuple, the tuple's tuple descriptor, etc). Note that much of
+ * this information is also kept in the ExprContext of each node.
+ * Soon the executor will be redesigned and ExprContext's will contain
+ * only slot pointers. -cim 3/14/91
*
- * NOTES
- * The tuple table stuff is relatively new, put here to alleviate
- * the process growth problems in the executor. The other routines
- * are old (from the original lisp system) and may someday become
- * obsolete. -cim 6/23/90
+ * NOTES
+ * The tuple table stuff is relatively new, put here to alleviate
+ * the process growth problems in the executor. The other routines
+ * are old (from the original lisp system) and may someday become
+ * obsolete. -cim 6/23/90
*
- * In the implementation of nested-dot queries such as
- * "retrieve (EMP.hobbies.all)", a single scan may return tuples
- * of many types, so now we return pointers to tuple descriptors
- * along with tuples returned via the tuple table. This means
- * we now have a bunch of routines to diddle the slot descriptors
- * too. -cim 1/18/90
+ * In the implementation of nested-dot queries such as
+ * "retrieve (EMP.hobbies.all)", a single scan may return tuples
+ * of many types, so now we return pointers to tuple descriptors
+ * along with tuples returned via the tuple table. This means
+ * we now have a bunch of routines to diddle the slot descriptors
+ * too. -cim 1/18/90
*
- * The tuple table stuff depends on the executor/tuptable.h macros,
- * and the TupleTableSlot node in execnodes.h.
+ * The tuple table stuff depends on the executor/tuptable.h macros,
+ * and the TupleTableSlot node in execnodes.h.
*
*/
#include <string.h>
@@ -131,902 +131,938 @@
#include "parser/catalog_utils.h"
#include "catalog/pg_type.h"
-static TupleTableSlot *NodeGetResultTupleSlot(Plan *node);
+static TupleTableSlot *NodeGetResultTupleSlot(Plan * node);
/* ----------------------------------------------------------------
- * tuple table create/delete functions
+ * tuple table create/delete functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecCreateTupleTable
+ * ExecCreateTupleTable
*
- * This creates a new tuple table of the specified initial
- * size. If the size is insufficient, ExecAllocTableSlot()
- * will grow the table as necessary.
+ * This creates a new tuple table of the specified initial
+ * size. If the size is insufficient, ExecAllocTableSlot()
+ * will grow the table as necessary.
*
- * This should be used by InitPlan() to allocate the table.
- * The table's address will be stored in the EState structure.
+ * This should be used by InitPlan() to allocate the table.
+ * The table's address will be stored in the EState structure.
* --------------------------------
*/
-TupleTable /* return: address of table */
-ExecCreateTupleTable(int initialSize) /* initial number of slots in table */
+TupleTable /* return: address of table */
+ExecCreateTupleTable(int initialSize) /* initial number of slots
+ * in table */
{
- TupleTable newtable; /* newly allocated table */
- TupleTableSlot* array; /* newly allocated slot array */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(initialSize >= 1);
-
- /* ----------------
- * Now allocate our new table along with space for the pointers
- * to the tuples.
- */
-
- newtable = (TupleTable) palloc(sizeof(TupleTableData));
- array = (TupleTableSlot*) palloc(initialSize * sizeof(TupleTableSlot));
-
- /* ----------------
- * clean out the slots we just allocated
- * ----------------
- */
- memset(array, 0, initialSize * sizeof(TupleTableSlot));
-
- /* ----------------
- * initialize the new table and return it to the caller.
- * ----------------
- */
- newtable->size = initialSize;
- newtable->next = 0;
- newtable->array = array;
-
- return newtable;
+ TupleTable newtable; /* newly allocated table */
+ TupleTableSlot *array; /* newly allocated slot array */
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(initialSize >= 1);
+
+ /* ----------------
+ * Now allocate our new table along with space for the pointers
+ * to the tuples.
+ */
+
+ newtable = (TupleTable) palloc(sizeof(TupleTableData));
+ array = (TupleTableSlot *) palloc(initialSize * sizeof(TupleTableSlot));
+
+ /* ----------------
+ * clean out the slots we just allocated
+ * ----------------
+ */
+ memset(array, 0, initialSize * sizeof(TupleTableSlot));
+
+ /* ----------------
+ * initialize the new table and return it to the caller.
+ * ----------------
+ */
+ newtable->size = initialSize;
+ newtable->next = 0;
+ newtable->array = array;
+
+ return newtable;
}
/* --------------------------------
- * ExecDestroyTupleTable
+ * ExecDestroyTupleTable
*
- * This pfrees the storage assigned to the tuple table and
- * optionally pfrees the contents of the table also.
- * It is expected that this routine be called by EndPlan().
+ * This pfrees the storage assigned to the tuple table and
+ * optionally pfrees the contents of the table also.
+ * It is expected that this routine be called by EndPlan().
* --------------------------------
*/
void
-ExecDestroyTupleTable(TupleTable table, /* tuple table */
- bool shouldFree) /* true if we should free slot contents */
+ExecDestroyTupleTable(TupleTable table, /* tuple table */
+ bool shouldFree) /* true if we should free slot
+ * contents */
{
- int next; /* next avaliable slot */
- TupleTableSlot *array; /* start of table array */
- int i; /* counter */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(table != NULL);
-
- /* ----------------
- * get information from the table
- * ----------------
- */
- array = table->array;
- next = table->next;
-
- /* ----------------
- * first free all the valid pointers in the tuple array
- * if that's what the caller wants..
- *
- * Note: we do nothing about the Buffer and Tuple Descriptor's
- * we store in the slots. This may have to change (ex: we should
- * probably worry about pfreeing tuple descs too) -cim 3/14/91
- * ----------------
- */
- if (shouldFree)
- for (i = 0; i < next; i++) {
- TupleTableSlot slot;
- HeapTuple tuple;
-
- slot = array[i];
- tuple = slot.val;
-
- if (tuple != NULL) {
- slot.val = (HeapTuple)NULL;
- if (slot.ttc_shouldFree) {
- /* ----------------
- * since a tuple may contain a pointer to
- * lock information allocated along with the
- * tuple, we have to be careful to free any
- * rule locks also -cim 1/17/90
- * ----------------
- */
- pfree(tuple);
+ int next; /* next avaliable slot */
+ TupleTableSlot *array; /* start of table array */
+ int i; /* counter */
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(table != NULL);
+
+ /* ----------------
+ * get information from the table
+ * ----------------
+ */
+ array = table->array;
+ next = table->next;
+
+ /* ----------------
+ * first free all the valid pointers in the tuple array
+ * if that's what the caller wants..
+ *
+ * Note: we do nothing about the Buffer and Tuple Descriptor's
+ * we store in the slots. This may have to change (ex: we should
+ * probably worry about pfreeing tuple descs too) -cim 3/14/91
+ * ----------------
+ */
+ if (shouldFree)
+ for (i = 0; i < next; i++)
+ {
+ TupleTableSlot slot;
+ HeapTuple tuple;
+
+ slot = array[i];
+ tuple = slot.val;
+
+ if (tuple != NULL)
+ {
+ slot.val = (HeapTuple) NULL;
+ if (slot.ttc_shouldFree)
+ {
+ /* ----------------
+ * since a tuple may contain a pointer to
+ * lock information allocated along with the
+ * tuple, we have to be careful to free any
+ * rule locks also -cim 1/17/90
+ * ----------------
+ */
+ pfree(tuple);
+ }
+ }
}
- }
- }
-
- /* ----------------
- * finally free the tuple array and the table itself.
- * ----------------
- */
- pfree(array);
- pfree(table);
-
+
+ /* ----------------
+ * finally free the tuple array and the table itself.
+ * ----------------
+ */
+ pfree(array);
+ pfree(table);
+
}
/* ----------------------------------------------------------------
- * tuple table slot reservation functions
+ * tuple table slot reservation functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecAllocTableSlot
+ * ExecAllocTableSlot
*
- * This routine is used to reserve slots in the table for
- * use by the various plan nodes. It is expected to be
- * called by the node init routines (ex: ExecInitNestLoop).
- * once per slot needed by the node. Not all nodes need
- * slots (some just pass tuples around).
+ * This routine is used to reserve slots in the table for
+ * use by the various plan nodes. It is expected to be
+ * called by the node init routines (ex: ExecInitNestLoop).
+ * once per slot needed by the node. Not all nodes need
+ * slots (some just pass tuples around).
* --------------------------------
*/
-TupleTableSlot* /* return: the slot allocated in the tuple table */
+TupleTableSlot * /* return: the slot allocated in the tuple
+ * table */
ExecAllocTableSlot(TupleTable table)
{
- int slotnum; /* new slot number */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(table != NULL);
-
- /* ----------------
- * if our table is full we have to allocate a larger
- * size table. Since ExecAllocTableSlot() is only called
- * before the table is ever used to store tuples, we don't
- * have to worry about the contents of the old table.
- * If this changes, then we will have to preserve the contents.
- * -cim 6/23/90
- *
- * Unfortunately, we *cannot* do this. All of the nodes in
- * the plan that have already initialized their slots will have
- * pointers into _freed_ memory. This leads to bad ends. We
- * now count the number of slots we will need and create all the
- * slots we will need ahead of time. The if below should never
- * happen now. Give a WARN if it does. -mer 4 Aug 1992
- * ----------------
- */
- if (table->next >= table->size) {
- /*
- * int newsize = NewTableSize(table->size);
+ int slotnum; /* new slot number */
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(table != NULL);
+
+ /* ----------------
+ * if our table is full we have to allocate a larger
+ * size table. Since ExecAllocTableSlot() is only called
+ * before the table is ever used to store tuples, we don't
+ * have to worry about the contents of the old table.
+ * If this changes, then we will have to preserve the contents.
+ * -cim 6/23/90
*
- * pfree(table->array);
- * table->array = (Pointer) palloc(newsize * TableSlotSize);
- * bzero(table->array, newsize * TableSlotSize);
- * table->size = newsize;
+ * Unfortunately, we *cannot* do this. All of the nodes in
+ * the plan that have already initialized their slots will have
+ * pointers into _freed_ memory. This leads to bad ends. We
+ * now count the number of slots we will need and create all the
+ * slots we will need ahead of time. The if below should never
+ * happen now. Give a WARN if it does. -mer 4 Aug 1992
+ * ----------------
*/
- elog(NOTICE, "Plan requires more slots than are available");
- elog(WARN, "send mail to your local executor guru to fix this");
- }
-
- /* ----------------
- * at this point, space in the table is guaranteed so we
- * reserve the next slot, initialize and return it.
- * ----------------
- */
- slotnum = table->next;
- table->next++;
-
- table->array[slotnum].type = T_TupleTableSlot;
-
- return &(table->array[slotnum]);
+ if (table->next >= table->size)
+ {
+
+ /*
+ * int newsize = NewTableSize(table->size);
+ *
+ * pfree(table->array); table->array = (Pointer) palloc(newsize *
+ * TableSlotSize); bzero(table->array, newsize * TableSlotSize);
+ * table->size = newsize;
+ */
+ elog(NOTICE, "Plan requires more slots than are available");
+ elog(WARN, "send mail to your local executor guru to fix this");
+ }
+
+ /* ----------------
+ * at this point, space in the table is guaranteed so we
+ * reserve the next slot, initialize and return it.
+ * ----------------
+ */
+ slotnum = table->next;
+ table->next++;
+
+ table->array[slotnum].type = T_TupleTableSlot;
+
+ return &(table->array[slotnum]);
}
/* ----------------------------------------------------------------
- * tuple table slot accessor functions
+ * tuple table slot accessor functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecStoreTuple
+ * ExecStoreTuple
*
- * This function is used to store a tuple into a specified
- * slot in the tuple table. Note: the only slots which should
- * be called with shouldFree == false are those slots used to
- * store tuples not allocated with pfree(). Currently the
- * seqscan and indexscan nodes use this for the tuples returned
- * by amgetattr, which are actually pointers onto disk pages.
+ * This function is used to store a tuple into a specified
+ * slot in the tuple table. Note: the only slots which should
+ * be called with shouldFree == false are those slots used to
+ * store tuples not allocated with pfree(). Currently the
+ * seqscan and indexscan nodes use this for the tuples returned
+ * by amgetattr, which are actually pointers onto disk pages.
* --------------------------------
*/
-TupleTableSlot* /* return: slot passed */
-ExecStoreTuple(HeapTuple tuple, /* tuple to store */
- TupleTableSlot* slot, /* slot in which to store tuple */
- Buffer buffer, /* buffer associated with tuple */
- bool shouldFree) /* true if we call pfree() when we gc. */
+TupleTableSlot * /* return: slot passed */
+ExecStoreTuple(HeapTuple tuple, /* tuple to store */
+ TupleTableSlot * slot, /* slot in which to store tuple */
+ Buffer buffer, /* buffer associated with tuple */
+ bool shouldFree) /* true if we call pfree() when we gc. */
{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(slot != NULL);
-
- /* clear out the slot first */
- ExecClearTuple(slot);
-
- /* ----------------
- * store the new tuple into the specified slot and
- * return the slot into which we stored the tuple.
- * ----------------
- */
- slot->val = tuple;
- slot->ttc_buffer = buffer;
- slot->ttc_shouldFree = shouldFree;
-
- return slot;
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(slot != NULL);
+
+ /* clear out the slot first */
+ ExecClearTuple(slot);
+
+ /* ----------------
+ * store the new tuple into the specified slot and
+ * return the slot into which we stored the tuple.
+ * ----------------
+ */
+ slot->val = tuple;
+ slot->ttc_buffer = buffer;
+ slot->ttc_shouldFree = shouldFree;
+
+ return slot;
}
/* --------------------------------
- * ExecClearTuple
+ * ExecClearTuple
*
- * This function is used to clear out a slot in the tuple table.
+ * This function is used to clear out a slot in the tuple table.
* --------------------------------
*/
-TupleTableSlot* /* return: slot passed */
-ExecClearTuple(TupleTableSlot* slot) /* slot in which to store tuple */
+TupleTableSlot * /* return: slot passed */
+ExecClearTuple(TupleTableSlot * slot) /* slot in which to store tuple */
{
- HeapTuple oldtuple; /* prior contents of slot */
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(slot != NULL);
-
- /* ----------------
- * get information from the tuple table
- * ----------------
- */
- oldtuple = slot->val;
-
- /* ----------------
- * free the old contents of the specified slot if necessary.
- * ----------------
- */
- if (slot->ttc_shouldFree && oldtuple != NULL) {
+ HeapTuple oldtuple; /* prior contents of slot */
+
/* ----------------
- * since a tuple may contain a pointer to
- * lock information allocated along with the
- * tuple, we have to be careful to free any
- * rule locks also -cim 1/17/90
+ * sanity checks
* ----------------
*/
- pfree(oldtuple);
- }
-
- /* ----------------
- * store NULL into the specified slot and return the slot.
- * - also set buffer to InvalidBuffer -cim 3/14/91
- * ----------------
- */
- slot->val = (HeapTuple)NULL;
-
- if (BufferIsValid(slot->ttc_buffer))
- ReleaseBuffer(slot->ttc_buffer);
-
- slot->ttc_buffer = InvalidBuffer;
- slot->ttc_shouldFree = true;
-
- return slot;
+ Assert(slot != NULL);
+
+ /* ----------------
+ * get information from the tuple table
+ * ----------------
+ */
+ oldtuple = slot->val;
+
+ /* ----------------
+ * free the old contents of the specified slot if necessary.
+ * ----------------
+ */
+ if (slot->ttc_shouldFree && oldtuple != NULL)
+ {
+ /* ----------------
+ * since a tuple may contain a pointer to
+ * lock information allocated along with the
+ * tuple, we have to be careful to free any
+ * rule locks also -cim 1/17/90
+ * ----------------
+ */
+ pfree(oldtuple);
+ }
+
+ /* ----------------
+ * store NULL into the specified slot and return the slot.
+ * - also set buffer to InvalidBuffer -cim 3/14/91
+ * ----------------
+ */
+ slot->val = (HeapTuple) NULL;
+
+ if (BufferIsValid(slot->ttc_buffer))
+ ReleaseBuffer(slot->ttc_buffer);
+
+ slot->ttc_buffer = InvalidBuffer;
+ slot->ttc_shouldFree = true;
+
+ return slot;
}
/* --------------------------------
- * ExecSlotPolicy
+ * ExecSlotPolicy
*
- * This function is used to get the call/don't call pfree
- * setting of a slot. Most executor routines don't need this.
- * It's only when you do tricky things like marking tuples for
- * merge joins that you need to diddle the slot policy.
+ * This function is used to get the call/don't call pfree
+ * setting of a slot. Most executor routines don't need this.
+ * It's only when you do tricky things like marking tuples for
+ * merge joins that you need to diddle the slot policy.
* --------------------------------
*/
#ifdef NOT_USED
-bool /* return: slot policy */
-ExecSlotPolicy(TupleTableSlot* slot) /* slot to inspect */
+bool /* return: slot policy */
+ExecSlotPolicy(TupleTableSlot * slot) /* slot to inspect */
{
- return slot->ttc_shouldFree;
+ return slot->ttc_shouldFree;
}
+
#endif
/* --------------------------------
- * ExecSetSlotPolicy
+ * ExecSetSlotPolicy
*
- * This function is used to change the call/don't call pfree
- * setting of a slot. Most executor routines don't need this.
- * It's only when you do tricky things like marking tuples for
- * merge joins that you need to diddle the slot policy.
+ * This function is used to change the call/don't call pfree
+ * setting of a slot. Most executor routines don't need this.
+ * It's only when you do tricky things like marking tuples for
+ * merge joins that you need to diddle the slot policy.
* --------------------------------
*/
-bool /* return: old slot policy */
-ExecSetSlotPolicy(TupleTableSlot* slot, /* slot to change */
- bool shouldFree) /* true if we call pfree() when we gc. */
+bool /* return: old slot policy */
+ExecSetSlotPolicy(TupleTableSlot * slot, /* slot to change */
+ bool shouldFree) /* true if we call pfree() when we
+ * gc. */
{
- bool old_shouldFree = slot->ttc_shouldFree;
- slot->ttc_shouldFree = shouldFree;
+ bool old_shouldFree = slot->ttc_shouldFree;
- return old_shouldFree;
+ slot->ttc_shouldFree = shouldFree;
+
+ return old_shouldFree;
}
/* --------------------------------
- * ExecSlotDescriptor
+ * ExecSlotDescriptor
*
- * This function is used to get the tuple descriptor associated
- * with the slot's tuple.
+ * This function is used to get the tuple descriptor associated
+ * with the slot's tuple.
*
* Now a macro in tuptable.h -mer 5 March 1992
* --------------------------------
*/
/* --------------------------------
- * ExecSetSlotDescriptor
+ * ExecSetSlotDescriptor
*
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple.
+ * This function is used to set the tuple descriptor associated
+ * with the slot's tuple.
* --------------------------------
*/
-TupleDesc /* return: old slot tuple descriptor */
-ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
- TupleDesc tupdesc) /* tuple descriptor */
+TupleDesc /* return: old slot tuple descriptor */
+ExecSetSlotDescriptor(TupleTableSlot * slot, /* slot to change */
+ TupleDesc tupdesc) /* tuple descriptor */
{
- TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
+ TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
- slot->ttc_tupleDescriptor = tupdesc;
- return old_tupdesc;
+ slot->ttc_tupleDescriptor = tupdesc;
+ return old_tupdesc;
}
/* --------------------------------
- * ExecSetSlotDescriptorIsNew
+ * ExecSetSlotDescriptorIsNew
*
- * This function is used to change the setting of the "isNew" flag
+ * This function is used to change the setting of the "isNew" flag
* --------------------------------
*/
void
-ExecSetSlotDescriptorIsNew(TupleTableSlot *slot,/* slot to change */
- bool isNew) /* "isNew" setting */
+ExecSetSlotDescriptorIsNew(TupleTableSlot * slot, /* slot to change */
+ bool isNew) /* "isNew" setting */
{
- slot->ttc_descIsNew = isNew;
+ slot->ttc_descIsNew = isNew;
}
/* --------------------------------
- * ExecSetNewSlotDescriptor
+ * ExecSetNewSlotDescriptor
*
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple, and set the "isNew" flag at the same time.
+ * This function is used to set the tuple descriptor associated
+ * with the slot's tuple, and set the "isNew" flag at the same time.
* --------------------------------
*/
#ifdef NOT_USED
-TupleDesc /* return: old slot tuple descriptor */
-ExecSetNewSlotDescriptor(TupleTableSlot *slot, /* slot to change */
- TupleDesc tupdesc) /* tuple descriptor */
+TupleDesc /* return: old slot tuple descriptor */
+ExecSetNewSlotDescriptor(TupleTableSlot * slot, /* slot to change */
+ TupleDesc tupdesc) /* tuple descriptor */
{
- TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
- slot->ttc_tupleDescriptor = tupdesc;
- slot->ttc_descIsNew = true;
-
- return old_tupdesc;
+ TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
+
+ slot->ttc_tupleDescriptor = tupdesc;
+ slot->ttc_descIsNew = true;
+
+ return old_tupdesc;
}
+
#endif
/* --------------------------------
- * ExecSlotBuffer
+ * ExecSlotBuffer
*
- * This function is used to get the tuple descriptor associated
- * with the slot's tuple. Be very careful with this as it does not
- * balance the reference counts. If the buffer returned is stored
- * someplace else, then also use ExecIncrSlotBufferRefcnt().
+ * This function is used to get the tuple descriptor associated
+ * with the slot's tuple. Be very careful with this as it does not
+ * balance the reference counts. If the buffer returned is stored
+ * someplace else, then also use ExecIncrSlotBufferRefcnt().
*
* Now a macro in tuptable.h
* --------------------------------
*/
/* --------------------------------
- * ExecSetSlotBuffer
+ * ExecSetSlotBuffer
*
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple. Be very careful with this as it does not
- * balance the reference counts. If we're using this then we should
- * also use ExecIncrSlotBufferRefcnt().
+ * This function is used to set the tuple descriptor associated
+ * with the slot's tuple. Be very careful with this as it does not
+ * balance the reference counts. If we're using this then we should
+ * also use ExecIncrSlotBufferRefcnt().
* --------------------------------
*/
#ifdef NOT_USED
-Buffer /* return: old slot buffer */
-ExecSetSlotBuffer(TupleTableSlot *slot, /* slot to change */
- Buffer b) /* tuple descriptor */
+Buffer /* return: old slot buffer */
+ExecSetSlotBuffer(TupleTableSlot * slot, /* slot to change */
+ Buffer b) /* tuple descriptor */
{
- Buffer oldb = slot->ttc_buffer;
- slot->ttc_buffer = b;
-
- return oldb;
+ Buffer oldb = slot->ttc_buffer;
+
+ slot->ttc_buffer = b;
+
+ return oldb;
}
+
#endif
/* --------------------------------
- * ExecIncrSlotBufferRefcnt
+ * ExecIncrSlotBufferRefcnt
*
- * When we pass around buffers in the tuple table, we have to
- * be careful to increment reference counts appropriately.
- * This is used mainly in the mergejoin code.
+ * When we pass around buffers in the tuple table, we have to
+ * be careful to increment reference counts appropriately.
+ * This is used mainly in the mergejoin code.
* --------------------------------
*/
void
-ExecIncrSlotBufferRefcnt(TupleTableSlot *slot) /* slot to bump refcnt */
+ExecIncrSlotBufferRefcnt(TupleTableSlot * slot) /* slot to bump refcnt */
{
-/* Buffer b = SlotBuffer((TupleTableSlot*) slot); */
- Buffer b = slot->ttc_buffer;
- if (BufferIsValid(b))
- IncrBufferRefCount(b);
+/* Buffer b = SlotBuffer((TupleTableSlot*) slot); */
+ Buffer b = slot->ttc_buffer;
+
+ if (BufferIsValid(b))
+ IncrBufferRefCount(b);
}
/* ----------------------------------------------------------------
- * tuple table slot status predicates
+ * tuple table slot status predicates
* ----------------------------------------------------------------
*/
/* ----------------
- * TupIsNull
+ * TupIsNull
*
- * This is used mainly to detect when there are no more
- * tuples to process.
+ * This is used mainly to detect when there are no more
+ * tuples to process.
* ----------------
*/
-bool /* return: true if tuple in slot is NULL */
-TupIsNull(TupleTableSlot* slot) /* slot to check */
+bool /* return: true if tuple in slot is NULL */
+TupIsNull(TupleTableSlot * slot) /* slot to check */
{
- HeapTuple tuple; /* contents of slot (returned) */
-
- /* ----------------
- * if the slot itself is null then we return true
- * ----------------
- */
- if (slot == NULL)
- return true;
-
- /* ----------------
- * get information from the slot and return true or
- * false depending on the contents of the slot.
- * ----------------
- */
- tuple = slot->val;
-
- return
- (tuple == NULL ? true : false);
+ HeapTuple tuple; /* contents of slot (returned) */
+
+ /* ----------------
+ * if the slot itself is null then we return true
+ * ----------------
+ */
+ if (slot == NULL)
+ return true;
+
+ /* ----------------
+ * get information from the slot and return true or
+ * false depending on the contents of the slot.
+ * ----------------
+ */
+ tuple = slot->val;
+
+ return
+ (tuple == NULL ? true : false);
}
/* --------------------------------
- * ExecSlotDescriptorIsNew
+ * ExecSlotDescriptorIsNew
*
- * This function is used to check if the tuple descriptor
- * associated with this slot has just changed. ie: we are
- * now storing a new type of tuple in this slot
+ * This function is used to check if the tuple descriptor
+ * associated with this slot has just changed. ie: we are
+ * now storing a new type of tuple in this slot
* --------------------------------
*/
#ifdef NOT_USED
-bool /* return: descriptor "is new" */
-ExecSlotDescriptorIsNew(TupleTableSlot *slot) /* slot to inspect */
+bool /* return: descriptor "is new" */
+ExecSlotDescriptorIsNew(TupleTableSlot * slot) /* slot to inspect */
{
-/* bool isNew = SlotTupleDescriptorIsNew((TupleTableSlot*) slot);
- return isNew; */
- return slot->ttc_descIsNew;
+/* bool isNew = SlotTupleDescriptorIsNew((TupleTableSlot*) slot);
+ return isNew; */
+ return slot->ttc_descIsNew;
}
+
#endif
/* ----------------------------------------------------------------
- * convenience initialization routines
+ * convenience initialization routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ExecInit{Result,Scan,Raw,Marked,Outer,Hash}TupleSlot
+ * ExecInit{Result,Scan,Raw,Marked,Outer,Hash}TupleSlot
*
- * These are convenience routines to initialize the specfied slot
- * in nodes inheriting the appropriate state.
+ * These are convenience routines to initialize the specfied slot
+ * in nodes inheriting the appropriate state.
* --------------------------------
*/
#define INIT_SLOT_DEFS \
- TupleTable tupleTable; \
- TupleTableSlot* slot
-
+ TupleTable tupleTable; \
+ TupleTableSlot* slot
+
#define INIT_SLOT_ALLOC \
- tupleTable = (TupleTable) estate->es_tupleTable; \
- slot = ExecAllocTableSlot(tupleTable); \
- slot->val = (HeapTuple)NULL; \
- slot->ttc_shouldFree = true; \
- slot->ttc_tupleDescriptor = (TupleDesc)NULL; \
- slot->ttc_whichplan = -1;\
- slot->ttc_descIsNew = true;
+ tupleTable = (TupleTable) estate->es_tupleTable; \
+ slot = ExecAllocTableSlot(tupleTable); \
+ slot->val = (HeapTuple)NULL; \
+ slot->ttc_shouldFree = true; \
+ slot->ttc_tupleDescriptor = (TupleDesc)NULL; \
+ slot->ttc_whichplan = -1;\
+ slot->ttc_descIsNew = true;
/* ----------------
- * ExecInitResultTupleSlot
+ * ExecInitResultTupleSlot
* ----------------
*/
void
-ExecInitResultTupleSlot(EState *estate, CommonState *commonstate)
+ExecInitResultTupleSlot(EState * estate, CommonState * commonstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- commonstate->cs_ResultTupleSlot = (TupleTableSlot *) slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ commonstate->cs_ResultTupleSlot = (TupleTableSlot *) slot;
}
/* ----------------
- * ExecInitScanTupleSlot
+ * ExecInitScanTupleSlot
* ----------------
*/
void
-ExecInitScanTupleSlot(EState *estate, CommonScanState *commonscanstate)
+ExecInitScanTupleSlot(EState * estate, CommonScanState * commonscanstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- commonscanstate->css_ScanTupleSlot = (TupleTableSlot *)slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ commonscanstate->css_ScanTupleSlot = (TupleTableSlot *) slot;
}
/* ----------------
- * ExecInitMarkedTupleSlot
+ * ExecInitMarkedTupleSlot
* ----------------
*/
void
-ExecInitMarkedTupleSlot(EState *estate, MergeJoinState *mergestate)
+ExecInitMarkedTupleSlot(EState * estate, MergeJoinState * mergestate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- mergestate->mj_MarkedTupleSlot = (TupleTableSlot *) slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ mergestate->mj_MarkedTupleSlot = (TupleTableSlot *) slot;
}
/* ----------------
- * ExecInitOuterTupleSlot
+ * ExecInitOuterTupleSlot
* ----------------
*/
void
-ExecInitOuterTupleSlot(EState *estate, HashJoinState *hashstate)
+ExecInitOuterTupleSlot(EState * estate, HashJoinState * hashstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- hashstate->hj_OuterTupleSlot = slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ hashstate->hj_OuterTupleSlot = slot;
}
/* ----------------
- * ExecInitHashTupleSlot
+ * ExecInitHashTupleSlot
* ----------------
*/
#ifdef NOT_USED
void
-ExecInitHashTupleSlot(EState *estate, HashJoinState *hashstate)
+ExecInitHashTupleSlot(EState * estate, HashJoinState * hashstate)
{
- INIT_SLOT_DEFS;
- INIT_SLOT_ALLOC;
- hashstate->hj_HashTupleSlot = slot;
+ INIT_SLOT_DEFS;
+ INIT_SLOT_ALLOC;
+ hashstate->hj_HashTupleSlot = slot;
}
+
#endif
static TupleTableSlot *
-NodeGetResultTupleSlot(Plan *node)
+NodeGetResultTupleSlot(Plan * node)
{
- TupleTableSlot *slot;
-
- switch(nodeTag(node)) {
-
- case T_Result:
- {
- ResultState *resstate = ((Result *)node)->resstate;
- slot = resstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_SeqScan:
- {
- CommonScanState *scanstate = ((SeqScan *)node)->scanstate;
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_NestLoop:
- {
- NestLoopState *nlstate = ((NestLoop *)node)->nlstate;
- slot = nlstate->jstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Append:
- {
- Append *n = (Append *)node;
- AppendState *unionstate;
- List *unionplans;
- int whichplan;
- Plan *subplan;
-
- unionstate = n->unionstate;
- unionplans = n->unionplans;
- whichplan = unionstate->as_whichplan;
-
- subplan = (Plan*) nth(whichplan, unionplans);
- slot = NodeGetResultTupleSlot(subplan);
- break;
- }
-
- case T_IndexScan:
- {
- CommonScanState *scanstate = ((IndexScan *)node)->scan.scanstate;
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Material:
- {
- MaterialState *matstate = ((Material *)node)->matstate;
- slot = matstate->csstate.css_ScanTupleSlot;
- }
- break;
-
- case T_Sort:
- {
- SortState *sortstate = ((Sort *)node)->sortstate;
- slot = sortstate->csstate.css_ScanTupleSlot;
- }
- break;
-
- case T_Agg:
- {
- AggState *aggstate = ((Agg *)node)->aggstate;
- slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Group:
- {
- GroupState *grpstate = ((Group *)node)->grpstate;
- slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Hash:
- {
- HashState *hashstate = ((Hash *)node)->hashstate;
- slot = hashstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Unique:
- {
- UniqueState *uniquestate = ((Unique *)node)->uniquestate;
- slot = uniquestate->cs_ResultTupleSlot;
- }
- break;
-
- case T_MergeJoin:
- {
- MergeJoinState *mergestate = ((MergeJoin *)node)->mergestate;
- slot = mergestate->jstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_HashJoin:
+ TupleTableSlot *slot;
+
+ switch (nodeTag(node))
{
- HashJoinState *hashjoinstate = ((HashJoin *)node)->hashjoinstate;
- slot = hashjoinstate->jstate.cs_ResultTupleSlot;
+
+ case T_Result:
+ {
+ ResultState *resstate = ((Result *) node)->resstate;
+
+ slot = resstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_SeqScan:
+ {
+ CommonScanState *scanstate = ((SeqScan *) node)->scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_NestLoop:
+ {
+ NestLoopState *nlstate = ((NestLoop *) node)->nlstate;
+
+ slot = nlstate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Append:
+ {
+ Append *n = (Append *) node;
+ AppendState *unionstate;
+ List *unionplans;
+ int whichplan;
+ Plan *subplan;
+
+ unionstate = n->unionstate;
+ unionplans = n->unionplans;
+ whichplan = unionstate->as_whichplan;
+
+ subplan = (Plan *) nth(whichplan, unionplans);
+ slot = NodeGetResultTupleSlot(subplan);
+ break;
+ }
+
+ case T_IndexScan:
+ {
+ CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Material:
+ {
+ MaterialState *matstate = ((Material *) node)->matstate;
+
+ slot = matstate->csstate.css_ScanTupleSlot;
+ }
+ break;
+
+ case T_Sort:
+ {
+ SortState *sortstate = ((Sort *) node)->sortstate;
+
+ slot = sortstate->csstate.css_ScanTupleSlot;
+ }
+ break;
+
+ case T_Agg:
+ {
+ AggState *aggstate = ((Agg *) node)->aggstate;
+
+ slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Group:
+ {
+ GroupState *grpstate = ((Group *) node)->grpstate;
+
+ slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Hash:
+ {
+ HashState *hashstate = ((Hash *) node)->hashstate;
+
+ slot = hashstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Unique:
+ {
+ UniqueState *uniquestate = ((Unique *) node)->uniquestate;
+
+ slot = uniquestate->cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_MergeJoin:
+ {
+ MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
+
+ slot = mergestate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_HashJoin:
+ {
+ HashJoinState *hashjoinstate = ((HashJoin *) node)->hashjoinstate;
+
+ slot = hashjoinstate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Tee:
+ {
+ TeeState *teestate = ((Tee *) node)->teestate;
+
+ slot = teestate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ default:
+ /* ----------------
+ * should never get here
+ * ----------------
+ */
+ elog(WARN, "NodeGetResultTupleSlot: node not yet supported: %d ",
+ nodeTag(node));
+
+ return NULL;
}
- break;
-
- case T_Tee:
- {
- TeeState *teestate = ((Tee*)node)->teestate;
- slot = teestate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- default:
- /* ----------------
- * should never get here
- * ----------------
- */
- elog(WARN, "NodeGetResultTupleSlot: node not yet supported: %d ",
- nodeTag(node));
-
- return NULL;
- }
- return slot;
+ return slot;
}
/* ----------------------------------------------------------------
- * ExecGetTupType
+ * ExecGetTupType
*
- * this gives you the tuple descriptor for tuples returned
- * by this node. I really wish I could ditch this routine,
- * but since not all nodes store their type info in the same
- * place, we have to do something special for each node type.
+ * this gives you the tuple descriptor for tuples returned
+ * by this node. I really wish I could ditch this routine,
+ * but since not all nodes store their type info in the same
+ * place, we have to do something special for each node type.
*
- * Soon, the system will have to adapt to deal with changing
- * tuple descriptors as we deal with dynamic tuple types
- * being returned from procedure nodes. Perhaps then this
- * routine can be retired. -cim 6/3/91
+ * Soon, the system will have to adapt to deal with changing
+ * tuple descriptors as we deal with dynamic tuple types
+ * being returned from procedure nodes. Perhaps then this
+ * routine can be retired. -cim 6/3/91
*
* old comments
- * This routine just gets the type information out of the
- * node's state. If you already have a node's state, you
- * can get this information directly, but this is a useful
- * routine if you want to get the type information from
- * the node's inner or outer subplan easily without having
- * to inspect the subplan.. -cim 10/16/89
+ * This routine just gets the type information out of the
+ * node's state. If you already have a node's state, you
+ * can get this information directly, but this is a useful
+ * routine if you want to get the type information from
+ * the node's inner or outer subplan easily without having
+ * to inspect the subplan.. -cim 10/16/89
*
- * Assume that for existential nodes, we get the targetlist out
- * of the right node's targetlist
+ * Assume that for existential nodes, we get the targetlist out
+ * of the right node's targetlist
* ----------------------------------------------------------------
*/
TupleDesc
-ExecGetTupType(Plan *node)
+ExecGetTupType(Plan * node)
{
- TupleTableSlot *slot;
- TupleDesc tupType;
-
- if (node == NULL)
- return NULL;
-
- slot = NodeGetResultTupleSlot(node);
- tupType = slot->ttc_tupleDescriptor;
- return tupType;
+ TupleTableSlot *slot;
+ TupleDesc tupType;
+
+ if (node == NULL)
+ return NULL;
+
+ slot = NodeGetResultTupleSlot(node);
+ tupType = slot->ttc_tupleDescriptor;
+ return tupType;
}
/*
TupleDesc
-ExecCopyTupType(TupleDesc td, int natts)
+ExecCopyTupType(TupleDesc td, int natts)
{
- TupleDesc newTd;
- int i;
-
- newTd = CreateTemplateTupleDesc(natts);
- i = 0;
- while (i < natts)
- {
- newTd[i] =
- (AttributeTupleForm)palloc(sizeof(FormData_pg_attribute));
- memmove(newTd[i], td[i], sizeof(FormData_pg_attribute));
- i++;
- }
- return newTd;
+ TupleDesc newTd;
+ int i;
+
+ newTd = CreateTemplateTupleDesc(natts);
+ i = 0;
+ while (i < natts)
+ {
+ newTd[i] =
+ (AttributeTupleForm)palloc(sizeof(FormData_pg_attribute));
+ memmove(newTd[i], td[i], sizeof(FormData_pg_attribute));
+ i++;
+ }
+ return newTd;
}
*/
/* ----------------------------------------------------------------
- * ExecTypeFromTL
- *
- * Currently there are about 4 different places where we create
- * TupleDescriptors. They should all be merged, or perhaps
- * be rewritten to call BuildDesc().
- *
- * old comments
- * Forms attribute type info from the target list in the node.
- * It assumes all domains are individually specified in the target list.
- * It fails if the target list contains something like Emp.all
- * which represents all the attributes from EMP relation.
- *
- * Conditions:
- * The inner and outer subtrees should be initialized because it
- * might be necessary to know the type infos of the subtrees.
+ * ExecTypeFromTL
+ *
+ * Currently there are about 4 different places where we create
+ * TupleDescriptors. They should all be merged, or perhaps
+ * be rewritten to call BuildDesc().
+ *
+ * old comments
+ * Forms attribute type info from the target list in the node.
+ * It assumes all domains are individually specified in the target list.
+ * It fails if the target list contains something like Emp.all
+ * which represents all the attributes from EMP relation.
+ *
+ * Conditions:
+ * The inner and outer subtrees should be initialized because it
+ * might be necessary to know the type infos of the subtrees.
* ----------------------------------------------------------------
*/
TupleDesc
-ExecTypeFromTL(List *targetList)
+ExecTypeFromTL(List * targetList)
{
- List *tlcdr;
- TupleDesc typeInfo;
- Resdom *resdom;
- Oid restype;
- int len;
-
- /* ----------------
- * examine targetlist - if empty then return NULL
- * ----------------
- */
- len = ExecTargetListLength(targetList);
-
- if (len == 0)
- return NULL;
-
- /* ----------------
- * allocate a new typeInfo
- * ----------------
- */
- typeInfo = CreateTemplateTupleDesc(len);
-
- /* ----------------
- * notes: get resdom from (resdom expr)
- * get_typbyval comes from src/lib/l-lisp/lsyscache.c
- * ----------------
- */
- tlcdr = targetList;
- while (tlcdr != NIL) {
- TargetEntry *tle = lfirst(tlcdr);
- if (tle->resdom != NULL) {
- resdom = tle->resdom;
- restype = resdom->restype;
-
- TupleDescInitEntry(typeInfo,
- resdom->resno,
- resdom->resname,
- /* fix for SELECT NULL ... */
- get_id_typname(restype?restype:UNKNOWNOID),
- 0,
- false);
+ List *tlcdr;
+ TupleDesc typeInfo;
+ Resdom *resdom;
+ Oid restype;
+ int len;
+
+ /* ----------------
+ * examine targetlist - if empty then return NULL
+ * ----------------
+ */
+ len = ExecTargetListLength(targetList);
+
+ if (len == 0)
+ return NULL;
+
+ /* ----------------
+ * allocate a new typeInfo
+ * ----------------
+ */
+ typeInfo = CreateTemplateTupleDesc(len);
+
+ /* ----------------
+ * notes: get resdom from (resdom expr)
+ * get_typbyval comes from src/lib/l-lisp/lsyscache.c
+ * ----------------
+ */
+ tlcdr = targetList;
+ while (tlcdr != NIL)
+ {
+ TargetEntry *tle = lfirst(tlcdr);
+
+ if (tle->resdom != NULL)
+ {
+ resdom = tle->resdom;
+ restype = resdom->restype;
+
+ TupleDescInitEntry(typeInfo,
+ resdom->resno,
+ resdom->resname,
+ /* fix for SELECT NULL ... */
+ get_id_typname(restype ? restype : UNKNOWNOID),
+ 0,
+ false);
/*
- ExecSetTypeInfo(resdom->resno - 1,
- typeInfo,
- (Oid) restype,
- resdom->resno,
- resdom->reslen,
- resdom->resname->data,
- get_typbyval(restype),
- get_typalign(restype));
+ ExecSetTypeInfo(resdom->resno - 1,
+ typeInfo,
+ (Oid) restype,
+ resdom->resno,
+ resdom->reslen,
+ resdom->resname->data,
+ get_typbyval(restype),
+ get_typalign(restype));
*/
- }
- else {
- Resdom *fjRes;
- List *fjTlistP;
- List *fjList = lfirst(tlcdr);
+ }
+ else
+ {
+ Resdom *fjRes;
+ List *fjTlistP;
+ List *fjList = lfirst(tlcdr);
+
#ifdef SETS_FIXED
- TargetEntry *tle;
- Fjoin *fjNode = ((TargetEntry *)lfirst(fjList))->fjoin;
+ TargetEntry *tle;
+ Fjoin *fjNode = ((TargetEntry *) lfirst(fjList))->fjoin;
- tle = fjNode->fj_innerNode; /* ??? */
+ tle = fjNode->fj_innerNode; /* ??? */
#endif
- fjRes = tle->resdom;
- restype = fjRes->restype;
-
- TupleDescInitEntry(typeInfo,
- fjRes->resno,
- fjRes->resname,
- get_id_typname(restype),
- 0,
- false);
+ fjRes = tle->resdom;
+ restype = fjRes->restype;
+
+ TupleDescInitEntry(typeInfo,
+ fjRes->resno,
+ fjRes->resname,
+ get_id_typname(restype),
+ 0,
+ false);
/*
- ExecSetTypeInfo(fjRes->resno - 1,
- typeInfo,
- (Oid) restype,
- fjRes->resno,
- fjRes->reslen,
- (char *) fjRes->resname,
- get_typbyval(restype),
- get_typalign(restype));
+ ExecSetTypeInfo(fjRes->resno - 1,
+ typeInfo,
+ (Oid) restype,
+ fjRes->resno,
+ fjRes->reslen,
+ (char *) fjRes->resname,
+ get_typbyval(restype),
+ get_typalign(restype));
*/
-
- foreach(fjTlistP, lnext(fjList)) {
- TargetEntry *fjTle = lfirst(fjTlistP);
-
- fjRes = fjTle->resdom;
-
- TupleDescInitEntry(typeInfo,
- fjRes->resno,
- fjRes->resname,
- get_id_typname(restype),
- 0,
- false);
-
+
+ foreach(fjTlistP, lnext(fjList))
+ {
+ TargetEntry *fjTle = lfirst(fjTlistP);
+
+ fjRes = fjTle->resdom;
+
+ TupleDescInitEntry(typeInfo,
+ fjRes->resno,
+ fjRes->resname,
+ get_id_typname(restype),
+ 0,
+ false);
+
/*
- ExecSetTypeInfo(fjRes->resno - 1,
- typeInfo,
- (Oid) fjRes->restype,
- fjRes->resno,
- fjRes->reslen,
- (char *) fjRes->resname,
- get_typbyval(fjRes->restype),
- get_typalign(fjRes->restype));
+ ExecSetTypeInfo(fjRes->resno - 1,
+ typeInfo,
+ (Oid) fjRes->restype,
+ fjRes->resno,
+ fjRes->reslen,
+ (char *) fjRes->resname,
+ get_typbyval(fjRes->restype),
+ get_typalign(fjRes->restype));
*/
- }
- }
-
- tlcdr = lnext(tlcdr);
- }
-
- return typeInfo;
-}
+ }
+ }
+ tlcdr = lnext(tlcdr);
+ }
+ return typeInfo;
+}
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index ac2d3516036..3795c2d1018 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -1,43 +1,43 @@
/*-------------------------------------------------------------------------
*
* execUtils.c--
- * miscellanious executor utility routines
+ * miscellanious executor utility routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.14 1997/08/22 03:12:19 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.15 1997/09/07 04:41:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecAssignNodeBaseInfo \
- * ExecAssignDebugHooks > preforms misc work done in all the
- * ExecAssignExprContext / init node routines.
+ * ExecAssignNodeBaseInfo \
+ * ExecAssignDebugHooks > preforms misc work done in all the
+ * ExecAssignExprContext / init node routines.
*
- * ExecGetTypeInfo | old execCStructs interface
- * ExecMakeTypeInfo | code from the version 1
- * ExecOrderTypeInfo | lisp system. These should
- * ExecSetTypeInfo | go away or be updated soon.
- * ExecFreeTypeInfo | -cim 11/1/89
- * ExecTupleAttributes /
+ * ExecGetTypeInfo | old execCStructs interface
+ * ExecMakeTypeInfo | code from the version 1
+ * ExecOrderTypeInfo | lisp system. These should
+ * ExecSetTypeInfo | go away or be updated soon.
+ * ExecFreeTypeInfo | -cim 11/1/89
+ * ExecTupleAttributes /
*
- * QueryDescGetTypeInfo - moved here from main.c
- * am not sure what uses it -cim 10/12/89
+ * QueryDescGetTypeInfo - moved here from main.c
+ * am not sure what uses it -cim 10/12/89
*
- * ExecGetIndexKeyInfo \
- * ExecOpenIndices | referenced by InitPlan, EndPlan,
- * ExecCloseIndices | ExecAppend, ExecReplace
- * ExecFormIndexTuple |
- * ExecInsertIndexTuple /
+ * ExecGetIndexKeyInfo \
+ * ExecOpenIndices | referenced by InitPlan, EndPlan,
+ * ExecCloseIndices | ExecAppend, ExecReplace
+ * ExecFormIndexTuple |
+ * ExecInsertIndexTuple /
+ *
+ * NOTES
+ * This file has traditionally been the place to stick misc.
+ * executor support stuff that doesn't really go anyplace else.
*
- * NOTES
- * This file has traditionally been the place to stick misc.
- * executor support stuff that doesn't really go anyplace else.
- *
*/
#include "postgres.h"
@@ -58,1149 +58,1195 @@
#include "catalog/pg_type.h"
#include "parser/parsetree.h"
-static void ExecGetIndexKeyInfo(IndexTupleForm indexTuple, int *numAttsOutP,
- AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
+static void
+ExecGetIndexKeyInfo(IndexTupleForm indexTuple, int *numAttsOutP,
+ AttrNumber ** attsOutP, FuncIndexInfoPtr fInfoP);
/* ----------------------------------------------------------------
- * global counters for number of tuples processed, retrieved,
- * appended, replaced, deleted.
+ * global counters for number of tuples processed, retrieved,
+ * appended, replaced, deleted.
* ----------------------------------------------------------------
*/
-int NTupleProcessed;
-int NTupleRetrieved;
-int NTupleReplaced;
-int NTupleAppended;
-int NTupleDeleted;
-int NIndexTupleInserted;
-extern int NIndexTupleProcessed; /* have to be defined in the access
- method level so that the cinterface.a
- will link ok. */
+int NTupleProcessed;
+int NTupleRetrieved;
+int NTupleReplaced;
+int NTupleAppended;
+int NTupleDeleted;
+int NIndexTupleInserted;
+extern int NIndexTupleProcessed; /* have to be defined in the
+ * access method level so that the
+ * cinterface.a will link ok. */
/* ----------------------------------------------------------------
- * statistic functions
+ * statistic functions
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
- * ResetTupleCount
+ * ResetTupleCount
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
void
ResetTupleCount(void)
{
- NTupleProcessed = 0;
- NTupleRetrieved = 0;
- NTupleAppended = 0;
- NTupleDeleted = 0;
- NTupleReplaced = 0;
- NIndexTupleProcessed = 0;
+ NTupleProcessed = 0;
+ NTupleRetrieved = 0;
+ NTupleAppended = 0;
+ NTupleDeleted = 0;
+ NTupleReplaced = 0;
+ NIndexTupleProcessed = 0;
}
+
#endif
/* ----------------------------------------------------------------
- * PrintTupleCount
+ * PrintTupleCount
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
void
-DisplayTupleCount(FILE *statfp)
+DisplayTupleCount(FILE * statfp)
{
- if (NTupleProcessed > 0)
- fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed,
- (NTupleProcessed == 1) ? "" : "s");
- else {
- fprintf(statfp, "!\tno tuples processed.\n");
- return;
- }
- if (NIndexTupleProcessed > 0)
- fprintf(statfp, "%d indextuple%s processed, ", NIndexTupleProcessed,
- (NIndexTupleProcessed == 1) ? "" : "s");
- if (NIndexTupleInserted > 0)
- fprintf(statfp, "%d indextuple%s inserted, ", NIndexTupleInserted,
- (NIndexTupleInserted == 1) ? "" : "s");
- if (NTupleRetrieved > 0)
- fprintf(statfp, "%d tuple%s retrieved. ", NTupleRetrieved,
- (NTupleRetrieved == 1) ? "" : "s");
- if (NTupleAppended > 0)
- fprintf(statfp, "%d tuple%s appended. ", NTupleAppended,
- (NTupleAppended == 1) ? "" : "s");
- if (NTupleDeleted > 0)
- fprintf(statfp, "%d tuple%s deleted. ", NTupleDeleted,
- (NTupleDeleted == 1) ? "" : "s");
- if (NTupleReplaced > 0)
- fprintf(statfp, "%d tuple%s replaced. ", NTupleReplaced,
- (NTupleReplaced == 1) ? "" : "s");
- fprintf(statfp, "\n");
+ if (NTupleProcessed > 0)
+ fprintf(statfp, "!\t%d tuple%s processed, ", NTupleProcessed,
+ (NTupleProcessed == 1) ? "" : "s");
+ else
+ {
+ fprintf(statfp, "!\tno tuples processed.\n");
+ return;
+ }
+ if (NIndexTupleProcessed > 0)
+ fprintf(statfp, "%d indextuple%s processed, ", NIndexTupleProcessed,
+ (NIndexTupleProcessed == 1) ? "" : "s");
+ if (NIndexTupleInserted > 0)
+ fprintf(statfp, "%d indextuple%s inserted, ", NIndexTupleInserted,
+ (NIndexTupleInserted == 1) ? "" : "s");
+ if (NTupleRetrieved > 0)
+ fprintf(statfp, "%d tuple%s retrieved. ", NTupleRetrieved,
+ (NTupleRetrieved == 1) ? "" : "s");
+ if (NTupleAppended > 0)
+ fprintf(statfp, "%d tuple%s appended. ", NTupleAppended,
+ (NTupleAppended == 1) ? "" : "s");
+ if (NTupleDeleted > 0)
+ fprintf(statfp, "%d tuple%s deleted. ", NTupleDeleted,
+ (NTupleDeleted == 1) ? "" : "s");
+ if (NTupleReplaced > 0)
+ fprintf(statfp, "%d tuple%s replaced. ", NTupleReplaced,
+ (NTupleReplaced == 1) ? "" : "s");
+ fprintf(statfp, "\n");
}
+
#endif
/* ----------------------------------------------------------------
- * miscellanious init node support functions
+ * miscellanious init node support functions
*
- * ExecAssignNodeBaseInfo - assigns the baseid field of the node
- * ExecAssignDebugHooks - assigns the node's debugging hooks
- * ExecAssignExprContext - assigns the node's expression context
+ * ExecAssignNodeBaseInfo - assigns the baseid field of the node
+ * ExecAssignDebugHooks - assigns the node's debugging hooks
+ * ExecAssignExprContext - assigns the node's expression context
* ----------------------------------------------------------------
*/
/* ----------------
- * ExecAssignNodeBaseInfo
+ * ExecAssignNodeBaseInfo
*
- * as it says, this assigns the baseid field of the node and
- * increments the counter in the estate. In addition, it initializes
- * the base_parent field of the basenode.
+ * as it says, this assigns the baseid field of the node and
+ * increments the counter in the estate. In addition, it initializes
+ * the base_parent field of the basenode.
* ----------------
*/
void
-ExecAssignNodeBaseInfo(EState *estate, CommonState *cstate, Plan *parent)
+ExecAssignNodeBaseInfo(EState * estate, CommonState * cstate, Plan * parent)
{
- int baseId;
-
- baseId = estate->es_BaseId;
- cstate->cs_base_id = baseId;
- estate->es_BaseId = baseId + 1;
+ int baseId;
+
+ baseId = estate->es_BaseId;
+ cstate->cs_base_id = baseId;
+ estate->es_BaseId = baseId + 1;
}
/* ----------------
- * ExecAssignExprContext
+ * ExecAssignExprContext
*
- * This initializes the ExprContext field. It is only necessary
- * to do this for nodes which use ExecQual or ExecTargetList
- * because those routines depend on econtext. Other nodes which
- * dont have to evaluate expressions don't need to do this.
+ * This initializes the ExprContext field. It is only necessary
+ * to do this for nodes which use ExecQual or ExecTargetList
+ * because those routines depend on econtext. Other nodes which
+ * dont have to evaluate expressions don't need to do this.
* ----------------
*/
void
-ExecAssignExprContext(EState *estate, CommonState *commonstate)
+ExecAssignExprContext(EState * estate, CommonState * commonstate)
{
- ExprContext *econtext;
- ParamListInfo paraminfo;
- List *rangeTable;
-
- paraminfo = estate->es_param_list_info;
- rangeTable = estate->es_range_table;
-
- econtext = makeNode(ExprContext);
- econtext->ecxt_scantuple = NULL; /* scan tuple slot */
- econtext->ecxt_innertuple = NULL; /* inner tuple slot */
- econtext->ecxt_outertuple = NULL; /* outer tuple slot */
- econtext->ecxt_relation = NULL; /* relation */
- econtext->ecxt_relid = 0; /* relid */
- econtext->ecxt_param_list_info = paraminfo; /* param list info */
- econtext->ecxt_range_table = rangeTable; /* range table */
-
- commonstate->cs_ExprContext = econtext;
+ ExprContext *econtext;
+ ParamListInfo paraminfo;
+ List *rangeTable;
+
+ paraminfo = estate->es_param_list_info;
+ rangeTable = estate->es_range_table;
+
+ econtext = makeNode(ExprContext);
+ econtext->ecxt_scantuple = NULL; /* scan tuple slot */
+ econtext->ecxt_innertuple = NULL; /* inner tuple slot */
+ econtext->ecxt_outertuple = NULL; /* outer tuple slot */
+ econtext->ecxt_relation = NULL; /* relation */
+ econtext->ecxt_relid = 0; /* relid */
+ econtext->ecxt_param_list_info = paraminfo; /* param list info */
+ econtext->ecxt_range_table = rangeTable; /* range table */
+
+ commonstate->cs_ExprContext = econtext;
}
/* ----------------------------------------------------------------
- * Result slot tuple type and ProjectionInfo support
+ * Result slot tuple type and ProjectionInfo support
* ----------------------------------------------------------------
*/
/* ----------------
- * ExecAssignResultType
+ * ExecAssignResultType
* ----------------
*/
void
-ExecAssignResultType(CommonState *commonstate,
- TupleDesc tupDesc)
+ExecAssignResultType(CommonState * commonstate,
+ TupleDesc tupDesc)
{
- TupleTableSlot *slot;
-
- slot = commonstate->cs_ResultTupleSlot;
- slot->ttc_tupleDescriptor = tupDesc;
+ TupleTableSlot *slot;
+
+ slot = commonstate->cs_ResultTupleSlot;
+ slot->ttc_tupleDescriptor = tupDesc;
}
/* ----------------
- * ExecAssignResultTypeFromOuterPlan
+ * ExecAssignResultTypeFromOuterPlan
* ----------------
*/
void
-ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate)
+ExecAssignResultTypeFromOuterPlan(Plan * node, CommonState * commonstate)
{
- Plan *outerPlan;
- TupleDesc tupDesc;
-
- outerPlan = outerPlan(node);
- tupDesc = ExecGetTupType(outerPlan);
-
- ExecAssignResultType(commonstate, tupDesc);
+ Plan *outerPlan;
+ TupleDesc tupDesc;
+
+ outerPlan = outerPlan(node);
+ tupDesc = ExecGetTupType(outerPlan);
+
+ ExecAssignResultType(commonstate, tupDesc);
}
/* ----------------
- * ExecAssignResultTypeFromTL
+ * ExecAssignResultTypeFromTL
* ----------------
*/
void
-ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
+ExecAssignResultTypeFromTL(Plan * node, CommonState * commonstate)
{
- List *targetList;
- int i;
- int len;
- List *tl;
- TargetEntry *tle;
- List *fjtl;
- TupleDesc origTupDesc;
-
- targetList = node->targetlist;
- origTupDesc = ExecTypeFromTL(targetList);
- len = ExecTargetListLength(targetList);
-
- fjtl = NIL;
- tl = targetList;
- i = 0;
- while (tl != NIL || fjtl != NIL) {
- if (fjtl != NIL) {
- tle = lfirst(fjtl);
- fjtl = lnext(fjtl);
- }
- else {
- tle = lfirst(tl);
- tl = lnext(tl);
- }
+ List *targetList;
+ int i;
+ int len;
+ List *tl;
+ TargetEntry *tle;
+ List *fjtl;
+ TupleDesc origTupDesc;
+
+ targetList = node->targetlist;
+ origTupDesc = ExecTypeFromTL(targetList);
+ len = ExecTargetListLength(targetList);
+
+ fjtl = NIL;
+ tl = targetList;
+ i = 0;
+ while (tl != NIL || fjtl != NIL)
+ {
+ if (fjtl != NIL)
+ {
+ tle = lfirst(fjtl);
+ fjtl = lnext(fjtl);
+ }
+ else
+ {
+ tle = lfirst(tl);
+ tl = lnext(tl);
+ }
#ifdef SETS_FIXED
- if (!tl_is_resdom(tle)) {
- Fjoin *fj = (Fjoin *)lfirst(tle);
- /* it is a FJoin */
- fjtl = lnext(tle);
- tle = fj->fj_innerNode;
- }
+ if (!tl_is_resdom(tle))
+ {
+ Fjoin *fj = (Fjoin *) lfirst(tle);
+
+ /* it is a FJoin */
+ fjtl = lnext(tle);
+ tle = fj->fj_innerNode;
+ }
#endif
- i++;
- }
- if (len > 0) {
- ExecAssignResultType(commonstate,
- origTupDesc);
- }
- else
- ExecAssignResultType(commonstate,
- (TupleDesc)NULL);
+ i++;
+ }
+ if (len > 0)
+ {
+ ExecAssignResultType(commonstate,
+ origTupDesc);
+ }
+ else
+ ExecAssignResultType(commonstate,
+ (TupleDesc) NULL);
}
/* ----------------
- * ExecGetResultType
+ * ExecGetResultType
* ----------------
*/
TupleDesc
-ExecGetResultType(CommonState *commonstate)
+ExecGetResultType(CommonState * commonstate)
{
- TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
-
- return slot->ttc_tupleDescriptor;
+ TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
+
+ return slot->ttc_tupleDescriptor;
}
/* ----------------
- * ExecFreeResultType
+ * ExecFreeResultType
* ----------------
*/
#ifdef NOT_USED
void
-ExecFreeResultType(CommonState *commonstate)
+ExecFreeResultType(CommonState * commonstate)
{
- TupleTableSlot *slot;
- TupleDesc tupType;
-
- slot = commonstate->cs_ResultTupleSlot;
- tupType = slot->ttc_tupleDescriptor;
-
-/* ExecFreeTypeInfo(tupType); */
- pfree(tupType);
+ TupleTableSlot *slot;
+ TupleDesc tupType;
+
+ slot = commonstate->cs_ResultTupleSlot;
+ tupType = slot->ttc_tupleDescriptor;
+
+/* ExecFreeTypeInfo(tupType); */
+ pfree(tupType);
}
+
#endif
/* ----------------
- * ExecAssignProjectionInfo
- forms the projection information from the node's targetlist
+ * ExecAssignProjectionInfo
+ forms the projection information from the node's targetlist
* ----------------
*/
void
-ExecAssignProjectionInfo(Plan *node, CommonState *commonstate)
+ExecAssignProjectionInfo(Plan * node, CommonState * commonstate)
{
- ProjectionInfo *projInfo;
- List *targetList;
- int len;
-
- targetList = node->targetlist;
- len = ExecTargetListLength(targetList);
-
- projInfo = makeNode(ProjectionInfo);
- projInfo->pi_targetlist = targetList;
- projInfo->pi_len = len;
- projInfo->pi_tupValue =
- (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
- projInfo->pi_exprContext = commonstate->cs_ExprContext;
- projInfo->pi_slot = commonstate->cs_ResultTupleSlot;
-
- commonstate->cs_ProjInfo = projInfo;
+ ProjectionInfo *projInfo;
+ List *targetList;
+ int len;
+
+ targetList = node->targetlist;
+ len = ExecTargetListLength(targetList);
+
+ projInfo = makeNode(ProjectionInfo);
+ projInfo->pi_targetlist = targetList;
+ projInfo->pi_len = len;
+ projInfo->pi_tupValue =
+ (len <= 0) ? NULL : (Datum *) palloc(sizeof(Datum) * len);
+ projInfo->pi_exprContext = commonstate->cs_ExprContext;
+ projInfo->pi_slot = commonstate->cs_ResultTupleSlot;
+
+ commonstate->cs_ProjInfo = projInfo;
}
/* ----------------
- * ExecFreeProjectionInfo
+ * ExecFreeProjectionInfo
* ----------------
*/
void
-ExecFreeProjectionInfo(CommonState *commonstate)
+ExecFreeProjectionInfo(CommonState * commonstate)
{
- ProjectionInfo *projInfo;
-
- /* ----------------
- * get projection info. if NULL then this node has
- * none so we just return.
- * ----------------
- */
- projInfo = commonstate->cs_ProjInfo;
- if (projInfo == NULL)
- return;
-
- /* ----------------
- * clean up memory used.
- * ----------------
- */
- if (projInfo->pi_tupValue != NULL)
- pfree(projInfo->pi_tupValue);
-
- pfree(projInfo);
- commonstate->cs_ProjInfo = NULL;
+ ProjectionInfo *projInfo;
+
+ /* ----------------
+ * get projection info. if NULL then this node has
+ * none so we just return.
+ * ----------------
+ */
+ projInfo = commonstate->cs_ProjInfo;
+ if (projInfo == NULL)
+ return;
+
+ /* ----------------
+ * clean up memory used.
+ * ----------------
+ */
+ if (projInfo->pi_tupValue != NULL)
+ pfree(projInfo->pi_tupValue);
+
+ pfree(projInfo);
+ commonstate->cs_ProjInfo = NULL;
}
/* ----------------------------------------------------------------
- * the following scan type support functions are for
- * those nodes which are stubborn and return tuples in
- * their Scan tuple slot instead of their Result tuple
- * slot.. luck fur us, these nodes do not do projections
- * so we don't have to worry about getting the ProjectionInfo
- * right for them... -cim 6/3/91
+ * the following scan type support functions are for
+ * those nodes which are stubborn and return tuples in
+ * their Scan tuple slot instead of their Result tuple
+ * slot.. luck fur us, these nodes do not do projections
+ * so we don't have to worry about getting the ProjectionInfo
+ * right for them... -cim 6/3/91
* ----------------------------------------------------------------
*/
/* ----------------
- * ExecGetScanType
+ * ExecGetScanType
* ----------------
*/
TupleDesc
-ExecGetScanType(CommonScanState *csstate)
+ExecGetScanType(CommonScanState * csstate)
{
- TupleTableSlot *slot = csstate->css_ScanTupleSlot;
- return slot->ttc_tupleDescriptor;
+ TupleTableSlot *slot = csstate->css_ScanTupleSlot;
+
+ return slot->ttc_tupleDescriptor;
}
/* ----------------
- * ExecFreeScanType
+ * ExecFreeScanType
* ----------------
*/
#ifdef NOT_USED
void
-ExecFreeScanType(CommonScanState *csstate)
+ExecFreeScanType(CommonScanState * csstate)
{
- TupleTableSlot *slot;
- TupleDesc tupType;
-
- slot = csstate->css_ScanTupleSlot;
- tupType = slot->ttc_tupleDescriptor;
-
-/* ExecFreeTypeInfo(tupType); */
- pfree(tupType);
+ TupleTableSlot *slot;
+ TupleDesc tupType;
+
+ slot = csstate->css_ScanTupleSlot;
+ tupType = slot->ttc_tupleDescriptor;
+
+/* ExecFreeTypeInfo(tupType); */
+ pfree(tupType);
}
+
#endif
/* ----------------
- * ExecAssignScanType
+ * ExecAssignScanType
* ----------------
*/
void
-ExecAssignScanType(CommonScanState *csstate,
- TupleDesc tupDesc)
+ExecAssignScanType(CommonScanState * csstate,
+ TupleDesc tupDesc)
{
- TupleTableSlot *slot;
-
- slot = (TupleTableSlot *) csstate->css_ScanTupleSlot;
- slot->ttc_tupleDescriptor = tupDesc;
+ TupleTableSlot *slot;
+
+ slot = (TupleTableSlot *) csstate->css_ScanTupleSlot;
+ slot->ttc_tupleDescriptor = tupDesc;
}
/* ----------------
- * ExecAssignScanTypeFromOuterPlan
+ * ExecAssignScanTypeFromOuterPlan
* ----------------
*/
void
-ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
+ExecAssignScanTypeFromOuterPlan(Plan * node, CommonScanState * csstate)
{
- Plan *outerPlan;
- TupleDesc tupDesc;
-
- outerPlan = outerPlan(node);
- tupDesc = ExecGetTupType(outerPlan);
+ Plan *outerPlan;
+ TupleDesc tupDesc;
+
+ outerPlan = outerPlan(node);
+ tupDesc = ExecGetTupType(outerPlan);
- ExecAssignScanType(csstate, tupDesc);
+ ExecAssignScanType(csstate, tupDesc);
}
/* ----------------------------------------------------------------
- * ExecTypeFromTL support routines.
+ * ExecTypeFromTL support routines.
*
- * these routines are used mainly from ExecTypeFromTL.
- * -cim 6/12/90
+ * these routines are used mainly from ExecTypeFromTL.
+ * -cim 6/12/90
*
* old comments
- * Routines dealing with the structure 'attribute' which conatains
- * the type information about attributes in a tuple:
+ * Routines dealing with the structure 'attribute' which conatains
+ * the type information about attributes in a tuple:
*
- * ExecMakeTypeInfo(noType) --
- * returns pointer to array of 'noType' structure 'attribute'.
- * ExecSetTypeInfo(index, typeInfo, attNum, attLen) --
- * sets the element indexed by 'index' in typeInfo with
- * the values: attNum, attLen.
- * ExecFreeTypeInfo(typeInfo) --
- * frees the structure 'typeInfo'.
+ * ExecMakeTypeInfo(noType) --
+ * returns pointer to array of 'noType' structure 'attribute'.
+ * ExecSetTypeInfo(index, typeInfo, attNum, attLen) --
+ * sets the element indexed by 'index' in typeInfo with
+ * the values: attNum, attLen.
+ * ExecFreeTypeInfo(typeInfo) --
+ * frees the structure 'typeInfo'.
* ----------------------------------------------------------------
*/
/* ----------------
- * ExecSetTypeInfo
+ * ExecSetTypeInfo
*
- * This initializes fields of a single attribute in a
- * tuple descriptor from the specified parameters.
+ * This initializes fields of a single attribute in a
+ * tuple descriptor from the specified parameters.
*
- * XXX this duplicates much of the functionality of TupleDescInitEntry.
- * the routines should be moved to the same place and be rewritten
- * to share common code.
+ * XXX this duplicates much of the functionality of TupleDescInitEntry.
+ * the routines should be moved to the same place and be rewritten
+ * to share common code.
* ----------------
*/
-#ifdef NOT_USED
+#ifdef NOT_USED
void
ExecSetTypeInfo(int index,
- TupleDesc typeInfo,
- Oid typeID,
- int attNum,
- int attLen,
- char *attName,
- bool attbyVal,
- char attalign)
+ TupleDesc typeInfo,
+ Oid typeID,
+ int attNum,
+ int attLen,
+ char *attName,
+ bool attbyVal,
+ char attalign)
{
- AttributeTupleForm att;
-
- /* ----------------
- * get attribute pointer and preform a sanity check..
- * ----------------
- */
- att = typeInfo[index];
- if (att == NULL)
- elog(WARN, "ExecSetTypeInfo: trying to assign through NULL");
-
- /* ----------------
- * assign values to the tuple descriptor, being careful not
- * to copy a null attName..
- *
- * XXX it is unknown exactly what information is needed to
- * initialize the attribute struct correctly so for now
- * we use 0. this should be fixed -- otherwise we run the
- * risk of using garbage data. -cim 5/5/91
- * ----------------
- */
- att->attrelid = 0; /* dummy value */
-
- if (attName != (char *) NULL)
- strNcpy(att->attname.data, attName, NAMEDATALEN-1);
- else
- memset(att->attname.data,0,NAMEDATALEN);
-
- att->atttypid = typeID;
- att->attdefrel = 0; /* dummy value */
- att->attdisbursion = 0; /* dummy value */
- att->atttyparg = 0; /* dummy value */
- att->attlen = attLen;
- att->attnum = attNum;
- att->attbound = 0; /* dummy value */
- att->attbyval = attbyVal;
- att->attcanindex = 0; /* dummy value */
- att->attproc = 0; /* dummy value */
- att->attnelems = 0; /* dummy value */
- att->attcacheoff = -1;
- att->attisset = false;
- att->attalign = attalign;
+ AttributeTupleForm att;
+
+ /* ----------------
+ * get attribute pointer and preform a sanity check..
+ * ----------------
+ */
+ att = typeInfo[index];
+ if (att == NULL)
+ elog(WARN, "ExecSetTypeInfo: trying to assign through NULL");
+
+ /* ----------------
+ * assign values to the tuple descriptor, being careful not
+ * to copy a null attName..
+ *
+ * XXX it is unknown exactly what information is needed to
+ * initialize the attribute struct correctly so for now
+ * we use 0. this should be fixed -- otherwise we run the
+ * risk of using garbage data. -cim 5/5/91
+ * ----------------
+ */
+ att->attrelid = 0; /* dummy value */
+
+ if (attName != (char *) NULL)
+ strNcpy(att->attname.data, attName, NAMEDATALEN - 1);
+ else
+ memset(att->attname.data, 0, NAMEDATALEN);
+
+ att->atttypid = typeID;
+ att->attdefrel = 0; /* dummy value */
+ att->attdisbursion = 0; /* dummy value */
+ att->atttyparg = 0; /* dummy value */
+ att->attlen = attLen;
+ att->attnum = attNum;
+ att->attbound = 0; /* dummy value */
+ att->attbyval = attbyVal;
+ att->attcanindex = 0; /* dummy value */
+ att->attproc = 0; /* dummy value */
+ att->attnelems = 0; /* dummy value */
+ att->attcacheoff = -1;
+ att->attisset = false;
+ att->attalign = attalign;
}
/* ----------------
- * ExecFreeTypeInfo frees the array of attrbutes
- * created by ExecMakeTypeInfo and returned by ExecTypeFromTL...
+ * ExecFreeTypeInfo frees the array of attrbutes
+ * created by ExecMakeTypeInfo and returned by ExecTypeFromTL...
* ----------------
*/
void
ExecFreeTypeInfo(TupleDesc typeInfo)
{
- /* ----------------
- * do nothing if asked to free a null pointer
- * ----------------
- */
- if (typeInfo == NULL)
- return;
-
- /* ----------------
- * the entire array of typeinfo pointers created by
- * ExecMakeTypeInfo was allocated with a single palloc()
- * so we can deallocate the whole array with a single pfree().
- * (we should not try and free all the elements in the array)
- * -cim 6/12/90
- * ----------------
- */
- pfree(typeInfo);
+ /* ----------------
+ * do nothing if asked to free a null pointer
+ * ----------------
+ */
+ if (typeInfo == NULL)
+ return;
+
+ /* ----------------
+ * the entire array of typeinfo pointers created by
+ * ExecMakeTypeInfo was allocated with a single palloc()
+ * so we can deallocate the whole array with a single pfree().
+ * (we should not try and free all the elements in the array)
+ * -cim 6/12/90
+ * ----------------
+ */
+ pfree(typeInfo);
}
/* ----------------------------------------------------------------
- * QueryDescGetTypeInfo
+ * QueryDescGetTypeInfo
*
- *| I don't know how this is used, all I know is that it
- *| appeared one day in main.c so I moved it here. -cim 11/1/89
+ *| I don't know how this is used, all I know is that it
+ *| appeared one day in main.c so I moved it here. -cim 11/1/89
* ----------------------------------------------------------------
*/
TupleDesc
-QueryDescGetTypeInfo(QueryDesc *queryDesc)
+QueryDescGetTypeInfo(QueryDesc * queryDesc)
{
- Plan *plan;
- TupleDesc tupleType;
- List *targetList;
- AttrInfo *attinfo = (AttrInfo *)palloc(sizeof(AttrInfo));
-
- plan = queryDesc->plantree;
- tupleType = (TupleDesc) ExecGetTupType(plan);
+ Plan *plan;
+ TupleDesc tupleType;
+ List *targetList;
+ AttrInfo *attinfo = (AttrInfo *) palloc(sizeof(AttrInfo));
+
+ plan = queryDesc->plantree;
+ tupleType = (TupleDesc) ExecGetTupType(plan);
/*
- targetList = plan->targetlist;
+ targetList = plan->targetlist;
- attinfo->numAttr = ExecTargetListLength(targetList);
- attinfo->attrs = tupleType;
+ attinfo->numAttr = ExecTargetListLength(targetList);
+ attinfo->attrs = tupleType;
*/
- attinfo->numAttr = tupleType->natts;
- attinfo->attrs = tupleType->attrs;
- return attinfo;
+ attinfo->numAttr = tupleType->natts;
+ attinfo->attrs = tupleType->attrs;
+ return attinfo;
}
+
#endif
/* ----------------------------------------------------------------
- * ExecInsertIndexTuples support
+ * ExecInsertIndexTuples support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
- * ExecGetIndexKeyInfo
+ * ExecGetIndexKeyInfo
*
- * Extracts the index key attribute numbers from
- * an index tuple form (i.e. a tuple from the pg_index relation)
- * into an array of attribute numbers. The array and the
- * size of the array are returned to the caller via return
- * parameters.
+ * Extracts the index key attribute numbers from
+ * an index tuple form (i.e. a tuple from the pg_index relation)
+ * into an array of attribute numbers. The array and the
+ * size of the array are returned to the caller via return
+ * parameters.
* ----------------------------------------------------------------
*/
static void
ExecGetIndexKeyInfo(IndexTupleForm indexTuple,
- int *numAttsOutP,
- AttrNumber **attsOutP,
- FuncIndexInfoPtr fInfoP)
+ int *numAttsOutP,
+ AttrNumber ** attsOutP,
+ FuncIndexInfoPtr fInfoP)
{
- int i;
- int numKeys;
- AttrNumber *attKeys;
-
- /* ----------------
- * check parameters
- * ----------------
- */
- if (numAttsOutP == NULL && attsOutP == NULL) {
- elog(DEBUG, "ExecGetIndexKeyInfo: %s",
- "invalid parameters: numAttsOutP and attsOutP must be non-NULL");
- }
-
- /* ----------------
- * set the procid for a possible functional index.
- * ----------------
- */
- FIsetProcOid(fInfoP, indexTuple->indproc);
-
- /* ----------------
- * count the number of keys..
- * ----------------
- */
- numKeys = 0;
- for (i=0; i<8 && indexTuple->indkey[i] != 0; i++)
- numKeys++;
-
- /* ----------------
- * place number keys in callers return area
- * or the number of arguments for a functional index.
- *
- * If we have a functional index then the number of
- * attributes defined in the index must 1 (the function's
- * single return value).
- * ----------------
- */
- if (FIgetProcOid(fInfoP) != InvalidOid) {
- FIsetnArgs(fInfoP, numKeys);
- (*numAttsOutP) = 1;
- }
- else
- (*numAttsOutP) = numKeys;
-
- if (numKeys < 1) {
- elog(DEBUG, "ExecGetIndexKeyInfo: %s",
- "all index key attribute numbers are zero!");
- (*attsOutP) = NULL;
- return;
- }
-
- /* ----------------
- * allocate and fill in array of key attribute numbers
- * ----------------
- */
- CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
-
- attKeys = (AttrNumber*)
- palloc(numKeys * sizeof(AttrNumber));
-
- for (i=0; i<numKeys; i++)
- attKeys[i] = indexTuple->indkey[i];
-
- /* ----------------
- * return array to caller.
- * ----------------
- */
- (*attsOutP) = attKeys;
-}
+ int i;
+ int numKeys;
+ AttrNumber *attKeys;
-/* ----------------------------------------------------------------
- * ExecOpenIndices
- *
- * Here we scan the pg_index relation to find indices
- * associated with a given heap relation oid. Since we
- * don't know in advance how many indices we have, we
- * form lists containing the information we need from
- * pg_index and then process these lists.
- *
- * Note: much of this code duplicates effort done by
- * the IndexCatalogInformation function in plancat.c
- * because IndexCatalogInformation is poorly written.
- *
- * It would be much better the functionality provided
- * by this function and IndexCatalogInformation was
- * in the form of a small set of orthogonal routines..
- * If you are trying to understand this, I suggest you
- * look at the code to IndexCatalogInformation and
- * FormIndexTuple.. -cim 9/27/89
- * ----------------------------------------------------------------
- */
-void
-ExecOpenIndices(Oid resultRelationOid,
- RelationInfo *resultRelationInfo)
-{
- Relation indexRd;
- HeapScanDesc indexSd;
- ScanKeyData key;
- HeapTuple tuple;
- IndexTupleForm indexStruct;
- Oid indexOid;
- List *oidList;
- List *nkeyList;
- List *keyList;
- List *fiList;
- char *predString;
- List *predList;
- List *indexoid;
- List *numkeys;
- List *indexkeys;
- List *indexfuncs;
- List *indexpreds;
- int len;
-
- RelationPtr relationDescs;
- IndexInfo **indexInfoArray;
- FuncIndexInfoPtr fInfoP;
- int numKeyAtts;
- AttrNumber *indexKeyAtts;
- PredInfo *predicate;
- int i;
-
- /* ----------------
- * open pg_index
- * ----------------
- */
- indexRd = heap_openr(IndexRelationName);
-
- /* ----------------
- * form a scan key
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(resultRelationOid));
-
- /* ----------------
- * scan the index relation, looking for indices for our
- * result relation..
- * ----------------
- */
- indexSd = heap_beginscan(indexRd, /* scan desc */
- false, /* scan backward flag */
- NowTimeQual, /* time qual */
- 1, /* number scan keys */
- &key); /* scan keys */
-
- oidList = NIL;
- nkeyList = NIL;
- keyList = NIL;
- fiList = NIL;
- predList = NIL;
-
- while(tuple = heap_getnext(indexSd, /* scan desc */
- false, /* scan backward flag */
- NULL), /* return: buffer */
- HeapTupleIsValid(tuple)) {
-
/* ----------------
- * For each index relation we find, extract the information
- * we need and store it in a list..
- *
- * first get the oid of the index relation from the tuple
+ * check parameters
* ----------------
*/
- indexStruct = (IndexTupleForm) GETSTRUCT(tuple);
- indexOid = indexStruct->indexrelid;
-
+ if (numAttsOutP == NULL && attsOutP == NULL)
+ {
+ elog(DEBUG, "ExecGetIndexKeyInfo: %s",
+ "invalid parameters: numAttsOutP and attsOutP must be non-NULL");
+ }
+
/* ----------------
- * allocate space for functional index information.
+ * set the procid for a possible functional index.
* ----------------
*/
- fInfoP = (FuncIndexInfoPtr)palloc( sizeof(*fInfoP) );
-
+ FIsetProcOid(fInfoP, indexTuple->indproc);
+
/* ----------------
- * next get the index key information from the tuple
+ * count the number of keys..
* ----------------
*/
- ExecGetIndexKeyInfo(indexStruct,
- &numKeyAtts,
- &indexKeyAtts,
- fInfoP);
-
+ numKeys = 0;
+ for (i = 0; i < 8 && indexTuple->indkey[i] != 0; i++)
+ numKeys++;
+
/* ----------------
- * next get the index predicate from the tuple
+ * place number keys in callers return area
+ * or the number of arguments for a functional index.
+ *
+ * If we have a functional index then the number of
+ * attributes defined in the index must 1 (the function's
+ * single return value).
* ----------------
*/
- if (VARSIZE(&indexStruct->indpred) != 0) {
- predString = fmgr(F_TEXTOUT, &indexStruct->indpred);
- predicate = (PredInfo*)stringToNode(predString);
- pfree(predString);
- } else {
- predicate = NULL;
+ if (FIgetProcOid(fInfoP) != InvalidOid)
+ {
+ FIsetnArgs(fInfoP, numKeys);
+ (*numAttsOutP) = 1;
+ }
+ else
+ (*numAttsOutP) = numKeys;
+
+ if (numKeys < 1)
+ {
+ elog(DEBUG, "ExecGetIndexKeyInfo: %s",
+ "all index key attribute numbers are zero!");
+ (*attsOutP) = NULL;
+ return;
}
-
+
/* ----------------
- * save the index information into lists
+ * allocate and fill in array of key attribute numbers
* ----------------
*/
- oidList = lconsi(indexOid, oidList);
- nkeyList = lconsi(numKeyAtts, nkeyList);
- keyList = lcons(indexKeyAtts, keyList);
- fiList = lcons(fInfoP, fiList);
- predList = lcons(predicate, predList);
- }
-
- /* ----------------
- * we have the info we need so close the pg_index relation..
- * ----------------
- */
- heap_endscan(indexSd);
- heap_close(indexRd);
-
- /* ----------------
- * Now that we've collected the index information into three
- * lists, we open the index relations and store the descriptors
- * and the key information into arrays.
- * ----------------
- */
- len = length(oidList);
- if (len > 0) {
+ CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
+
+ attKeys = (AttrNumber *)
+ palloc(numKeys * sizeof(AttrNumber));
+
+ for (i = 0; i < numKeys; i++)
+ attKeys[i] = indexTuple->indkey[i];
+
/* ----------------
- * allocate space for relation descs
+ * return array to caller.
* ----------------
*/
- CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
- relationDescs = (RelationPtr)
- palloc(len * sizeof(Relation));
-
+ (*attsOutP) = attKeys;
+}
+
+/* ----------------------------------------------------------------
+ * ExecOpenIndices
+ *
+ * Here we scan the pg_index relation to find indices
+ * associated with a given heap relation oid. Since we
+ * don't know in advance how many indices we have, we
+ * form lists containing the information we need from
+ * pg_index and then process these lists.
+ *
+ * Note: much of this code duplicates effort done by
+ * the IndexCatalogInformation function in plancat.c
+ * because IndexCatalogInformation is poorly written.
+ *
+ * It would be much better the functionality provided
+ * by this function and IndexCatalogInformation was
+ * in the form of a small set of orthogonal routines..
+ * If you are trying to understand this, I suggest you
+ * look at the code to IndexCatalogInformation and
+ * FormIndexTuple.. -cim 9/27/89
+ * ----------------------------------------------------------------
+ */
+void
+ExecOpenIndices(Oid resultRelationOid,
+ RelationInfo * resultRelationInfo)
+{
+ Relation indexRd;
+ HeapScanDesc indexSd;
+ ScanKeyData key;
+ HeapTuple tuple;
+ IndexTupleForm indexStruct;
+ Oid indexOid;
+ List *oidList;
+ List *nkeyList;
+ List *keyList;
+ List *fiList;
+ char *predString;
+ List *predList;
+ List *indexoid;
+ List *numkeys;
+ List *indexkeys;
+ List *indexfuncs;
+ List *indexpreds;
+ int len;
+
+ RelationPtr relationDescs;
+ IndexInfo **indexInfoArray;
+ FuncIndexInfoPtr fInfoP;
+ int numKeyAtts;
+ AttrNumber *indexKeyAtts;
+ PredInfo *predicate;
+ int i;
+
/* ----------------
- * initialize index info array
+ * open pg_index
* ----------------
*/
- CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
- indexInfoArray = (IndexInfo**)
- palloc(len * sizeof(IndexInfo*));
-
- for (i=0; i<len; i++) {
- IndexInfo *ii = makeNode(IndexInfo);
- ii->ii_NumKeyAttributes = 0;
- ii->ii_KeyAttributeNumbers = (AttrNumber*) NULL;
- ii->ii_FuncIndexInfo = (FuncIndexInfoPtr) NULL;
- ii->ii_Predicate = NULL;
- indexInfoArray[i] = ii;
- }
-
+ indexRd = heap_openr(IndexRelationName);
+
/* ----------------
- * attempt to open each of the indices. If we succeed,
- * then store the index relation descriptor into the
- * relation descriptor array.
+ * form a scan key
* ----------------
*/
- i = 0;
- foreach (indexoid, oidList) {
- Relation indexDesc;
-
- indexOid = lfirsti(indexoid);
- indexDesc = index_open(indexOid);
- if (indexDesc != NULL)
- relationDescs[i++] = indexDesc;
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_index_indrelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(resultRelationOid));
+
+ /* ----------------
+ * scan the index relation, looking for indices for our
+ * result relation..
+ * ----------------
+ */
+ indexSd = heap_beginscan(indexRd, /* scan desc */
+ false, /* scan backward flag */
+ NowTimeQual, /* time qual */
+ 1, /* number scan keys */
+ &key); /* scan keys */
+
+ oidList = NIL;
+ nkeyList = NIL;
+ keyList = NIL;
+ fiList = NIL;
+ predList = NIL;
+
+ while (tuple = heap_getnext(indexSd, /* scan desc */
+ false, /* scan backward flag */
+ NULL), /* return: buffer */
+ HeapTupleIsValid(tuple))
+ {
+
+ /* ----------------
+ * For each index relation we find, extract the information
+ * we need and store it in a list..
+ *
+ * first get the oid of the index relation from the tuple
+ * ----------------
+ */
+ indexStruct = (IndexTupleForm) GETSTRUCT(tuple);
+ indexOid = indexStruct->indexrelid;
+
+ /* ----------------
+ * allocate space for functional index information.
+ * ----------------
+ */
+ fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP));
+
+ /* ----------------
+ * next get the index key information from the tuple
+ * ----------------
+ */
+ ExecGetIndexKeyInfo(indexStruct,
+ &numKeyAtts,
+ &indexKeyAtts,
+ fInfoP);
+
+ /* ----------------
+ * next get the index predicate from the tuple
+ * ----------------
+ */
+ if (VARSIZE(&indexStruct->indpred) != 0)
+ {
+ predString = fmgr(F_TEXTOUT, &indexStruct->indpred);
+ predicate = (PredInfo *) stringToNode(predString);
+ pfree(predString);
+ }
+ else
+ {
+ predicate = NULL;
+ }
+
+ /* ----------------
+ * save the index information into lists
+ * ----------------
+ */
+ oidList = lconsi(indexOid, oidList);
+ nkeyList = lconsi(numKeyAtts, nkeyList);
+ keyList = lcons(indexKeyAtts, keyList);
+ fiList = lcons(fInfoP, fiList);
+ predList = lcons(predicate, predList);
}
-
+
/* ----------------
- * store the relation descriptor array and number of
- * descs into the result relation info.
+ * we have the info we need so close the pg_index relation..
* ----------------
*/
- resultRelationInfo->ri_NumIndices = i;
- resultRelationInfo->ri_IndexRelationDescs = relationDescs;
-
+ heap_endscan(indexSd);
+ heap_close(indexRd);
+
/* ----------------
- * store the index key information collected in our
- * lists into the index info array
+ * Now that we've collected the index information into three
+ * lists, we open the index relations and store the descriptors
+ * and the key information into arrays.
* ----------------
*/
- i = 0;
- foreach (numkeys, nkeyList) {
- numKeyAtts = lfirsti(numkeys);
- indexInfoArray[i++]->ii_NumKeyAttributes = numKeyAtts;
- }
-
- i = 0;
- foreach (indexkeys, keyList) {
- indexKeyAtts = (AttrNumber*) lfirst(indexkeys);
- indexInfoArray[i++]->ii_KeyAttributeNumbers = indexKeyAtts;
- }
-
- i = 0;
- foreach (indexfuncs, fiList) {
- FuncIndexInfoPtr fiP = (FuncIndexInfoPtr)lfirst(indexfuncs);
- indexInfoArray[i++]->ii_FuncIndexInfo = fiP;
- }
-
- i = 0;
- foreach (indexpreds, predList) {
- indexInfoArray[i++]->ii_Predicate = lfirst(indexpreds);
+ len = length(oidList);
+ if (len > 0)
+ {
+ /* ----------------
+ * allocate space for relation descs
+ * ----------------
+ */
+ CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
+ relationDescs = (RelationPtr)
+ palloc(len * sizeof(Relation));
+
+ /* ----------------
+ * initialize index info array
+ * ----------------
+ */
+ CXT1_printf("ExecOpenIndices: context is %d\n", CurrentMemoryContext);
+ indexInfoArray = (IndexInfo **)
+ palloc(len * sizeof(IndexInfo *));
+
+ for (i = 0; i < len; i++)
+ {
+ IndexInfo *ii = makeNode(IndexInfo);
+
+ ii->ii_NumKeyAttributes = 0;
+ ii->ii_KeyAttributeNumbers = (AttrNumber *) NULL;
+ ii->ii_FuncIndexInfo = (FuncIndexInfoPtr) NULL;
+ ii->ii_Predicate = NULL;
+ indexInfoArray[i] = ii;
+ }
+
+ /* ----------------
+ * attempt to open each of the indices. If we succeed,
+ * then store the index relation descriptor into the
+ * relation descriptor array.
+ * ----------------
+ */
+ i = 0;
+ foreach(indexoid, oidList)
+ {
+ Relation indexDesc;
+
+ indexOid = lfirsti(indexoid);
+ indexDesc = index_open(indexOid);
+ if (indexDesc != NULL)
+ relationDescs[i++] = indexDesc;
+ }
+
+ /* ----------------
+ * store the relation descriptor array and number of
+ * descs into the result relation info.
+ * ----------------
+ */
+ resultRelationInfo->ri_NumIndices = i;
+ resultRelationInfo->ri_IndexRelationDescs = relationDescs;
+
+ /* ----------------
+ * store the index key information collected in our
+ * lists into the index info array
+ * ----------------
+ */
+ i = 0;
+ foreach(numkeys, nkeyList)
+ {
+ numKeyAtts = lfirsti(numkeys);
+ indexInfoArray[i++]->ii_NumKeyAttributes = numKeyAtts;
+ }
+
+ i = 0;
+ foreach(indexkeys, keyList)
+ {
+ indexKeyAtts = (AttrNumber *) lfirst(indexkeys);
+ indexInfoArray[i++]->ii_KeyAttributeNumbers = indexKeyAtts;
+ }
+
+ i = 0;
+ foreach(indexfuncs, fiList)
+ {
+ FuncIndexInfoPtr fiP = (FuncIndexInfoPtr) lfirst(indexfuncs);
+
+ indexInfoArray[i++]->ii_FuncIndexInfo = fiP;
+ }
+
+ i = 0;
+ foreach(indexpreds, predList)
+ {
+ indexInfoArray[i++]->ii_Predicate = lfirst(indexpreds);
+ }
+ /* ----------------
+ * store the index info array into relation info
+ * ----------------
+ */
+ resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
}
+
/* ----------------
- * store the index info array into relation info
+ * All done, resultRelationInfo now contains complete information
+ * on the indices associated with the result relation.
* ----------------
*/
- resultRelationInfo->ri_IndexRelationInfo = indexInfoArray;
- }
-
- /* ----------------
- * All done, resultRelationInfo now contains complete information
- * on the indices associated with the result relation.
- * ----------------
- */
-
- /* should free oidList, nkeyList and keyList here */
- /* OK - let's do it -jolly */
- freeList(oidList);
- freeList(nkeyList);
- freeList(keyList);
- freeList(fiList);
- freeList(predList);
+
+ /* should free oidList, nkeyList and keyList here */
+ /* OK - let's do it -jolly */
+ freeList(oidList);
+ freeList(nkeyList);
+ freeList(keyList);
+ freeList(fiList);
+ freeList(predList);
}
/* ----------------------------------------------------------------
- * ExecCloseIndices
+ * ExecCloseIndices
*
- * Close the index relations stored in resultRelationInfo
+ * Close the index relations stored in resultRelationInfo
* ----------------------------------------------------------------
*/
void
-ExecCloseIndices(RelationInfo *resultRelationInfo)
+ExecCloseIndices(RelationInfo * resultRelationInfo)
{
- int i;
- int numIndices;
- RelationPtr relationDescs;
-
- numIndices = resultRelationInfo->ri_NumIndices;
- relationDescs = resultRelationInfo->ri_IndexRelationDescs;
-
- for (i=0; i<numIndices; i++)
- if (relationDescs[i] != NULL)
- index_close(relationDescs[i]);
- /*
- * XXX should free indexInfo array here too.
- */
+ int i;
+ int numIndices;
+ RelationPtr relationDescs;
+
+ numIndices = resultRelationInfo->ri_NumIndices;
+ relationDescs = resultRelationInfo->ri_IndexRelationDescs;
+
+ for (i = 0; i < numIndices; i++)
+ if (relationDescs[i] != NULL)
+ index_close(relationDescs[i]);
+
+ /*
+ * XXX should free indexInfo array here too.
+ */
}
/* ----------------------------------------------------------------
- * ExecFormIndexTuple
+ * ExecFormIndexTuple
*
- * Most of this code is cannabilized from DefaultBuild().
- * As said in the comments for ExecOpenIndices, most of
- * this functionality should be rearranged into a proper
- * set of routines..
+ * Most of this code is cannabilized from DefaultBuild().
+ * As said in the comments for ExecOpenIndices, most of
+ * this functionality should be rearranged into a proper
+ * set of routines..
* ----------------------------------------------------------------
*/
#ifdef NOT_USED
IndexTuple
ExecFormIndexTuple(HeapTuple heapTuple,
- Relation heapRelation,
- Relation indexRelation,
- IndexInfo *indexInfo)
+ Relation heapRelation,
+ Relation indexRelation,
+ IndexInfo * indexInfo)
{
- IndexTuple indexTuple;
- TupleDesc heapDescriptor;
- TupleDesc indexDescriptor;
- Datum *datum;
- char *nulls;
-
- int numberOfAttributes;
- AttrNumber *keyAttributeNumbers;
- FuncIndexInfoPtr fInfoP;
-
- /* ----------------
- * get information from index info structure
- * ----------------
- */
- numberOfAttributes = indexInfo->ii_NumKeyAttributes;
- keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
- fInfoP = indexInfo->ii_FuncIndexInfo;
-
- /* ----------------
- * datum and null are arrays in which we collect the index attributes
- * when forming a new index tuple.
- * ----------------
- */
- CXT1_printf("ExecFormIndexTuple: context is %d\n", CurrentMemoryContext);
- datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
- nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
-
- /* ----------------
- * get the tuple descriptors from the relations so we know
- * how to form the index tuples..
- * ----------------
- */
- heapDescriptor = RelationGetTupleDescriptor(heapRelation);
- indexDescriptor = RelationGetTupleDescriptor(indexRelation);
-
- /* ----------------
- * FormIndexDatum fills in its datum and null parameters
- * with attribute information taken from the given heap tuple.
- * ----------------
- */
- FormIndexDatum(numberOfAttributes, /* num attributes */
- keyAttributeNumbers, /* array of att nums to extract */
- heapTuple, /* tuple from base relation */
- heapDescriptor, /* heap tuple's descriptor */
- InvalidBuffer, /* buffer associated with heap tuple */
- datum, /* return: array of attributes */
- nulls, /* return: array of char's */
- fInfoP); /* functional index information */
-
- indexTuple = index_formtuple(indexDescriptor,
- datum,
- nulls);
-
- /* ----------------
- * free temporary arrays
- *
- * XXX should store these in the IndexInfo instead of allocating
- * and freeing on every insertion, but efficency here is not
- * that important and FormIndexTuple is wasteful anyways..
- * -cim 9/27/89
- * ----------------
- */
- pfree(nulls);
- pfree(datum);
-
- return indexTuple;
+ IndexTuple indexTuple;
+ TupleDesc heapDescriptor;
+ TupleDesc indexDescriptor;
+ Datum *datum;
+ char *nulls;
+
+ int numberOfAttributes;
+ AttrNumber *keyAttributeNumbers;
+ FuncIndexInfoPtr fInfoP;
+
+ /* ----------------
+ * get information from index info structure
+ * ----------------
+ */
+ numberOfAttributes = indexInfo->ii_NumKeyAttributes;
+ keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
+ fInfoP = indexInfo->ii_FuncIndexInfo;
+
+ /* ----------------
+ * datum and null are arrays in which we collect the index attributes
+ * when forming a new index tuple.
+ * ----------------
+ */
+ CXT1_printf("ExecFormIndexTuple: context is %d\n", CurrentMemoryContext);
+ datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
+ nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
+
+ /* ----------------
+ * get the tuple descriptors from the relations so we know
+ * how to form the index tuples..
+ * ----------------
+ */
+ heapDescriptor = RelationGetTupleDescriptor(heapRelation);
+ indexDescriptor = RelationGetTupleDescriptor(indexRelation);
+
+ /* ----------------
+ * FormIndexDatum fills in its datum and null parameters
+ * with attribute information taken from the given heap tuple.
+ * ----------------
+ */
+ FormIndexDatum(numberOfAttributes, /* num attributes */
+ keyAttributeNumbers, /* array of att nums to extract */
+ heapTuple, /* tuple from base relation */
+ heapDescriptor, /* heap tuple's descriptor */
+ InvalidBuffer, /* buffer associated with heap
+ * tuple */
+ datum, /* return: array of attributes */
+ nulls, /* return: array of char's */
+ fInfoP); /* functional index information */
+
+ indexTuple = index_formtuple(indexDescriptor,
+ datum,
+ nulls);
+
+ /* ----------------
+ * free temporary arrays
+ *
+ * XXX should store these in the IndexInfo instead of allocating
+ * and freeing on every insertion, but efficency here is not
+ * that important and FormIndexTuple is wasteful anyways..
+ * -cim 9/27/89
+ * ----------------
+ */
+ pfree(nulls);
+ pfree(datum);
+
+ return indexTuple;
}
+
#endif
/* ----------------------------------------------------------------
- * ExecInsertIndexTuples
+ * ExecInsertIndexTuples
*
- * This routine takes care of inserting index tuples
- * into all the relations indexing the result relation
- * when a heap tuple is inserted into the result relation.
- * Much of this code should be moved into the genam
- * stuff as it only exists here because the genam stuff
- * doesn't provide the functionality needed by the
- * executor.. -cim 9/27/89
+ * This routine takes care of inserting index tuples
+ * into all the relations indexing the result relation
+ * when a heap tuple is inserted into the result relation.
+ * Much of this code should be moved into the genam
+ * stuff as it only exists here because the genam stuff
+ * doesn't provide the functionality needed by the
+ * executor.. -cim 9/27/89
* ----------------------------------------------------------------
*/
void
-ExecInsertIndexTuples(TupleTableSlot *slot,
- ItemPointer tupleid,
- EState *estate,
- bool is_update)
+ExecInsertIndexTuples(TupleTableSlot * slot,
+ ItemPointer tupleid,
+ EState * estate,
+ bool is_update)
{
- HeapTuple heapTuple;
- RelationInfo *resultRelationInfo;
- int i;
- int numIndices;
- RelationPtr relationDescs;
- Relation heapRelation;
- IndexInfo **indexInfoArray;
- IndexInfo *indexInfo;
- Node *predicate;
- bool satisfied;
- ExprContext *econtext;
- InsertIndexResult result;
- int numberOfAttributes;
- AttrNumber *keyAttributeNumbers;
- FuncIndexInfoPtr fInfoP;
- TupleDesc heapDescriptor;
- Datum *datum;
- char *nulls;
-
- heapTuple = slot->val;
-
- /* ----------------
- * get information from the result relation info structure.
- * ----------------
- */
- resultRelationInfo = estate->es_result_relation_info;
- numIndices = resultRelationInfo->ri_NumIndices;
- relationDescs = resultRelationInfo->ri_IndexRelationDescs;
- indexInfoArray = resultRelationInfo->ri_IndexRelationInfo;
- heapRelation = resultRelationInfo->ri_RelationDesc;
-
- /* ----------------
- * for each index, form and insert the index tuple
- * ----------------
- */
- econtext = NULL;
- for (i=0; i<numIndices; i++) {
- if (relationDescs[i] == NULL) continue;
-
- indexInfo = indexInfoArray[i];
- predicate = indexInfo->ii_Predicate;
- if (predicate != NULL) {
- if (econtext == NULL) {
- econtext = makeNode(ExprContext);
- }
- econtext->ecxt_scantuple = slot;
-
- /* Skip this index-update if the predicate isn't satisfied */
- satisfied = ExecQual((List*)predicate, econtext);
- if (satisfied == false)
- continue;
- }
+ HeapTuple heapTuple;
+ RelationInfo *resultRelationInfo;
+ int i;
+ int numIndices;
+ RelationPtr relationDescs;
+ Relation heapRelation;
+ IndexInfo **indexInfoArray;
+ IndexInfo *indexInfo;
+ Node *predicate;
+ bool satisfied;
+ ExprContext *econtext;
+ InsertIndexResult result;
+ int numberOfAttributes;
+ AttrNumber *keyAttributeNumbers;
+ FuncIndexInfoPtr fInfoP;
+ TupleDesc heapDescriptor;
+ Datum *datum;
+ char *nulls;
+
+ heapTuple = slot->val;
/* ----------------
- * get information from index info structure
+ * get information from the result relation info structure.
* ----------------
*/
- numberOfAttributes = indexInfo->ii_NumKeyAttributes;
- keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
- fInfoP = indexInfo->ii_FuncIndexInfo;
- datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
- nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
- heapDescriptor = (TupleDesc)RelationGetTupleDescriptor(heapRelation);
-
- FormIndexDatum(numberOfAttributes, /* num attributes */
- keyAttributeNumbers, /* array of att nums to extract */
- heapTuple, /* tuple from base relation */
- heapDescriptor, /* heap tuple's descriptor */
- InvalidBuffer, /* buffer associated with heap tuple */
- datum, /* return: array of attributes */
- nulls, /* return: array of char's */
- fInfoP); /* functional index information */
-
-
- result = index_insert(relationDescs[i], /* index relation */
- datum, /* array of heaptuple Datums */
- nulls, /* info on nulls */
- &(heapTuple->t_ctid), /* oid of heap tuple */
- heapRelation);
-
- /* ----------------
- * keep track of index inserts for debugging
- * ----------------
- */
- IncrIndexInserted();
-
+ resultRelationInfo = estate->es_result_relation_info;
+ numIndices = resultRelationInfo->ri_NumIndices;
+ relationDescs = resultRelationInfo->ri_IndexRelationDescs;
+ indexInfoArray = resultRelationInfo->ri_IndexRelationInfo;
+ heapRelation = resultRelationInfo->ri_RelationDesc;
+
/* ----------------
- * free index tuple after insertion
+ * for each index, form and insert the index tuple
* ----------------
*/
- if (result) pfree(result);
- }
- if (econtext != NULL) pfree(econtext);
+ econtext = NULL;
+ for (i = 0; i < numIndices; i++)
+ {
+ if (relationDescs[i] == NULL)
+ continue;
+
+ indexInfo = indexInfoArray[i];
+ predicate = indexInfo->ii_Predicate;
+ if (predicate != NULL)
+ {
+ if (econtext == NULL)
+ {
+ econtext = makeNode(ExprContext);
+ }
+ econtext->ecxt_scantuple = slot;
+
+ /* Skip this index-update if the predicate isn't satisfied */
+ satisfied = ExecQual((List *) predicate, econtext);
+ if (satisfied == false)
+ continue;
+ }
+
+ /* ----------------
+ * get information from index info structure
+ * ----------------
+ */
+ numberOfAttributes = indexInfo->ii_NumKeyAttributes;
+ keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers;
+ fInfoP = indexInfo->ii_FuncIndexInfo;
+ datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
+ nulls = (char *) palloc(numberOfAttributes * sizeof *nulls);
+ heapDescriptor = (TupleDesc) RelationGetTupleDescriptor(heapRelation);
+
+ FormIndexDatum(numberOfAttributes, /* num attributes */
+ keyAttributeNumbers, /* array of att nums to
+ * extract */
+ heapTuple, /* tuple from base relation */
+ heapDescriptor, /* heap tuple's descriptor */
+ InvalidBuffer, /* buffer associated with heap
+ * tuple */
+ datum, /* return: array of attributes */
+ nulls, /* return: array of char's */
+ fInfoP); /* functional index information */
+
+
+ result = index_insert(relationDescs[i], /* index relation */
+ datum, /* array of heaptuple Datums */
+ nulls, /* info on nulls */
+ &(heapTuple->t_ctid), /* oid of heap tuple */
+ heapRelation);
+
+ /* ----------------
+ * keep track of index inserts for debugging
+ * ----------------
+ */
+ IncrIndexInserted();
+
+ /* ----------------
+ * free index tuple after insertion
+ * ----------------
+ */
+ if (result)
+ pfree(result);
+ }
+ if (econtext != NULL)
+ pfree(econtext);
}
/* ----------------------------------------------------------------
* setVarAttrLenForCreateTable -
- * called when we do a SELECT * INTO TABLE tab
- * needed for attributes that have a defined length, like bpchar and
- * varchar
+ * called when we do a SELECT * INTO TABLE tab
+ * needed for attributes that have a defined length, like bpchar and
+ * varchar
* ----------------------------------------------------------------
*/
void
-setVarAttrLenForCreateTable(TupleDesc tupType, List *targetList,
- List *rangeTable)
+setVarAttrLenForCreateTable(TupleDesc tupType, List * targetList,
+ List * rangeTable)
{
- List *tl;
- TargetEntry *tle;
- Node *expr;
- int varno;
-
- tl = targetList;
-
- for (varno = 0; varno < tupType->natts; varno++) {
- tle = lfirst(tl);
-
- if (tupType->attrs[varno]->atttypid == BPCHAROID ||
- tupType->attrs[varno]->atttypid == VARCHAROID) {
- expr = tle->expr;
- if (expr && IsA(expr,Var)) {
- Var *var;
- RangeTblEntry *rtentry;
- Relation rd;
-
- var = (Var *)expr;
- rtentry = rt_fetch(var->varnoold, rangeTable);
- rd = heap_open(rtentry->relid);
- /* set length to that defined in relation */
- tupType->attrs[varno]->attlen =
- (*rd->rd_att->attrs[var->varoattno-1]).attlen;
- heap_close(rd);
- }
- else
- elog(WARN, "setVarAttrLenForCreateTable: can't get length for variable-length field");
- }
- tl = lnext(tl);
- }
+ List *tl;
+ TargetEntry *tle;
+ Node *expr;
+ int varno;
+
+ tl = targetList;
+
+ for (varno = 0; varno < tupType->natts; varno++)
+ {
+ tle = lfirst(tl);
+
+ if (tupType->attrs[varno]->atttypid == BPCHAROID ||
+ tupType->attrs[varno]->atttypid == VARCHAROID)
+ {
+ expr = tle->expr;
+ if (expr && IsA(expr, Var))
+ {
+ Var *var;
+ RangeTblEntry *rtentry;
+ Relation rd;
+
+ var = (Var *) expr;
+ rtentry = rt_fetch(var->varnoold, rangeTable);
+ rd = heap_open(rtentry->relid);
+ /* set length to that defined in relation */
+ tupType->attrs[varno]->attlen =
+ (*rd->rd_att->attrs[var->varoattno - 1]).attlen;
+ heap_close(rd);
+ }
+ else
+ elog(WARN, "setVarAttrLenForCreateTable: can't get length for variable-length field");
+ }
+ tl = lnext(tl);
+ }
}
-#ifdef NOT_USED /* look at execMain.c */
+#ifdef NOT_USED /* look at execMain.c */
/* ----------------------------------------------------------------
* resetVarAttrLenForCreateTable -
- * called when we do a SELECT * INTO TABLE tab
- * needed for attributes that have a defined length, like bpchar and
- * varchar
- * resets length to -1 for those types
+ * called when we do a SELECT * INTO TABLE tab
+ * needed for attributes that have a defined length, like bpchar and
+ * varchar
+ * resets length to -1 for those types
* ----------------------------------------------------------------
*/
void
resetVarAttrLenForCreateTable(TupleDesc tupType)
{
- int varno;
-
- for (varno = 0; varno < tupType->natts; varno++) {
- if (tupType->attrs[varno]->atttypid == BPCHAROID ||
- tupType->attrs[varno]->atttypid == VARCHAROID)
- /* set length to original -1 */
- tupType->attrs[varno]->attlen = -1;
- }
+ int varno;
+
+ for (varno = 0; varno < tupType->natts; varno++)
+ {
+ if (tupType->attrs[varno]->atttypid == BPCHAROID ||
+ tupType->attrs[varno]->atttypid == VARCHAROID)
+ /* set length to original -1 */
+ tupType->attrs[varno]->attlen = -1;
+ }
}
+
#endif
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 79f8bede085..96b9b19dcb6 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* functions.c--
- * Routines to handle functions called from the executor
- * Putting this stuff in fmgr makes the postmaster a mess....
+ * Routines to handle functions called from the executor
+ * Putting this stuff in fmgr makes the postmaster a mess....
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.7 1997/08/29 09:02:50 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.8 1997/09/07 04:41:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,401 +41,438 @@
#undef new
-typedef enum {F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE} ExecStatus;
+typedef enum
+{
+ F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
+} ExecStatus;
-typedef struct local_es {
- QueryDesc *qd;
- EState *estate;
- struct local_es *next;
- ExecStatus status;
-} execution_state;
+typedef struct local_es
+{
+ QueryDesc *qd;
+ EState *estate;
+ struct local_es *next;
+ ExecStatus status;
+} execution_state;
#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL)
/* non-export function prototypes */
-static TupleDesc postquel_start(execution_state *es);
-static execution_state *init_execution_state(FunctionCachePtr fcache,
- char *args[]);
-static TupleTableSlot *postquel_getnext(execution_state *es);
-static void postquel_end(execution_state *es);
-static void postquel_sub_params(execution_state *es, int nargs,
- char *args[], bool *nullV);
-static Datum postquel_execute(execution_state *es, FunctionCachePtr fcache,
- List *fTlist, char **args, bool *isNull);
-
+static TupleDesc postquel_start(execution_state * es);
+static execution_state *
+init_execution_state(FunctionCachePtr fcache,
+ char *args[]);
+static TupleTableSlot *postquel_getnext(execution_state * es);
+static void postquel_end(execution_state * es);
+static void
+postquel_sub_params(execution_state * es, int nargs,
+ char *args[], bool * nullV);
+static Datum
+postquel_execute(execution_state * es, FunctionCachePtr fcache,
+ List * fTlist, char **args, bool * isNull);
+
Datum
ProjectAttribute(TupleDesc TD,
- TargetEntry *tlist,
- HeapTuple tup,
- bool *isnullP)
+ TargetEntry * tlist,
+ HeapTuple tup,
+ bool * isnullP)
{
- Datum val,valueP;
- Var *attrVar = (Var *)tlist->expr;
- AttrNumber attrno = attrVar->varattno;
-
-
- val = PointerGetDatum(heap_getattr(tup,
- InvalidBuffer,
- attrno,
- TD,
- isnullP));
- if (*isnullP)
- return (Datum) NULL;
-
- valueP = datumCopy(val,
- TD->attrs[attrno-1]->atttypid,
- TD->attrs[attrno-1]->attbyval,
- (Size) TD->attrs[attrno-1]->attlen);
- return valueP;
+ Datum val,
+ valueP;
+ Var *attrVar = (Var *) tlist->expr;
+ AttrNumber attrno = attrVar->varattno;
+
+
+ val = PointerGetDatum(heap_getattr(tup,
+ InvalidBuffer,
+ attrno,
+ TD,
+ isnullP));
+ if (*isnullP)
+ return (Datum) NULL;
+
+ valueP = datumCopy(val,
+ TD->attrs[attrno - 1]->atttypid,
+ TD->attrs[attrno - 1]->attbyval,
+ (Size) TD->attrs[attrno - 1]->attlen);
+ return valueP;
}
static execution_state *
init_execution_state(FunctionCachePtr fcache,
- char *args[])
+ char *args[])
{
- execution_state *newes;
- execution_state *nextes;
- execution_state *preves;
- QueryTreeList *queryTree_list;
- int i;
- List *planTree_list;
- int nargs;
-
- nargs = fcache->nargs;
-
- newes = (execution_state *) palloc(sizeof(execution_state));
- nextes = newes;
- preves = (execution_state *)NULL;
-
-
- planTree_list = (List *)
- pg_plan(fcache->src, fcache->argOidVect, nargs, &queryTree_list, None);
-
- for (i=0; i < queryTree_list->len; i++) {
- EState *estate;
- Query *queryTree = (Query*) (queryTree_list->qtrees[i]);
- Plan *planTree = lfirst(planTree_list);
-
- if (!nextes)
- nextes = (execution_state *) palloc(sizeof(execution_state));
- if (preves)
- preves->next = nextes;
-
- nextes->next = NULL;
- nextes->status = F_EXEC_START;
- nextes->qd = CreateQueryDesc(queryTree,
- planTree,
- None);
- estate = CreateExecutorState();
-
- if (nargs > 0) {
- int i;
- ParamListInfo paramLI;
-
- paramLI =
- (ParamListInfo)palloc((nargs+1)*sizeof(ParamListInfoData));
-
- memset(paramLI, 0, nargs*sizeof(ParamListInfoData));
-
- estate->es_param_list_info = paramLI;
-
- for (i=0; i<nargs; paramLI++, i++) {
- paramLI->kind = PARAM_NUM;
- paramLI->id = i+1;
- paramLI->isnull = false;
- paramLI->value = (Datum) NULL;
- }
- paramLI->kind = PARAM_INVALID;
+ execution_state *newes;
+ execution_state *nextes;
+ execution_state *preves;
+ QueryTreeList *queryTree_list;
+ int i;
+ List *planTree_list;
+ int nargs;
+
+ nargs = fcache->nargs;
+
+ newes = (execution_state *) palloc(sizeof(execution_state));
+ nextes = newes;
+ preves = (execution_state *) NULL;
+
+
+ planTree_list = (List *)
+ pg_plan(fcache->src, fcache->argOidVect, nargs, &queryTree_list, None);
+
+ for (i = 0; i < queryTree_list->len; i++)
+ {
+ EState *estate;
+ Query *queryTree = (Query *) (queryTree_list->qtrees[i]);
+ Plan *planTree = lfirst(planTree_list);
+
+ if (!nextes)
+ nextes = (execution_state *) palloc(sizeof(execution_state));
+ if (preves)
+ preves->next = nextes;
+
+ nextes->next = NULL;
+ nextes->status = F_EXEC_START;
+ nextes->qd = CreateQueryDesc(queryTree,
+ planTree,
+ None);
+ estate = CreateExecutorState();
+
+ if (nargs > 0)
+ {
+ int i;
+ ParamListInfo paramLI;
+
+ paramLI =
+ (ParamListInfo) palloc((nargs + 1) * sizeof(ParamListInfoData));
+
+ memset(paramLI, 0, nargs * sizeof(ParamListInfoData));
+
+ estate->es_param_list_info = paramLI;
+
+ for (i = 0; i < nargs; paramLI++, i++)
+ {
+ paramLI->kind = PARAM_NUM;
+ paramLI->id = i + 1;
+ paramLI->isnull = false;
+ paramLI->value = (Datum) NULL;
+ }
+ paramLI->kind = PARAM_INVALID;
+ }
+ else
+ estate->es_param_list_info = (ParamListInfo) NULL;
+ nextes->estate = estate;
+ preves = nextes;
+ nextes = (execution_state *) NULL;
+
+ planTree_list = lnext(planTree_list);
}
- else
- estate->es_param_list_info = (ParamListInfo)NULL;
- nextes->estate = estate;
- preves = nextes;
- nextes = (execution_state *)NULL;
-
- planTree_list = lnext(planTree_list);
- }
-
- return newes;
+
+ return newes;
}
-static TupleDesc
-postquel_start(execution_state *es)
+static TupleDesc
+postquel_start(execution_state * es)
{
#ifdef FUNC_UTIL_PATCH
- /*
- * Do nothing for utility commands. (create, destroy...) DZ - 30-8-1996
- */
- if (es->qd->operation == CMD_UTILITY) {
- return (TupleDesc) NULL;
- }
+
+ /*
+ * Do nothing for utility commands. (create, destroy...) DZ -
+ * 30-8-1996
+ */
+ if (es->qd->operation == CMD_UTILITY)
+ {
+ return (TupleDesc) NULL;
+ }
#endif
- return ExecutorStart(es->qd, es->estate);
+ return ExecutorStart(es->qd, es->estate);
}
static TupleTableSlot *
-postquel_getnext(execution_state *es)
+postquel_getnext(execution_state * es)
{
- int feature;
-
+ int feature;
+
#ifdef FUNC_UTIL_PATCH
- if (es->qd->operation == CMD_UTILITY) {
- /*
- * Process an utility command. (create, destroy...) DZ - 30-8-1996
- */
- ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
- if (!LAST_POSTQUEL_COMMAND(es)) CommandCounterIncrement();
- return (TupleTableSlot*) NULL;
- }
+ if (es->qd->operation == CMD_UTILITY)
+ {
+
+ /*
+ * Process an utility command. (create, destroy...) DZ -
+ * 30-8-1996
+ */
+ ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest);
+ if (!LAST_POSTQUEL_COMMAND(es))
+ CommandCounterIncrement();
+ return (TupleTableSlot *) NULL;
+ }
#endif
- feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
-
- return ExecutorRun(es->qd, es->estate, feature, 0);
+ feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
+
+ return ExecutorRun(es->qd, es->estate, feature, 0);
}
static void
-postquel_end(execution_state *es)
+postquel_end(execution_state * es)
{
#ifdef FUNC_UTIL_PATCH
- /*
- * Do nothing for utility commands. (create, destroy...) DZ - 30-8-1996
- */
- if (es->qd->operation == CMD_UTILITY) {
- return;
- }
+
+ /*
+ * Do nothing for utility commands. (create, destroy...) DZ -
+ * 30-8-1996
+ */
+ if (es->qd->operation == CMD_UTILITY)
+ {
+ return;
+ }
#endif
- ExecutorEnd(es->qd, es->estate);
+ ExecutorEnd(es->qd, es->estate);
}
static void
-postquel_sub_params(execution_state *es,
- int nargs,
- char *args[],
- bool *nullV)
+postquel_sub_params(execution_state * es,
+ int nargs,
+ char *args[],
+ bool * nullV)
{
- ParamListInfo paramLI;
- EState *estate;
-
- estate = es->estate;
- paramLI = estate->es_param_list_info;
-
- while (paramLI->kind != PARAM_INVALID) {
- if (paramLI->kind == PARAM_NUM) {
- Assert(paramLI->id <= nargs);
- paramLI->value = (Datum)args[(paramLI->id - 1)];
- paramLI->isnull = nullV[(paramLI->id - 1)];
+ ParamListInfo paramLI;
+ EState *estate;
+
+ estate = es->estate;
+ paramLI = estate->es_param_list_info;
+
+ while (paramLI->kind != PARAM_INVALID)
+ {
+ if (paramLI->kind == PARAM_NUM)
+ {
+ Assert(paramLI->id <= nargs);
+ paramLI->value = (Datum) args[(paramLI->id - 1)];
+ paramLI->isnull = nullV[(paramLI->id - 1)];
+ }
+ paramLI++;
}
- paramLI++;
- }
}
static TupleTableSlot *
copy_function_result(FunctionCachePtr fcache,
- TupleTableSlot *resultSlot)
+ TupleTableSlot * resultSlot)
{
- TupleTableSlot *funcSlot;
- TupleDesc resultTd;
- HeapTuple newTuple;
- HeapTuple oldTuple;
-
- Assert(! TupIsNull(resultSlot));
- oldTuple = resultSlot->val;
-
- funcSlot = (TupleTableSlot*)fcache->funcSlot;
-
- if (funcSlot == (TupleTableSlot*)NULL)
- return resultSlot;
-
- resultTd = resultSlot->ttc_tupleDescriptor;
- /*
- * When the funcSlot is NULL we have to initialize the funcSlot's
- * tuple descriptor.
- */
- if (TupIsNull(funcSlot)) {
- int i= 0;
- TupleDesc funcTd = funcSlot->ttc_tupleDescriptor;
-
- while (i < oldTuple->t_natts) {
- funcTd->attrs[i] =
- (AttributeTupleForm)palloc(ATTRIBUTE_TUPLE_SIZE);
- memmove(funcTd->attrs[i],
- resultTd->attrs[i],
- ATTRIBUTE_TUPLE_SIZE);
- i++;
+ TupleTableSlot *funcSlot;
+ TupleDesc resultTd;
+ HeapTuple newTuple;
+ HeapTuple oldTuple;
+
+ Assert(!TupIsNull(resultSlot));
+ oldTuple = resultSlot->val;
+
+ funcSlot = (TupleTableSlot *) fcache->funcSlot;
+
+ if (funcSlot == (TupleTableSlot *) NULL)
+ return resultSlot;
+
+ resultTd = resultSlot->ttc_tupleDescriptor;
+
+ /*
+ * When the funcSlot is NULL we have to initialize the funcSlot's
+ * tuple descriptor.
+ */
+ if (TupIsNull(funcSlot))
+ {
+ int i = 0;
+ TupleDesc funcTd = funcSlot->ttc_tupleDescriptor;
+
+ while (i < oldTuple->t_natts)
+ {
+ funcTd->attrs[i] =
+ (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+ memmove(funcTd->attrs[i],
+ resultTd->attrs[i],
+ ATTRIBUTE_TUPLE_SIZE);
+ i++;
+ }
}
- }
-
- newTuple = heap_copytuple(oldTuple);
-
- return ExecStoreTuple(newTuple,funcSlot,InvalidBuffer,true);
+
+ newTuple = heap_copytuple(oldTuple);
+
+ return ExecStoreTuple(newTuple, funcSlot, InvalidBuffer, true);
}
-static Datum
-postquel_execute(execution_state *es,
- FunctionCachePtr fcache,
- List *fTlist,
- char **args,
- bool *isNull)
+static Datum
+postquel_execute(execution_state * es,
+ FunctionCachePtr fcache,
+ List * fTlist,
+ char **args,
+ bool * isNull)
{
- TupleTableSlot *slot;
- Datum value;
+ TupleTableSlot *slot;
+ Datum value;
#ifdef INDEXSCAN_PATCH
- /*
- * It's more right place to do it (before postquel_start->ExecutorStart).
- * Now ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok.
- * (But note: I HOPE we can do it here). - vadim 01/22/97
- */
- if (fcache->nargs > 0)
- postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
+
+ /*
+ * It's more right place to do it (before
+ * postquel_start->ExecutorStart). Now
+ * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But
+ * note: I HOPE we can do it here). - vadim 01/22/97
+ */
+ if (fcache->nargs > 0)
+ postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
#endif
-
- if (es->status == F_EXEC_START)
+
+ if (es->status == F_EXEC_START)
{
- postquel_start(es);
- es->status = F_EXEC_RUN;
+ postquel_start(es);
+ es->status = F_EXEC_RUN;
}
#ifndef INDEXSCAN_PATCH
- if (fcache->nargs > 0)
- postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
+ if (fcache->nargs > 0)
+ postquel_sub_params(es, fcache->nargs, args, fcache->nullVect);
#endif
-
- slot = postquel_getnext(es);
-
- if (TupIsNull(slot)) {
- postquel_end(es);
- es->status = F_EXEC_DONE;
- *isNull = true;
- /*
- * If this isn't the last command for the function
- * we have to increment the command
- * counter so that subsequent commands can see changes made
- * by previous ones.
- */
- if (!LAST_POSTQUEL_COMMAND(es)) CommandCounterIncrement();
- return (Datum)NULL;
- }
-
- if (LAST_POSTQUEL_COMMAND(es)) {
- TupleTableSlot *resSlot;
-
- /*
- * Copy the result. copy_function_result is smart enough
- * to do nothing when no action is called for. This helps
- * reduce the logic and code redundancy here.
- */
- resSlot = copy_function_result(fcache, slot);
- if (fTlist != NIL) {
- HeapTuple tup;
- TargetEntry *tle = lfirst(fTlist);
-
- tup = resSlot->val;
- value = ProjectAttribute(resSlot->ttc_tupleDescriptor,
- tle,
- tup,
- isNull);
- }else {
- value = (Datum)resSlot;
- *isNull = false;
+
+ slot = postquel_getnext(es);
+
+ if (TupIsNull(slot))
+ {
+ postquel_end(es);
+ es->status = F_EXEC_DONE;
+ *isNull = true;
+
+ /*
+ * If this isn't the last command for the function we have to
+ * increment the command counter so that subsequent commands can
+ * see changes made by previous ones.
+ */
+ if (!LAST_POSTQUEL_COMMAND(es))
+ CommandCounterIncrement();
+ return (Datum) NULL;
}
-
+
+ if (LAST_POSTQUEL_COMMAND(es))
+ {
+ TupleTableSlot *resSlot;
+
+ /*
+ * Copy the result. copy_function_result is smart enough to do
+ * nothing when no action is called for. This helps reduce the
+ * logic and code redundancy here.
+ */
+ resSlot = copy_function_result(fcache, slot);
+ if (fTlist != NIL)
+ {
+ HeapTuple tup;
+ TargetEntry *tle = lfirst(fTlist);
+
+ tup = resSlot->val;
+ value = ProjectAttribute(resSlot->ttc_tupleDescriptor,
+ tle,
+ tup,
+ isNull);
+ }
+ else
+ {
+ value = (Datum) resSlot;
+ *isNull = false;
+ }
+
+ /*
+ * If this is a single valued function we have to end the function
+ * execution now.
+ */
+ if (fcache->oneResult)
+ {
+ postquel_end(es);
+ es->status = F_EXEC_DONE;
+ }
+
+ return value;
+ }
+
/*
- * If this is a single valued function we have to end the
- * function execution now.
+ * If this isn't the last command for the function, we don't return
+ * any results, but we have to increment the command counter so that
+ * subsequent commands can see changes made by previous ones.
*/
- if (fcache->oneResult) {
- postquel_end(es);
- es->status = F_EXEC_DONE;
- }
-
- return value;
- }
- /*
- * If this isn't the last command for the function, we don't
- * return any results, but we have to increment the command
- * counter so that subsequent commands can see changes made
- * by previous ones.
- */
- CommandCounterIncrement();
- return (Datum)NULL;
+ CommandCounterIncrement();
+ return (Datum) NULL;
}
Datum
-postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone)
+postquel_function(Func * funcNode, char **args, bool * isNull, bool * isDone)
{
- execution_state *es;
- Datum result = 0;
- FunctionCachePtr fcache = funcNode->func_fcache;
- CommandId savedId;
-
- /*
- * Before we start do anything we must save CurrentScanCommandId
- * to restore it before return to upper Executor. Also, we have to
- * set CurrentScanCommandId equal to CurrentCommandId.
- * - vadim 08/29/97
- */
- savedId = GetScanCommandId ();
- SetScanCommandId (GetCurrentCommandId ());
-
- es = (execution_state *) fcache->func_state;
- if (es == NULL)
+ execution_state *es;
+ Datum result = 0;
+ FunctionCachePtr fcache = funcNode->func_fcache;
+ CommandId savedId;
+
+ /*
+ * Before we start do anything we must save CurrentScanCommandId to
+ * restore it before return to upper Executor. Also, we have to set
+ * CurrentScanCommandId equal to CurrentCommandId. - vadim 08/29/97
+ */
+ savedId = GetScanCommandId();
+ SetScanCommandId(GetCurrentCommandId());
+
+ es = (execution_state *) fcache->func_state;
+ if (es == NULL)
{
- es = init_execution_state(fcache, args);
- fcache->func_state = (char *) es;
+ es = init_execution_state(fcache, args);
+ fcache->func_state = (char *) es;
}
-
- while (es && es->status == F_EXEC_DONE)
- es = es->next;
-
- Assert(es);
- /*
- * Execute each command in the function one after another until we're
- * executing the final command and get a result or we run out of
- * commands.
- */
- while (es != (execution_state *)NULL)
+
+ while (es && es->status == F_EXEC_DONE)
+ es = es->next;
+
+ Assert(es);
+
+ /*
+ * Execute each command in the function one after another until we're
+ * executing the final command and get a result or we run out of
+ * commands.
+ */
+ while (es != (execution_state *) NULL)
{
- result = postquel_execute(es,
- fcache,
- funcNode->func_tlist,
- args,
- isNull);
- if (es->status != F_EXEC_DONE)
- break;
- es = es->next;
+ result = postquel_execute(es,
+ fcache,
+ funcNode->func_tlist,
+ args,
+ isNull);
+ if (es->status != F_EXEC_DONE)
+ break;
+ es = es->next;
}
-
- /*
- * If we've gone through every command in this function, we are done.
- */
- if (es == (execution_state *)NULL)
- {
+
/*
- * Reset the execution states to start over again
+ * If we've gone through every command in this function, we are done.
*/
- es = (execution_state *)fcache->func_state;
- while (es)
+ if (es == (execution_state *) NULL)
{
- es->status = F_EXEC_START;
- es = es->next;
+
+ /*
+ * Reset the execution states to start over again
+ */
+ es = (execution_state *) fcache->func_state;
+ while (es)
+ {
+ es->status = F_EXEC_START;
+ es = es->next;
+ }
+
+ /*
+ * Let caller know we're finished.
+ */
+ *isDone = true;
+ SetScanCommandId(savedId);
+ return (fcache->oneResult) ? result : (Datum) NULL;
}
+
/*
- * Let caller know we're finished.
+ * If we got a result from a command within the function it has to be
+ * the final command. All others shouldn't be returing anything.
*/
- *isDone = true;
- SetScanCommandId (savedId);
- return (fcache->oneResult) ? result : (Datum)NULL;
- }
- /*
- * If we got a result from a command within the function it has
- * to be the final command. All others shouldn't be returing
- * anything.
- */
- Assert ( LAST_POSTQUEL_COMMAND(es) );
- *isDone = false;
-
- SetScanCommandId (savedId);
- return result;
+ Assert(LAST_POSTQUEL_COMMAND(es));
+ *isDone = false;
+
+ SetScanCommandId(savedId);
+ return result;
}
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index c6e5b269cde..ee03f6854d9 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* nodeAgg.c--
- * Routines to handle aggregate nodes.
+ * Routines to handle aggregate nodes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* NOTE
- * The implementation of Agg node has been reworked to handle legal
- * SQL aggregates. (Do not expect POSTQUEL semantics.) -- ay 2/95
+ * The implementation of Agg node has been reworked to handle legal
+ * SQL aggregates. (Do not expect POSTQUEL semantics.) -- ay 2/95
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/executor/nodeAgg.c,v 1.13 1995/08/01 20:19:07 jolly Exp
+ * /usr/local/devel/pglite/cvs/src/backend/executor/nodeAgg.c,v 1.13 1995/08/01 20:19:07 jolly Exp
*
*-------------------------------------------------------------------------
*/
@@ -32,570 +32,625 @@
/*
* AggFuncInfo -
- * keeps the transition functions information around
+ * keeps the transition functions information around
*/
-typedef struct AggFuncInfo {
- Oid xfn1_oid;
- Oid xfn2_oid;
- Oid finalfn_oid;
- func_ptr xfn1;
- func_ptr xfn2;
- func_ptr finalfn;
- int xfn1_nargs;
- int xfn2_nargs;
- int finalfn_nargs;
-} AggFuncInfo;
+typedef struct AggFuncInfo
+{
+ Oid xfn1_oid;
+ Oid xfn2_oid;
+ Oid finalfn_oid;
+ func_ptr xfn1;
+ func_ptr xfn2;
+ func_ptr finalfn;
+ int xfn1_nargs;
+ int xfn2_nargs;
+ int finalfn_nargs;
+} AggFuncInfo;
-static Datum aggGetAttr(TupleTableSlot *tuple, Aggreg *agg, bool *isNull);
+static Datum aggGetAttr(TupleTableSlot * tuple, Aggreg * agg, bool * isNull);
/* ---------------------------------------
*
* ExecAgg -
*
- * ExecAgg receives tuples from its outer subplan and aggregates over
- * the appropriate attribute for each (unique) aggregate in the target
- * list. (The number of tuples to aggregate over depends on whether a
- * GROUP BY clause is present. It might be the number of tuples in a
- * group or all the tuples that satisfy the qualifications.) The value of
- * each aggregate is stored in the expression context for ExecProject to
- * evaluate the result tuple.
- *
- * ExecAgg evaluates each aggregate in the following steps: (initcond1,
- * initcond2 are the initial values and sfunc1, sfunc2, and finalfunc are
- * the transition functions.)
+ * ExecAgg receives tuples from its outer subplan and aggregates over
+ * the appropriate attribute for each (unique) aggregate in the target
+ * list. (The number of tuples to aggregate over depends on whether a
+ * GROUP BY clause is present. It might be the number of tuples in a
+ * group or all the tuples that satisfy the qualifications.) The value of
+ * each aggregate is stored in the expression context for ExecProject to
+ * evaluate the result tuple.
+ *
+ * ExecAgg evaluates each aggregate in the following steps: (initcond1,
+ * initcond2 are the initial values and sfunc1, sfunc2, and finalfunc are
+ * the transition functions.)
*
- * value1[i] = initcond1
- * value2[i] = initcond2
- * forall tuples do
- * value1[i] = sfunc1(aggregate_attribute, value1[i])
- * value2[i] = sfunc2(value2[i])
- * value1[i] = finalfunc(value1[i], value2[i])
+ * value1[i] = initcond1
+ * value2[i] = initcond2
+ * forall tuples do
+ * value1[i] = sfunc1(aggregate_attribute, value1[i])
+ * value2[i] = sfunc2(value2[i])
+ * value1[i] = finalfunc(value1[i], value2[i])
*
- * If the outer subplan is a Group node, ExecAgg returns as many tuples
- * as there are groups.
+ * If the outer subplan is a Group node, ExecAgg returns as many tuples
+ * as there are groups.
*
- * XXX handling of NULL doesn't work
+ * XXX handling of NULL doesn't work
*
- * OLD COMMENTS
+ * OLD COMMENTS
*
- * XXX Aggregates should probably have another option: what to do
- * with transfn2 if we hit a null value. "count" (transfn1 = null,
- * transfn2 = increment) will want to have transfn2 called; "avg"
- * (transfn1 = add, transfn2 = increment) will not. -pma 1/3/93
+ * XXX Aggregates should probably have another option: what to do
+ * with transfn2 if we hit a null value. "count" (transfn1 = null,
+ * transfn2 = increment) will want to have transfn2 called; "avg"
+ * (transfn1 = add, transfn2 = increment) will not. -pma 1/3/93
*
* ------------------------------------------
*/
TupleTableSlot *
-ExecAgg(Agg *node)
+ExecAgg(Agg * node)
{
- AggState *aggstate;
- EState *estate;
- Aggreg **aggregates;
- Plan *outerPlan;
- int i, nagg;
- Datum *value1, *value2;
- int *noInitValue;
- AggFuncInfo *aggFuncInfo;
- long nTuplesAgged = 0;
- ExprContext *econtext;
- ProjectionInfo *projInfo;
- TupleTableSlot *resultSlot;
- HeapTuple oneTuple;
- char* nulls;
- bool isDone;
- bool isNull = FALSE, isNull1 = FALSE, isNull2 = FALSE;
-
- /* ---------------------
- * get state info from node
- * ---------------------
- */
- aggstate = node->aggstate;
- if (aggstate->agg_done)
- return NULL;
-
- estate = node->plan.state;
- econtext = aggstate->csstate.cstate.cs_ExprContext;
- aggregates = node->aggs;
- nagg = node->numAgg;
-
- value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values;
- nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls;
-
- value2 = (Datum *)palloc(sizeof(Datum) * nagg);
- memset(value2, 0, sizeof(Datum) * nagg);
-
- aggFuncInfo = (AggFuncInfo *)palloc(sizeof(AggFuncInfo) * nagg);
- memset(aggFuncInfo, 0, sizeof(AggFuncInfo) * nagg);
-
- noInitValue = (int *)palloc(sizeof(int) * nagg);
- memset(noInitValue, 0, sizeof(noInitValue) * nagg);
-
- outerPlan = outerPlan(node);
- oneTuple = NULL;
-
- projInfo = aggstate->csstate.cstate.cs_ProjInfo;
-
- for(i = 0; i < nagg; i++) {
- Aggreg *agg;
- char *aggname;
- HeapTuple aggTuple;
- Form_pg_aggregate aggp;
- Oid xfn1_oid, xfn2_oid, finalfn_oid;
- func_ptr xfn1_ptr, xfn2_ptr, finalfn_ptr;
- int xfn1_nargs, xfn2_nargs, finalfn_nargs;
-
- agg = aggregates[i];
+ AggState *aggstate;
+ EState *estate;
+ Aggreg **aggregates;
+ Plan *outerPlan;
+ int i,
+ nagg;
+ Datum *value1,
+ *value2;
+ int *noInitValue;
+ AggFuncInfo *aggFuncInfo;
+ long nTuplesAgged = 0;
+ ExprContext *econtext;
+ ProjectionInfo *projInfo;
+ TupleTableSlot *resultSlot;
+ HeapTuple oneTuple;
+ char *nulls;
+ bool isDone;
+ bool isNull = FALSE,
+ isNull1 = FALSE,
+ isNull2 = FALSE;
/* ---------------------
- * find transfer functions of all the aggregates and initialize
- * their initial values
+ * get state info from node
* ---------------------
*/
- aggname = agg->aggname;
- aggTuple = SearchSysCacheTuple(AGGNAME,
- PointerGetDatum(aggname),
- ObjectIdGetDatum(agg->basetype),
- 0,0);
- if (!HeapTupleIsValid(aggTuple))
- elog(WARN, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)",
- aggname,
- tname(get_id_type(agg->basetype)));
- aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple);
-
- xfn1_oid = aggp->aggtransfn1;
- xfn2_oid = aggp->aggtransfn2;
- finalfn_oid = aggp->aggfinalfn;
-
- if (OidIsValid(finalfn_oid)) {
- fmgr_info(finalfn_oid, &finalfn_ptr, &finalfn_nargs);
- aggFuncInfo[i].finalfn_oid = finalfn_oid;
- aggFuncInfo[i].finalfn = finalfn_ptr;
- aggFuncInfo[i].finalfn_nargs = finalfn_nargs;
- }
+ aggstate = node->aggstate;
+ if (aggstate->agg_done)
+ return NULL;
+
+ estate = node->plan.state;
+ econtext = aggstate->csstate.cstate.cs_ExprContext;
+ aggregates = node->aggs;
+ nagg = node->numAgg;
+
+ value1 = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_values;
+ nulls = node->aggstate->csstate.cstate.cs_ExprContext->ecxt_nulls;
+
+ value2 = (Datum *) palloc(sizeof(Datum) * nagg);
+ memset(value2, 0, sizeof(Datum) * nagg);
+
+ aggFuncInfo = (AggFuncInfo *) palloc(sizeof(AggFuncInfo) * nagg);
+ memset(aggFuncInfo, 0, sizeof(AggFuncInfo) * nagg);
+
+ noInitValue = (int *) palloc(sizeof(int) * nagg);
+ memset(noInitValue, 0, sizeof(noInitValue) * nagg);
+
+ outerPlan = outerPlan(node);
+ oneTuple = NULL;
+
+ projInfo = aggstate->csstate.cstate.cs_ProjInfo;
+
+ for (i = 0; i < nagg; i++)
+ {
+ Aggreg *agg;
+ char *aggname;
+ HeapTuple aggTuple;
+ Form_pg_aggregate aggp;
+ Oid xfn1_oid,
+ xfn2_oid,
+ finalfn_oid;
+ func_ptr xfn1_ptr,
+ xfn2_ptr,
+ finalfn_ptr;
+ int xfn1_nargs,
+ xfn2_nargs,
+ finalfn_nargs;
+
+ agg = aggregates[i];
+
+ /* ---------------------
+ * find transfer functions of all the aggregates and initialize
+ * their initial values
+ * ---------------------
+ */
+ aggname = agg->aggname;
+ aggTuple = SearchSysCacheTuple(AGGNAME,
+ PointerGetDatum(aggname),
+ ObjectIdGetDatum(agg->basetype),
+ 0, 0);
+ if (!HeapTupleIsValid(aggTuple))
+ elog(WARN, "ExecAgg: cache lookup failed for aggregate \"%s\"(%s)",
+ aggname,
+ tname(get_id_type(agg->basetype)));
+ aggp = (Form_pg_aggregate) GETSTRUCT(aggTuple);
+
+ xfn1_oid = aggp->aggtransfn1;
+ xfn2_oid = aggp->aggtransfn2;
+ finalfn_oid = aggp->aggfinalfn;
+
+ if (OidIsValid(finalfn_oid))
+ {
+ fmgr_info(finalfn_oid, &finalfn_ptr, &finalfn_nargs);
+ aggFuncInfo[i].finalfn_oid = finalfn_oid;
+ aggFuncInfo[i].finalfn = finalfn_ptr;
+ aggFuncInfo[i].finalfn_nargs = finalfn_nargs;
+ }
- if (OidIsValid(xfn2_oid)) {
- fmgr_info(xfn2_oid, &xfn2_ptr, &xfn2_nargs);
- aggFuncInfo[i].xfn2_oid = xfn2_oid;
- aggFuncInfo[i].xfn2 = xfn2_ptr;
- aggFuncInfo[i].xfn2_nargs = xfn2_nargs;
- value2[i] = (Datum)AggNameGetInitVal((char*)aggname,
- aggp->aggbasetype,
- 2,
- &isNull2);
- /* ------------------------------------------
- * If there is a second transition function, its initial
- * value must exist -- as it does not depend on data values,
- * we have no other way of determining an initial value.
- * ------------------------------------------
- */
- if (isNull2)
- elog(WARN, "ExecAgg: agginitval2 is null");
- }
+ if (OidIsValid(xfn2_oid))
+ {
+ fmgr_info(xfn2_oid, &xfn2_ptr, &xfn2_nargs);
+ aggFuncInfo[i].xfn2_oid = xfn2_oid;
+ aggFuncInfo[i].xfn2 = xfn2_ptr;
+ aggFuncInfo[i].xfn2_nargs = xfn2_nargs;
+ value2[i] = (Datum) AggNameGetInitVal((char *) aggname,
+ aggp->aggbasetype,
+ 2,
+ &isNull2);
+ /* ------------------------------------------
+ * If there is a second transition function, its initial
+ * value must exist -- as it does not depend on data values,
+ * we have no other way of determining an initial value.
+ * ------------------------------------------
+ */
+ if (isNull2)
+ elog(WARN, "ExecAgg: agginitval2 is null");
+ }
- if (OidIsValid(xfn1_oid)) {
- fmgr_info(xfn1_oid, &xfn1_ptr, &xfn1_nargs);
- aggFuncInfo[i].xfn1_oid = xfn1_oid;
- aggFuncInfo[i].xfn1 = xfn1_ptr;
- aggFuncInfo[i].xfn1_nargs = xfn1_nargs;
- value1[i] = (Datum)AggNameGetInitVal((char*)aggname,
- aggp->aggbasetype,
- 1,
- &isNull1);
-
- /* ------------------------------------------
- * If the initial value for the first transition function
- * doesn't exist in the pg_aggregate table then we let
- * the first value returned from the outer procNode become
- * the initial value. (This is useful for aggregates like
- * max{} and min{}.)
- * ------------------------------------------
- */
- if (isNull1) {
- noInitValue[i] = 1;
- nulls[i] = 1;
- }
- }
- }
-
- /* ----------------
- * for each tuple from the the outer plan, apply all the aggregates
- * ----------------
- */
- for (;;) {
- HeapTuple outerTuple = NULL;
- TupleTableSlot *outerslot;
-
- isNull = isNull1 = isNull2 = 0;
- outerslot = ExecProcNode(outerPlan, (Plan*)node);
- if (outerslot) outerTuple = outerslot->val;
- if (!HeapTupleIsValid(outerTuple)) {
- /* when the outerplan doesn't return a single tuple,
- create a dummy heaptuple anyway
- because we still need to return a valid aggregate value.
- The value returned will be the initial values of the
- transition functions */
- if (nTuplesAgged == 0) {
- TupleDesc tupType;
- Datum *tupValue;
- char* null_array;
-
- tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor;
- tupValue = projInfo->pi_tupValue;
-
- /* initially, set all the values to NULL */
- null_array = malloc(tupType->natts);
- for (i=0;i<tupType->natts;i++)
- null_array[i] = 'n';
- oneTuple = heap_formtuple(tupType, tupValue, null_array);
- free(null_array);
- }
- break;
+ if (OidIsValid(xfn1_oid))
+ {
+ fmgr_info(xfn1_oid, &xfn1_ptr, &xfn1_nargs);
+ aggFuncInfo[i].xfn1_oid = xfn1_oid;
+ aggFuncInfo[i].xfn1 = xfn1_ptr;
+ aggFuncInfo[i].xfn1_nargs = xfn1_nargs;
+ value1[i] = (Datum) AggNameGetInitVal((char *) aggname,
+ aggp->aggbasetype,
+ 1,
+ &isNull1);
+
+ /* ------------------------------------------
+ * If the initial value for the first transition function
+ * doesn't exist in the pg_aggregate table then we let
+ * the first value returned from the outer procNode become
+ * the initial value. (This is useful for aggregates like
+ * max{} and min{}.)
+ * ------------------------------------------
+ */
+ if (isNull1)
+ {
+ noInitValue[i] = 1;
+ nulls[i] = 1;
+ }
+ }
}
- for(i = 0; i < nagg; i++) {
- AttrNumber attnum;
- int2 attlen;
- Datum newVal = (Datum) NULL;
- AggFuncInfo *aggfns = &aggFuncInfo[i];
- Datum args[2];
- Node *tagnode = NULL;
-
- switch(nodeTag(aggregates[i]->target))
- {
- case T_Var:
- tagnode = NULL;
- newVal = aggGetAttr(outerslot,
- aggregates[i],
- &isNull);
- break;
- case T_Expr:
- tagnode = ((Expr*)aggregates[i]->target)->oper;
- econtext->ecxt_scantuple = outerslot;
- newVal = ExecEvalExpr (aggregates[i]->target, econtext,
- &isNull, NULL);
+ /* ----------------
+ * for each tuple from the the outer plan, apply all the aggregates
+ * ----------------
+ */
+ for (;;)
+ {
+ HeapTuple outerTuple = NULL;
+ TupleTableSlot *outerslot;
+
+ isNull = isNull1 = isNull2 = 0;
+ outerslot = ExecProcNode(outerPlan, (Plan *) node);
+ if (outerslot)
+ outerTuple = outerslot->val;
+ if (!HeapTupleIsValid(outerTuple))
+ {
+
+ /*
+ * when the outerplan doesn't return a single tuple, create a
+ * dummy heaptuple anyway because we still need to return a
+ * valid aggregate value. The value returned will be the
+ * initial values of the transition functions
+ */
+ if (nTuplesAgged == 0)
+ {
+ TupleDesc tupType;
+ Datum *tupValue;
+ char *null_array;
+
+ tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor;
+ tupValue = projInfo->pi_tupValue;
+
+ /* initially, set all the values to NULL */
+ null_array = malloc(tupType->natts);
+ for (i = 0; i < tupType->natts; i++)
+ null_array[i] = 'n';
+ oneTuple = heap_formtuple(tupType, tupValue, null_array);
+ free(null_array);
+ }
break;
- default:
- elog(WARN, "ExecAgg: Bad Agg->Target for Agg %d", i);
- }
-
- if (isNull)
- continue; /* ignore this tuple for this agg */
-
- if (aggfns->xfn1) {
- if (noInitValue[i]) {
- int byVal;
-
- /*
- * value1 and value2 has not been initialized. This
- * is the first non-NULL value. We use it as the
- * initial value.
- */
- /* but we can't just use it straight, we have
- to make a copy of it since the tuple from which
- it came will be freed on the next iteration
- of the scan */
- if ( tagnode != NULL )
- {
- FunctionCachePtr fcache_ptr;
-
- if ( nodeTag(tagnode) == T_Func )
- fcache_ptr = ((Func*)tagnode)->func_fcache;
- else
- fcache_ptr = ((Oper*)tagnode)->op_fcache;
- attlen = fcache_ptr->typlen;
- byVal = fcache_ptr->typbyval;
- }
- else
- {
- attnum = ((Var*)aggregates[i]->target)->varattno;
- attlen = outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attlen;
- byVal = outerslot->ttc_tupleDescriptor->attrs[attnum-1]->attbyval;
- }
- if (attlen == -1) {
- /* variable length */
- attlen = VARSIZE((struct varlena*) newVal);
- }
- value1[i] = (Datum)palloc(attlen);
- if ( byVal )
- value1[i] = newVal;
- else
- memmove((char*)(value1[i]), (char*)newVal, attlen);
- /* value1[i] = newVal; */
- noInitValue[i] = 0;
- nulls[i] = 0;
- } else {
- /*
- * apply the transition functions.
- */
- args[0] = value1[i];
- args[1] = newVal;
- value1[i] =
- (Datum)fmgr_c(aggfns->xfn1, aggfns->xfn1_oid,
- aggfns->xfn1_nargs, (FmgrValues *)args,
- &isNull1);
- Assert(!isNull1);
}
- }
-
- if (aggfns->xfn2) {
- Datum xfn2_val = value2[i];
-
- value2[i] =
- (Datum)fmgr_c(aggfns->xfn2, aggfns->xfn2_oid,
- aggfns->xfn2_nargs,
- (FmgrValues *)&xfn2_val, &isNull2);
- Assert(!isNull2);
- }
+
+ for (i = 0; i < nagg; i++)
+ {
+ AttrNumber attnum;
+ int2 attlen;
+ Datum newVal = (Datum) NULL;
+ AggFuncInfo *aggfns = &aggFuncInfo[i];
+ Datum args[2];
+ Node *tagnode = NULL;
+
+ switch (nodeTag(aggregates[i]->target))
+ {
+ case T_Var:
+ tagnode = NULL;
+ newVal = aggGetAttr(outerslot,
+ aggregates[i],
+ &isNull);
+ break;
+ case T_Expr:
+ tagnode = ((Expr *) aggregates[i]->target)->oper;
+ econtext->ecxt_scantuple = outerslot;
+ newVal = ExecEvalExpr(aggregates[i]->target, econtext,
+ &isNull, NULL);
+ break;
+ default:
+ elog(WARN, "ExecAgg: Bad Agg->Target for Agg %d", i);
+ }
+
+ if (isNull)
+ continue; /* ignore this tuple for this agg */
+
+ if (aggfns->xfn1)
+ {
+ if (noInitValue[i])
+ {
+ int byVal;
+
+ /*
+ * value1 and value2 has not been initialized. This is
+ * the first non-NULL value. We use it as the initial
+ * value.
+ */
+
+ /*
+ * but we can't just use it straight, we have to make
+ * a copy of it since the tuple from which it came
+ * will be freed on the next iteration of the scan
+ */
+ if (tagnode != NULL)
+ {
+ FunctionCachePtr fcache_ptr;
+
+ if (nodeTag(tagnode) == T_Func)
+ fcache_ptr = ((Func *) tagnode)->func_fcache;
+ else
+ fcache_ptr = ((Oper *) tagnode)->op_fcache;
+ attlen = fcache_ptr->typlen;
+ byVal = fcache_ptr->typbyval;
+ }
+ else
+ {
+ attnum = ((Var *) aggregates[i]->target)->varattno;
+ attlen = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attlen;
+ byVal = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attbyval;
+ }
+ if (attlen == -1)
+ {
+ /* variable length */
+ attlen = VARSIZE((struct varlena *) newVal);
+ }
+ value1[i] = (Datum) palloc(attlen);
+ if (byVal)
+ value1[i] = newVal;
+ else
+ memmove((char *) (value1[i]), (char *) newVal, attlen);
+ /* value1[i] = newVal; */
+ noInitValue[i] = 0;
+ nulls[i] = 0;
+ }
+ else
+ {
+
+ /*
+ * apply the transition functions.
+ */
+ args[0] = value1[i];
+ args[1] = newVal;
+ value1[i] =
+ (Datum) fmgr_c(aggfns->xfn1, aggfns->xfn1_oid,
+ aggfns->xfn1_nargs, (FmgrValues *) args,
+ &isNull1);
+ Assert(!isNull1);
+ }
+ }
+
+ if (aggfns->xfn2)
+ {
+ Datum xfn2_val = value2[i];
+
+ value2[i] =
+ (Datum) fmgr_c(aggfns->xfn2, aggfns->xfn2_oid,
+ aggfns->xfn2_nargs,
+ (FmgrValues *) & xfn2_val, &isNull2);
+ Assert(!isNull2);
+ }
+ }
+
+ /*
+ * keep this for the projection (we only need one of these - all
+ * the tuples we aggregate over share the same group column)
+ */
+ if (!oneTuple)
+ {
+ oneTuple = heap_copytuple(outerslot->val);
+ }
+
+ nTuplesAgged++;
+ }
+
+ /* --------------
+ * finalize the aggregate (if necessary), and get the resultant value
+ * --------------
+ */
+ for (i = 0; i < nagg; i++)
+ {
+ char *args[2];
+ AggFuncInfo *aggfns = &aggFuncInfo[i];
+
+ if (noInitValue[i])
+ {
+
+ /*
+ * No values found for this agg; return current state. This
+ * seems to fix behavior for avg() aggregate. -tgl 12/96
+ */
+ }
+ else if (aggfns->finalfn && nTuplesAgged > 0)
+ {
+ if (aggfns->finalfn_nargs > 1)
+ {
+ args[0] = (char *) value1[i];
+ args[1] = (char *) value2[i];
+ }
+ else if (aggfns->xfn1)
+ {
+ args[0] = (char *) value1[i];
+ }
+ else if (aggfns->xfn2)
+ {
+ args[0] = (char *) value2[i];
+ }
+ else
+ elog(WARN, "ExecAgg: no valid transition functions??");
+ value1[i] =
+ (Datum) fmgr_c(aggfns->finalfn, aggfns->finalfn_oid,
+ aggfns->finalfn_nargs, (FmgrValues *) args,
+ &(nulls[i]));
+ }
+ else if (aggfns->xfn1)
+ {
+
+ /*
+ * value in the right place, ignore. (If you remove this case,
+ * fix the else part. -ay 2/95)
+ */
+ }
+ else if (aggfns->xfn2)
+ {
+ value1[i] = value2[i];
+ }
+ else
+ elog(WARN, "ExecAgg: no valid transition functions??");
}
/*
- * keep this for the projection (we only need one of these -
- * all the tuples we aggregate over share the same group column)
+ * whether the aggregation is done depends on whether we are doing
+ * aggregation over groups or the entire table
*/
- if (!oneTuple) {
- oneTuple = heap_copytuple(outerslot->val);
+ if (nodeTag(outerPlan) == T_Group)
+ {
+ /* aggregation over groups */
+ aggstate->agg_done = ((Group *) outerPlan)->grpstate->grp_done;
+ }
+ else
+ {
+ aggstate->agg_done = TRUE;
}
- nTuplesAgged++;
- }
-
- /* --------------
- * finalize the aggregate (if necessary), and get the resultant value
- * --------------
- */
- for(i = 0; i < nagg; i++) {
- char *args[2];
- AggFuncInfo *aggfns = &aggFuncInfo[i];
-
- if (noInitValue[i]) {
- /*
- * No values found for this agg; return current state.
- * This seems to fix behavior for avg() aggregate. -tgl 12/96
- */
- } else if (aggfns->finalfn && nTuplesAgged > 0) {
- if (aggfns->finalfn_nargs > 1) {
- args[0] = (char*)value1[i];
- args[1] = (char*)value2[i];
- } else if (aggfns->xfn1) {
- args[0] = (char*)value1[i];
- } else if (aggfns->xfn2) {
- args[0] = (char*)value2[i];
- } else
- elog(WARN, "ExecAgg: no valid transition functions??");
- value1[i] =
- (Datum)fmgr_c(aggfns->finalfn, aggfns->finalfn_oid,
- aggfns->finalfn_nargs, (FmgrValues *) args,
- &(nulls[i]));
- } else if (aggfns->xfn1) {
- /*
- * value in the right place, ignore. (If you remove this
- * case, fix the else part. -ay 2/95)
- */
- } else if (aggfns->xfn2) {
- value1[i] = value2[i];
- } else
- elog(WARN, "ExecAgg: no valid transition functions??");
- }
-
- /*
- * whether the aggregation is done depends on whether we are doing
- * aggregation over groups or the entire table
- */
- if (nodeTag(outerPlan)==T_Group) {
- /* aggregation over groups */
- aggstate->agg_done = ((Group*)outerPlan)->grpstate->grp_done;
- } else {
- aggstate->agg_done = TRUE;
- }
-
- /* ----------------
- * form a projection tuple, store it in the result tuple
- * slot and return it.
- * ----------------
- */
- ExecStoreTuple(oneTuple,
- aggstate->csstate.css_ScanTupleSlot,
- InvalidBuffer,
- false);
- econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot;
- resultSlot = ExecProject(projInfo, &isDone);
-
- if (oneTuple)
- pfree(oneTuple);
-
- return resultSlot;
+ /* ----------------
+ * form a projection tuple, store it in the result tuple
+ * slot and return it.
+ * ----------------
+ */
+ ExecStoreTuple(oneTuple,
+ aggstate->csstate.css_ScanTupleSlot,
+ InvalidBuffer,
+ false);
+ econtext->ecxt_scantuple = aggstate->csstate.css_ScanTupleSlot;
+ resultSlot = ExecProject(projInfo, &isDone);
+
+ if (oneTuple)
+ pfree(oneTuple);
+
+ return resultSlot;
}
/* -----------------
* ExecInitAgg
*
- * Creates the run-time information for the agg node produced by the
- * planner and initializes its outer subtree
+ * Creates the run-time information for the agg node produced by the
+ * planner and initializes its outer subtree
* -----------------
*/
bool
-ExecInitAgg(Agg *node, EState *estate, Plan *parent)
+ExecInitAgg(Agg * node, EState * estate, Plan * parent)
{
- AggState *aggstate;
- Plan *outerPlan;
- ExprContext *econtext;
-
- /*
- * assign the node's execution state
- */
- node->plan.state = estate;
-
- /*
- * create state structure
- */
- aggstate = makeNode(AggState);
- node->aggstate = aggstate;
- aggstate->agg_done = FALSE;
-
- /*
- * assign node's base id and create expression context
- */
- ExecAssignNodeBaseInfo(estate, &aggstate->csstate.cstate,
- (Plan*) parent);
- ExecAssignExprContext(estate, &aggstate->csstate.cstate);
-
+ AggState *aggstate;
+ Plan *outerPlan;
+ ExprContext *econtext;
+
+ /*
+ * assign the node's execution state
+ */
+ node->plan.state = estate;
+
+ /*
+ * create state structure
+ */
+ aggstate = makeNode(AggState);
+ node->aggstate = aggstate;
+ aggstate->agg_done = FALSE;
+
+ /*
+ * assign node's base id and create expression context
+ */
+ ExecAssignNodeBaseInfo(estate, &aggstate->csstate.cstate,
+ (Plan *) parent);
+ ExecAssignExprContext(estate, &aggstate->csstate.cstate);
+
#define AGG_NSLOTS 2
- /*
- * tuple table initialization
- */
- ExecInitScanTupleSlot(estate, &aggstate->csstate);
- ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
-
- econtext = aggstate->csstate.cstate.cs_ExprContext;
- econtext->ecxt_values =
- (Datum *)palloc(sizeof(Datum) * node->numAgg);
- memset(econtext->ecxt_values, 0, sizeof(Datum) * node->numAgg);
- econtext->ecxt_nulls = (char *)palloc(node->numAgg);
- memset(econtext->ecxt_nulls, 0, node->numAgg);
-
- /*
- * initializes child nodes
- */
- outerPlan = outerPlan(node);
- ExecInitNode(outerPlan, estate, (Plan *)node);
-
- /* ----------------
- * initialize tuple type.
- * ----------------
- */
- ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
-
- /*
- * Initialize tuple type for both result and scan.
- * This node does no projection
- */
- ExecAssignResultTypeFromTL((Plan*) node, &aggstate->csstate.cstate);
- ExecAssignProjectionInfo((Plan*)node, &aggstate->csstate.cstate);
-
- return TRUE;
+
+ /*
+ * tuple table initialization
+ */
+ ExecInitScanTupleSlot(estate, &aggstate->csstate);
+ ExecInitResultTupleSlot(estate, &aggstate->csstate.cstate);
+
+ econtext = aggstate->csstate.cstate.cs_ExprContext;
+ econtext->ecxt_values =
+ (Datum *) palloc(sizeof(Datum) * node->numAgg);
+ memset(econtext->ecxt_values, 0, sizeof(Datum) * node->numAgg);
+ econtext->ecxt_nulls = (char *) palloc(node->numAgg);
+ memset(econtext->ecxt_nulls, 0, node->numAgg);
+
+ /*
+ * initializes child nodes
+ */
+ outerPlan = outerPlan(node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * initialize tuple type.
+ * ----------------
+ */
+ ExecAssignScanTypeFromOuterPlan((Plan *) node, &aggstate->csstate);
+
+ /*
+ * Initialize tuple type for both result and scan. This node does no
+ * projection
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &aggstate->csstate.cstate);
+ ExecAssignProjectionInfo((Plan *) node, &aggstate->csstate.cstate);
+
+ return TRUE;
}
int
-ExecCountSlotsAgg(Agg *node)
+ExecCountSlotsAgg(Agg * node)
{
- return ExecCountSlotsNode(outerPlan(node)) +
+ return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
- AGG_NSLOTS;
+ AGG_NSLOTS;
}
/* ------------------------
- * ExecEndAgg(node)
+ * ExecEndAgg(node)
*
* -----------------------
*/
void
-ExecEndAgg(Agg *node)
+ExecEndAgg(Agg * node)
{
- AggState *aggstate;
- Plan *outerPlan;
+ AggState *aggstate;
+ Plan *outerPlan;
- aggstate = node->aggstate;
+ aggstate = node->aggstate;
- ExecFreeProjectionInfo(&aggstate->csstate.cstate);
+ ExecFreeProjectionInfo(&aggstate->csstate.cstate);
- outerPlan = outerPlan(node);
- ExecEndNode(outerPlan, (Plan*)node);
-
- /* clean up tuple table */
- ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
+ outerPlan = outerPlan(node);
+ ExecEndNode(outerPlan, (Plan *) node);
+
+ /* clean up tuple table */
+ ExecClearTuple(aggstate->csstate.css_ScanTupleSlot);
}
/*****************************************************************************
- * Support Routines
+ * Support Routines
*****************************************************************************/
/*
* aggGetAttr -
- * get the attribute (specified in the Var node in agg) to aggregate
- * over from the tuple
+ * get the attribute (specified in the Var node in agg) to aggregate
+ * over from the tuple
*/
-static Datum
-aggGetAttr(TupleTableSlot *slot,
- Aggreg *agg,
- bool *isNull)
+static Datum
+aggGetAttr(TupleTableSlot * slot,
+ Aggreg * agg,
+ bool * isNull)
{
- Datum result;
- AttrNumber attnum;
- HeapTuple heapTuple;
- TupleDesc tuple_type;
- Buffer buffer;
-
- /* ----------------
- * extract tuple information from the slot
- * ----------------
- */
- heapTuple = slot->val;
- tuple_type = slot->ttc_tupleDescriptor;
- buffer = slot->ttc_buffer;
-
- attnum = ((Var*)agg->target)->varattno;
-
- /*
- * If the attribute number is invalid, then we are supposed to
- * return the entire tuple, we give back a whole slot so that
- * callers know what the tuple looks like.
- */
- if (attnum == InvalidAttrNumber) {
- TupleTableSlot *tempSlot;
- TupleDesc td;
- HeapTuple tup;
-
- tempSlot = makeNode(TupleTableSlot);
- tempSlot->ttc_shouldFree = false;
- tempSlot->ttc_descIsNew = true;
- tempSlot->ttc_tupleDescriptor = (TupleDesc)NULL,
- tempSlot->ttc_buffer = InvalidBuffer;
- tempSlot->ttc_whichplan = -1;
-
- tup = heap_copytuple(slot->val);
- td = CreateTupleDescCopy(slot->ttc_tupleDescriptor);
-
- ExecSetSlotDescriptor(tempSlot, td);
-
- ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
- return (Datum) tempSlot;
- }
-
- result = (Datum)
- heap_getattr(heapTuple, /* tuple containing attribute */
- buffer, /* buffer associated with tuple */
- attnum, /* attribute number of desired attribute */
- tuple_type, /* tuple descriptor of tuple */
- isNull); /* return: is attribute null? */
-
- /* ----------------
- * return null if att is null
- * ----------------
- */
- if (*isNull)
- return (Datum) NULL;
-
- return result;
+ Datum result;
+ AttrNumber attnum;
+ HeapTuple heapTuple;
+ TupleDesc tuple_type;
+ Buffer buffer;
+
+ /* ----------------
+ * extract tuple information from the slot
+ * ----------------
+ */
+ heapTuple = slot->val;
+ tuple_type = slot->ttc_tupleDescriptor;
+ buffer = slot->ttc_buffer;
+
+ attnum = ((Var *) agg->target)->varattno;
+
+ /*
+ * If the attribute number is invalid, then we are supposed to return
+ * the entire tuple, we give back a whole slot so that callers know
+ * what the tuple looks like.
+ */
+ if (attnum == InvalidAttrNumber)
+ {
+ TupleTableSlot *tempSlot;
+ TupleDesc td;
+ HeapTuple tup;
+
+ tempSlot = makeNode(TupleTableSlot);
+ tempSlot->ttc_shouldFree = false;
+ tempSlot->ttc_descIsNew = true;
+ tempSlot->ttc_tupleDescriptor = (TupleDesc) NULL,
+ tempSlot->ttc_buffer = InvalidBuffer;
+ tempSlot->ttc_whichplan = -1;
+
+ tup = heap_copytuple(slot->val);
+ td = CreateTupleDescCopy(slot->ttc_tupleDescriptor);
+
+ ExecSetSlotDescriptor(tempSlot, td);
+
+ ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
+ return (Datum) tempSlot;
+ }
+
+ result = (Datum)
+ heap_getattr(heapTuple, /* tuple containing attribute */
+ buffer, /* buffer associated with tuple */
+ attnum, /* attribute number of desired attribute */
+ tuple_type,/* tuple descriptor of tuple */
+ isNull); /* return: is attribute null? */
+
+ /* ----------------
+ * return null if att is null
+ * ----------------
+ */
+ if (*isNull)
+ return (Datum) NULL;
+
+ return result;
}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 7abc6d91744..043ad5d9743 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -1,56 +1,56 @@
/*-------------------------------------------------------------------------
*
* nodeAppend.c--
- * routines to handle append nodes.
+ * routines to handle append nodes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.5 1997/08/19 21:31:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.6 1997/09/07 04:41:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* INTERFACE ROUTINES
- * ExecInitAppend - initialize the append node
- * ExecProcAppend - retrieve the next tuple from the node
- * ExecEndAppend - shut down the append node
+ * ExecInitAppend - initialize the append node
+ * ExecProcAppend - retrieve the next tuple from the node
+ * ExecEndAppend - shut down the append node
*
- * NOTES
- * Each append node contains a list of one or more subplans which
- * must be iteratively processed (forwards or backwards).
- * Tuples are retrieved by executing the 'whichplan'th subplan
- * until the subplan stops returning tuples, at which point that
- * plan is shut down and the next started up.
+ * NOTES
+ * Each append node contains a list of one or more subplans which
+ * must be iteratively processed (forwards or backwards).
+ * Tuples are retrieved by executing the 'whichplan'th subplan
+ * until the subplan stops returning tuples, at which point that
+ * plan is shut down and the next started up.
*
- * Append nodes don't make use of their left and right
- * subtrees, rather they maintain a list of subplans so
- * a typical append node looks like this in the plan tree:
+ * Append nodes don't make use of their left and right
+ * subtrees, rather they maintain a list of subplans so
+ * a typical append node looks like this in the plan tree:
*
- * ...
- * /
- * Append -------+------+------+--- nil
- * / \ | | |
- * nil nil ... ... ...
- * subplans
+ * ...
+ * /
+ * Append -------+------+------+--- nil
+ * / \ | | |
+ * nil nil ... ... ...
+ * subplans
*
- * Append nodes are currently used to support inheritance
- * queries, where several relations need to be scanned.
- * For example, in our standard person/student/employee/student-emp
- * example, where student and employee inherit from person
- * and student-emp inherits from student and employee, the
- * query:
+ * Append nodes are currently used to support inheritance
+ * queries, where several relations need to be scanned.
+ * For example, in our standard person/student/employee/student-emp
+ * example, where student and employee inherit from person
+ * and student-emp inherits from student and employee, the
+ * query:
*
- * retrieve (e.name) from e in person*
+ * retrieve (e.name) from e in person*
*
- * generates the plan:
+ * generates the plan:
*
- * |
- * Append -------+-------+--------+--------+
- * / \ | | | |
- * nil nil Scan Scan Scan Scan
- * | | | |
- * person employee student student-emp
+ * |
+ * Append -------+-------+--------+--------+
+ * / \ | | | |
+ * nil nil Scan Scan Scan Scan
+ * | | | |
+ * person employee student student-emp
*/
#include "postgres.h"
@@ -62,429 +62,451 @@
#include "executor/nodeIndexscan.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
-#include "parser/parsetree.h" /* for rt_store() macro */
+#include "parser/parsetree.h" /* for rt_store() macro */
-static bool exec_append_initialize_next(Append *node);
+static bool exec_append_initialize_next(Append * node);
/* ----------------------------------------------------------------
- * exec-append-initialize-next
- *
- * Sets up the append node state (i.e. the append state node)
- * for the "next" scan.
- *
- * Returns t iff there is a "next" scan to process.
+ * exec-append-initialize-next
+ *
+ * Sets up the append node state (i.e. the append state node)
+ * for the "next" scan.
+ *
+ * Returns t iff there is a "next" scan to process.
* ----------------------------------------------------------------
*/
-static bool
-exec_append_initialize_next(Append *node)
+static bool
+exec_append_initialize_next(Append * node)
{
- EState *estate;
- AppendState *unionstate;
- TupleTableSlot *result_slot;
- List *rangeTable;
-
- int whichplan;
- int nplans;
- List *rtentries;
- ResTarget *rtentry;
-
- Index unionrelid;
-
- /* ----------------
- * get information from the append node
- * ----------------
- */
- estate = node->plan.state;
- unionstate = node->unionstate;
- result_slot = unionstate->cstate.cs_ResultTupleSlot;
- rangeTable = estate->es_range_table;
-
- whichplan = unionstate->as_whichplan;
- nplans = unionstate->as_nplans;
- rtentries = node->unionrtentries;
-
- if (whichplan < 0) {
- /* ----------------
- * if scanning in reverse, we start at
- * the last scan in the list and then
- * proceed back to the first.. in any case
- * we inform ExecProcAppend that we are
- * at the end of the line by returning FALSE
- * ----------------
- */
- unionstate->as_whichplan = 0;
- return FALSE;
-
- } else if (whichplan >= nplans) {
- /* ----------------
- * as above, end the scan if we go beyond
- * the last scan in our list..
- * ----------------
- */
- unionstate->as_whichplan = nplans - 1;
- return FALSE;
-
- } else {
- /* ----------------
- * initialize the scan
- * (and update the range table appropriately)
- * (doesn't this leave the range table hosed for anybody upstream
- * of the Append node??? - jolly )
- * ----------------
- */
- if (node->unionrelid > 0) {
- rtentry = nth(whichplan, rtentries);
- if (rtentry == NULL)
- elog(DEBUG, "exec_append_initialize_next: rtentry is nil");
-
- unionrelid = node->unionrelid;
-
- rt_store(unionrelid, rangeTable, rtentry);
-
- if (unionstate->as_junkFilter_list) {
- estate->es_junkFilter =
- (JunkFilter*)nth(whichplan,
- unionstate->as_junkFilter_list);
- }
- if (unionstate->as_result_relation_info_list) {
- estate->es_result_relation_info =
- (RelationInfo*) nth(whichplan,
- unionstate->as_result_relation_info_list);
- }
- result_slot->ttc_whichplan = whichplan;
+ EState *estate;
+ AppendState *unionstate;
+ TupleTableSlot *result_slot;
+ List *rangeTable;
+
+ int whichplan;
+ int nplans;
+ List *rtentries;
+ ResTarget *rtentry;
+
+ Index unionrelid;
+
+ /* ----------------
+ * get information from the append node
+ * ----------------
+ */
+ estate = node->plan.state;
+ unionstate = node->unionstate;
+ result_slot = unionstate->cstate.cs_ResultTupleSlot;
+ rangeTable = estate->es_range_table;
+
+ whichplan = unionstate->as_whichplan;
+ nplans = unionstate->as_nplans;
+ rtentries = node->unionrtentries;
+
+ if (whichplan < 0)
+ {
+ /* ----------------
+ * if scanning in reverse, we start at
+ * the last scan in the list and then
+ * proceed back to the first.. in any case
+ * we inform ExecProcAppend that we are
+ * at the end of the line by returning FALSE
+ * ----------------
+ */
+ unionstate->as_whichplan = 0;
+ return FALSE;
+
+ }
+ else if (whichplan >= nplans)
+ {
+ /* ----------------
+ * as above, end the scan if we go beyond
+ * the last scan in our list..
+ * ----------------
+ */
+ unionstate->as_whichplan = nplans - 1;
+ return FALSE;
+
+ }
+ else
+ {
+ /* ----------------
+ * initialize the scan
+ * (and update the range table appropriately)
+ * (doesn't this leave the range table hosed for anybody upstream
+ * of the Append node??? - jolly )
+ * ----------------
+ */
+ if (node->unionrelid > 0)
+ {
+ rtentry = nth(whichplan, rtentries);
+ if (rtentry == NULL)
+ elog(DEBUG, "exec_append_initialize_next: rtentry is nil");
+
+ unionrelid = node->unionrelid;
+
+ rt_store(unionrelid, rangeTable, rtentry);
+
+ if (unionstate->as_junkFilter_list)
+ {
+ estate->es_junkFilter =
+ (JunkFilter *) nth(whichplan,
+ unionstate->as_junkFilter_list);
+ }
+ if (unionstate->as_result_relation_info_list)
+ {
+ estate->es_result_relation_info =
+ (RelationInfo *) nth(whichplan,
+ unionstate->as_result_relation_info_list);
+ }
+ result_slot->ttc_whichplan = whichplan;
+ }
+
+ return TRUE;
}
-
- return TRUE;
- }
}
/* ----------------------------------------------------------------
- * ExecInitAppend
- *
- * Begins all of the subscans of the append node, storing the
- * scan structures in the 'initialized' vector of the append-state
- * structure.
+ * ExecInitAppend
+ *
+ * Begins all of the subscans of the append node, storing the
+ * scan structures in the 'initialized' vector of the append-state
+ * structure.
*
- * (This is potentially wasteful, since the entire result of the
- * append node may not be scanned, but this way all of the
- * structures get allocated in the executor's top level memory
- * block instead of that of the call to ExecProcAppend.)
- *
- * Returns the scan result of the first scan.
+ * (This is potentially wasteful, since the entire result of the
+ * append node may not be scanned, but this way all of the
+ * structures get allocated in the executor's top level memory
+ * block instead of that of the call to ExecProcAppend.)
+ *
+ * Returns the scan result of the first scan.
* ----------------------------------------------------------------
*/
bool
-ExecInitAppend(Append *node, EState *estate, Plan *parent)
+ExecInitAppend(Append * node, EState * estate, Plan * parent)
{
- AppendState *unionstate;
- int nplans;
- List *resultList = NULL;
- List *rtentries;
- List *unionplans;
- bool *initialized;
- int i;
- Plan *initNode;
- List *junkList;
- RelationInfo *es_rri = estate->es_result_relation_info;
-
- /* ----------------
- * assign execution state to node and get information
- * for append state
- * ----------------
- */
- node->plan.state = estate;
-
- unionplans = node->unionplans;
- nplans = length(unionplans);
- rtentries = node->unionrtentries;
-
- CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
- initialized = (bool *)palloc(nplans * sizeof(bool));
-
- /* ----------------
- * create new AppendState for our append node
- * ----------------
- */
- unionstate = makeNode(AppendState);
- unionstate->as_whichplan = 0;
- unionstate->as_nplans = nplans;
- unionstate->as_initialized = initialized;
- unionstate->as_rtentries = rtentries;
-
- node->unionstate = unionstate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks
- *
- * Append plans don't have expression contexts because they
- * never call ExecQual or ExecTargetList.
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &unionstate->cstate, parent);
-
+ AppendState *unionstate;
+ int nplans;
+ List *resultList = NULL;
+ List *rtentries;
+ List *unionplans;
+ bool *initialized;
+ int i;
+ Plan *initNode;
+ List *junkList;
+ RelationInfo *es_rri = estate->es_result_relation_info;
+
+ /* ----------------
+ * assign execution state to node and get information
+ * for append state
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ unionplans = node->unionplans;
+ nplans = length(unionplans);
+ rtentries = node->unionrtentries;
+
+ CXT1_printf("ExecInitAppend: context is %d\n", CurrentMemoryContext);
+ initialized = (bool *) palloc(nplans * sizeof(bool));
+
+ /* ----------------
+ * create new AppendState for our append node
+ * ----------------
+ */
+ unionstate = makeNode(AppendState);
+ unionstate->as_whichplan = 0;
+ unionstate->as_nplans = nplans;
+ unionstate->as_initialized = initialized;
+ unionstate->as_rtentries = rtentries;
+
+ node->unionstate = unionstate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks
+ *
+ * Append plans don't have expression contexts because they
+ * never call ExecQual or ExecTargetList.
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &unionstate->cstate, parent);
+
#define APPEND_NSLOTS 1
- /* ----------------
- * append nodes still have Result slots, which hold pointers
- * to tuples, so we have to initialize them..
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &unionstate->cstate);
-
- /*
- * If the inherits rtentry is the result relation, we have to make
- * a result relation info list for all inheritors so we can update
- * their indices and put the result tuples in the right place etc.
- *
- * e.g. replace p (age = p.age + 1) from p in person*
- */
- if ((es_rri != (RelationInfo*)NULL) &&
- (node->unionrelid == es_rri->ri_RangeTableIndex))
+ /* ----------------
+ * append nodes still have Result slots, which hold pointers
+ * to tuples, so we have to initialize them..
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &unionstate->cstate);
+
+ /*
+ * If the inherits rtentry is the result relation, we have to make a
+ * result relation info list for all inheritors so we can update their
+ * indices and put the result tuples in the right place etc.
+ *
+ * e.g. replace p (age = p.age + 1) from p in person*
+ */
+ if ((es_rri != (RelationInfo *) NULL) &&
+ (node->unionrelid == es_rri->ri_RangeTableIndex))
{
- RelationInfo *rri;
- List *rtentryP;
-
- foreach(rtentryP,rtentries)
+ RelationInfo *rri;
+ List *rtentryP;
+
+ foreach(rtentryP, rtentries)
{
- Oid reloid;
- RangeTblEntry *rtentry = lfirst(rtentryP);
-
- reloid = rtentry->relid;
- rri = makeNode(RelationInfo);
- rri->ri_RangeTableIndex = es_rri->ri_RangeTableIndex;
- rri->ri_RelationDesc = heap_open(reloid);
- rri->ri_NumIndices = 0;
- rri->ri_IndexRelationDescs = NULL; /* index descs */
- rri->ri_IndexRelationInfo = NULL; /* index key info */
-
- resultList = lcons(rri,resultList);
- ExecOpenIndices(reloid, rri);
+ Oid reloid;
+ RangeTblEntry *rtentry = lfirst(rtentryP);
+
+ reloid = rtentry->relid;
+ rri = makeNode(RelationInfo);
+ rri->ri_RangeTableIndex = es_rri->ri_RangeTableIndex;
+ rri->ri_RelationDesc = heap_open(reloid);
+ rri->ri_NumIndices = 0;
+ rri->ri_IndexRelationDescs = NULL; /* index descs */
+ rri->ri_IndexRelationInfo = NULL; /* index key info */
+
+ resultList = lcons(rri, resultList);
+ ExecOpenIndices(reloid, rri);
}
- unionstate->as_result_relation_info_list = resultList;
+ unionstate->as_result_relation_info_list = resultList;
}
- /* ----------------
- * call ExecInitNode on each of the plans in our list
- * and save the results into the array "initialized"
- * ----------------
- */
- junkList = NIL;
-
- for(i = 0; i < nplans ; i++ ) {
- JunkFilter *j;
- List *targetList;
- /* ----------------
- * NOTE: we first modify range table in
- * exec_append_initialize_next() and
- * then initialize the subnode,
- * since it may use the range table.
- * ----------------
- */
- unionstate->as_whichplan = i;
- exec_append_initialize_next(node);
-
- initNode = (Plan *) nth(i, unionplans);
- initialized[i] = ExecInitNode(initNode, estate, (Plan*) node);
-
- /* ---------------
- * Each targetlist in the subplan may need its own junk filter
- *
- * This is true only when the reln being replaced/deleted is
- * the one that we're looking at the subclasses of
- * ---------------
+ /* ----------------
+ * call ExecInitNode on each of the plans in our list
+ * and save the results into the array "initialized"
+ * ----------------
*/
- if ((es_rri != (RelationInfo*)NULL) &&
- (node->unionrelid == es_rri->ri_RangeTableIndex)) {
-
- targetList = initNode->targetlist;
- j = (JunkFilter *) ExecInitJunkFilter(targetList);
- junkList = lappend(junkList, j);
+ junkList = NIL;
+
+ for (i = 0; i < nplans; i++)
+ {
+ JunkFilter *j;
+ List *targetList;
+
+ /* ----------------
+ * NOTE: we first modify range table in
+ * exec_append_initialize_next() and
+ * then initialize the subnode,
+ * since it may use the range table.
+ * ----------------
+ */
+ unionstate->as_whichplan = i;
+ exec_append_initialize_next(node);
+
+ initNode = (Plan *) nth(i, unionplans);
+ initialized[i] = ExecInitNode(initNode, estate, (Plan *) node);
+
+ /* ---------------
+ * Each targetlist in the subplan may need its own junk filter
+ *
+ * This is true only when the reln being replaced/deleted is
+ * the one that we're looking at the subclasses of
+ * ---------------
+ */
+ if ((es_rri != (RelationInfo *) NULL) &&
+ (node->unionrelid == es_rri->ri_RangeTableIndex))
+ {
+
+ targetList = initNode->targetlist;
+ j = (JunkFilter *) ExecInitJunkFilter(targetList);
+ junkList = lappend(junkList, j);
+ }
+
}
-
- }
- unionstate->as_junkFilter_list = junkList;
- if (junkList != NIL)
- estate->es_junkFilter = (JunkFilter *)lfirst(junkList);
-
- /* ----------------
- * initialize the return type from the appropriate subplan.
- * ----------------
- */
- initNode = (Plan *) nth(0, unionplans);
- ExecAssignResultType(&unionstate->cstate,
-/* ExecGetExecTupDesc(initNode), */
- ExecGetTupType(initNode));
- unionstate->cstate.cs_ProjInfo = NULL;
-
- /* ----------------
- * return the result from the first subplan's initialization
- * ----------------
- */
- unionstate->as_whichplan = 0;
- exec_append_initialize_next(node);
+ unionstate->as_junkFilter_list = junkList;
+ if (junkList != NIL)
+ estate->es_junkFilter = (JunkFilter *) lfirst(junkList);
+
+ /* ----------------
+ * initialize the return type from the appropriate subplan.
+ * ----------------
+ */
+ initNode = (Plan *) nth(0, unionplans);
+ ExecAssignResultType(&unionstate->cstate,
+/* ExecGetExecTupDesc(initNode), */
+ ExecGetTupType(initNode));
+ unionstate->cstate.cs_ProjInfo = NULL;
+
+ /* ----------------
+ * return the result from the first subplan's initialization
+ * ----------------
+ */
+ unionstate->as_whichplan = 0;
+ exec_append_initialize_next(node);
#if 0
- result = (List *) initialized[0];
-#endif
- return TRUE;
+ result = (List *) initialized[0];
+#endif
+ return TRUE;
}
int
-ExecCountSlotsAppend(Append *node)
+ExecCountSlotsAppend(Append * node)
{
- List *plan;
- List *unionplans = node->unionplans;
- int nSlots = 0;
-
- foreach (plan,unionplans) {
- nSlots += ExecCountSlotsNode((Plan *)lfirst(plan));
- }
- return nSlots + APPEND_NSLOTS;
+ List *plan;
+ List *unionplans = node->unionplans;
+ int nSlots = 0;
+
+ foreach(plan, unionplans)
+ {
+ nSlots += ExecCountSlotsNode((Plan *) lfirst(plan));
+ }
+ return nSlots + APPEND_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecProcAppend
- *
- * Handles the iteration over the multiple scans.
- *
- * NOTE: Can't call this ExecAppend, that name is used in execMain.l
+ * ExecProcAppend
+ *
+ * Handles the iteration over the multiple scans.
+ *
+ * NOTE: Can't call this ExecAppend, that name is used in execMain.l
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecProcAppend(Append *node)
+ExecProcAppend(Append * node)
{
- EState *estate;
- AppendState *unionstate;
-
- int whichplan;
- List *unionplans;
- Plan *subnode;
- TupleTableSlot *result;
- TupleTableSlot *result_slot;
- ScanDirection direction;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- unionstate = node->unionstate;
- estate = node->plan.state;
- direction = estate->es_direction;
-
- unionplans = node->unionplans;
- whichplan = unionstate->as_whichplan;
- result_slot = unionstate->cstate.cs_ResultTupleSlot;
-
- /* ----------------
- * figure out which subplan we are currently processing
- * ----------------
- */
- subnode = (Plan *) nth(whichplan, unionplans);
-
- if (subnode == NULL)
- elog(DEBUG, "ExecProcAppend: subnode is NULL");
-
- /* ----------------
- * get a tuple from the subplan
- * ----------------
- */
- result = ExecProcNode(subnode, (Plan*)node);
-
- if (! TupIsNull(result)) {
- /* ----------------
- * if the subplan gave us something then place a copy of
- * whatever we get into our result slot and return it, else..
- * ----------------
- */
- return ExecStoreTuple(result->val,
- result_slot, result->ttc_buffer, false);
-
- } else {
- /* ----------------
- * .. go on to the "next" subplan in the appropriate
- * direction and try processing again (recursively)
- * ----------------
- */
- whichplan = unionstate->as_whichplan;
-
- if (ScanDirectionIsForward(direction))
- {
- unionstate->as_whichplan = whichplan + 1;
- }
- else
- {
- unionstate->as_whichplan = whichplan - 1;
- }
-
+ EState *estate;
+ AppendState *unionstate;
+
+ int whichplan;
+ List *unionplans;
+ Plan *subnode;
+ TupleTableSlot *result;
+ TupleTableSlot *result_slot;
+ ScanDirection direction;
+
/* ----------------
- * return something from next node or an empty slot
- * all of our subplans have been exhausted.
+ * get information from the node
* ----------------
*/
- if (exec_append_initialize_next(node)) {
- ExecSetSlotDescriptorIsNew(result_slot, true);
- return
- ExecProcAppend(node);
- } else
- return ExecClearTuple(result_slot);
- }
+ unionstate = node->unionstate;
+ estate = node->plan.state;
+ direction = estate->es_direction;
+
+ unionplans = node->unionplans;
+ whichplan = unionstate->as_whichplan;
+ result_slot = unionstate->cstate.cs_ResultTupleSlot;
+
+ /* ----------------
+ * figure out which subplan we are currently processing
+ * ----------------
+ */
+ subnode = (Plan *) nth(whichplan, unionplans);
+
+ if (subnode == NULL)
+ elog(DEBUG, "ExecProcAppend: subnode is NULL");
+
+ /* ----------------
+ * get a tuple from the subplan
+ * ----------------
+ */
+ result = ExecProcNode(subnode, (Plan *) node);
+
+ if (!TupIsNull(result))
+ {
+ /* ----------------
+ * if the subplan gave us something then place a copy of
+ * whatever we get into our result slot and return it, else..
+ * ----------------
+ */
+ return ExecStoreTuple(result->val,
+ result_slot, result->ttc_buffer, false);
+
+ }
+ else
+ {
+ /* ----------------
+ * .. go on to the "next" subplan in the appropriate
+ * direction and try processing again (recursively)
+ * ----------------
+ */
+ whichplan = unionstate->as_whichplan;
+
+ if (ScanDirectionIsForward(direction))
+ {
+ unionstate->as_whichplan = whichplan + 1;
+ }
+ else
+ {
+ unionstate->as_whichplan = whichplan - 1;
+ }
+
+ /* ----------------
+ * return something from next node or an empty slot
+ * all of our subplans have been exhausted.
+ * ----------------
+ */
+ if (exec_append_initialize_next(node))
+ {
+ ExecSetSlotDescriptorIsNew(result_slot, true);
+ return
+ ExecProcAppend(node);
+ }
+ else
+ return ExecClearTuple(result_slot);
+ }
}
/* ----------------------------------------------------------------
- * ExecEndAppend
- *
- * Shuts down the subscans of the append node.
- *
- * Returns nothing of interest.
+ * ExecEndAppend
+ *
+ * Shuts down the subscans of the append node.
+ *
+ * Returns nothing of interest.
* ----------------------------------------------------------------
*/
void
-ExecEndAppend(Append *node)
+ExecEndAppend(Append * node)
{
- AppendState *unionstate;
- int nplans;
- List *unionplans;
- bool *initialized;
- int i;
- List *resultRelationInfoList;
- RelationInfo *resultRelationInfo;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- unionstate = node->unionstate;
- unionplans = node->unionplans;
- nplans = unionstate->as_nplans;
- initialized = unionstate->as_initialized;
-
- /* ----------------
- * shut down each of the subscans
- * ----------------
- */
- for(i = 0; i < nplans; i++) {
- if (initialized[i]==TRUE) {
- ExecEndNode( (Plan *) nth(i, unionplans), (Plan*)node );
- }
- }
-
- /* ----------------
- * close out the different result relations
- * ----------------
- */
- resultRelationInfoList = unionstate->as_result_relation_info_list;
- while (resultRelationInfoList != NIL) {
- Relation resultRelationDesc;
-
- resultRelationInfo = (RelationInfo*) lfirst(resultRelationInfoList);
- resultRelationDesc = resultRelationInfo->ri_RelationDesc;
- heap_close(resultRelationDesc);
- pfree(resultRelationInfo);
- resultRelationInfoList = lnext(resultRelationInfoList);
- }
- if (unionstate->as_result_relation_info_list)
- pfree(unionstate->as_result_relation_info_list);
-
- /* XXX should free unionstate->as_rtentries and unionstate->as_junkfilter_list here */
-}
+ AppendState *unionstate;
+ int nplans;
+ List *unionplans;
+ bool *initialized;
+ int i;
+ List *resultRelationInfoList;
+ RelationInfo *resultRelationInfo;
+
+ /* ----------------
+ * get information from the node
+ * ----------------
+ */
+ unionstate = node->unionstate;
+ unionplans = node->unionplans;
+ nplans = unionstate->as_nplans;
+ initialized = unionstate->as_initialized;
+
+ /* ----------------
+ * shut down each of the subscans
+ * ----------------
+ */
+ for (i = 0; i < nplans; i++)
+ {
+ if (initialized[i] == TRUE)
+ {
+ ExecEndNode((Plan *) nth(i, unionplans), (Plan *) node);
+ }
+ }
+
+ /* ----------------
+ * close out the different result relations
+ * ----------------
+ */
+ resultRelationInfoList = unionstate->as_result_relation_info_list;
+ while (resultRelationInfoList != NIL)
+ {
+ Relation resultRelationDesc;
+ resultRelationInfo = (RelationInfo *) lfirst(resultRelationInfoList);
+ resultRelationDesc = resultRelationInfo->ri_RelationDesc;
+ heap_close(resultRelationDesc);
+ pfree(resultRelationInfo);
+ resultRelationInfoList = lnext(resultRelationInfoList);
+ }
+ if (unionstate->as_result_relation_info_list)
+ pfree(unionstate->as_result_relation_info_list);
+
+ /*
+ * XXX should free unionstate->as_rtentries and
+ * unionstate->as_junkfilter_list here
+ */
+}
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index 0637a8dd282..1a96a1ee911 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* nodeGroup.c--
- * Routines to handle group nodes (used for queries with GROUP BY clause).
+ * Routines to handle group nodes (used for queries with GROUP BY clause).
*
* Copyright (c) 1994, Regents of the University of California
*
*
* DESCRIPTION
- * The Group node is designed for handling queries with a GROUP BY clause.
- * It's outer plan must be a sort node. It assumes that the tuples it gets
- * back from the outer plan is sorted in the order specified by the group
- * columns. (ie. tuples from the same group are consecutive)
+ * The Group node is designed for handling queries with a GROUP BY clause.
+ * It's outer plan must be a sort node. It assumes that the tuples it gets
+ * back from the outer plan is sorted in the order specified by the group
+ * columns. (ie. tuples from the same group are consecutive)
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.5 1997/01/10 20:17:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.6 1997/09/07 04:41:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,329 +28,348 @@
#include "executor/executor.h"
#include "executor/nodeGroup.h"
-static TupleTableSlot *ExecGroupEveryTuple(Group *node);
-static TupleTableSlot *ExecGroupOneTuple(Group *node);
-static bool sameGroup(TupleTableSlot *oldslot, TupleTableSlot *newslot,
- int numCols, AttrNumber *grpColIdx, TupleDesc tupdesc);
+static TupleTableSlot *ExecGroupEveryTuple(Group * node);
+static TupleTableSlot *ExecGroupOneTuple(Group * node);
+static bool
+sameGroup(TupleTableSlot * oldslot, TupleTableSlot * newslot,
+ int numCols, AttrNumber * grpColIdx, TupleDesc tupdesc);
/* ---------------------------------------
- * ExecGroup -
+ * ExecGroup -
*
- * There are two modes in which tuples are returned by ExecGroup. If
- * tuplePerGroup is TRUE, every tuple from the same group will be
- * returned, followed by a NULL at the end of each group. This is
- * useful for Agg node which needs to aggregate over tuples of the same
- * group. (eg. SELECT salary, count{*} FROM emp GROUP BY salary)
+ * There are two modes in which tuples are returned by ExecGroup. If
+ * tuplePerGroup is TRUE, every tuple from the same group will be
+ * returned, followed by a NULL at the end of each group. This is
+ * useful for Agg node which needs to aggregate over tuples of the same
+ * group. (eg. SELECT salary, count{*} FROM emp GROUP BY salary)
*
- * If tuplePerGroup is FALSE, only one tuple per group is returned. The
- * tuple returned contains only the group columns. NULL is returned only
- * at the end when no more groups is present. This is useful when
- * the query does not involve aggregates. (eg. SELECT salary FROM emp
- * GROUP BY salary)
+ * If tuplePerGroup is FALSE, only one tuple per group is returned. The
+ * tuple returned contains only the group columns. NULL is returned only
+ * at the end when no more groups is present. This is useful when
+ * the query does not involve aggregates. (eg. SELECT salary FROM emp
+ * GROUP BY salary)
* ------------------------------------------
*/
TupleTableSlot *
-ExecGroup(Group *node)
+ExecGroup(Group * node)
{
- if (node->tuplePerGroup)
- return ExecGroupEveryTuple(node);
- else
- return ExecGroupOneTuple(node);
+ if (node->tuplePerGroup)
+ return ExecGroupEveryTuple(node);
+ else
+ return ExecGroupOneTuple(node);
}
/*
* ExecGroupEveryTuple -
- * return every tuple with a NULL between each group
+ * return every tuple with a NULL between each group
*/
static TupleTableSlot *
-ExecGroupEveryTuple(Group *node)
+ExecGroupEveryTuple(Group * node)
{
- GroupState *grpstate;
- EState *estate;
- ExprContext *econtext;
+ GroupState *grpstate;
+ EState *estate;
+ ExprContext *econtext;
- HeapTuple outerTuple = NULL;
- TupleTableSlot *outerslot, *lastslot;
- ProjectionInfo *projInfo;
- TupleTableSlot *resultSlot;
+ HeapTuple outerTuple = NULL;
+ TupleTableSlot *outerslot,
+ *lastslot;
+ ProjectionInfo *projInfo;
+ TupleTableSlot *resultSlot;
- bool isDone;
+ bool isDone;
- /* ---------------------
- * get state info from node
- * ---------------------
- */
- grpstate = node->grpstate;
- if (grpstate->grp_done)
- return NULL;
+ /* ---------------------
+ * get state info from node
+ * ---------------------
+ */
+ grpstate = node->grpstate;
+ if (grpstate->grp_done)
+ return NULL;
- estate = node->plan.state;
+ estate = node->plan.state;
- econtext = grpstate->csstate.cstate.cs_ExprContext;
+ econtext = grpstate->csstate.cstate.cs_ExprContext;
- if (grpstate->grp_useLastTuple) {
- /*
- * we haven't returned last tuple yet because it is not of the
- * same group
- */
- grpstate->grp_useLastTuple = FALSE;
+ if (grpstate->grp_useLastTuple)
+ {
+
+ /*
+ * we haven't returned last tuple yet because it is not of the
+ * same group
+ */
+ grpstate->grp_useLastTuple = FALSE;
- ExecStoreTuple(grpstate->grp_lastSlot->val,
- grpstate->csstate.css_ScanTupleSlot,
- grpstate->grp_lastSlot->ttc_buffer,
- false);
- } else {
- outerslot = ExecProcNode(outerPlan(node), (Plan*)node);
- if (outerslot)
- outerTuple = outerslot->val;
- if (!HeapTupleIsValid(outerTuple)) {
- grpstate->grp_done = TRUE;
- return NULL;
+ ExecStoreTuple(grpstate->grp_lastSlot->val,
+ grpstate->csstate.css_ScanTupleSlot,
+ grpstate->grp_lastSlot->ttc_buffer,
+ false);
+ }
+ else
+ {
+ outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
+ if (outerslot)
+ outerTuple = outerslot->val;
+ if (!HeapTupleIsValid(outerTuple))
+ {
+ grpstate->grp_done = TRUE;
+ return NULL;
+ }
+
+ /* ----------------
+ * Compare with last tuple and see if this tuple is of
+ * the same group.
+ * ----------------
+ */
+ lastslot = grpstate->csstate.css_ScanTupleSlot;
+
+ if (lastslot->val != NULL &&
+ (!sameGroup(lastslot, outerslot,
+ node->numCols, node->grpColIdx,
+ ExecGetScanType(&grpstate->csstate))))
+ {
+/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
+
+ grpstate->grp_useLastTuple = TRUE;
+
+ /* save it for next time */
+ grpstate->grp_lastSlot = outerslot;
+
+ /*
+ * signifies the end of the group
+ */
+ return NULL;
+ }
+
+ ExecStoreTuple(outerTuple,
+ grpstate->csstate.css_ScanTupleSlot,
+ outerslot->ttc_buffer,
+ false);
}
/* ----------------
- * Compare with last tuple and see if this tuple is of
- * the same group.
+ * form a projection tuple, store it in the result tuple
+ * slot and return it.
* ----------------
*/
- lastslot = grpstate->csstate.css_ScanTupleSlot;
-
- if (lastslot->val != NULL &&
- (!sameGroup(lastslot, outerslot,
- node->numCols, node->grpColIdx,
- ExecGetScanType(&grpstate->csstate)))) {
-/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
-
- grpstate->grp_useLastTuple = TRUE;
+ projInfo = grpstate->csstate.cstate.cs_ProjInfo;
- /* save it for next time */
- grpstate->grp_lastSlot = outerslot;
+ econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
+ resultSlot = ExecProject(projInfo, &isDone);
- /*
- * signifies the end of the group
- */
- return NULL;
- }
-
- ExecStoreTuple(outerTuple,
- grpstate->csstate.css_ScanTupleSlot,
- outerslot->ttc_buffer,
- false);
- }
-
- /* ----------------
- * form a projection tuple, store it in the result tuple
- * slot and return it.
- * ----------------
- */
- projInfo = grpstate->csstate.cstate.cs_ProjInfo;
-
- econtext->ecxt_scantuple = grpstate->csstate.css_ScanTupleSlot;
- resultSlot = ExecProject(projInfo, &isDone);
-
- return resultSlot;
+ return resultSlot;
}
/*
* ExecGroupOneTuple -
- * returns one tuple per group, a NULL at the end when there are no more
- * tuples.
+ * returns one tuple per group, a NULL at the end when there are no more
+ * tuples.
*/
static TupleTableSlot *
-ExecGroupOneTuple(Group *node)
+ExecGroupOneTuple(Group * node)
{
- GroupState *grpstate;
- EState *estate;
- ExprContext *econtext;
+ GroupState *grpstate;
+ EState *estate;
+ ExprContext *econtext;
- HeapTuple outerTuple = NULL;
- TupleTableSlot *outerslot, *lastslot;
- ProjectionInfo *projInfo;
- TupleTableSlot *resultSlot;
+ HeapTuple outerTuple = NULL;
+ TupleTableSlot *outerslot,
+ *lastslot;
+ ProjectionInfo *projInfo;
+ TupleTableSlot *resultSlot;
- bool isDone;
+ bool isDone;
- /* ---------------------
- * get state info from node
- * ---------------------
- */
- grpstate = node->grpstate;
- if (grpstate->grp_done)
- return NULL;
+ /* ---------------------
+ * get state info from node
+ * ---------------------
+ */
+ grpstate = node->grpstate;
+ if (grpstate->grp_done)
+ return NULL;
- estate = node->plan.state;
+ estate = node->plan.state;
- econtext = node->grpstate->csstate.cstate.cs_ExprContext;
+ econtext = node->grpstate->csstate.cstate.cs_ExprContext;
- if (grpstate->grp_useLastTuple) {
- grpstate->grp_useLastTuple = FALSE;
- ExecStoreTuple(grpstate->grp_lastSlot->val,
- grpstate->csstate.css_ScanTupleSlot,
- grpstate->grp_lastSlot->ttc_buffer,
- false);
- } else {
- outerslot = ExecProcNode(outerPlan(node), (Plan*)node);
- if (outerslot) outerTuple = outerslot->val;
- if (!HeapTupleIsValid(outerTuple)) {
- grpstate->grp_done = TRUE;
- return NULL;
+ if (grpstate->grp_useLastTuple)
+ {
+ grpstate->grp_useLastTuple = FALSE;
+ ExecStoreTuple(grpstate->grp_lastSlot->val,
+ grpstate->csstate.css_ScanTupleSlot,
+ grpstate->grp_lastSlot->ttc_buffer,
+ false);
}
- ExecStoreTuple(outerTuple,
- grpstate->csstate.css_ScanTupleSlot,
- outerslot->ttc_buffer,
- false);
- }
- lastslot = grpstate->csstate.css_ScanTupleSlot;
-
- /*
- * find all tuples that belong to a group
- */
- for(;;) {
- outerslot = ExecProcNode(outerPlan(node), (Plan*)node);
- outerTuple = (outerslot) ? outerslot->val : NULL;
- if (!HeapTupleIsValid(outerTuple)) {
- /*
- * we have at least one tuple (lastslot) if we reach here
- */
- grpstate->grp_done = TRUE;
-
- /* return lastslot */
- break;
+ else
+ {
+ outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
+ if (outerslot)
+ outerTuple = outerslot->val;
+ if (!HeapTupleIsValid(outerTuple))
+ {
+ grpstate->grp_done = TRUE;
+ return NULL;
+ }
+ ExecStoreTuple(outerTuple,
+ grpstate->csstate.css_ScanTupleSlot,
+ outerslot->ttc_buffer,
+ false);
}
+ lastslot = grpstate->csstate.css_ScanTupleSlot;
- /* ----------------
- * Compare with last tuple and see if this tuple is of
- * the same group.
- * ----------------
+ /*
+ * find all tuples that belong to a group
*/
- if ((!sameGroup(lastslot, outerslot,
- node->numCols, node->grpColIdx,
- ExecGetScanType(&grpstate->csstate)))) {
-/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
+ for (;;)
+ {
+ outerslot = ExecProcNode(outerPlan(node), (Plan *) node);
+ outerTuple = (outerslot) ? outerslot->val : NULL;
+ if (!HeapTupleIsValid(outerTuple))
+ {
+
+ /*
+ * we have at least one tuple (lastslot) if we reach here
+ */
+ grpstate->grp_done = TRUE;
+
+ /* return lastslot */
+ break;
+ }
+
+ /* ----------------
+ * Compare with last tuple and see if this tuple is of
+ * the same group.
+ * ----------------
+ */
+ if ((!sameGroup(lastslot, outerslot,
+ node->numCols, node->grpColIdx,
+ ExecGetScanType(&grpstate->csstate))))
+ {
+/* ExecGetResultType(&grpstate->csstate.cstate)))) {*/
+
+ grpstate->grp_useLastTuple = TRUE;
+
+ /* save it for next time */
+ grpstate->grp_lastSlot = outerslot;
+
+ /* return lastslot */
+ break;
+ }
+
+ ExecStoreTuple(outerTuple,
+ grpstate->csstate.css_ScanTupleSlot,
+ outerslot->ttc_buffer,
+ false);
+
+ lastslot = grpstate->csstate.css_ScanTupleSlot;
+ }
- grpstate->grp_useLastTuple = TRUE;
+ ExecStoreTuple(lastslot->val,
+ grpstate->csstate.css_ScanTupleSlot,
+ lastslot->ttc_buffer,
+ false);
- /* save it for next time */
- grpstate->grp_lastSlot = outerslot;
+ /* ----------------
+ * form a projection tuple, store it in the result tuple
+ * slot and return it.
+ * ----------------
+ */
+ projInfo = grpstate->csstate.cstate.cs_ProjInfo;
- /* return lastslot */
- break;
- }
-
- ExecStoreTuple(outerTuple,
- grpstate->csstate.css_ScanTupleSlot,
- outerslot->ttc_buffer,
- false);
+ econtext->ecxt_scantuple = lastslot;
+ resultSlot = ExecProject(projInfo, &isDone);
- lastslot = grpstate->csstate.css_ScanTupleSlot;
- }
-
- ExecStoreTuple(lastslot->val,
- grpstate->csstate.css_ScanTupleSlot,
- lastslot->ttc_buffer,
- false);
-
- /* ----------------
- * form a projection tuple, store it in the result tuple
- * slot and return it.
- * ----------------
- */
- projInfo = grpstate->csstate.cstate.cs_ProjInfo;
-
- econtext->ecxt_scantuple = lastslot;
- resultSlot = ExecProject(projInfo, &isDone);
-
- return resultSlot;
+ return resultSlot;
}
/* -----------------
- * ExecInitGroup
+ * ExecInitGroup
*
- * Creates the run-time information for the group node produced by the
- * planner and initializes its outer subtree
+ * Creates the run-time information for the group node produced by the
+ * planner and initializes its outer subtree
* -----------------
*/
bool
-ExecInitGroup(Group *node, EState *estate, Plan *parent)
+ExecInitGroup(Group * node, EState * estate, Plan * parent)
{
- GroupState *grpstate;
- Plan *outerPlan;
-
- /*
- * assign the node's execution state
- */
- node->plan.state = estate;
-
- /*
- * create state structure
- */
- grpstate = makeNode(GroupState);
- node->grpstate = grpstate;
- grpstate->grp_useLastTuple = FALSE;
- grpstate->grp_done = FALSE;
-
- /*
- * assign node's base id and create expression context
- */
- ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,
- (Plan*) parent);
- ExecAssignExprContext(estate, &grpstate->csstate.cstate);
-
+ GroupState *grpstate;
+ Plan *outerPlan;
+
+ /*
+ * assign the node's execution state
+ */
+ node->plan.state = estate;
+
+ /*
+ * create state structure
+ */
+ grpstate = makeNode(GroupState);
+ node->grpstate = grpstate;
+ grpstate->grp_useLastTuple = FALSE;
+ grpstate->grp_done = FALSE;
+
+ /*
+ * assign node's base id and create expression context
+ */
+ ExecAssignNodeBaseInfo(estate, &grpstate->csstate.cstate,
+ (Plan *) parent);
+ ExecAssignExprContext(estate, &grpstate->csstate.cstate);
+
#define GROUP_NSLOTS 2
- /*
- * tuple table initialization
- */
- ExecInitScanTupleSlot(estate, &grpstate->csstate);
- ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
-
- /*
- * initializes child nodes
- */
- outerPlan = outerPlan(node);
- ExecInitNode(outerPlan, estate, (Plan *)node);
-
- /* ----------------
- * initialize tuple type.
- * ----------------
- */
- ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
-
- /*
- * Initialize tuple type for both result and scan.
- * This node does no projection
- */
- ExecAssignResultTypeFromTL((Plan*) node, &grpstate->csstate.cstate);
- ExecAssignProjectionInfo((Plan*)node, &grpstate->csstate.cstate);
-
- return TRUE;
+
+ /*
+ * tuple table initialization
+ */
+ ExecInitScanTupleSlot(estate, &grpstate->csstate);
+ ExecInitResultTupleSlot(estate, &grpstate->csstate.cstate);
+
+ /*
+ * initializes child nodes
+ */
+ outerPlan = outerPlan(node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * initialize tuple type.
+ * ----------------
+ */
+ ExecAssignScanTypeFromOuterPlan((Plan *) node, &grpstate->csstate);
+
+ /*
+ * Initialize tuple type for both result and scan. This node does no
+ * projection
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &grpstate->csstate.cstate);
+ ExecAssignProjectionInfo((Plan *) node, &grpstate->csstate.cstate);
+
+ return TRUE;
}
int
-ExecCountSlotsGroup(Group *node)
+ExecCountSlotsGroup(Group * node)
{
- return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
+ return ExecCountSlotsNode(outerPlan(node)) + GROUP_NSLOTS;
}
/* ------------------------
- * ExecEndGroup(node)
+ * ExecEndGroup(node)
*
* -----------------------
*/
void
-ExecEndGroup(Group *node)
+ExecEndGroup(Group * node)
{
- GroupState *grpstate;
- Plan *outerPlan;
+ GroupState *grpstate;
+ Plan *outerPlan;
+
+ grpstate = node->grpstate;
- grpstate = node->grpstate;
+ ExecFreeProjectionInfo(&grpstate->csstate.cstate);
- ExecFreeProjectionInfo(&grpstate->csstate.cstate);
+ outerPlan = outerPlan(node);
+ ExecEndNode(outerPlan, (Plan *) node);
- outerPlan = outerPlan(node);
- ExecEndNode(outerPlan, (Plan*)node);
-
- /* clean up tuple table */
- ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
+ /* clean up tuple table */
+ ExecClearTuple(grpstate->csstate.css_ScanTupleSlot);
}
/*****************************************************************************
@@ -360,54 +379,63 @@ ExecEndGroup(Group *node)
/*
* code swiped from nodeUnique.c
*/
-static bool
-sameGroup(TupleTableSlot *oldslot,
- TupleTableSlot *newslot,
- int numCols,
- AttrNumber *grpColIdx,
- TupleDesc tupdesc)
+static bool
+sameGroup(TupleTableSlot * oldslot,
+ TupleTableSlot * newslot,
+ int numCols,
+ AttrNumber * grpColIdx,
+ TupleDesc tupdesc)
{
- bool isNull1,isNull2;
- char *attr1, *attr2;
- char *val1, *val2;
- int i;
- AttrNumber att;
- Oid typoutput;
-
- for(i = 0; i < numCols; i++) {
- att = grpColIdx[i];
- typoutput = typtoout((Oid)tupdesc->attrs[att-1]->atttypid);
-
- attr1 = heap_getattr(oldslot->val,
- InvalidBuffer,
- att,
- tupdesc,
- &isNull1);
-
- attr2 = heap_getattr(newslot->val,
- InvalidBuffer,
- att,
- tupdesc,
- &isNull2);
-
- if (isNull1 == isNull2) {
- if (isNull1) /* both are null, they are equal */
- continue;
-
- val1 = fmgr(typoutput, attr1,
- gettypelem(tupdesc->attrs[att-1]->atttypid));
- val2 = fmgr(typoutput, attr2,
- gettypelem(tupdesc->attrs[att-1]->atttypid));
-
- /* now, val1 and val2 are ascii representations so we can
- use strcmp for comparison */
- if (strcmp(val1,val2) != 0)
- return FALSE;
- } else {
- /* one is null and the other isn't, they aren't equal */
- return FALSE;
+ bool isNull1,
+ isNull2;
+ char *attr1,
+ *attr2;
+ char *val1,
+ *val2;
+ int i;
+ AttrNumber att;
+ Oid typoutput;
+
+ for (i = 0; i < numCols; i++)
+ {
+ att = grpColIdx[i];
+ typoutput = typtoout((Oid) tupdesc->attrs[att - 1]->atttypid);
+
+ attr1 = heap_getattr(oldslot->val,
+ InvalidBuffer,
+ att,
+ tupdesc,
+ &isNull1);
+
+ attr2 = heap_getattr(newslot->val,
+ InvalidBuffer,
+ att,
+ tupdesc,
+ &isNull2);
+
+ if (isNull1 == isNull2)
+ {
+ if (isNull1) /* both are null, they are equal */
+ continue;
+
+ val1 = fmgr(typoutput, attr1,
+ gettypelem(tupdesc->attrs[att - 1]->atttypid));
+ val2 = fmgr(typoutput, attr2,
+ gettypelem(tupdesc->attrs[att - 1]->atttypid));
+
+ /*
+ * now, val1 and val2 are ascii representations so we can use
+ * strcmp for comparison
+ */
+ if (strcmp(val1, val2) != 0)
+ return FALSE;
+ }
+ else
+ {
+ /* one is null and the other isn't, they aren't equal */
+ return FALSE;
+ }
}
- }
- return TRUE;
+ return TRUE;
}
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 10bfe9842cf..b25939fa832 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -1,26 +1,26 @@
/*-------------------------------------------------------------------------
*
* nodeHash.c--
- * Routines to hash relations for hashjoin
+ * Routines to hash relations for hashjoin
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.10 1997/08/19 21:31:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHash.c,v 1.11 1997/09/07 04:41:32 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecHash - generate an in-memory hash table of the relation
- * ExecInitHash - initialize node and subnodes..
- * ExecEndHash - shutdown node and subnodes
+ * ExecHash - generate an in-memory hash table of the relation
+ * ExecInitHash - initialize node and subnodes..
+ * ExecEndHash - shutdown node and subnodes
*
*/
#include <sys/types.h>
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <math.h>
#include <string.h>
#include <sys/file.h>
@@ -32,9 +32,9 @@
#include "postgres.h"
-#include "storage/fd.h" /* for SEEK_ */
+#include "storage/fd.h" /* for SEEK_ */
#include "storage/ipc.h"
-#include "storage/bufmgr.h" /* for BLCKSZ */
+#include "storage/bufmgr.h" /* for BLCKSZ */
#include "executor/executor.h"
#include "executor/nodeHash.h"
#include "executor/nodeHashjoin.h"
@@ -42,827 +42,855 @@
#include "utils/palloc.h"
#include "utils/hsearch.h"
-extern int NBuffers;
-static int HashTBSize;
+extern int NBuffers;
+static int HashTBSize;
-static void mk_hj_temp(char *tempname);
-static int hashFunc(char *key, int len);
-static int ExecHashPartition(Hash *node);
+static void mk_hj_temp(char *tempname);
+static int hashFunc(char *key, int len);
+static int ExecHashPartition(Hash * node);
static RelativeAddr hashTableAlloc(int size, HashJoinTable hashtable);
-static void ExecHashOverflowInsert(HashJoinTable hashtable,
- HashBucket bucket,
- HeapTuple heapTuple);
+static void
+ExecHashOverflowInsert(HashJoinTable hashtable,
+ HashBucket bucket,
+ HeapTuple heapTuple);
/* ----------------------------------------------------------------
- * ExecHash
+ * ExecHash
*
- * build hash table for hashjoin, all do partitioning if more
- * than one batches are required.
+ * build hash table for hashjoin, all do partitioning if more
+ * than one batches are required.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecHash(Hash *node)
+ExecHash(Hash * node)
{
- EState *estate;
- HashState *hashstate;
- Plan *outerNode;
- Var *hashkey;
- HashJoinTable hashtable;
- TupleTableSlot *slot;
- ExprContext *econtext;
-
- int nbatch;
- File *batches = NULL;
- RelativeAddr *batchPos;
- int *batchSizes;
- int i;
- RelativeAddr *innerbatchNames;
-
- /* ----------------
- * get state info from node
- * ----------------
- */
-
- hashstate = node->hashstate;
- estate = node->plan.state;
- outerNode = outerPlan(node);
-
- hashtable = node->hashtable;
- if (hashtable == NULL)
- elog(WARN, "ExecHash: hash table is NULL.");
-
- nbatch = hashtable->nbatch;
-
- if (nbatch > 0) { /* if needs hash partition */
- innerbatchNames = (RelativeAddr *) ABSADDR(hashtable->innerbatchNames);
-
- /* --------------
- * allocate space for the file descriptors of batch files
- * then open the batch files in the current processes.
- * --------------
- */
- batches = (File*)palloc(nbatch * sizeof(File));
- for (i=0; i<nbatch; i++) {
- batches[i] = FileNameOpenFile(ABSADDR(innerbatchNames[i]),
- O_CREAT | O_RDWR, 0600);
+ EState *estate;
+ HashState *hashstate;
+ Plan *outerNode;
+ Var *hashkey;
+ HashJoinTable hashtable;
+ TupleTableSlot *slot;
+ ExprContext *econtext;
+
+ int nbatch;
+ File *batches = NULL;
+ RelativeAddr *batchPos;
+ int *batchSizes;
+ int i;
+ RelativeAddr *innerbatchNames;
+
+ /* ----------------
+ * get state info from node
+ * ----------------
+ */
+
+ hashstate = node->hashstate;
+ estate = node->plan.state;
+ outerNode = outerPlan(node);
+
+ hashtable = node->hashtable;
+ if (hashtable == NULL)
+ elog(WARN, "ExecHash: hash table is NULL.");
+
+ nbatch = hashtable->nbatch;
+
+ if (nbatch > 0)
+ { /* if needs hash partition */
+ innerbatchNames = (RelativeAddr *) ABSADDR(hashtable->innerbatchNames);
+
+ /* --------------
+ * allocate space for the file descriptors of batch files
+ * then open the batch files in the current processes.
+ * --------------
+ */
+ batches = (File *) palloc(nbatch * sizeof(File));
+ for (i = 0; i < nbatch; i++)
+ {
+ batches[i] = FileNameOpenFile(ABSADDR(innerbatchNames[i]),
+ O_CREAT | O_RDWR, 0600);
+ }
+ hashstate->hashBatches = batches;
+ batchPos = (RelativeAddr *) ABSADDR(hashtable->innerbatchPos);
+ batchSizes = (int *) ABSADDR(hashtable->innerbatchSizes);
+ }
+
+ /* ----------------
+ * set expression context
+ * ----------------
+ */
+ hashkey = node->hashkey;
+ econtext = hashstate->cstate.cs_ExprContext;
+
+ /* ----------------
+ * get tuple and insert into the hash table
+ * ----------------
+ */
+ for (;;)
+ {
+ slot = ExecProcNode(outerNode, (Plan *) node);
+ if (TupIsNull(slot))
+ break;
+
+ econtext->ecxt_innertuple = slot;
+ ExecHashTableInsert(hashtable, econtext, hashkey,
+ hashstate->hashBatches);
+
+ ExecClearTuple(slot);
+ }
+
+ /*
+ * end of build phase, flush all the last pages of the batches.
+ */
+ for (i = 0; i < nbatch; i++)
+ {
+ if (FileSeek(batches[i], 0L, SEEK_END) < 0)
+ perror("FileSeek");
+ if (FileWrite(batches[i], ABSADDR(hashtable->batch) + i * BLCKSZ, BLCKSZ) < 0)
+ perror("FileWrite");
+ NDirectFileWrite++;
}
- hashstate->hashBatches = batches;
- batchPos = (RelativeAddr*) ABSADDR(hashtable->innerbatchPos);
- batchSizes = (int*) ABSADDR(hashtable->innerbatchSizes);
- }
-
- /* ----------------
- * set expression context
- * ----------------
- */
- hashkey = node->hashkey;
- econtext = hashstate->cstate.cs_ExprContext;
-
- /* ----------------
- * get tuple and insert into the hash table
- * ----------------
- */
- for (;;) {
- slot = ExecProcNode(outerNode, (Plan*)node);
- if (TupIsNull(slot))
- break;
-
- econtext->ecxt_innertuple = slot;
- ExecHashTableInsert(hashtable, econtext, hashkey,
- hashstate->hashBatches);
-
- ExecClearTuple(slot);
- }
-
- /*
- * end of build phase, flush all the last pages of the batches.
- */
- for (i=0; i<nbatch; i++) {
- if (FileSeek(batches[i], 0L, SEEK_END) < 0)
- perror("FileSeek");
- if (FileWrite(batches[i],ABSADDR(hashtable->batch)+i*BLCKSZ,BLCKSZ) < 0)
- perror("FileWrite");
- NDirectFileWrite++;
- }
-
- /* ---------------------
- * Return the slot so that we have the tuple descriptor
- * when we need to save/restore them. -Jeff 11 July 1991
- * ---------------------
- */
- return slot;
+
+ /* ---------------------
+ * Return the slot so that we have the tuple descriptor
+ * when we need to save/restore them. -Jeff 11 July 1991
+ * ---------------------
+ */
+ return slot;
}
/* ----------------------------------------------------------------
- * ExecInitHash
+ * ExecInitHash
*
- * Init routine for Hash node
+ * Init routine for Hash node
* ----------------------------------------------------------------
*/
bool
-ExecInitHash(Hash *node, EState *estate, Plan *parent)
+ExecInitHash(Hash * node, EState * estate, Plan * parent)
{
- HashState *hashstate;
- Plan *outerPlan;
-
- SO1_printf("ExecInitHash: %s\n",
- "initializing hash node");
-
- /* ----------------
- * assign the node's execution state
- * ----------------
- */
- node->plan.state = estate;
-
- /* ----------------
- * create state structure
- * ----------------
- */
- hashstate = makeNode(HashState);
- node->hashstate = hashstate;
- hashstate->hashBatches = NULL;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &hashstate->cstate, parent);
- ExecAssignExprContext(estate, &hashstate->cstate);
-
+ HashState *hashstate;
+ Plan *outerPlan;
+
+ SO1_printf("ExecInitHash: %s\n",
+ "initializing hash node");
+
+ /* ----------------
+ * assign the node's execution state
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create state structure
+ * ----------------
+ */
+ hashstate = makeNode(HashState);
+ node->hashstate = hashstate;
+ hashstate->hashBatches = NULL;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &hashstate->cstate, parent);
+ ExecAssignExprContext(estate, &hashstate->cstate);
+
#define HASH_NSLOTS 1
- /* ----------------
- * initialize our result slot
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &hashstate->cstate);
-
- /* ----------------
- * initializes child nodes
- * ----------------
- */
- outerPlan = outerPlan(node);
- ExecInitNode(outerPlan, estate, (Plan *)node);
-
- /* ----------------
- * initialize tuple type. no need to initialize projection
- * info because this node doesn't do projections
- * ----------------
- */
- ExecAssignResultTypeFromOuterPlan((Plan *) node, &hashstate->cstate);
- hashstate->cstate.cs_ProjInfo = NULL;
-
- return TRUE;
+ /* ----------------
+ * initialize our result slot
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &hashstate->cstate);
+
+ /* ----------------
+ * initializes child nodes
+ * ----------------
+ */
+ outerPlan = outerPlan(node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * initialize tuple type. no need to initialize projection
+ * info because this node doesn't do projections
+ * ----------------
+ */
+ ExecAssignResultTypeFromOuterPlan((Plan *) node, &hashstate->cstate);
+ hashstate->cstate.cs_ProjInfo = NULL;
+
+ return TRUE;
}
int
-ExecCountSlotsHash(Hash *node)
+ExecCountSlotsHash(Hash * node)
{
- return ExecCountSlotsNode(outerPlan(node)) +
+ return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
- HASH_NSLOTS;
+ HASH_NSLOTS;
}
/* ---------------------------------------------------------------
- * ExecEndHash
+ * ExecEndHash
*
- * clean up routine for Hash node
+ * clean up routine for Hash node
* ----------------------------------------------------------------
*/
void
-ExecEndHash(Hash *node)
+ExecEndHash(Hash * node)
{
- HashState *hashstate;
- Plan *outerPlan;
- File *batches;
-
- /* ----------------
- * get info from the hash state
- * ----------------
- */
- hashstate = node->hashstate;
- batches = hashstate->hashBatches;
- if (batches != NULL)
- pfree(batches);
-
- /* ----------------
- * free projection info. no need to free result type info
- * because that came from the outer plan...
- * ----------------
- */
- ExecFreeProjectionInfo(&hashstate->cstate);
-
- /* ----------------
- * shut down the subplan
- * ----------------
- */
- outerPlan = outerPlan(node);
- ExecEndNode(outerPlan, (Plan*)node);
-}
-
-static RelativeAddr
+ HashState *hashstate;
+ Plan *outerPlan;
+ File *batches;
+
+ /* ----------------
+ * get info from the hash state
+ * ----------------
+ */
+ hashstate = node->hashstate;
+ batches = hashstate->hashBatches;
+ if (batches != NULL)
+ pfree(batches);
+
+ /* ----------------
+ * free projection info. no need to free result type info
+ * because that came from the outer plan...
+ * ----------------
+ */
+ ExecFreeProjectionInfo(&hashstate->cstate);
+
+ /* ----------------
+ * shut down the subplan
+ * ----------------
+ */
+ outerPlan = outerPlan(node);
+ ExecEndNode(outerPlan, (Plan *) node);
+}
+
+static RelativeAddr
hashTableAlloc(int size, HashJoinTable hashtable)
{
- RelativeAddr p;
- p = hashtable->top;
- hashtable->top += size;
- return p;
+ RelativeAddr p;
+
+ p = hashtable->top;
+ hashtable->top += size;
+ return p;
}
/* ----------------------------------------------------------------
- * ExecHashTableCreate
+ * ExecHashTableCreate
*
- * create a hashtable in shared memory for hashjoin.
+ * create a hashtable in shared memory for hashjoin.
* ----------------------------------------------------------------
*/
-#define NTUP_PER_BUCKET 10
-#define FUDGE_FAC 1.5
+#define NTUP_PER_BUCKET 10
+#define FUDGE_FAC 1.5
HashJoinTable
-ExecHashTableCreate(Hash *node)
+ExecHashTableCreate(Hash * node)
{
- Plan *outerNode;
- int nbatch;
- int ntuples;
- int tupsize;
- IpcMemoryId shmid;
- HashJoinTable hashtable;
- HashBucket bucket;
- int nbuckets;
- int totalbuckets;
- int bucketsize;
- int i;
- RelativeAddr *outerbatchNames;
- RelativeAddr *outerbatchPos;
- RelativeAddr *innerbatchNames;
- RelativeAddr *innerbatchPos;
- int *innerbatchSizes;
- RelativeAddr tempname;
-
- nbatch = -1;
- HashTBSize = NBuffers/2;
- while (nbatch < 0) {
+ Plan *outerNode;
+ int nbatch;
+ int ntuples;
+ int tupsize;
+ IpcMemoryId shmid;
+ HashJoinTable hashtable;
+ HashBucket bucket;
+ int nbuckets;
+ int totalbuckets;
+ int bucketsize;
+ int i;
+ RelativeAddr *outerbatchNames;
+ RelativeAddr *outerbatchPos;
+ RelativeAddr *innerbatchNames;
+ RelativeAddr *innerbatchPos;
+ int *innerbatchSizes;
+ RelativeAddr tempname;
+
+ nbatch = -1;
+ HashTBSize = NBuffers / 2;
+ while (nbatch < 0)
+ {
+
+ /*
+ * determine number of batches for the hashjoin
+ */
+ HashTBSize *= 2;
+ nbatch = ExecHashPartition(node);
+ }
+ /* ----------------
+ * get information about the size of the relation
+ * ----------------
+ */
+ outerNode = outerPlan(node);
+ ntuples = outerNode->plan_size;
+ if (ntuples <= 0)
+ ntuples = 1000; /* XXX just a hack */
+ tupsize = outerNode->plan_width + sizeof(HeapTupleData);
+
+ /*
+ * totalbuckets is the total number of hash buckets needed for the
+ * entire relation
+ */
+ totalbuckets = ceil((double) ntuples / NTUP_PER_BUCKET);
+ bucketsize = LONGALIGN(NTUP_PER_BUCKET * tupsize + sizeof(*bucket));
+
/*
- * determine number of batches for the hashjoin
- */
- HashTBSize *= 2;
- nbatch = ExecHashPartition(node);
- }
- /* ----------------
- * get information about the size of the relation
- * ----------------
- */
- outerNode = outerPlan(node);
- ntuples = outerNode->plan_size;
- if (ntuples <= 0)
- ntuples = 1000; /* XXX just a hack */
- tupsize = outerNode->plan_width + sizeof(HeapTupleData);
-
- /*
- * totalbuckets is the total number of hash buckets needed for
- * the entire relation
- */
- totalbuckets = ceil((double)ntuples/NTUP_PER_BUCKET);
- bucketsize = LONGALIGN (NTUP_PER_BUCKET * tupsize + sizeof(*bucket));
-
- /*
- * nbuckets is the number of hash buckets for the first pass
- * of hybrid hashjoin
- */
- nbuckets = (HashTBSize - nbatch) * BLCKSZ / (bucketsize * FUDGE_FAC);
- if (totalbuckets < nbuckets)
- totalbuckets = nbuckets;
- if (nbatch == 0)
- nbuckets = totalbuckets;
+ * nbuckets is the number of hash buckets for the first pass of hybrid
+ * hashjoin
+ */
+ nbuckets = (HashTBSize - nbatch) * BLCKSZ / (bucketsize * FUDGE_FAC);
+ if (totalbuckets < nbuckets)
+ totalbuckets = nbuckets;
+ if (nbatch == 0)
+ nbuckets = totalbuckets;
#ifdef HJDEBUG
- printf("nbatch = %d, totalbuckets = %d, nbuckets = %d\n", nbatch, totalbuckets, nbuckets);
+ printf("nbatch = %d, totalbuckets = %d, nbuckets = %d\n", nbatch, totalbuckets, nbuckets);
#endif
-
- /* ----------------
- * in non-parallel machines, we don't need to put the hash table
- * in the shared memory. We just palloc it.
- * ----------------
- */
- hashtable = (HashJoinTable)palloc((HashTBSize+1)*BLCKSZ);
- shmid = 0;
-
- if (hashtable == NULL) {
- elog(WARN, "not enough memory for hashjoin.");
- }
- /* ----------------
- * initialize the hash table header
- * ----------------
- */
- hashtable->nbuckets = nbuckets;
- hashtable->totalbuckets = totalbuckets;
- hashtable->bucketsize = bucketsize;
- hashtable->shmid = shmid;
- hashtable->top = sizeof(HashTableData);
- hashtable->bottom = HashTBSize * BLCKSZ;
- /*
- * hashtable->readbuf has to be long aligned!!!
- */
- hashtable->readbuf = hashtable->bottom;
- hashtable->nbatch = nbatch;
- hashtable->curbatch = 0;
- hashtable->pcount = hashtable->nprocess = 0;
- if (nbatch > 0) {
- /* ---------------
- * allocate and initialize the outer batches
- * ---------------
- */
- outerbatchNames = (RelativeAddr*)ABSADDR(
- hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
- outerbatchPos = (RelativeAddr*)ABSADDR(
- hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
- for (i=0; i<nbatch; i++) {
- tempname = hashTableAlloc(12, hashtable);
- mk_hj_temp(ABSADDR(tempname));
- outerbatchNames[i] = tempname;
- outerbatchPos[i] = -1;
+
+ /* ----------------
+ * in non-parallel machines, we don't need to put the hash table
+ * in the shared memory. We just palloc it.
+ * ----------------
+ */
+ hashtable = (HashJoinTable) palloc((HashTBSize + 1) * BLCKSZ);
+ shmid = 0;
+
+ if (hashtable == NULL)
+ {
+ elog(WARN, "not enough memory for hashjoin.");
+ }
+ /* ----------------
+ * initialize the hash table header
+ * ----------------
+ */
+ hashtable->nbuckets = nbuckets;
+ hashtable->totalbuckets = totalbuckets;
+ hashtable->bucketsize = bucketsize;
+ hashtable->shmid = shmid;
+ hashtable->top = sizeof(HashTableData);
+ hashtable->bottom = HashTBSize * BLCKSZ;
+
+ /*
+ * hashtable->readbuf has to be long aligned!!!
+ */
+ hashtable->readbuf = hashtable->bottom;
+ hashtable->nbatch = nbatch;
+ hashtable->curbatch = 0;
+ hashtable->pcount = hashtable->nprocess = 0;
+ if (nbatch > 0)
+ {
+ /* ---------------
+ * allocate and initialize the outer batches
+ * ---------------
+ */
+ outerbatchNames = (RelativeAddr *) ABSADDR(
+ hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
+ outerbatchPos = (RelativeAddr *) ABSADDR(
+ hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
+ for (i = 0; i < nbatch; i++)
+ {
+ tempname = hashTableAlloc(12, hashtable);
+ mk_hj_temp(ABSADDR(tempname));
+ outerbatchNames[i] = tempname;
+ outerbatchPos[i] = -1;
+ }
+ hashtable->outerbatchNames = RELADDR(outerbatchNames);
+ hashtable->outerbatchPos = RELADDR(outerbatchPos);
+ /* ---------------
+ * allocate and initialize the inner batches
+ * ---------------
+ */
+ innerbatchNames = (RelativeAddr *) ABSADDR(
+ hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
+ innerbatchPos = (RelativeAddr *) ABSADDR(
+ hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
+ innerbatchSizes = (int *) ABSADDR(
+ hashTableAlloc(nbatch * sizeof(int), hashtable));
+ for (i = 0; i < nbatch; i++)
+ {
+ tempname = hashTableAlloc(12, hashtable);
+ mk_hj_temp(ABSADDR(tempname));
+ innerbatchNames[i] = tempname;
+ innerbatchPos[i] = -1;
+ innerbatchSizes[i] = 0;
+ }
+ hashtable->innerbatchNames = RELADDR(innerbatchNames);
+ hashtable->innerbatchPos = RELADDR(innerbatchPos);
+ hashtable->innerbatchSizes = RELADDR(innerbatchSizes);
}
- hashtable->outerbatchNames = RELADDR(outerbatchNames);
- hashtable->outerbatchPos = RELADDR(outerbatchPos);
- /* ---------------
- * allocate and initialize the inner batches
- * ---------------
- */
- innerbatchNames = (RelativeAddr*)ABSADDR(
- hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
- innerbatchPos = (RelativeAddr*)ABSADDR(
- hashTableAlloc(nbatch * sizeof(RelativeAddr), hashtable));
- innerbatchSizes = (int*)ABSADDR(
- hashTableAlloc(nbatch * sizeof(int), hashtable));
- for (i=0; i<nbatch; i++) {
- tempname = hashTableAlloc(12, hashtable);
- mk_hj_temp(ABSADDR(tempname));
- innerbatchNames[i] = tempname;
- innerbatchPos[i] = -1;
- innerbatchSizes[i] = 0;
+ else
+ {
+ hashtable->outerbatchNames = (RelativeAddr) NULL;
+ hashtable->outerbatchPos = (RelativeAddr) NULL;
+ hashtable->innerbatchNames = (RelativeAddr) NULL;
+ hashtable->innerbatchPos = (RelativeAddr) NULL;
+ hashtable->innerbatchSizes = (RelativeAddr) NULL;
}
- hashtable->innerbatchNames = RELADDR(innerbatchNames);
- hashtable->innerbatchPos = RELADDR(innerbatchPos);
- hashtable->innerbatchSizes = RELADDR(innerbatchSizes);
- }
- else {
- hashtable->outerbatchNames = (RelativeAddr)NULL;
- hashtable->outerbatchPos = (RelativeAddr)NULL;
- hashtable->innerbatchNames = (RelativeAddr)NULL;
- hashtable->innerbatchPos = (RelativeAddr)NULL;
- hashtable->innerbatchSizes = (RelativeAddr)NULL;
- }
-
- hashtable->batch = (RelativeAddr)LONGALIGN(hashtable->top +
- bucketsize * nbuckets);
- hashtable->overflownext=hashtable->batch + nbatch * BLCKSZ;
- /* ----------------
- * initialize each hash bucket
- * ----------------
- */
- bucket = (HashBucket)ABSADDR(hashtable->top);
- for (i=0; i<nbuckets; i++) {
- bucket->top = RELADDR((char*)bucket + sizeof(*bucket));
- bucket->bottom = bucket->top;
- bucket->firstotuple = bucket->lastotuple = -1;
- bucket = (HashBucket)LONGALIGN(((char*)bucket + bucketsize));
- }
- return(hashtable);
+
+ hashtable->batch = (RelativeAddr) LONGALIGN(hashtable->top +
+ bucketsize * nbuckets);
+ hashtable->overflownext = hashtable->batch + nbatch * BLCKSZ;
+ /* ----------------
+ * initialize each hash bucket
+ * ----------------
+ */
+ bucket = (HashBucket) ABSADDR(hashtable->top);
+ for (i = 0; i < nbuckets; i++)
+ {
+ bucket->top = RELADDR((char *) bucket + sizeof(*bucket));
+ bucket->bottom = bucket->top;
+ bucket->firstotuple = bucket->lastotuple = -1;
+ bucket = (HashBucket) LONGALIGN(((char *) bucket + bucketsize));
+ }
+ return (hashtable);
}
/* ----------------------------------------------------------------
- * ExecHashTableInsert
+ * ExecHashTableInsert
*
- * insert a tuple into the hash table depending on the hash value
- * it may just go to a tmp file for other batches
+ * insert a tuple into the hash table depending on the hash value
+ * it may just go to a tmp file for other batches
* ----------------------------------------------------------------
*/
void
ExecHashTableInsert(HashJoinTable hashtable,
- ExprContext *econtext,
- Var *hashkey,
- File *batches)
+ ExprContext * econtext,
+ Var * hashkey,
+ File * batches)
{
- TupleTableSlot *slot;
- HeapTuple heapTuple;
- HashBucket bucket;
- int bucketno;
- int nbatch;
- int batchno;
- char *buffer;
- RelativeAddr *batchPos;
- int *batchSizes;
- char *pos;
-
- nbatch = hashtable->nbatch;
- batchPos = (RelativeAddr*)ABSADDR(hashtable->innerbatchPos);
- batchSizes = (int*)ABSADDR(hashtable->innerbatchSizes);
-
- slot = econtext->ecxt_innertuple;
- heapTuple = slot->val;
-
+ TupleTableSlot *slot;
+ HeapTuple heapTuple;
+ HashBucket bucket;
+ int bucketno;
+ int nbatch;
+ int batchno;
+ char *buffer;
+ RelativeAddr *batchPos;
+ int *batchSizes;
+ char *pos;
+
+ nbatch = hashtable->nbatch;
+ batchPos = (RelativeAddr *) ABSADDR(hashtable->innerbatchPos);
+ batchSizes = (int *) ABSADDR(hashtable->innerbatchSizes);
+
+ slot = econtext->ecxt_innertuple;
+ heapTuple = slot->val;
+
#ifdef HJDEBUG
- printf("Inserting ");
+ printf("Inserting ");
#endif
-
- bucketno = ExecHashGetBucket(hashtable, econtext, hashkey);
-
- /* ----------------
- * decide whether to put the tuple in the hash table or a tmp file
- * ----------------
- */
- if (bucketno < hashtable->nbuckets) {
- /* ---------------
- * put the tuple in hash table
- * ---------------
- */
- bucket = (HashBucket)
- (ABSADDR(hashtable->top) + bucketno * hashtable->bucketsize);
- if ((char*)LONGALIGN(ABSADDR(bucket->bottom))
- -(char*)bucket+heapTuple->t_len > hashtable->bucketsize)
- ExecHashOverflowInsert(hashtable, bucket, heapTuple);
- else {
- memmove((char*)LONGALIGN(ABSADDR(bucket->bottom)),
- heapTuple,
- heapTuple->t_len);
- bucket->bottom =
- ((RelativeAddr)LONGALIGN(bucket->bottom) + heapTuple->t_len);
+
+ bucketno = ExecHashGetBucket(hashtable, econtext, hashkey);
+
+ /* ----------------
+ * decide whether to put the tuple in the hash table or a tmp file
+ * ----------------
+ */
+ if (bucketno < hashtable->nbuckets)
+ {
+ /* ---------------
+ * put the tuple in hash table
+ * ---------------
+ */
+ bucket = (HashBucket)
+ (ABSADDR(hashtable->top) + bucketno * hashtable->bucketsize);
+ if ((char *) LONGALIGN(ABSADDR(bucket->bottom))
+ - (char *) bucket + heapTuple->t_len > hashtable->bucketsize)
+ ExecHashOverflowInsert(hashtable, bucket, heapTuple);
+ else
+ {
+ memmove((char *) LONGALIGN(ABSADDR(bucket->bottom)),
+ heapTuple,
+ heapTuple->t_len);
+ bucket->bottom =
+ ((RelativeAddr) LONGALIGN(bucket->bottom) + heapTuple->t_len);
+ }
+ }
+ else
+ {
+ /* -----------------
+ * put the tuple into a tmp file for other batches
+ * -----------------
+ */
+ batchno = (float) (bucketno - hashtable->nbuckets) /
+ (float) (hashtable->totalbuckets - hashtable->nbuckets)
+ * nbatch;
+ buffer = ABSADDR(hashtable->batch) + batchno * BLCKSZ;
+ batchSizes[batchno]++;
+ pos = (char *)
+ ExecHashJoinSaveTuple(heapTuple,
+ buffer,
+ batches[batchno],
+ (char *) ABSADDR(batchPos[batchno]));
+ batchPos[batchno] = RELADDR(pos);
}
- }
- else {
- /* -----------------
- * put the tuple into a tmp file for other batches
- * -----------------
- */
- batchno = (float)(bucketno - hashtable->nbuckets)/
- (float)(hashtable->totalbuckets - hashtable->nbuckets)
- * nbatch;
- buffer = ABSADDR(hashtable->batch) + batchno * BLCKSZ;
- batchSizes[batchno]++;
- pos= (char *)
- ExecHashJoinSaveTuple(heapTuple,
- buffer,
- batches[batchno],
- (char*)ABSADDR(batchPos[batchno]));
- batchPos[batchno] = RELADDR(pos);
- }
}
/* ----------------------------------------------------------------
- * ExecHashTableDestroy
+ * ExecHashTableDestroy
*
- * destroy a hash table
+ * destroy a hash table
* ----------------------------------------------------------------
*/
void
ExecHashTableDestroy(HashJoinTable hashtable)
{
- pfree(hashtable);
+ pfree(hashtable);
}
/* ----------------------------------------------------------------
- * ExecHashGetBucket
+ * ExecHashGetBucket
*
- * Get the hash value for a tuple
+ * Get the hash value for a tuple
* ----------------------------------------------------------------
*/
int
ExecHashGetBucket(HashJoinTable hashtable,
- ExprContext *econtext,
- Var *hashkey)
+ ExprContext * econtext,
+ Var * hashkey)
{
- int bucketno;
- Datum keyval;
- bool isNull;
-
-
- /* ----------------
- * Get the join attribute value of the tuple
- * ----------------
- * ...It's quick hack - use ExecEvalExpr instead of ExecEvalVar:
- * hashkey may be T_ArrayRef, not just T_Var. - vadim 04/22/97
- */
- keyval = ExecEvalExpr((Node*)hashkey, econtext, &isNull, NULL);
-
- /*
- * keyval could be null, so we better point it to something
- * valid before trying to run hashFunc on it. --djm 8/17/96
- */
- if(isNull) {
- execConstByVal = 0;
- execConstLen = 0;
- keyval = (Datum)"";
- }
-
- /* ------------------
- * compute the hash function
- * ------------------
- */
- if (execConstByVal)
- bucketno =
- hashFunc((char *) &keyval, execConstLen) % hashtable->totalbuckets;
- else
- bucketno =
- hashFunc((char *) keyval, execConstLen) % hashtable->totalbuckets;
+ int bucketno;
+ Datum keyval;
+ bool isNull;
+
+
+ /* ----------------
+ * Get the join attribute value of the tuple
+ * ----------------
+ * ...It's quick hack - use ExecEvalExpr instead of ExecEvalVar:
+ * hashkey may be T_ArrayRef, not just T_Var. - vadim 04/22/97
+ */
+ keyval = ExecEvalExpr((Node *) hashkey, econtext, &isNull, NULL);
+
+ /*
+ * keyval could be null, so we better point it to something valid
+ * before trying to run hashFunc on it. --djm 8/17/96
+ */
+ if (isNull)
+ {
+ execConstByVal = 0;
+ execConstLen = 0;
+ keyval = (Datum) "";
+ }
+
+ /* ------------------
+ * compute the hash function
+ * ------------------
+ */
+ if (execConstByVal)
+ bucketno =
+ hashFunc((char *) &keyval, execConstLen) % hashtable->totalbuckets;
+ else
+ bucketno =
+ hashFunc((char *) keyval, execConstLen) % hashtable->totalbuckets;
#ifdef HJDEBUG
- if (bucketno >= hashtable->nbuckets)
- printf("hash(%d) = %d SAVED\n", keyval, bucketno);
- else
- printf("hash(%d) = %d\n", keyval, bucketno);
+ if (bucketno >= hashtable->nbuckets)
+ printf("hash(%d) = %d SAVED\n", keyval, bucketno);
+ else
+ printf("hash(%d) = %d\n", keyval, bucketno);
#endif
-
- return(bucketno);
+
+ return (bucketno);
}
/* ----------------------------------------------------------------
- * ExecHashOverflowInsert
+ * ExecHashOverflowInsert
*
- * insert into the overflow area of a hash bucket
+ * insert into the overflow area of a hash bucket
* ----------------------------------------------------------------
*/
static void
ExecHashOverflowInsert(HashJoinTable hashtable,
- HashBucket bucket,
- HeapTuple heapTuple)
+ HashBucket bucket,
+ HeapTuple heapTuple)
{
- OverflowTuple otuple;
- RelativeAddr newend;
- OverflowTuple firstotuple;
- OverflowTuple lastotuple;
-
- firstotuple = (OverflowTuple)ABSADDR(bucket->firstotuple);
- lastotuple = (OverflowTuple)ABSADDR(bucket->lastotuple);
- /* ----------------
- * see if we run out of overflow space
- * ----------------
- */
- newend = (RelativeAddr)LONGALIGN(hashtable->overflownext + sizeof(*otuple)
- + heapTuple->t_len);
- if (newend > hashtable->bottom) {
-#if 0
- elog(DEBUG, "hash table out of memory. expanding.");
- /* ------------------
- * XXX this is a temporary hack
- * eventually, recursive hash partitioning will be
- * implemented
- * ------------------
+ OverflowTuple otuple;
+ RelativeAddr newend;
+ OverflowTuple firstotuple;
+ OverflowTuple lastotuple;
+
+ firstotuple = (OverflowTuple) ABSADDR(bucket->firstotuple);
+ lastotuple = (OverflowTuple) ABSADDR(bucket->lastotuple);
+ /* ----------------
+ * see if we run out of overflow space
+ * ----------------
*/
- hashtable->readbuf = hashtable->bottom = 2 * hashtable->bottom;
- hashtable =
- (HashJoinTable)repalloc(hashtable, hashtable->bottom+BLCKSZ);
- if (hashtable == NULL) {
- perror("repalloc");
- elog(WARN, "can't expand hashtable.");
- }
+ newend = (RelativeAddr) LONGALIGN(hashtable->overflownext + sizeof(*otuple)
+ + heapTuple->t_len);
+ if (newend > hashtable->bottom)
+ {
+#if 0
+ elog(DEBUG, "hash table out of memory. expanding.");
+ /* ------------------
+ * XXX this is a temporary hack
+ * eventually, recursive hash partitioning will be
+ * implemented
+ * ------------------
+ */
+ hashtable->readbuf = hashtable->bottom = 2 * hashtable->bottom;
+ hashtable =
+ (HashJoinTable) repalloc(hashtable, hashtable->bottom + BLCKSZ);
+ if (hashtable == NULL)
+ {
+ perror("repalloc");
+ elog(WARN, "can't expand hashtable.");
+ }
#else
- /* ------------------
- * XXX the temporary hack above doesn't work because things
- * above us don't know that we've moved the hash table!
- * - Chris Dunlop, <[email protected]>
- * ------------------
- */
- elog(WARN, "hash table out of memory. Use -B parameter to increase buffers.");
+ /* ------------------
+ * XXX the temporary hack above doesn't work because things
+ * above us don't know that we've moved the hash table!
+ * - Chris Dunlop, <[email protected]>
+ * ------------------
+ */
+ elog(WARN, "hash table out of memory. Use -B parameter to increase buffers.");
#endif
- }
-
- /* ----------------
- * establish the overflow chain
- * ----------------
- */
- otuple = (OverflowTuple)ABSADDR(hashtable->overflownext);
- hashtable->overflownext = newend;
- if (firstotuple == NULL)
- bucket->firstotuple = bucket->lastotuple = RELADDR(otuple);
- else {
- lastotuple->next = RELADDR(otuple);
- bucket->lastotuple = RELADDR(otuple);
- }
-
- /* ----------------
- * copy the tuple into the overflow area
- * ----------------
- */
- otuple->next = -1;
- otuple->tuple = RELADDR(LONGALIGN(((char*)otuple + sizeof(*otuple))));
- memmove(ABSADDR(otuple->tuple),
- heapTuple,
- heapTuple->t_len);
+ }
+
+ /* ----------------
+ * establish the overflow chain
+ * ----------------
+ */
+ otuple = (OverflowTuple) ABSADDR(hashtable->overflownext);
+ hashtable->overflownext = newend;
+ if (firstotuple == NULL)
+ bucket->firstotuple = bucket->lastotuple = RELADDR(otuple);
+ else
+ {
+ lastotuple->next = RELADDR(otuple);
+ bucket->lastotuple = RELADDR(otuple);
+ }
+
+ /* ----------------
+ * copy the tuple into the overflow area
+ * ----------------
+ */
+ otuple->next = -1;
+ otuple->tuple = RELADDR(LONGALIGN(((char *) otuple + sizeof(*otuple))));
+ memmove(ABSADDR(otuple->tuple),
+ heapTuple,
+ heapTuple->t_len);
}
/* ----------------------------------------------------------------
- * ExecScanHashBucket
+ * ExecScanHashBucket
*
- * scan a hash bucket of matches
+ * scan a hash bucket of matches
* ----------------------------------------------------------------
*/
HeapTuple
-ExecScanHashBucket(HashJoinState *hjstate,
- HashBucket bucket,
- HeapTuple curtuple,
- List *hjclauses,
- ExprContext *econtext)
+ExecScanHashBucket(HashJoinState * hjstate,
+ HashBucket bucket,
+ HeapTuple curtuple,
+ List * hjclauses,
+ ExprContext * econtext)
{
- HeapTuple heapTuple;
- bool qualResult;
- OverflowTuple otuple = NULL;
- OverflowTuple curotuple;
- TupleTableSlot *inntuple;
- OverflowTuple firstotuple;
- OverflowTuple lastotuple;
- HashJoinTable hashtable;
-
- hashtable = hjstate->hj_HashTable;
- firstotuple = (OverflowTuple)ABSADDR(bucket->firstotuple);
- lastotuple = (OverflowTuple)ABSADDR(bucket->lastotuple);
-
- /* ----------------
- * search the hash bucket
- * ----------------
- */
- if (curtuple == NULL || curtuple < (HeapTuple)ABSADDR(bucket->bottom)) {
- if (curtuple == NULL)
- heapTuple = (HeapTuple)
- LONGALIGN(ABSADDR(bucket->top));
- else
- heapTuple = (HeapTuple)
- LONGALIGN(((char*)curtuple+curtuple->t_len));
-
- while (heapTuple < (HeapTuple)ABSADDR(bucket->bottom)) {
-
- inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
- hjstate->hj_HashTupleSlot, /* slot */
- InvalidBuffer,/* tuple has no buffer */
- false); /* do not pfree this tuple */
-
- econtext->ecxt_innertuple = inntuple;
- qualResult = ExecQual((List*)hjclauses, econtext);
-
- if (qualResult)
- return heapTuple;
-
- heapTuple = (HeapTuple)
- LONGALIGN(((char*)heapTuple+heapTuple->t_len));
+ HeapTuple heapTuple;
+ bool qualResult;
+ OverflowTuple otuple = NULL;
+ OverflowTuple curotuple;
+ TupleTableSlot *inntuple;
+ OverflowTuple firstotuple;
+ OverflowTuple lastotuple;
+ HashJoinTable hashtable;
+
+ hashtable = hjstate->hj_HashTable;
+ firstotuple = (OverflowTuple) ABSADDR(bucket->firstotuple);
+ lastotuple = (OverflowTuple) ABSADDR(bucket->lastotuple);
+
+ /* ----------------
+ * search the hash bucket
+ * ----------------
+ */
+ if (curtuple == NULL || curtuple < (HeapTuple) ABSADDR(bucket->bottom))
+ {
+ if (curtuple == NULL)
+ heapTuple = (HeapTuple)
+ LONGALIGN(ABSADDR(bucket->top));
+ else
+ heapTuple = (HeapTuple)
+ LONGALIGN(((char *) curtuple + curtuple->t_len));
+
+ while (heapTuple < (HeapTuple) ABSADDR(bucket->bottom))
+ {
+
+ inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
+ hjstate->hj_HashTupleSlot, /* slot */
+ InvalidBuffer, /* tuple has no buffer */
+ false); /* do not pfree this tuple */
+
+ econtext->ecxt_innertuple = inntuple;
+ qualResult = ExecQual((List *) hjclauses, econtext);
+
+ if (qualResult)
+ return heapTuple;
+
+ heapTuple = (HeapTuple)
+ LONGALIGN(((char *) heapTuple + heapTuple->t_len));
+ }
+
+ if (firstotuple == NULL)
+ return NULL;
+ otuple = firstotuple;
}
-
- if (firstotuple == NULL)
- return NULL;
- otuple = firstotuple;
- }
-
- /* ----------------
- * search the overflow area of the hash bucket
- * ----------------
- */
- if (otuple == NULL) {
- curotuple = hjstate->hj_CurOTuple;
- otuple = (OverflowTuple)ABSADDR(curotuple->next);
- }
-
- while (otuple != NULL) {
- heapTuple = (HeapTuple)ABSADDR(otuple->tuple);
-
- inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
- hjstate->hj_HashTupleSlot, /* slot */
- InvalidBuffer, /* SP?? this tuple has no buffer */
- false); /* do not pfree this tuple */
-
- econtext->ecxt_innertuple = inntuple;
- qualResult = ExecQual((List*)hjclauses, econtext);
-
- if (qualResult) {
- hjstate->hj_CurOTuple = otuple;
- return heapTuple;
+
+ /* ----------------
+ * search the overflow area of the hash bucket
+ * ----------------
+ */
+ if (otuple == NULL)
+ {
+ curotuple = hjstate->hj_CurOTuple;
+ otuple = (OverflowTuple) ABSADDR(curotuple->next);
+ }
+
+ while (otuple != NULL)
+ {
+ heapTuple = (HeapTuple) ABSADDR(otuple->tuple);
+
+ inntuple = ExecStoreTuple(heapTuple, /* tuple to store */
+ hjstate->hj_HashTupleSlot, /* slot */
+ InvalidBuffer, /* SP?? this tuple has
+ * no buffer */
+ false); /* do not pfree this tuple */
+
+ econtext->ecxt_innertuple = inntuple;
+ qualResult = ExecQual((List *) hjclauses, econtext);
+
+ if (qualResult)
+ {
+ hjstate->hj_CurOTuple = otuple;
+ return heapTuple;
+ }
+
+ otuple = (OverflowTuple) ABSADDR(otuple->next);
}
-
- otuple = (OverflowTuple)ABSADDR(otuple->next);
- }
-
- /* ----------------
- * no match
- * ----------------
- */
- return NULL;
+
+ /* ----------------
+ * no match
+ * ----------------
+ */
+ return NULL;
}
/* ----------------------------------------------------------------
- * hashFunc
+ * hashFunc
*
- * the hash function, copied from Margo
+ * the hash function, copied from Margo
* ----------------------------------------------------------------
*/
static int
hashFunc(char *key, int len)
{
- register unsigned int h;
- register int l;
- register unsigned char *k;
-
- /*
- * If this is a variable length type, then 'k' points
- * to a "struct varlena" and len == -1.
- * NOTE:
- * VARSIZE returns the "real" data length plus the sizeof the
- * "vl_len" attribute of varlena (the length information).
- * 'k' points to the beginning of the varlena struct, so
- * we have to use "VARDATA" to find the beginning of the "real"
- * data.
- */
- if (len == -1) {
- l = VARSIZE(key) - VARHDRSZ;
- k = (unsigned char*) VARDATA(key);
- } else {
- l = len;
- k = (unsigned char *) key;
- }
-
- h = 0;
-
- /*
- * Convert string to integer
- */
- while (l--) h = h * PRIME1 ^ (*k++);
- h %= PRIME2;
-
- return (h);
+ register unsigned int h;
+ register int l;
+ register unsigned char *k;
+
+ /*
+ * If this is a variable length type, then 'k' points to a "struct
+ * varlena" and len == -1. NOTE: VARSIZE returns the "real" data
+ * length plus the sizeof the "vl_len" attribute of varlena (the
+ * length information). 'k' points to the beginning of the varlena
+ * struct, so we have to use "VARDATA" to find the beginning of the
+ * "real" data.
+ */
+ if (len == -1)
+ {
+ l = VARSIZE(key) - VARHDRSZ;
+ k = (unsigned char *) VARDATA(key);
+ }
+ else
+ {
+ l = len;
+ k = (unsigned char *) key;
+ }
+
+ h = 0;
+
+ /*
+ * Convert string to integer
+ */
+ while (l--)
+ h = h * PRIME1 ^ (*k++);
+ h %= PRIME2;
+
+ return (h);
}
/* ----------------------------------------------------------------
- * ExecHashPartition
+ * ExecHashPartition
*
- * determine the number of batches needed for a hashjoin
+ * determine the number of batches needed for a hashjoin
* ----------------------------------------------------------------
*/
static int
-ExecHashPartition(Hash *node)
+ExecHashPartition(Hash * node)
{
- Plan *outerNode;
- int b;
- int pages;
- int ntuples;
- int tupsize;
-
- /*
- * get size information for plan node
- */
- outerNode = outerPlan(node);
- ntuples = outerNode->plan_size;
- if (ntuples == 0) ntuples = 1000;
- tupsize = outerNode->plan_width + sizeof(HeapTupleData);
- pages = ceil((double)ntuples * tupsize * FUDGE_FAC / BLCKSZ);
-
- /*
- * if amount of buffer space below hashjoin threshold,
- * return negative
- */
- if (ceil(sqrt((double)pages)) > HashTBSize)
- return -1;
- if (pages <= HashTBSize)
- b = 0; /* fit in memory, no partitioning */
- else
- b = ceil((double)(pages - HashTBSize)/(double)(HashTBSize - 1));
-
- return b;
+ Plan *outerNode;
+ int b;
+ int pages;
+ int ntuples;
+ int tupsize;
+
+ /*
+ * get size information for plan node
+ */
+ outerNode = outerPlan(node);
+ ntuples = outerNode->plan_size;
+ if (ntuples == 0)
+ ntuples = 1000;
+ tupsize = outerNode->plan_width + sizeof(HeapTupleData);
+ pages = ceil((double) ntuples * tupsize * FUDGE_FAC / BLCKSZ);
+
+ /*
+ * if amount of buffer space below hashjoin threshold, return negative
+ */
+ if (ceil(sqrt((double) pages)) > HashTBSize)
+ return -1;
+ if (pages <= HashTBSize)
+ b = 0; /* fit in memory, no partitioning */
+ else
+ b = ceil((double) (pages - HashTBSize) / (double) (HashTBSize - 1));
+
+ return b;
}
/* ----------------------------------------------------------------
- * ExecHashTableReset
+ * ExecHashTableReset
*
- * reset hash table header for new batch
+ * reset hash table header for new batch
* ----------------------------------------------------------------
*/
void
ExecHashTableReset(HashJoinTable hashtable, int ntuples)
{
- int i;
- HashBucket bucket;
-
- hashtable->nbuckets = hashtable->totalbuckets
- = ceil((double)ntuples/NTUP_PER_BUCKET);
-
- hashtable->overflownext = hashtable->top + hashtable->bucketsize *
- hashtable->nbuckets;
-
- bucket = (HashBucket)ABSADDR(hashtable->top);
- for (i=0; i<hashtable->nbuckets; i++) {
- bucket->top = RELADDR((char*)bucket + sizeof(*bucket));
- bucket->bottom = bucket->top;
- bucket->firstotuple = bucket->lastotuple = -1;
- bucket = (HashBucket)((char*)bucket + hashtable->bucketsize);
- }
- hashtable->pcount = hashtable->nprocess;
+ int i;
+ HashBucket bucket;
+
+ hashtable->nbuckets = hashtable->totalbuckets
+ = ceil((double) ntuples / NTUP_PER_BUCKET);
+
+ hashtable->overflownext = hashtable->top + hashtable->bucketsize *
+ hashtable->nbuckets;
+
+ bucket = (HashBucket) ABSADDR(hashtable->top);
+ for (i = 0; i < hashtable->nbuckets; i++)
+ {
+ bucket->top = RELADDR((char *) bucket + sizeof(*bucket));
+ bucket->bottom = bucket->top;
+ bucket->firstotuple = bucket->lastotuple = -1;
+ bucket = (HashBucket) ((char *) bucket + hashtable->bucketsize);
+ }
+ hashtable->pcount = hashtable->nprocess;
}
-static int hjtmpcnt = 0;
+static int hjtmpcnt = 0;
static void
mk_hj_temp(char *tempname)
{
- sprintf(tempname, "HJ%d.%d", (int)getpid(), hjtmpcnt);
- hjtmpcnt = (hjtmpcnt + 1) % 1000;
+ sprintf(tempname, "HJ%d.%d", (int) getpid(), hjtmpcnt);
+ hjtmpcnt = (hjtmpcnt + 1) % 1000;
}
-
-
-
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index c9f24efe193..3548e38cc86 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* nodeHashjoin.c--
- * Routines to handle hash join nodes
+ * Routines to handle hash join nodes
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.5 1997/08/19 21:31:09 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.6 1997/09/07 04:41:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,8 +20,8 @@
#include "postgres.h"
-#include "storage/bufmgr.h" /* for BLCKSZ */
-#include "storage/fd.h" /* for SEEK_ */
+#include "storage/bufmgr.h" /* for BLCKSZ */
+#include "storage/fd.h" /* for SEEK_ */
#include "executor/executor.h"
#include "executor/execdebug.h"
#include "executor/nodeHash.h"
@@ -33,775 +33,818 @@
#include "utils/palloc.h"
static TupleTableSlot *
-ExecHashJoinOuterGetTuple(Plan *node, Plan* parent, HashJoinState *hjstate);
+ ExecHashJoinOuterGetTuple(Plan * node, Plan * parent, HashJoinState * hjstate);
static TupleTableSlot *
-ExecHashJoinGetSavedTuple(HashJoinState *hjstate, char *buffer,
- File file, TupleTableSlot *tupleSlot, int *block, char **position);
+ExecHashJoinGetSavedTuple(HashJoinState * hjstate, char *buffer,
+ File file, TupleTableSlot * tupleSlot, int *block, char **position);
-static int ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable,
- int nbatch);
+static int
+ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable,
+ int nbatch);
-static int ExecHashJoinNewBatch(HashJoinState *hjstate);
+static int ExecHashJoinNewBatch(HashJoinState * hjstate);
/* ----------------------------------------------------------------
- * ExecHashJoin
+ * ExecHashJoin
*
- * This function implements the Hybrid Hashjoin algorithm.
- * recursive partitioning remains to be added.
- * Note: the relation we build hash table on is the inner
- * the other one is outer.
+ * This function implements the Hybrid Hashjoin algorithm.
+ * recursive partitioning remains to be added.
+ * Note: the relation we build hash table on is the inner
+ * the other one is outer.
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecHashJoin(HashJoin *node)
+TupleTableSlot * /* return: a tuple or NULL */
+ExecHashJoin(HashJoin * node)
{
- HashJoinState *hjstate;
- EState *estate;
- Plan *outerNode;
- Hash *hashNode;
- List *hjclauses;
- Expr *clause;
- List *qual;
- ScanDirection dir;
- TupleTableSlot *inntuple;
- Var *outerVar;
- ExprContext *econtext;
-
- HashJoinTable hashtable;
- int bucketno;
- HashBucket bucket;
- HeapTuple curtuple;
-
- bool qualResult;
-
- TupleTableSlot *outerTupleSlot;
- TupleTableSlot *innerTupleSlot;
- int nbatch;
- int curbatch;
- File *outerbatches;
- RelativeAddr *outerbatchNames;
- RelativeAddr *outerbatchPos;
- Var *innerhashkey;
- int batch;
- int batchno;
- char *buffer;
- int i;
- bool hashPhaseDone;
- char *pos;
-
- /* ----------------
- * get information from HashJoin node
- * ----------------
- */
- hjstate = node->hashjoinstate;
- hjclauses = node->hashclauses;
- clause = lfirst(hjclauses);
- estate = node->join.state;
- qual = node->join.qual;
- hashNode = (Hash *)innerPlan(node);
- outerNode = outerPlan(node);
- hashPhaseDone = node->hashdone;
-
- dir = estate->es_direction;
-
- /* -----------------
- * get information from HashJoin state
- * -----------------
- */
- hashtable = hjstate->hj_HashTable;
- bucket = hjstate->hj_CurBucket;
- curtuple = hjstate->hj_CurTuple;
-
- /* --------------------
- * initialize expression context
- * --------------------
- */
- econtext = hjstate->jstate.cs_ExprContext;
-
- if (hjstate->jstate.cs_TupFromTlist) {
- TupleTableSlot *result;
- bool isDone;
-
- result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
- if (!isDone)
- return result;
- }
- /* ----------------
- * if this is the first call, build the hash table for inner relation
- * ----------------
- */
- if (!hashPhaseDone) { /* if the hash phase not completed */
- hashtable = node->hashjointable;
- if (hashtable == NULL) { /* if the hash table has not been created */
- /* ----------------
- * create the hash table
- * ----------------
- */
- hashtable = ExecHashTableCreate(hashNode);
- hjstate->hj_HashTable = hashtable;
- innerhashkey = hashNode->hashkey;
- hjstate->hj_InnerHashKey = innerhashkey;
-
- /* ----------------
- * execute the Hash node, to build the hash table
- * ----------------
- */
- hashNode->hashtable = hashtable;
- innerTupleSlot = ExecProcNode((Plan *)hashNode, (Plan*) node);
- }
- bucket = NULL;
- curtuple = NULL;
- curbatch = 0;
- node->hashdone = true;
- }
- nbatch = hashtable->nbatch;
- outerbatches = hjstate->hj_OuterBatches;
- if (nbatch > 0 && outerbatches == NULL) { /* if needs hash partition */
+ HashJoinState *hjstate;
+ EState *estate;
+ Plan *outerNode;
+ Hash *hashNode;
+ List *hjclauses;
+ Expr *clause;
+ List *qual;
+ ScanDirection dir;
+ TupleTableSlot *inntuple;
+ Var *outerVar;
+ ExprContext *econtext;
+
+ HashJoinTable hashtable;
+ int bucketno;
+ HashBucket bucket;
+ HeapTuple curtuple;
+
+ bool qualResult;
+
+ TupleTableSlot *outerTupleSlot;
+ TupleTableSlot *innerTupleSlot;
+ int nbatch;
+ int curbatch;
+ File *outerbatches;
+ RelativeAddr *outerbatchNames;
+ RelativeAddr *outerbatchPos;
+ Var *innerhashkey;
+ int batch;
+ int batchno;
+ char *buffer;
+ int i;
+ bool hashPhaseDone;
+ char *pos;
+
+ /* ----------------
+ * get information from HashJoin node
+ * ----------------
+ */
+ hjstate = node->hashjoinstate;
+ hjclauses = node->hashclauses;
+ clause = lfirst(hjclauses);
+ estate = node->join.state;
+ qual = node->join.qual;
+ hashNode = (Hash *) innerPlan(node);
+ outerNode = outerPlan(node);
+ hashPhaseDone = node->hashdone;
+
+ dir = estate->es_direction;
+
/* -----------------
- * allocate space for file descriptors of outer batch files
- * then open the batch files in the current process
+ * get information from HashJoin state
* -----------------
*/
- innerhashkey = hashNode->hashkey;
- hjstate->hj_InnerHashKey = innerhashkey;
- outerbatchNames = (RelativeAddr*)
- ABSADDR(hashtable->outerbatchNames);
- outerbatches = (File*)
- palloc(nbatch * sizeof(File));
- for (i=0; i<nbatch; i++) {
- outerbatches[i] = FileNameOpenFile(
- ABSADDR(outerbatchNames[i]),
- O_CREAT | O_RDWR, 0600);
- }
- hjstate->hj_OuterBatches = outerbatches;
+ hashtable = hjstate->hj_HashTable;
+ bucket = hjstate->hj_CurBucket;
+ curtuple = hjstate->hj_CurTuple;
- /* ------------------
- * get the inner batch file descriptors from the
- * hash node
- * ------------------
- */
- hjstate->hj_InnerBatches =
- hashNode->hashstate->hashBatches;
- }
- outerbatchPos = (RelativeAddr*)ABSADDR(hashtable->outerbatchPos);
- curbatch = hashtable->curbatch;
- outerbatchNames = (RelativeAddr*)ABSADDR(hashtable->outerbatchNames);
-
- /* ----------------
- * Now get an outer tuple and probe into the hash table for matches
- * ----------------
- */
- outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
- outerVar = get_leftop(clause);
-
- bucketno = -1; /* if bucketno remains -1, means use old outer tuple */
- if (TupIsNull(outerTupleSlot)) {
- /*
- * if the current outer tuple is nil, get a new one
+ /* --------------------
+ * initialize expression context
+ * --------------------
*/
- outerTupleSlot = (TupleTableSlot*)
- ExecHashJoinOuterGetTuple(outerNode, (Plan*)node, hjstate);
-
- while (curbatch <= nbatch && TupIsNull(outerTupleSlot)) {
- /*
- * if the current batch runs out, switch to new batch
- */
- curbatch = ExecHashJoinNewBatch(hjstate);
- if (curbatch > nbatch) {
- /*
- * when the last batch runs out, clean up
- */
- ExecHashTableDestroy(hashtable);
- hjstate->hj_HashTable = NULL;
- return NULL;
- }
- else
- outerTupleSlot = (TupleTableSlot*)
- ExecHashJoinOuterGetTuple(outerNode, (Plan*)node, hjstate);
+ econtext = hjstate->jstate.cs_ExprContext;
+
+ if (hjstate->jstate.cs_TupFromTlist)
+ {
+ TupleTableSlot *result;
+ bool isDone;
+
+ result = ExecProject(hjstate->jstate.cs_ProjInfo, &isDone);
+ if (!isDone)
+ return result;
}
- /*
- * now we get an outer tuple, find the corresponding bucket for
- * this tuple from the hash table
- */
- econtext->ecxt_outertuple = outerTupleSlot;
-
-#ifdef HJDEBUG
- printf("Probing ");
-#endif
- bucketno = ExecHashGetBucket(hashtable, econtext, outerVar);
- bucket=(HashBucket)(ABSADDR(hashtable->top)
- + bucketno * hashtable->bucketsize);
- }
-
- for (;;) {
/* ----------------
- * Now we've got an outer tuple and the corresponding hash bucket,
- * but this tuple may not belong to the current batch.
+ * if this is the first call, build the hash table for inner relation
* ----------------
*/
- if (curbatch == 0 && bucketno != -1) /* if this is the first pass */
- batch = ExecHashJoinGetBatch(bucketno, hashtable, nbatch);
- else
- batch = 0;
- if (batch > 0) {
- /*
- * if the current outer tuple does not belong to
- * the current batch, save to the tmp file for
- * the corresponding batch.
- */
- buffer = ABSADDR(hashtable->batch) + (batch - 1) * BLCKSZ;
- batchno = batch - 1;
- pos = ExecHashJoinSaveTuple(outerTupleSlot->val,
- buffer,
- outerbatches[batchno],
- ABSADDR(outerbatchPos[batchno]));
-
- outerbatchPos[batchno] = RELADDR(pos);
+ if (!hashPhaseDone)
+ { /* if the hash phase not completed */
+ hashtable = node->hashjointable;
+ if (hashtable == NULL)
+ { /* if the hash table has not been created */
+ /* ----------------
+ * create the hash table
+ * ----------------
+ */
+ hashtable = ExecHashTableCreate(hashNode);
+ hjstate->hj_HashTable = hashtable;
+ innerhashkey = hashNode->hashkey;
+ hjstate->hj_InnerHashKey = innerhashkey;
+
+ /* ----------------
+ * execute the Hash node, to build the hash table
+ * ----------------
+ */
+ hashNode->hashtable = hashtable;
+ innerTupleSlot = ExecProcNode((Plan *) hashNode, (Plan *) node);
+ }
+ bucket = NULL;
+ curtuple = NULL;
+ curbatch = 0;
+ node->hashdone = true;
}
- else if (bucket != NULL) {
- do {
- /*
- * scan the hash bucket for matches
+ nbatch = hashtable->nbatch;
+ outerbatches = hjstate->hj_OuterBatches;
+ if (nbatch > 0 && outerbatches == NULL)
+ { /* if needs hash partition */
+ /* -----------------
+ * allocate space for file descriptors of outer batch files
+ * then open the batch files in the current process
+ * -----------------
*/
- curtuple = ExecScanHashBucket(hjstate,
- bucket,
- curtuple,
- hjclauses,
- econtext);
-
- if (curtuple != NULL) {
- /*
- * we've got a match, but still need to test qpqual
- */
- inntuple = ExecStoreTuple(curtuple,
- hjstate->hj_HashTupleSlot,
- InvalidBuffer,
- false); /* don't pfree this tuple */
-
- econtext->ecxt_innertuple = inntuple;
-
- /* ----------------
- * test to see if we pass the qualification
- * ----------------
- */
- qualResult = ExecQual((List*)qual, econtext);
-
- /* ----------------
- * if we pass the qual, then save state for next call and
- * have ExecProject form the projection, store it
- * in the tuple table, and return the slot.
- * ----------------
- */
- if (qualResult) {
- ProjectionInfo *projInfo;
- TupleTableSlot *result;
- bool isDone;
-
- hjstate->hj_CurBucket = bucket;
- hjstate->hj_CurTuple = curtuple;
- hashtable->curbatch = curbatch;
- hjstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
-
- projInfo = hjstate->jstate.cs_ProjInfo;
- result = ExecProject(projInfo, &isDone);
- hjstate->jstate.cs_TupFromTlist = !isDone;
- return result;
- }
+ innerhashkey = hashNode->hashkey;
+ hjstate->hj_InnerHashKey = innerhashkey;
+ outerbatchNames = (RelativeAddr *)
+ ABSADDR(hashtable->outerbatchNames);
+ outerbatches = (File *)
+ palloc(nbatch * sizeof(File));
+ for (i = 0; i < nbatch; i++)
+ {
+ outerbatches[i] = FileNameOpenFile(
+ ABSADDR(outerbatchNames[i]),
+ O_CREAT | O_RDWR, 0600);
}
- }
- while (curtuple != NULL);
+ hjstate->hj_OuterBatches = outerbatches;
+
+ /* ------------------
+ * get the inner batch file descriptors from the
+ * hash node
+ * ------------------
+ */
+ hjstate->hj_InnerBatches =
+ hashNode->hashstate->hashBatches;
}
-
+ outerbatchPos = (RelativeAddr *) ABSADDR(hashtable->outerbatchPos);
+ curbatch = hashtable->curbatch;
+ outerbatchNames = (RelativeAddr *) ABSADDR(hashtable->outerbatchNames);
+
/* ----------------
- * Now the current outer tuple has run out of matches,
- * so we free it and get a new outer tuple.
+ * Now get an outer tuple and probe into the hash table for matches
* ----------------
*/
- outerTupleSlot = (TupleTableSlot*)
- ExecHashJoinOuterGetTuple(outerNode, (Plan*) node, hjstate);
-
- while (curbatch <= nbatch && TupIsNull(outerTupleSlot)) {
- /*
- * if the current batch runs out, switch to new batch
- */
- curbatch = ExecHashJoinNewBatch(hjstate);
- if (curbatch > nbatch) {
+ outerTupleSlot = hjstate->jstate.cs_OuterTupleSlot;
+ outerVar = get_leftop(clause);
+
+ bucketno = -1; /* if bucketno remains -1, means use old
+ * outer tuple */
+ if (TupIsNull(outerTupleSlot))
+ {
+
/*
- * when the last batch runs out, clean up
+ * if the current outer tuple is nil, get a new one
*/
- ExecHashTableDestroy(hashtable);
- hjstate->hj_HashTable = NULL;
- return NULL;
- }
- else
- outerTupleSlot = (TupleTableSlot*)
- ExecHashJoinOuterGetTuple(outerNode, (Plan*)node, hjstate);
+ outerTupleSlot = (TupleTableSlot *)
+ ExecHashJoinOuterGetTuple(outerNode, (Plan *) node, hjstate);
+
+ while (curbatch <= nbatch && TupIsNull(outerTupleSlot))
+ {
+
+ /*
+ * if the current batch runs out, switch to new batch
+ */
+ curbatch = ExecHashJoinNewBatch(hjstate);
+ if (curbatch > nbatch)
+ {
+
+ /*
+ * when the last batch runs out, clean up
+ */
+ ExecHashTableDestroy(hashtable);
+ hjstate->hj_HashTable = NULL;
+ return NULL;
+ }
+ else
+ outerTupleSlot = (TupleTableSlot *)
+ ExecHashJoinOuterGetTuple(outerNode, (Plan *) node, hjstate);
+ }
+
+ /*
+ * now we get an outer tuple, find the corresponding bucket for
+ * this tuple from the hash table
+ */
+ econtext->ecxt_outertuple = outerTupleSlot;
+
+#ifdef HJDEBUG
+ printf("Probing ");
+#endif
+ bucketno = ExecHashGetBucket(hashtable, econtext, outerVar);
+ bucket = (HashBucket) (ABSADDR(hashtable->top)
+ + bucketno * hashtable->bucketsize);
}
-
- /* ----------------
- * Now get the corresponding hash bucket for the new
- * outer tuple.
- * ----------------
- */
- econtext->ecxt_outertuple = outerTupleSlot;
+
+ for (;;)
+ {
+ /* ----------------
+ * Now we've got an outer tuple and the corresponding hash bucket,
+ * but this tuple may not belong to the current batch.
+ * ----------------
+ */
+ if (curbatch == 0 && bucketno != -1) /* if this is the first
+ * pass */
+ batch = ExecHashJoinGetBatch(bucketno, hashtable, nbatch);
+ else
+ batch = 0;
+ if (batch > 0)
+ {
+
+ /*
+ * if the current outer tuple does not belong to the current
+ * batch, save to the tmp file for the corresponding batch.
+ */
+ buffer = ABSADDR(hashtable->batch) + (batch - 1) * BLCKSZ;
+ batchno = batch - 1;
+ pos = ExecHashJoinSaveTuple(outerTupleSlot->val,
+ buffer,
+ outerbatches[batchno],
+ ABSADDR(outerbatchPos[batchno]));
+
+ outerbatchPos[batchno] = RELADDR(pos);
+ }
+ else if (bucket != NULL)
+ {
+ do
+ {
+
+ /*
+ * scan the hash bucket for matches
+ */
+ curtuple = ExecScanHashBucket(hjstate,
+ bucket,
+ curtuple,
+ hjclauses,
+ econtext);
+
+ if (curtuple != NULL)
+ {
+
+ /*
+ * we've got a match, but still need to test qpqual
+ */
+ inntuple = ExecStoreTuple(curtuple,
+ hjstate->hj_HashTupleSlot,
+ InvalidBuffer,
+ false); /* don't pfree this
+ * tuple */
+
+ econtext->ecxt_innertuple = inntuple;
+
+ /* ----------------
+ * test to see if we pass the qualification
+ * ----------------
+ */
+ qualResult = ExecQual((List *) qual, econtext);
+
+ /* ----------------
+ * if we pass the qual, then save state for next call and
+ * have ExecProject form the projection, store it
+ * in the tuple table, and return the slot.
+ * ----------------
+ */
+ if (qualResult)
+ {
+ ProjectionInfo *projInfo;
+ TupleTableSlot *result;
+ bool isDone;
+
+ hjstate->hj_CurBucket = bucket;
+ hjstate->hj_CurTuple = curtuple;
+ hashtable->curbatch = curbatch;
+ hjstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
+
+ projInfo = hjstate->jstate.cs_ProjInfo;
+ result = ExecProject(projInfo, &isDone);
+ hjstate->jstate.cs_TupFromTlist = !isDone;
+ return result;
+ }
+ }
+ }
+ while (curtuple != NULL);
+ }
+
+ /* ----------------
+ * Now the current outer tuple has run out of matches,
+ * so we free it and get a new outer tuple.
+ * ----------------
+ */
+ outerTupleSlot = (TupleTableSlot *)
+ ExecHashJoinOuterGetTuple(outerNode, (Plan *) node, hjstate);
+
+ while (curbatch <= nbatch && TupIsNull(outerTupleSlot))
+ {
+
+ /*
+ * if the current batch runs out, switch to new batch
+ */
+ curbatch = ExecHashJoinNewBatch(hjstate);
+ if (curbatch > nbatch)
+ {
+
+ /*
+ * when the last batch runs out, clean up
+ */
+ ExecHashTableDestroy(hashtable);
+ hjstate->hj_HashTable = NULL;
+ return NULL;
+ }
+ else
+ outerTupleSlot = (TupleTableSlot *)
+ ExecHashJoinOuterGetTuple(outerNode, (Plan *) node, hjstate);
+ }
+
+ /* ----------------
+ * Now get the corresponding hash bucket for the new
+ * outer tuple.
+ * ----------------
+ */
+ econtext->ecxt_outertuple = outerTupleSlot;
#ifdef HJDEBUG
- printf("Probing ");
+ printf("Probing ");
#endif
- bucketno = ExecHashGetBucket(hashtable, econtext, outerVar);
- bucket=(HashBucket)(ABSADDR(hashtable->top)
- + bucketno * hashtable->bucketsize);
- curtuple = NULL;
- }
+ bucketno = ExecHashGetBucket(hashtable, econtext, outerVar);
+ bucket = (HashBucket) (ABSADDR(hashtable->top)
+ + bucketno * hashtable->bucketsize);
+ curtuple = NULL;
+ }
}
/* ----------------------------------------------------------------
- * ExecInitHashJoin
+ * ExecInitHashJoin
*
- * Init routine for HashJoin node.
+ * Init routine for HashJoin node.
* ----------------------------------------------------------------
*/
-bool /* return: initialization status */
-ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent)
+bool /* return: initialization status */
+ExecInitHashJoin(HashJoin * node, EState * estate, Plan * parent)
{
- HashJoinState *hjstate;
- Plan *outerNode;
- Hash *hashNode;
-
- /* ----------------
- * assign the node's execution state
- * ----------------
- */
- node->join.state = estate;
-
- /* ----------------
- * create state structure
- * ----------------
- */
- hjstate = makeNode(HashJoinState);
-
- node->hashjoinstate = hjstate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &hjstate->jstate, parent);
- ExecAssignExprContext(estate, &hjstate->jstate);
-
+ HashJoinState *hjstate;
+ Plan *outerNode;
+ Hash *hashNode;
+
+ /* ----------------
+ * assign the node's execution state
+ * ----------------
+ */
+ node->join.state = estate;
+
+ /* ----------------
+ * create state structure
+ * ----------------
+ */
+ hjstate = makeNode(HashJoinState);
+
+ node->hashjoinstate = hjstate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &hjstate->jstate, parent);
+ ExecAssignExprContext(estate, &hjstate->jstate);
+
#define HASHJOIN_NSLOTS 2
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &hjstate->jstate);
- ExecInitOuterTupleSlot(estate, hjstate);
-
- /* ----------------
- * initializes child nodes
- * ----------------
- */
- outerNode = outerPlan((Plan *)node);
- hashNode = (Hash*)innerPlan((Plan *)node);
-
- ExecInitNode(outerNode, estate, (Plan *) node);
- ExecInitNode((Plan*)hashNode, estate, (Plan *) node);
-
- /* ----------------
- * now for some voodoo. our temporary tuple slot
- * is actually the result tuple slot of the Hash node
- * (which is our inner plan). we do this because Hash
- * nodes don't return tuples via ExecProcNode() -- instead
- * the hash join node uses ExecScanHashBucket() to get
- * at the contents of the hash table. -cim 6/9/91
- * ----------------
- */
- {
- HashState *hashstate = hashNode->hashstate;
- TupleTableSlot *slot =
- hashstate->cstate.cs_ResultTupleSlot;
- hjstate->hj_HashTupleSlot = slot;
- }
- hjstate->hj_OuterTupleSlot->ttc_tupleDescriptor =
- ExecGetTupType(outerNode);
-
+ /* ----------------
+ * tuple table initialization
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &hjstate->jstate);
+ ExecInitOuterTupleSlot(estate, hjstate);
+
+ /* ----------------
+ * initializes child nodes
+ * ----------------
+ */
+ outerNode = outerPlan((Plan *) node);
+ hashNode = (Hash *) innerPlan((Plan *) node);
+
+ ExecInitNode(outerNode, estate, (Plan *) node);
+ ExecInitNode((Plan *) hashNode, estate, (Plan *) node);
+
+ /* ----------------
+ * now for some voodoo. our temporary tuple slot
+ * is actually the result tuple slot of the Hash node
+ * (which is our inner plan). we do this because Hash
+ * nodes don't return tuples via ExecProcNode() -- instead
+ * the hash join node uses ExecScanHashBucket() to get
+ * at the contents of the hash table. -cim 6/9/91
+ * ----------------
+ */
+ {
+ HashState *hashstate = hashNode->hashstate;
+ TupleTableSlot *slot =
+ hashstate->cstate.cs_ResultTupleSlot;
+
+ hjstate->hj_HashTupleSlot = slot;
+ }
+ hjstate->hj_OuterTupleSlot->ttc_tupleDescriptor =
+ ExecGetTupType(outerNode);
+
/*
- hjstate->hj_OuterTupleSlot->ttc_execTupDescriptor =
- ExecGetExecTupDesc(outerNode);
+ hjstate->hj_OuterTupleSlot->ttc_execTupDescriptor =
+ ExecGetExecTupDesc(outerNode);
*/
-
- /* ----------------
- * initialize tuple type and projection info
- * ----------------
- */
- ExecAssignResultTypeFromTL((Plan*) node, &hjstate->jstate);
- ExecAssignProjectionInfo((Plan*) node, &hjstate->jstate);
-
- /* ----------------
- * XXX comment me
- * ----------------
- */
-
- node->hashdone = false;
-
- hjstate->hj_HashTable = (HashJoinTable)NULL;
- hjstate->hj_HashTableShmId = (IpcMemoryId)0;
- hjstate->hj_CurBucket = (HashBucket )NULL;
- hjstate->hj_CurTuple = (HeapTuple )NULL;
- hjstate->hj_CurOTuple = (OverflowTuple )NULL;
- hjstate->hj_InnerHashKey = (Var*)NULL;
- hjstate->hj_OuterBatches = (File*)NULL;
- hjstate->hj_InnerBatches = (File*)NULL;
- hjstate->hj_OuterReadPos = (char*)NULL;
- hjstate->hj_OuterReadBlk = (int)0;
-
- hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot*) NULL;
- hjstate->jstate.cs_TupFromTlist = (bool) false;
-
- return TRUE;
+
+ /* ----------------
+ * initialize tuple type and projection info
+ * ----------------
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &hjstate->jstate);
+ ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate);
+
+ /* ----------------
+ * XXX comment me
+ * ----------------
+ */
+
+ node->hashdone = false;
+
+ hjstate->hj_HashTable = (HashJoinTable) NULL;
+ hjstate->hj_HashTableShmId = (IpcMemoryId) 0;
+ hjstate->hj_CurBucket = (HashBucket) NULL;
+ hjstate->hj_CurTuple = (HeapTuple) NULL;
+ hjstate->hj_CurOTuple = (OverflowTuple) NULL;
+ hjstate->hj_InnerHashKey = (Var *) NULL;
+ hjstate->hj_OuterBatches = (File *) NULL;
+ hjstate->hj_InnerBatches = (File *) NULL;
+ hjstate->hj_OuterReadPos = (char *) NULL;
+ hjstate->hj_OuterReadBlk = (int) 0;
+
+ hjstate->jstate.cs_OuterTupleSlot = (TupleTableSlot *) NULL;
+ hjstate->jstate.cs_TupFromTlist = (bool) false;
+
+ return TRUE;
}
int
-ExecCountSlotsHashJoin(HashJoin *node)
+ExecCountSlotsHashJoin(HashJoin * node)
{
- return ExecCountSlotsNode(outerPlan(node)) +
+ return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
- HASHJOIN_NSLOTS;
+ HASHJOIN_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndHashJoin
+ * ExecEndHashJoin
*
- * clean up routine for HashJoin node
+ * clean up routine for HashJoin node
* ----------------------------------------------------------------
*/
void
-ExecEndHashJoin(HashJoin *node)
+ExecEndHashJoin(HashJoin * node)
{
- HashJoinState *hjstate;
-
- /* ----------------
- * get info from the HashJoin state
- * ----------------
- */
- hjstate = node->hashjoinstate;
-
- /* ----------------
- * free hash table in case we end plan before all tuples are retrieved
- * ---------------
- */
- if (hjstate->hj_HashTable) {
- ExecHashTableDestroy(hjstate->hj_HashTable);
- hjstate->hj_HashTable = NULL;
- }
-
- /* ----------------
- * Free the projection info and the scan attribute info
- *
- * Note: we don't ExecFreeResultType(hjstate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo(&hjstate->jstate);
-
- /* ----------------
- * clean up subtrees
- * ----------------
- */
- ExecEndNode(outerPlan((Plan *) node), (Plan*)node);
- ExecEndNode(innerPlan((Plan *) node), (Plan*)node);
-
- /* ----------------
- * clean out the tuple table
- * ----------------
- */
- ExecClearTuple(hjstate->jstate.cs_ResultTupleSlot);
- ExecClearTuple(hjstate->hj_OuterTupleSlot);
- ExecClearTuple(hjstate->hj_HashTupleSlot);
-
+ HashJoinState *hjstate;
+
+ /* ----------------
+ * get info from the HashJoin state
+ * ----------------
+ */
+ hjstate = node->hashjoinstate;
+
+ /* ----------------
+ * free hash table in case we end plan before all tuples are retrieved
+ * ---------------
+ */
+ if (hjstate->hj_HashTable)
+ {
+ ExecHashTableDestroy(hjstate->hj_HashTable);
+ hjstate->hj_HashTable = NULL;
+ }
+
+ /* ----------------
+ * Free the projection info and the scan attribute info
+ *
+ * Note: we don't ExecFreeResultType(hjstate)
+ * because the rule manager depends on the tupType
+ * returned by ExecMain(). So for now, this
+ * is freed at end-transaction time. -cim 6/2/91
+ * ----------------
+ */
+ ExecFreeProjectionInfo(&hjstate->jstate);
+
+ /* ----------------
+ * clean up subtrees
+ * ----------------
+ */
+ ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
+ ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(hjstate->jstate.cs_ResultTupleSlot);
+ ExecClearTuple(hjstate->hj_OuterTupleSlot);
+ ExecClearTuple(hjstate->hj_HashTupleSlot);
+
}
/* ----------------------------------------------------------------
- * ExecHashJoinOuterGetTuple
+ * ExecHashJoinOuterGetTuple
*
- * get the next outer tuple for hashjoin: either by
- * executing a plan node as in the first pass, or from
- * the tmp files for the hashjoin batches.
+ * get the next outer tuple for hashjoin: either by
+ * executing a plan node as in the first pass, or from
+ * the tmp files for the hashjoin batches.
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-ExecHashJoinOuterGetTuple(Plan *node, Plan* parent, HashJoinState *hjstate)
+ExecHashJoinOuterGetTuple(Plan * node, Plan * parent, HashJoinState * hjstate)
{
- TupleTableSlot *slot;
- HashJoinTable hashtable;
- int curbatch;
- File *outerbatches;
- char *outerreadPos;
- int batchno;
- char *outerreadBuf;
- int outerreadBlk;
-
- hashtable = hjstate->hj_HashTable;
- curbatch = hashtable->curbatch;
-
- if (curbatch == 0) { /* if it is the first pass */
- slot = ExecProcNode(node, parent);
+ TupleTableSlot *slot;
+ HashJoinTable hashtable;
+ int curbatch;
+ File *outerbatches;
+ char *outerreadPos;
+ int batchno;
+ char *outerreadBuf;
+ int outerreadBlk;
+
+ hashtable = hjstate->hj_HashTable;
+ curbatch = hashtable->curbatch;
+
+ if (curbatch == 0)
+ { /* if it is the first pass */
+ slot = ExecProcNode(node, parent);
+ return slot;
+ }
+
+ /*
+ * otherwise, read from the tmp files
+ */
+ outerbatches = hjstate->hj_OuterBatches;
+ outerreadPos = hjstate->hj_OuterReadPos;
+ outerreadBlk = hjstate->hj_OuterReadBlk;
+ outerreadBuf = ABSADDR(hashtable->readbuf);
+ batchno = curbatch - 1;
+
+ slot = ExecHashJoinGetSavedTuple(hjstate,
+ outerreadBuf,
+ outerbatches[batchno],
+ hjstate->hj_OuterTupleSlot,
+ &outerreadBlk,
+ &outerreadPos);
+
+ hjstate->hj_OuterReadPos = outerreadPos;
+ hjstate->hj_OuterReadBlk = outerreadBlk;
+
return slot;
- }
-
- /*
- * otherwise, read from the tmp files
- */
- outerbatches = hjstate->hj_OuterBatches;
- outerreadPos = hjstate->hj_OuterReadPos;
- outerreadBlk = hjstate->hj_OuterReadBlk;
- outerreadBuf = ABSADDR(hashtable->readbuf);
- batchno = curbatch - 1;
-
- slot = ExecHashJoinGetSavedTuple(hjstate,
- outerreadBuf,
- outerbatches[batchno],
- hjstate->hj_OuterTupleSlot,
- &outerreadBlk,
- &outerreadPos);
-
- hjstate->hj_OuterReadPos = outerreadPos;
- hjstate->hj_OuterReadBlk = outerreadBlk;
-
- return slot;
}
/* ----------------------------------------------------------------
- * ExecHashJoinGetSavedTuple
+ * ExecHashJoinGetSavedTuple
*
- * read the next tuple from a tmp file using a certain buffer
+ * read the next tuple from a tmp file using a certain buffer
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
- char *buffer,
- File file,
- TupleTableSlot *tupleSlot,
- int *block, /* return parameter */
- char **position) /* return parameter */
+ExecHashJoinGetSavedTuple(HashJoinState * hjstate,
+ char *buffer,
+ File file,
+ TupleTableSlot * tupleSlot,
+ int *block, /* return parameter */
+ char **position) /* return parameter */
{
- char *bufstart;
- char *bufend;
- int cc;
- HeapTuple heapTuple;
- HashJoinTable hashtable;
-
- hashtable = hjstate->hj_HashTable;
- bufend = buffer + *(long*)buffer;
- bufstart = (char*)(buffer + sizeof(long));
- if ((*position == NULL) || (*position >= bufend)) {
- if (*position == NULL)
- (*block) = 0;
- else
- (*block)++;
- FileSeek(file, *block * BLCKSZ, SEEK_SET);
- cc = FileRead(file, buffer, BLCKSZ);
- NDirectFileRead++;
- if (cc < 0)
- perror("FileRead");
- if (cc == 0) /* end of file */
- return NULL;
- else
- (*position) = bufstart;
- }
- heapTuple = (HeapTuple) (*position);
- (*position) = (char*)LONGALIGN(*position + heapTuple->t_len);
-
- return ExecStoreTuple(heapTuple,tupleSlot,InvalidBuffer,false);
+ char *bufstart;
+ char *bufend;
+ int cc;
+ HeapTuple heapTuple;
+ HashJoinTable hashtable;
+
+ hashtable = hjstate->hj_HashTable;
+ bufend = buffer + *(long *) buffer;
+ bufstart = (char *) (buffer + sizeof(long));
+ if ((*position == NULL) || (*position >= bufend))
+ {
+ if (*position == NULL)
+ (*block) = 0;
+ else
+ (*block)++;
+ FileSeek(file, *block * BLCKSZ, SEEK_SET);
+ cc = FileRead(file, buffer, BLCKSZ);
+ NDirectFileRead++;
+ if (cc < 0)
+ perror("FileRead");
+ if (cc == 0) /* end of file */
+ return NULL;
+ else
+ (*position) = bufstart;
+ }
+ heapTuple = (HeapTuple) (*position);
+ (*position) = (char *) LONGALIGN(*position + heapTuple->t_len);
+
+ return ExecStoreTuple(heapTuple, tupleSlot, InvalidBuffer, false);
}
/* ----------------------------------------------------------------
- * ExecHashJoinNewBatch
+ * ExecHashJoinNewBatch
*
- * switch to a new hashjoin batch
+ * switch to a new hashjoin batch
* ----------------------------------------------------------------
*/
static int
-ExecHashJoinNewBatch(HashJoinState *hjstate)
+ExecHashJoinNewBatch(HashJoinState * hjstate)
{
- File *innerBatches;
- File *outerBatches;
- int *innerBatchSizes;
- Var *innerhashkey;
- HashJoinTable hashtable;
- int nbatch;
- char *readPos;
- int readBlk;
- char *readBuf;
- TupleTableSlot *slot;
- ExprContext *econtext;
- int i;
- int cc;
- int newbatch;
-
- hashtable = hjstate->hj_HashTable;
- outerBatches = hjstate->hj_OuterBatches;
- innerBatches = hjstate->hj_InnerBatches;
- nbatch = hashtable->nbatch;
- newbatch = hashtable->curbatch + 1;
-
- /* ------------------
- * this is the last process, so it will do the cleanup and
- * batch-switching.
- * ------------------
- */
- if (newbatch == 1) {
- /*
- * if it is end of the first pass, flush all the last pages for
- * the batches.
- */
- outerBatches = hjstate->hj_OuterBatches;
- for (i=0; i<nbatch; i++) {
- cc = FileSeek(outerBatches[i], 0L, SEEK_END);
- if (cc < 0)
- perror("FileSeek");
- cc = FileWrite(outerBatches[i],
- ABSADDR(hashtable->batch) + i * BLCKSZ, BLCKSZ);
- NDirectFileWrite++;
- if (cc < 0)
- perror("FileWrite");
- }
+ File *innerBatches;
+ File *outerBatches;
+ int *innerBatchSizes;
+ Var *innerhashkey;
+ HashJoinTable hashtable;
+ int nbatch;
+ char *readPos;
+ int readBlk;
+ char *readBuf;
+ TupleTableSlot *slot;
+ ExprContext *econtext;
+ int i;
+ int cc;
+ int newbatch;
+
+ hashtable = hjstate->hj_HashTable;
+ outerBatches = hjstate->hj_OuterBatches;
+ innerBatches = hjstate->hj_InnerBatches;
+ nbatch = hashtable->nbatch;
+ newbatch = hashtable->curbatch + 1;
+
+ /* ------------------
+ * this is the last process, so it will do the cleanup and
+ * batch-switching.
+ * ------------------
+ */
+ if (newbatch == 1)
+ {
+
+ /*
+ * if it is end of the first pass, flush all the last pages for
+ * the batches.
+ */
+ outerBatches = hjstate->hj_OuterBatches;
+ for (i = 0; i < nbatch; i++)
+ {
+ cc = FileSeek(outerBatches[i], 0L, SEEK_END);
+ if (cc < 0)
+ perror("FileSeek");
+ cc = FileWrite(outerBatches[i],
+ ABSADDR(hashtable->batch) + i * BLCKSZ, BLCKSZ);
+ NDirectFileWrite++;
+ if (cc < 0)
+ perror("FileWrite");
+ }
}
- if (newbatch > 1) {
+ if (newbatch > 1)
+ {
+
+ /*
+ * remove the previous outer batch
+ */
+ FileUnlink(outerBatches[newbatch - 2]);
+ }
+
/*
- * remove the previous outer batch
+ * rebuild the hash table for the new inner batch
+ */
+ innerBatchSizes = (int *) ABSADDR(hashtable->innerbatchSizes);
+ /* --------------
+ * skip over empty inner batches
+ * --------------
*/
- FileUnlink(outerBatches[newbatch - 2]);
- }
- /*
- * rebuild the hash table for the new inner batch
- */
- innerBatchSizes = (int*)ABSADDR(hashtable->innerbatchSizes);
- /* --------------
- * skip over empty inner batches
- * --------------
- */
- while (newbatch <= nbatch && innerBatchSizes[newbatch - 1] == 0) {
- FileUnlink(outerBatches[newbatch-1]);
- FileUnlink(innerBatches[newbatch-1]);
- newbatch++;
+ while (newbatch <= nbatch && innerBatchSizes[newbatch - 1] == 0)
+ {
+ FileUnlink(outerBatches[newbatch - 1]);
+ FileUnlink(innerBatches[newbatch - 1]);
+ newbatch++;
}
- if (newbatch > nbatch) {
+ if (newbatch > nbatch)
+ {
+ hashtable->pcount = hashtable->nprocess;
+
+ return newbatch;
+ }
+ ExecHashTableReset(hashtable, innerBatchSizes[newbatch - 1]);
+
+
+ econtext = hjstate->jstate.cs_ExprContext;
+ innerhashkey = hjstate->hj_InnerHashKey;
+ readPos = NULL;
+ readBlk = 0;
+ readBuf = ABSADDR(hashtable->readbuf);
+
+ while ((slot = ExecHashJoinGetSavedTuple(hjstate,
+ readBuf,
+ innerBatches[newbatch - 1],
+ hjstate->hj_HashTupleSlot,
+ &readBlk,
+ &readPos))
+ && !TupIsNull(slot))
+ {
+ econtext->ecxt_innertuple = slot;
+ ExecHashTableInsert(hashtable, econtext, innerhashkey, NULL);
+ /* possible bug - glass */
+ }
+
+
+ /* -----------------
+ * only the last process comes to this branch
+ * now all the processes have finished the build phase
+ * ----------------
+ */
+
+ /*
+ * after we build the hash table, the inner batch is no longer needed
+ */
+ FileUnlink(innerBatches[newbatch - 1]);
+ hjstate->hj_OuterReadPos = NULL;
hashtable->pcount = hashtable->nprocess;
+ hashtable->curbatch = newbatch;
return newbatch;
- }
- ExecHashTableReset(hashtable, innerBatchSizes[newbatch - 1]);
-
-
- econtext = hjstate->jstate.cs_ExprContext;
- innerhashkey = hjstate->hj_InnerHashKey;
- readPos = NULL;
- readBlk = 0;
- readBuf = ABSADDR(hashtable->readbuf);
-
- while ((slot = ExecHashJoinGetSavedTuple(hjstate,
- readBuf,
- innerBatches[newbatch-1],
- hjstate->hj_HashTupleSlot,
- &readBlk,
- &readPos))
- && ! TupIsNull(slot)) {
- econtext->ecxt_innertuple = slot;
- ExecHashTableInsert(hashtable, econtext, innerhashkey,NULL);
- /* possible bug - glass */
- }
-
-
- /* -----------------
- * only the last process comes to this branch
- * now all the processes have finished the build phase
- * ----------------
- */
-
- /*
- * after we build the hash table, the inner batch is no longer needed
- */
- FileUnlink(innerBatches[newbatch - 1]);
- hjstate->hj_OuterReadPos = NULL;
- hashtable->pcount = hashtable->nprocess;
-
- hashtable->curbatch = newbatch;
- return newbatch;
}
/* ----------------------------------------------------------------
- * ExecHashJoinGetBatch
+ * ExecHashJoinGetBatch
*
- * determine the batch number for a bucketno
- * +----------------+-------+-------+ ... +-------+
- * 0 nbuckets totalbuckets
- * batch 0 1 2 ...
+ * determine the batch number for a bucketno
+ * +----------------+-------+-------+ ... +-------+
+ * 0 nbuckets totalbuckets
+ * batch 0 1 2 ...
* ----------------------------------------------------------------
*/
static int
ExecHashJoinGetBatch(int bucketno, HashJoinTable hashtable, int nbatch)
{
- int b;
- if (bucketno < hashtable->nbuckets || nbatch == 0)
- return 0;
-
- b = (float)(bucketno - hashtable->nbuckets) /
- (float)(hashtable->totalbuckets - hashtable->nbuckets) *
- nbatch;
- return b+1;
+ int b;
+
+ if (bucketno < hashtable->nbuckets || nbatch == 0)
+ return 0;
+
+ b = (float) (bucketno - hashtable->nbuckets) /
+ (float) (hashtable->totalbuckets - hashtable->nbuckets) *
+ nbatch;
+ return b + 1;
}
/* ----------------------------------------------------------------
- * ExecHashJoinSaveTuple
+ * ExecHashJoinSaveTuple
*
- * save a tuple to a tmp file using a buffer.
- * the first few bytes in a page is an offset to the end
- * of the page.
+ * save a tuple to a tmp file using a buffer.
+ * the first few bytes in a page is an offset to the end
+ * of the page.
* ----------------------------------------------------------------
*/
-char *
+char *
ExecHashJoinSaveTuple(HeapTuple heapTuple,
- char *buffer,
- File file,
- char *position)
+ char *buffer,
+ File file,
+ char *position)
{
- long *pageend;
- char *pagestart;
- char *pagebound;
- int cc;
-
- pageend = (long*)buffer;
- pagestart = (char*)(buffer + sizeof(long));
- pagebound = buffer + BLCKSZ;
- if (position == NULL)
- position = pagestart;
-
- if (position + heapTuple->t_len >= pagebound) {
- cc = FileSeek(file, 0L, SEEK_END);
- if (cc < 0)
- perror("FileSeek");
- cc = FileWrite(file, buffer, BLCKSZ);
- NDirectFileWrite++;
- if (cc < 0)
- perror("FileWrite");
- position = pagestart;
- *pageend = 0;
- }
- memmove(position, heapTuple, heapTuple->t_len);
- position = (char*)LONGALIGN(position + heapTuple->t_len);
- *pageend = position - buffer;
-
- return position;
+ long *pageend;
+ char *pagestart;
+ char *pagebound;
+ int cc;
+
+ pageend = (long *) buffer;
+ pagestart = (char *) (buffer + sizeof(long));
+ pagebound = buffer + BLCKSZ;
+ if (position == NULL)
+ position = pagestart;
+
+ if (position + heapTuple->t_len >= pagebound)
+ {
+ cc = FileSeek(file, 0L, SEEK_END);
+ if (cc < 0)
+ perror("FileSeek");
+ cc = FileWrite(file, buffer, BLCKSZ);
+ NDirectFileWrite++;
+ if (cc < 0)
+ perror("FileWrite");
+ position = pagestart;
+ *pageend = 0;
+ }
+ memmove(position, heapTuple, heapTuple->t_len);
+ position = (char *) LONGALIGN(position + heapTuple->t_len);
+ *pageend = position - buffer;
+
+ return position;
}
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index bc0c4c3d288..c89a4fcb081 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -1,31 +1,31 @@
/*-------------------------------------------------------------------------
*
* nodeIndexscan.c--
- * Routines to support indexes and indexed scans of relations
+ * Routines to support indexes and indexed scans of relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.7 1997/03/12 20:58:26 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.8 1997/09/07 04:41:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecInsertIndexTuples inserts tuples into indices on result relation
+ * ExecInsertIndexTuples inserts tuples into indices on result relation
*
- * ExecIndexScan scans a relation using indices
- * ExecIndexNext using index to retrieve next tuple
- * ExecInitIndexScan creates and initializes state info.
- * ExecIndexReScan rescans the indexed relation.
- * ExecEndIndexScan releases all storage.
- * ExecIndexMarkPos marks scan position.
- * ExecIndexRestrPos restores scan position.
+ * ExecIndexScan scans a relation using indices
+ * ExecIndexNext using index to retrieve next tuple
+ * ExecInitIndexScan creates and initializes state info.
+ * ExecIndexReScan rescans the indexed relation.
+ * ExecEndIndexScan releases all storage.
+ * ExecIndexMarkPos marks scan position.
+ * ExecIndexRestrPos restores scan position.
*
- * NOTES
- * the code supporting ExecInsertIndexTuples should be
- * collected and merged with the genam stuff.
+ * NOTES
+ * the code supporting ExecInsertIndexTuples should be
+ * collected and merged with the genam stuff.
*
*/
#include "postgres.h"
@@ -48,894 +48,939 @@
#include "nodes/nodeFuncs.h"
/* ----------------
- * Misc stuff to move to executor.h soon -cim 6/5/90
+ * Misc stuff to move to executor.h soon -cim 6/5/90
* ----------------
*/
-#define NO_OP 0
-#define LEFT_OP 1
-#define RIGHT_OP 2
+#define NO_OP 0
+#define LEFT_OP 1
+#define RIGHT_OP 2
-static TupleTableSlot *IndexNext(IndexScan *node);
+static TupleTableSlot *IndexNext(IndexScan * node);
/* ----------------------------------------------------------------
- * IndexNext
+ * IndexNext
*
- * Retrieve a tuple from the IndexScan node's currentRelation
- * using the indices in the IndexScanState information.
+ * Retrieve a tuple from the IndexScan node's currentRelation
+ * using the indices in the IndexScanState information.
*
- * note: the old code mentions 'Primary indices'. to my knowledge
- * we only support a single secondary index. -cim 9/11/89
+ * note: the old code mentions 'Primary indices'. to my knowledge
+ * we only support a single secondary index. -cim 9/11/89
*
* old comments:
- * retrieve a tuple from relation using the indices given.
- * The indices are used in the order they appear in 'indices'.
- * The indices may be primary or secondary indices:
- * * primary index -- scan the relation 'relID' using keys supplied.
- * * secondary index -- scan the index relation to get the 'tid' for
- * a tuple in the relation 'relID'.
- * If the current index(pointed by 'indexPtr') fails to return a
- * tuple, the next index in the indices is used.
- *
- * bug fix so that it should retrieve on a null scan key.
+ * retrieve a tuple from relation using the indices given.
+ * The indices are used in the order they appear in 'indices'.
+ * The indices may be primary or secondary indices:
+ * * primary index -- scan the relation 'relID' using keys supplied.
+ * * secondary index -- scan the index relation to get the 'tid' for
+ * a tuple in the relation 'relID'.
+ * If the current index(pointed by 'indexPtr') fails to return a
+ * tuple, the next index in the indices is used.
+ *
+ * bug fix so that it should retrieve on a null scan key.
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-IndexNext(IndexScan *node)
+IndexNext(IndexScan * node)
{
- EState *estate;
- CommonScanState *scanstate;
- IndexScanState *indexstate;
- ScanDirection direction;
- int indexPtr;
- IndexScanDescPtr scanDescs;
- IndexScanDesc scandesc;
- Relation heapRelation;
- RetrieveIndexResult result;
- ItemPointer iptr;
- HeapTuple tuple;
- TupleTableSlot *slot;
- Buffer buffer = InvalidBuffer;
-
- /* ----------------
- * extract necessary information from index scan node
- * ----------------
- */
- estate = node->scan.plan.state;
- direction = estate->es_direction;
- scanstate = node->scan.scanstate;
- indexstate = node->indxstate;
- indexPtr = indexstate->iss_IndexPtr;
- scanDescs = indexstate->iss_ScanDescs;
- scandesc = scanDescs[ indexPtr ];
- heapRelation = scanstate->css_currentRelation;
-
- slot = scanstate->css_ScanTupleSlot;
-
- /* ----------------
- * ok, now that we have what we need, fetch an index tuple.
- * ----------------
- */
-
- for(;;) {
- result = index_getnext(scandesc, direction);
+ EState *estate;
+ CommonScanState *scanstate;
+ IndexScanState *indexstate;
+ ScanDirection direction;
+ int indexPtr;
+ IndexScanDescPtr scanDescs;
+ IndexScanDesc scandesc;
+ Relation heapRelation;
+ RetrieveIndexResult result;
+ ItemPointer iptr;
+ HeapTuple tuple;
+ TupleTableSlot *slot;
+ Buffer buffer = InvalidBuffer;
+
/* ----------------
- * if scanning this index succeeded then return the
- * appropriate heap tuple.. else return NULL.
+ * extract necessary information from index scan node
* ----------------
*/
- if (result) {
- iptr = &result->heap_iptr;
- tuple = heap_fetch(heapRelation,
- NowTimeQual,
- iptr,
- &buffer);
- /* be tidy */
- pfree(result);
-
- if (tuple == NULL) {
+ estate = node->scan.plan.state;
+ direction = estate->es_direction;
+ scanstate = node->scan.scanstate;
+ indexstate = node->indxstate;
+ indexPtr = indexstate->iss_IndexPtr;
+ scanDescs = indexstate->iss_ScanDescs;
+ scandesc = scanDescs[indexPtr];
+ heapRelation = scanstate->css_currentRelation;
+
+ slot = scanstate->css_ScanTupleSlot;
+
+ /* ----------------
+ * ok, now that we have what we need, fetch an index tuple.
+ * ----------------
+ */
+
+ for (;;)
+ {
+ result = index_getnext(scandesc, direction);
+ /* ----------------
+ * if scanning this index succeeded then return the
+ * appropriate heap tuple.. else return NULL.
+ * ----------------
+ */
+ if (result)
+ {
+ iptr = &result->heap_iptr;
+ tuple = heap_fetch(heapRelation,
+ NowTimeQual,
+ iptr,
+ &buffer);
+ /* be tidy */
+ pfree(result);
+
+ if (tuple == NULL)
+ {
+ /* ----------------
+ * we found a deleted tuple, so keep on scanning..
+ * ----------------
+ */
+ if (BufferIsValid(buffer))
+ ReleaseBuffer(buffer);
+ continue;
+ }
+
+ /* ----------------
+ * store the scanned tuple in the scan tuple slot of
+ * the scan state. Eventually we will only do this and not
+ * return a tuple. Note: we pass 'false' because tuples
+ * returned by amgetnext are pointers onto disk pages and
+ * were not created with palloc() and so should not be pfree()'d.
+ * ----------------
+ */
+ ExecStoreTuple(tuple, /* tuple to store */
+ slot,/* slot to store in */
+ buffer, /* buffer associated with tuple */
+ false); /* don't pfree */
+
+ return slot;
+ }
+
/* ----------------
- * we found a deleted tuple, so keep on scanning..
+ * if we get here it means the index scan failed so we
+ * are at the end of the scan..
* ----------------
*/
- if (BufferIsValid(buffer))
- ReleaseBuffer(buffer);
- continue;
- }
-
- /* ----------------
- * store the scanned tuple in the scan tuple slot of
- * the scan state. Eventually we will only do this and not
- * return a tuple. Note: we pass 'false' because tuples
- * returned by amgetnext are pointers onto disk pages and
- * were not created with palloc() and so should not be pfree()'d.
- * ----------------
- */
- ExecStoreTuple(tuple, /* tuple to store */
- slot, /* slot to store in */
- buffer, /* buffer associated with tuple */
- false); /* don't pfree */
-
- return slot;
+ return ExecClearTuple(slot);
}
-
- /* ----------------
- * if we get here it means the index scan failed so we
- * are at the end of the scan..
- * ----------------
- */
- return ExecClearTuple(slot);
- }
}
/* ----------------------------------------------------------------
- * ExecIndexScan(node)
+ * ExecIndexScan(node)
*
* old comments:
- * Scans the relation using primary or secondary indices and returns
- * the next qualifying tuple in the direction specified.
- * It calls ExecScan() and passes it the access methods which returns
- * the next tuple using the indices.
- *
- * Conditions:
- * -- the "cursor" maintained by the AMI is positioned at the tuple
- * returned previously.
- *
- * Initial States:
- * -- the relation indicated is opened for scanning so that the
- * "cursor" is positioned before the first qualifying tuple.
- * -- all index realtions are opened for scanning.
- * -- indexPtr points to the first index.
- * -- state variable ruleFlag = nil.
+ * Scans the relation using primary or secondary indices and returns
+ * the next qualifying tuple in the direction specified.
+ * It calls ExecScan() and passes it the access methods which returns
+ * the next tuple using the indices.
+ *
+ * Conditions:
+ * -- the "cursor" maintained by the AMI is positioned at the tuple
+ * returned previously.
+ *
+ * Initial States:
+ * -- the relation indicated is opened for scanning so that the
+ * "cursor" is positioned before the first qualifying tuple.
+ * -- all index realtions are opened for scanning.
+ * -- indexPtr points to the first index.
+ * -- state variable ruleFlag = nil.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecIndexScan(IndexScan *node)
+ExecIndexScan(IndexScan * node)
{
- TupleTableSlot *returnTuple;
+ TupleTableSlot *returnTuple;
- /* ----------------
- * use IndexNext as access method
- * ----------------
- */
- returnTuple = ExecScan(&node->scan, IndexNext);
- return returnTuple;
-}
+ /* ----------------
+ * use IndexNext as access method
+ * ----------------
+ */
+ returnTuple = ExecScan(&node->scan, IndexNext);
+ return returnTuple;
+}
/* ----------------------------------------------------------------
- * ExecIndexReScan(node)
+ * ExecIndexReScan(node)
*
- * Recalculates the value of the scan keys whose value depends on
- * information known at runtime and rescans the indexed relation.
- * Updating the scan key was formerly done separately in
- * ExecUpdateIndexScanKeys. Integrating it into ReScan
- * makes rescans of indices and
- * relations/general streams more uniform.
+ * Recalculates the value of the scan keys whose value depends on
+ * information known at runtime and rescans the indexed relation.
+ * Updating the scan key was formerly done separately in
+ * ExecUpdateIndexScanKeys. Integrating it into ReScan
+ * makes rescans of indices and
+ * relations/general streams more uniform.
*
* ----------------------------------------------------------------
*/
void
-ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan* parent)
+ExecIndexReScan(IndexScan * node, ExprContext * exprCtxt, Plan * parent)
{
- EState *estate;
- IndexScanState *indexstate;
- ScanDirection direction;
- IndexScanDescPtr scanDescs;
- ScanKey *scanKeys;
- IndexScanDesc sdesc;
- ScanKey skey;
- int numIndices;
- int i;
-
- Pointer *runtimeKeyInfo;
- int indexPtr;
- int *numScanKeys;
- List *indxqual;
- List *qual;
- int n_keys;
- ScanKey scan_keys;
- int *run_keys;
- int j;
- Expr *clause;
- Node *scanexpr;
- Datum scanvalue;
- bool isNull;
- bool isDone;
-
- indexstate = node->indxstate;
- estate = node->scan.plan.state;
- direction = estate->es_direction;
- indexstate = node->indxstate;
- numIndices = indexstate->iss_NumIndices;
- scanDescs = indexstate->iss_ScanDescs;
- scanKeys = indexstate->iss_ScanKeys;
-
- runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
-
- if (runtimeKeyInfo != NULL) {
- /*
- * get the index qualifications and
- * recalculate the appropriate values
- */
- indexPtr = indexstate->iss_IndexPtr;
- indxqual = node->indxqual;
- qual = nth(indexPtr, indxqual);
- numScanKeys = indexstate->iss_NumScanKeys;
- n_keys = numScanKeys[indexPtr];
- run_keys = (int *) runtimeKeyInfo[indexPtr];
- scan_keys = (ScanKey) scanKeys[indexPtr];
-
- for (j=0; j < n_keys; j++) {
- /*
- * If we have a run-time key, then extract the run-time
- * expression and evaluate it with respect to the current
- * outer tuple. We then stick the result into the scan
- * key.
- */
- if (run_keys[j] != NO_OP) {
- clause = nth(j, qual);
- scanexpr = (run_keys[j] == RIGHT_OP) ?
- (Node*) get_rightop(clause) : (Node*) get_leftop(clause) ;
- /* pass in isDone but ignore it. We don't iterate in quals */
- scanvalue = (Datum)
- ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
- scan_keys[j].sk_argument = scanvalue;
- if (isNull) {
- scan_keys[j].sk_flags |= SK_ISNULL;
- } else {
- scan_keys[j].sk_flags &= ~SK_ISNULL;
+ EState *estate;
+ IndexScanState *indexstate;
+ ScanDirection direction;
+ IndexScanDescPtr scanDescs;
+ ScanKey *scanKeys;
+ IndexScanDesc sdesc;
+ ScanKey skey;
+ int numIndices;
+ int i;
+
+ Pointer *runtimeKeyInfo;
+ int indexPtr;
+ int *numScanKeys;
+ List *indxqual;
+ List *qual;
+ int n_keys;
+ ScanKey scan_keys;
+ int *run_keys;
+ int j;
+ Expr *clause;
+ Node *scanexpr;
+ Datum scanvalue;
+ bool isNull;
+ bool isDone;
+
+ indexstate = node->indxstate;
+ estate = node->scan.plan.state;
+ direction = estate->es_direction;
+ indexstate = node->indxstate;
+ numIndices = indexstate->iss_NumIndices;
+ scanDescs = indexstate->iss_ScanDescs;
+ scanKeys = indexstate->iss_ScanKeys;
+
+ runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo;
+
+ if (runtimeKeyInfo != NULL)
+ {
+
+ /*
+ * get the index qualifications and recalculate the appropriate
+ * values
+ */
+ indexPtr = indexstate->iss_IndexPtr;
+ indxqual = node->indxqual;
+ qual = nth(indexPtr, indxqual);
+ numScanKeys = indexstate->iss_NumScanKeys;
+ n_keys = numScanKeys[indexPtr];
+ run_keys = (int *) runtimeKeyInfo[indexPtr];
+ scan_keys = (ScanKey) scanKeys[indexPtr];
+
+ for (j = 0; j < n_keys; j++)
+ {
+
+ /*
+ * If we have a run-time key, then extract the run-time
+ * expression and evaluate it with respect to the current
+ * outer tuple. We then stick the result into the scan key.
+ */
+ if (run_keys[j] != NO_OP)
+ {
+ clause = nth(j, qual);
+ scanexpr = (run_keys[j] == RIGHT_OP) ?
+ (Node *) get_rightop(clause) : (Node *) get_leftop(clause);
+
+ /*
+ * pass in isDone but ignore it. We don't iterate in
+ * quals
+ */
+ scanvalue = (Datum)
+ ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone);
+ scan_keys[j].sk_argument = scanvalue;
+ if (isNull)
+ {
+ scan_keys[j].sk_flags |= SK_ISNULL;
+ }
+ else
+ {
+ scan_keys[j].sk_flags &= ~SK_ISNULL;
+ }
+ }
}
- }
}
- }
-
- /*
- * rescans all indices
- *
- * note: AMrescan assumes only one scan key. This may have
- * to change if we ever decide to support multiple keys.
- */
- for (i = 0; i < numIndices; i++) {
- sdesc = scanDescs[ i ];
- skey = scanKeys[ i ];
- index_rescan(sdesc, direction, skey);
- }
-
- /* ----------------
- * perhaps return something meaningful
- * ----------------
- */
- return;
+
+ /*
+ * rescans all indices
+ *
+ * note: AMrescan assumes only one scan key. This may have to change if
+ * we ever decide to support multiple keys.
+ */
+ for (i = 0; i < numIndices; i++)
+ {
+ sdesc = scanDescs[i];
+ skey = scanKeys[i];
+ index_rescan(sdesc, direction, skey);
+ }
+
+ /* ----------------
+ * perhaps return something meaningful
+ * ----------------
+ */
+ return;
}
/* ----------------------------------------------------------------
- * ExecEndIndexScan
+ * ExecEndIndexScan
*
* old comments
- * Releases any storage allocated through C routines.
- * Returns nothing.
+ * Releases any storage allocated through C routines.
+ * Returns nothing.
* ----------------------------------------------------------------
*/
void
-ExecEndIndexScan(IndexScan *node)
+ExecEndIndexScan(IndexScan * node)
{
- CommonScanState *scanstate;
- IndexScanState *indexstate;
- ScanKey *scanKeys;
- int numIndices;
- int i;
-
- scanstate = node->scan.scanstate;
- indexstate = node->indxstate;
-
- /* ----------------
- * extract information from the node
- * ----------------
- */
- numIndices = indexstate->iss_NumIndices;
- scanKeys = indexstate->iss_ScanKeys;
-
- /* ----------------
- * Free the projection info and the scan attribute info
- *
- * Note: we don't ExecFreeResultType(scanstate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo(&scanstate->cstate);
-
- /* ----------------
- * close the heap and index relations
- * ----------------
- */
- ExecCloseR((Plan *) node);
-
- /* ----------------
- * free the scan keys used in scanning the indices
- * ----------------
- */
- for (i=0; i<numIndices; i++) {
- if (scanKeys[i]!=NULL)
- pfree(scanKeys[i]);
-
- }
-
- /* ----------------
- * clear out tuple table slots
- * ----------------
- */
- ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
- ExecClearTuple(scanstate->css_ScanTupleSlot);
-/* ExecClearTuple(scanstate->css_RawTupleSlot); */
+ CommonScanState *scanstate;
+ IndexScanState *indexstate;
+ ScanKey *scanKeys;
+ int numIndices;
+ int i;
+
+ scanstate = node->scan.scanstate;
+ indexstate = node->indxstate;
+
+ /* ----------------
+ * extract information from the node
+ * ----------------
+ */
+ numIndices = indexstate->iss_NumIndices;
+ scanKeys = indexstate->iss_ScanKeys;
+
+ /* ----------------
+ * Free the projection info and the scan attribute info
+ *
+ * Note: we don't ExecFreeResultType(scanstate)
+ * because the rule manager depends on the tupType
+ * returned by ExecMain(). So for now, this
+ * is freed at end-transaction time. -cim 6/2/91
+ * ----------------
+ */
+ ExecFreeProjectionInfo(&scanstate->cstate);
+
+ /* ----------------
+ * close the heap and index relations
+ * ----------------
+ */
+ ExecCloseR((Plan *) node);
+
+ /* ----------------
+ * free the scan keys used in scanning the indices
+ * ----------------
+ */
+ for (i = 0; i < numIndices; i++)
+ {
+ if (scanKeys[i] != NULL)
+ pfree(scanKeys[i]);
+
+ }
+
+ /* ----------------
+ * clear out tuple table slots
+ * ----------------
+ */
+ ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
+ ExecClearTuple(scanstate->css_ScanTupleSlot);
+/* ExecClearTuple(scanstate->css_RawTupleSlot); */
}
/* ----------------------------------------------------------------
- * ExecIndexMarkPos
+ * ExecIndexMarkPos
*
* old comments
- * Marks scan position by marking the current index.
- * Returns nothing.
+ * Marks scan position by marking the current index.
+ * Returns nothing.
* ----------------------------------------------------------------
*/
void
-ExecIndexMarkPos(IndexScan *node)
+ExecIndexMarkPos(IndexScan * node)
{
- IndexScanState *indexstate;
- IndexScanDescPtr indexScanDescs;
- IndexScanDesc scanDesc;
- int indexPtr;
-
- indexstate = node->indxstate;
- indexPtr = indexstate->iss_IndexPtr;
- indexScanDescs = indexstate->iss_ScanDescs;
- scanDesc = indexScanDescs[ indexPtr ];
-
- /* ----------------
- * XXX access methods don't return marked positions so
- * ----------------
- */
- IndexScanMarkPosition( scanDesc );
- return;
+ IndexScanState *indexstate;
+ IndexScanDescPtr indexScanDescs;
+ IndexScanDesc scanDesc;
+ int indexPtr;
+
+ indexstate = node->indxstate;
+ indexPtr = indexstate->iss_IndexPtr;
+ indexScanDescs = indexstate->iss_ScanDescs;
+ scanDesc = indexScanDescs[indexPtr];
+
+ /* ----------------
+ * XXX access methods don't return marked positions so
+ * ----------------
+ */
+ IndexScanMarkPosition(scanDesc);
+ return;
}
/* ----------------------------------------------------------------
- * ExecIndexRestrPos
+ * ExecIndexRestrPos
*
* old comments
- * Restores scan position by restoring the current index.
- * Returns nothing.
- *
- * XXX Assumes previously marked scan position belongs to current index
+ * Restores scan position by restoring the current index.
+ * Returns nothing.
+ *
+ * XXX Assumes previously marked scan position belongs to current index
* ----------------------------------------------------------------
*/
void
-ExecIndexRestrPos(IndexScan *node)
+ExecIndexRestrPos(IndexScan * node)
{
- IndexScanState *indexstate;
- IndexScanDescPtr indexScanDescs;
- IndexScanDesc scanDesc;
- int indexPtr;
+ IndexScanState *indexstate;
+ IndexScanDescPtr indexScanDescs;
+ IndexScanDesc scanDesc;
+ int indexPtr;
- indexstate = node->indxstate;
- indexPtr = indexstate->iss_IndexPtr;
- indexScanDescs = indexstate->iss_ScanDescs;
- scanDesc = indexScanDescs[ indexPtr ];
+ indexstate = node->indxstate;
+ indexPtr = indexstate->iss_IndexPtr;
+ indexScanDescs = indexstate->iss_ScanDescs;
+ scanDesc = indexScanDescs[indexPtr];
- IndexScanRestorePosition( scanDesc );
+ IndexScanRestorePosition(scanDesc);
}
/* ----------------------------------------------------------------
- * ExecInitIndexScan
+ * ExecInitIndexScan
+ *
+ * Initializes the index scan's state information, creates
+ * scan keys, and opens the base and index relations.
*
- * Initializes the index scan's state information, creates
- * scan keys, and opens the base and index relations.
+ * Note: index scans have 2 sets of state information because
+ * we have to keep track of the base relation and the
+ * index relations.
*
- * Note: index scans have 2 sets of state information because
- * we have to keep track of the base relation and the
- * index relations.
- *
* old comments
- * Creates the run-time state information for the node and
- * sets the relation id to contain relevant decriptors.
- *
- * Parameters:
- * node: IndexNode node produced by the planner.
- * estate: the execution state initialized in InitPlan.
+ * Creates the run-time state information for the node and
+ * sets the relation id to contain relevant decriptors.
+ *
+ * Parameters:
+ * node: IndexNode node produced by the planner.
+ * estate: the execution state initialized in InitPlan.
* ----------------------------------------------------------------
*/
bool
-ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
+ExecInitIndexScan(IndexScan * node, EState * estate, Plan * parent)
{
- IndexScanState *indexstate;
- CommonScanState *scanstate;
- List *indxqual;
- List *indxid;
- int i;
- int numIndices;
- int indexPtr;
- ScanKey *scanKeys;
- int *numScanKeys;
- RelationPtr relationDescs;
- IndexScanDescPtr scanDescs;
- Pointer *runtimeKeyInfo;
- bool have_runtime_keys;
- List *rangeTable;
- RangeTblEntry *rtentry;
- Index relid;
- Oid reloid;
- TimeQual timeQual;
-
- Relation currentRelation;
- HeapScanDesc currentScanDesc;
- ScanDirection direction;
- int baseid;
-
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- node->scan.plan.state = estate;
-
- /* --------------------------------
- * Part 1) initialize scan state
- *
- * create new CommonScanState for node
- * --------------------------------
- */
- scanstate = makeNode(CommonScanState);
+ IndexScanState *indexstate;
+ CommonScanState *scanstate;
+ List *indxqual;
+ List *indxid;
+ int i;
+ int numIndices;
+ int indexPtr;
+ ScanKey *scanKeys;
+ int *numScanKeys;
+ RelationPtr relationDescs;
+ IndexScanDescPtr scanDescs;
+ Pointer *runtimeKeyInfo;
+ bool have_runtime_keys;
+ List *rangeTable;
+ RangeTblEntry *rtentry;
+ Index relid;
+ Oid reloid;
+ TimeQual timeQual;
+
+ Relation currentRelation;
+ HeapScanDesc currentScanDesc;
+ ScanDirection direction;
+ int baseid;
+
+ /* ----------------
+ * assign execution state to node
+ * ----------------
+ */
+ node->scan.plan.state = estate;
+
+ /* --------------------------------
+ * Part 1) initialize scan state
+ *
+ * create new CommonScanState for node
+ * --------------------------------
+ */
+ scanstate = makeNode(CommonScanState);
/*
- scanstate->ss_ProcOuterFlag = false;
- scanstate->ss_OldRelId = 0;
+ scanstate->ss_ProcOuterFlag = false;
+ scanstate->ss_OldRelId = 0;
*/
- node->scan.scanstate = scanstate;
+ node->scan.scanstate = scanstate;
- /* ----------------
- * assign node's base_id .. we don't use AssignNodeBaseid() because
- * the increment is done later on after we assign the index scan's
- * scanstate. see below.
- * ----------------
- */
- baseid = estate->es_BaseId;
-/* scanstate->csstate.cstate.bnode.base_id = baseid; */
- scanstate->cstate.cs_base_id = baseid;
+ /* ----------------
+ * assign node's base_id .. we don't use AssignNodeBaseid() because
+ * the increment is done later on after we assign the index scan's
+ * scanstate. see below.
+ * ----------------
+ */
+ baseid = estate->es_BaseId;
+/* scanstate->csstate.cstate.bnode.base_id = baseid; */
+ scanstate->cstate.cs_base_id = baseid;
- /* ----------------
- * create expression context for node
- * ----------------
- */
- ExecAssignExprContext(estate, &scanstate->cstate);
+ /* ----------------
+ * create expression context for node
+ * ----------------
+ */
+ ExecAssignExprContext(estate, &scanstate->cstate);
#define INDEXSCAN_NSLOTS 3
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &scanstate->cstate);
- ExecInitScanTupleSlot(estate, scanstate);
-/* ExecInitRawTupleSlot(estate, scanstate); */
-
- /* ----------------
- * initialize projection info. result type comes from scan desc
- * below..
- * ----------------
- */
- ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
-
- /* --------------------------------
- * Part 2) initialize index scan state
- *
- * create new IndexScanState for node
- * --------------------------------
- */
- indexstate = makeNode(IndexScanState);
- indexstate->iss_NumIndices = 0;
- indexstate->iss_IndexPtr = 0;
- indexstate->iss_ScanKeys = NULL;
- indexstate->iss_NumScanKeys = NULL;
- indexstate->iss_RuntimeKeyInfo = NULL;
- indexstate->iss_RelationDescs = NULL;
- indexstate->iss_ScanDescs = NULL;
-
- node->indxstate = indexstate;
-
- /* ----------------
- * assign base id to index scan state also
- * ----------------
- */
- indexstate->cstate.cs_base_id = baseid;
- baseid++;
- estate->es_BaseId = baseid;
-
- /* ----------------
- * get the index node information
- * ----------------
- */
- indxid = node->indxid;
- indxqual = node->indxqual;
- numIndices = length(indxid);
- indexPtr = 0;
-
- CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
-
- /* ----------------
- * scanKeys is used to keep track of the ScanKey's. This is needed
- * because a single scan may use several indices and each index has
- * its own ScanKey.
- * ----------------
- */
- numScanKeys = (int *) palloc(numIndices * sizeof(int));
- scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
- relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
- scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
-
- /* ----------------
- * initialize runtime key info.
- * ----------------
- */
- have_runtime_keys = false;
- runtimeKeyInfo = (Pointer *)
- palloc(numIndices * sizeof(Pointer));
-
- /* ----------------
- * build the index scan keys from the index qualification
- * ----------------
- */
- for (i=0; i < numIndices; i++) {
- int j;
- List *qual;
- int n_keys;
- ScanKey scan_keys;
- int *run_keys;
-
- qual = nth(i, indxqual);
- n_keys = length(qual);
- scan_keys = (n_keys <= 0) ? NULL :
- (ScanKey)palloc(n_keys * sizeof(ScanKeyData));
- run_keys = (n_keys <= 0) ? NULL :
- (int *)palloc(n_keys * sizeof(int));
-
- CXT1_printf("ExecInitIndexScan: context is %d\n",
- CurrentMemoryContext);
-
/* ----------------
- * for each opclause in the given qual,
- * convert each qual's opclause into a single scan key
+ * tuple table initialization
* ----------------
*/
- for (j=0; j < n_keys; j++) {
- Expr *clause; /* one part of index qual */
- Oper *op; /* operator used in scan.. */
- Node *leftop; /* expr on lhs of operator */
- Node *rightop; /* expr on rhs ... */
- bits16 flags = 0;
-
- int scanvar; /* which var identifies varattno */
- AttrNumber varattno = 0; /* att number used in scan */
- Oid opid; /* operator id used in scan */
- Datum scanvalue = 0; /* value used in scan (if const) */
-
- /* ----------------
- * extract clause information from the qualification
- * ----------------
- */
- clause = nth(j, qual);
-
- op = (Oper*)clause->oper;
- if (!IsA(op,Oper))
- elog(WARN, "ExecInitIndexScan: op not an Oper!");
-
- opid = op->opid;
-
- /* ----------------
- * Here we figure out the contents of the index qual.
- * The usual case is (op var const) or (op const var)
- * which means we form a scan key for the attribute
- * listed in the var node and use the value of the const.
- *
- * If we don't have a const node, then it means that
- * one of the var nodes refers to the "scan" tuple and
- * is used to determine which attribute to scan, and the
- * other expression is used to calculate the value used in
- * scanning the index.
- *
- * This means our index scan's scan key is a function of
- * information obtained during the execution of the plan
- * in which case we need to recalculate the index scan key
- * at run time.
- *
- * Hence, we set have_runtime_keys to true and then set
- * the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
- * The corresponding scan keys are recomputed at run time.
- * ----------------
- */
-
- scanvar = NO_OP;
-
- /* ----------------
- * determine information in leftop
- * ----------------
- */
- leftop = (Node*) get_leftop(clause);
-
- if (IsA(leftop,Var) && var_is_rel((Var*)leftop)) {
- /* ----------------
- * if the leftop is a "rel-var", then it means
- * that it is a var node which tells us which
- * attribute to use for our scan key.
- * ----------------
- */
- varattno = ((Var*) leftop)->varattno;
- scanvar = LEFT_OP;
- } else if (IsA(leftop,Const)) {
+ ExecInitResultTupleSlot(estate, &scanstate->cstate);
+ ExecInitScanTupleSlot(estate, scanstate);
+/* ExecInitRawTupleSlot(estate, scanstate); */
+
+ /* ----------------
+ * initialize projection info. result type comes from scan desc
+ * below..
+ * ----------------
+ */
+ ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
+
+ /* --------------------------------
+ * Part 2) initialize index scan state
+ *
+ * create new IndexScanState for node
+ * --------------------------------
+ */
+ indexstate = makeNode(IndexScanState);
+ indexstate->iss_NumIndices = 0;
+ indexstate->iss_IndexPtr = 0;
+ indexstate->iss_ScanKeys = NULL;
+ indexstate->iss_NumScanKeys = NULL;
+ indexstate->iss_RuntimeKeyInfo = NULL;
+ indexstate->iss_RelationDescs = NULL;
+ indexstate->iss_ScanDescs = NULL;
+
+ node->indxstate = indexstate;
+
+ /* ----------------
+ * assign base id to index scan state also
+ * ----------------
+ */
+ indexstate->cstate.cs_base_id = baseid;
+ baseid++;
+ estate->es_BaseId = baseid;
+
+ /* ----------------
+ * get the index node information
+ * ----------------
+ */
+ indxid = node->indxid;
+ indxqual = node->indxqual;
+ numIndices = length(indxid);
+ indexPtr = 0;
+
+ CXT1_printf("ExecInitIndexScan: context is %d\n", CurrentMemoryContext);
+
+ /* ----------------
+ * scanKeys is used to keep track of the ScanKey's. This is needed
+ * because a single scan may use several indices and each index has
+ * its own ScanKey.
+ * ----------------
+ */
+ numScanKeys = (int *) palloc(numIndices * sizeof(int));
+ scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
+ relationDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
+ scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
+
+ /* ----------------
+ * initialize runtime key info.
+ * ----------------
+ */
+ have_runtime_keys = false;
+ runtimeKeyInfo = (Pointer *)
+ palloc(numIndices * sizeof(Pointer));
+
+ /* ----------------
+ * build the index scan keys from the index qualification
+ * ----------------
+ */
+ for (i = 0; i < numIndices; i++)
+ {
+ int j;
+ List *qual;
+ int n_keys;
+ ScanKey scan_keys;
+ int *run_keys;
+
+ qual = nth(i, indxqual);
+ n_keys = length(qual);
+ scan_keys = (n_keys <= 0) ? NULL :
+ (ScanKey) palloc(n_keys * sizeof(ScanKeyData));
+ run_keys = (n_keys <= 0) ? NULL :
+ (int *) palloc(n_keys * sizeof(int));
+
+ CXT1_printf("ExecInitIndexScan: context is %d\n",
+ CurrentMemoryContext);
+
/* ----------------
- * if the leftop is a const node then it means
- * it identifies the value to place in our scan key.
+ * for each opclause in the given qual,
+ * convert each qual's opclause into a single scan key
* ----------------
*/
- run_keys[ j ] = NO_OP;
- scanvalue = ((Const*) leftop)->constvalue;
+ for (j = 0; j < n_keys; j++)
+ {
+ Expr *clause; /* one part of index qual */
+ Oper *op; /* operator used in scan.. */
+ Node *leftop; /* expr on lhs of operator */
+ Node *rightop; /* expr on rhs ... */
+ bits16 flags = 0;
+
+ int scanvar; /* which var identifies varattno */
+ AttrNumber varattno = 0; /* att number used in scan */
+ Oid opid; /* operator id used in scan */
+ Datum scanvalue = 0; /* value used in scan (if
+ * const) */
+
+ /* ----------------
+ * extract clause information from the qualification
+ * ----------------
+ */
+ clause = nth(j, qual);
+
+ op = (Oper *) clause->oper;
+ if (!IsA(op, Oper))
+ elog(WARN, "ExecInitIndexScan: op not an Oper!");
+
+ opid = op->opid;
+
+ /* ----------------
+ * Here we figure out the contents of the index qual.
+ * The usual case is (op var const) or (op const var)
+ * which means we form a scan key for the attribute
+ * listed in the var node and use the value of the const.
+ *
+ * If we don't have a const node, then it means that
+ * one of the var nodes refers to the "scan" tuple and
+ * is used to determine which attribute to scan, and the
+ * other expression is used to calculate the value used in
+ * scanning the index.
+ *
+ * This means our index scan's scan key is a function of
+ * information obtained during the execution of the plan
+ * in which case we need to recalculate the index scan key
+ * at run time.
+ *
+ * Hence, we set have_runtime_keys to true and then set
+ * the appropriate flag in run_keys to LEFT_OP or RIGHT_OP.
+ * The corresponding scan keys are recomputed at run time.
+ * ----------------
+ */
+
+ scanvar = NO_OP;
+
+ /* ----------------
+ * determine information in leftop
+ * ----------------
+ */
+ leftop = (Node *) get_leftop(clause);
+
+ if (IsA(leftop, Var) && var_is_rel((Var *) leftop))
+ {
+ /* ----------------
+ * if the leftop is a "rel-var", then it means
+ * that it is a var node which tells us which
+ * attribute to use for our scan key.
+ * ----------------
+ */
+ varattno = ((Var *) leftop)->varattno;
+ scanvar = LEFT_OP;
+ }
+ else if (IsA(leftop, Const))
+ {
+ /* ----------------
+ * if the leftop is a const node then it means
+ * it identifies the value to place in our scan key.
+ * ----------------
+ */
+ run_keys[j] = NO_OP;
+ scanvalue = ((Const *) leftop)->constvalue;
#ifdef INDEXSCAN_PATCH
- } else if (IsA(leftop,Param)) {
- bool isnull;
- /* ----------------
- * if the leftop is a Param node then it means
- * it identifies the value to place in our scan key.
- * ----------------
- */
- run_keys[ j ] = NO_OP;
- scanvalue = ExecEvalParam((Param*) leftop,
- scanstate->cstate.cs_ExprContext,
- &isnull);
- if ( isnull )
- flags |= SK_ISNULL;
+ }
+ else if (IsA(leftop, Param))
+ {
+ bool isnull;
+
+ /* ----------------
+ * if the leftop is a Param node then it means
+ * it identifies the value to place in our scan key.
+ * ----------------
+ */
+ run_keys[j] = NO_OP;
+ scanvalue = ExecEvalParam((Param *) leftop,
+ scanstate->cstate.cs_ExprContext,
+ &isnull);
+ if (isnull)
+ flags |= SK_ISNULL;
#endif
- } else if (leftop != NULL &&
- is_funcclause(leftop) &&
- var_is_rel(lfirst(((Expr*)leftop)->args))) {
- /* ----------------
- * if the leftop is a func node then it means
- * it identifies the value to place in our scan key.
- * Since functional indices have only one attribute
- * the attno must always be set to 1.
- * ----------------
- */
- varattno = 1;
- scanvar = LEFT_OP;
-
- } else {
- /* ----------------
- * otherwise, the leftop contains information usable
- * at runtime to figure out the value to place in our
- * scan key.
- * ----------------
- */
- have_runtime_keys = true;
- run_keys[ j ] = LEFT_OP;
- scanvalue = Int32GetDatum((int32) true);
- }
-
- /* ----------------
- * now determine information in rightop
- * ----------------
- */
- rightop = (Node*) get_rightop(clause);
-
- if (IsA(rightop,Var) && var_is_rel((Var*)rightop)) {
- /* ----------------
- * here we make sure only one op identifies the
- * scan-attribute...
- * ----------------
- */
- if (scanvar == LEFT_OP)
- elog(WARN, "ExecInitIndexScan: %s",
- "both left and right op's are rel-vars");
-
- /* ----------------
- * if the rightop is a "rel-var", then it means
- * that it is a var node which tells us which
- * attribute to use for our scan key.
- * ----------------
- */
- varattno = ((Var*) rightop)->varattno;
- scanvar = RIGHT_OP;
-
- } else if (IsA(rightop,Const)) {
- /* ----------------
- * if the leftop is a const node then it means
- * it identifies the value to place in our scan key.
- * ----------------
- */
- run_keys[ j ] = NO_OP;
- scanvalue = ((Const*) rightop)->constvalue;
+ }
+ else if (leftop != NULL &&
+ is_funcclause(leftop) &&
+ var_is_rel(lfirst(((Expr *) leftop)->args)))
+ {
+ /* ----------------
+ * if the leftop is a func node then it means
+ * it identifies the value to place in our scan key.
+ * Since functional indices have only one attribute
+ * the attno must always be set to 1.
+ * ----------------
+ */
+ varattno = 1;
+ scanvar = LEFT_OP;
+
+ }
+ else
+ {
+ /* ----------------
+ * otherwise, the leftop contains information usable
+ * at runtime to figure out the value to place in our
+ * scan key.
+ * ----------------
+ */
+ have_runtime_keys = true;
+ run_keys[j] = LEFT_OP;
+ scanvalue = Int32GetDatum((int32) true);
+ }
+
+ /* ----------------
+ * now determine information in rightop
+ * ----------------
+ */
+ rightop = (Node *) get_rightop(clause);
+
+ if (IsA(rightop, Var) && var_is_rel((Var *) rightop))
+ {
+ /* ----------------
+ * here we make sure only one op identifies the
+ * scan-attribute...
+ * ----------------
+ */
+ if (scanvar == LEFT_OP)
+ elog(WARN, "ExecInitIndexScan: %s",
+ "both left and right op's are rel-vars");
+
+ /* ----------------
+ * if the rightop is a "rel-var", then it means
+ * that it is a var node which tells us which
+ * attribute to use for our scan key.
+ * ----------------
+ */
+ varattno = ((Var *) rightop)->varattno;
+ scanvar = RIGHT_OP;
+
+ }
+ else if (IsA(rightop, Const))
+ {
+ /* ----------------
+ * if the leftop is a const node then it means
+ * it identifies the value to place in our scan key.
+ * ----------------
+ */
+ run_keys[j] = NO_OP;
+ scanvalue = ((Const *) rightop)->constvalue;
#ifdef INDEXSCAN_PATCH
- } else if (IsA(rightop,Param)) {
- bool isnull;
- /* ----------------
- * if the rightop is a Param node then it means
- * it identifies the value to place in our scan key.
- * ----------------
- */
- run_keys[ j ] = NO_OP;
- scanvalue = ExecEvalParam((Param*) rightop,
- scanstate->cstate.cs_ExprContext,
- &isnull);
- if ( isnull )
- flags |= SK_ISNULL;
+ }
+ else if (IsA(rightop, Param))
+ {
+ bool isnull;
+
+ /* ----------------
+ * if the rightop is a Param node then it means
+ * it identifies the value to place in our scan key.
+ * ----------------
+ */
+ run_keys[j] = NO_OP;
+ scanvalue = ExecEvalParam((Param *) rightop,
+ scanstate->cstate.cs_ExprContext,
+ &isnull);
+ if (isnull)
+ flags |= SK_ISNULL;
#endif
- } else if (rightop!=NULL &&
- is_funcclause(rightop) &&
- var_is_rel(lfirst(((Expr*)rightop)->args))) {
- /* ----------------
- * if the rightop is a func node then it means
- * it identifies the value to place in our scan key.
- * Since functional indices have only one attribute
- * the attno must always be set to 1.
- * ----------------
- */
- if (scanvar == LEFT_OP)
- elog(WARN, "ExecInitIndexScan: %s",
- "both left and right ops are rel-vars");
-
- varattno = 1;
- scanvar = RIGHT_OP;
-
- } else {
+ }
+ else if (rightop != NULL &&
+ is_funcclause(rightop) &&
+ var_is_rel(lfirst(((Expr *) rightop)->args)))
+ {
+ /* ----------------
+ * if the rightop is a func node then it means
+ * it identifies the value to place in our scan key.
+ * Since functional indices have only one attribute
+ * the attno must always be set to 1.
+ * ----------------
+ */
+ if (scanvar == LEFT_OP)
+ elog(WARN, "ExecInitIndexScan: %s",
+ "both left and right ops are rel-vars");
+
+ varattno = 1;
+ scanvar = RIGHT_OP;
+
+ }
+ else
+ {
+ /* ----------------
+ * otherwise, the leftop contains information usable
+ * at runtime to figure out the value to place in our
+ * scan key.
+ * ----------------
+ */
+ have_runtime_keys = true;
+ run_keys[j] = RIGHT_OP;
+ scanvalue = Int32GetDatum((int32) true);
+ }
+
+ /* ----------------
+ * now check that at least one op tells us the scan
+ * attribute...
+ * ----------------
+ */
+ if (scanvar == NO_OP)
+ elog(WARN, "ExecInitIndexScan: %s",
+ "neither leftop nor rightop refer to scan relation");
+
+ /* ----------------
+ * initialize the scan key's fields appropriately
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&scan_keys[j],
+ flags,
+ varattno, /* attribute number to
+ * scan */
+ (RegProcedure) opid, /* reg proc to use */
+ (Datum) scanvalue); /* constant */
+ }
+
/* ----------------
- * otherwise, the leftop contains information usable
- * at runtime to figure out the value to place in our
- * scan key.
+ * store the key information into our array.
* ----------------
*/
- have_runtime_keys = true;
- run_keys[ j ] = RIGHT_OP;
- scanvalue = Int32GetDatum((int32) true);
- }
-
- /* ----------------
- * now check that at least one op tells us the scan
- * attribute...
- * ----------------
- */
- if (scanvar == NO_OP)
- elog(WARN, "ExecInitIndexScan: %s",
- "neither leftop nor rightop refer to scan relation");
-
- /* ----------------
- * initialize the scan key's fields appropriately
- * ----------------
- */
- ScanKeyEntryInitialize(&scan_keys[j],
- flags,
- varattno, /* attribute number to scan */
- (RegProcedure) opid, /* reg proc to use */
- (Datum) scanvalue); /* constant */
+ numScanKeys[i] = n_keys;
+ scanKeys[i] = scan_keys;
+ runtimeKeyInfo[i] = (Pointer) run_keys;
}
-
+
+ indexstate->iss_NumIndices = numIndices;
+ indexstate->iss_IndexPtr = indexPtr;
+ indexstate->iss_ScanKeys = scanKeys;
+ indexstate->iss_NumScanKeys = numScanKeys;
+
/* ----------------
- * store the key information into our array.
+ * If all of our keys have the form (op var const) , then we have no
+ * runtime keys so we store NULL in the runtime key info.
+ * Otherwise runtime key info contains an array of pointers
+ * (one for each index) to arrays of flags (one for each key)
+ * which indicate that the qual needs to be evaluated at runtime.
+ * -cim 10/24/89
* ----------------
*/
- numScanKeys[ i ] = n_keys;
- scanKeys[ i ] = scan_keys;
- runtimeKeyInfo[ i ] = (Pointer) run_keys;
- }
-
- indexstate->iss_NumIndices = numIndices;
- indexstate->iss_IndexPtr = indexPtr;
- indexstate->iss_ScanKeys = scanKeys;
- indexstate->iss_NumScanKeys = numScanKeys;
-
- /* ----------------
- * If all of our keys have the form (op var const) , then we have no
- * runtime keys so we store NULL in the runtime key info.
- * Otherwise runtime key info contains an array of pointers
- * (one for each index) to arrays of flags (one for each key)
- * which indicate that the qual needs to be evaluated at runtime.
- * -cim 10/24/89
- * ----------------
- */
- if (have_runtime_keys)
+ if (have_runtime_keys)
{
- indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
+ indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo;
}
- else {
- indexstate->iss_RuntimeKeyInfo = NULL;
- for (i=0; i < numIndices; i++) {
- List *qual;
- int n_keys;
- qual = nth(i, indxqual);
- n_keys = length(qual);
- if (n_keys > 0)
- pfree(runtimeKeyInfo[i]);
+ else
+ {
+ indexstate->iss_RuntimeKeyInfo = NULL;
+ for (i = 0; i < numIndices; i++)
+ {
+ List *qual;
+ int n_keys;
+
+ qual = nth(i, indxqual);
+ n_keys = length(qual);
+ if (n_keys > 0)
+ pfree(runtimeKeyInfo[i]);
+ }
+ pfree(runtimeKeyInfo);
}
- pfree(runtimeKeyInfo);
- }
-
- /* ----------------
- * get the range table and direction information
- * from the execution state (these are needed to
- * open the relations).
- * ----------------
- */
- rangeTable = estate->es_range_table;
- direction = estate->es_direction;
-
- /* ----------------
- * open the base relation
- * ----------------
- */
- relid = node->scan.scanrelid;
- rtentry = rt_fetch(relid, rangeTable);
- reloid = rtentry->relid;
- timeQual = rtentry->timeQual;
-
- ExecOpenScanR(reloid, /* relation */
- 0, /* nkeys */
- (ScanKey) NULL, /* scan key */
- 0, /* is index */
- direction, /* scan direction */
- timeQual, /* time qual */
- &currentRelation, /* return: rel desc */
- (Pointer *) &currentScanDesc); /* return: scan desc */
-
- scanstate->css_currentRelation = currentRelation;
- scanstate->css_currentScanDesc = currentScanDesc;
-
-
- /* ----------------
- * get the scan type from the relation descriptor.
- * ----------------
- */
- ExecAssignScanType(scanstate, RelationGetTupleDescriptor(currentRelation));
- ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
-
- /* ----------------
- * index scans don't have subtrees..
- * ----------------
- */
-/* scanstate->ss_ProcOuterFlag = false; */
-
- /* ----------------
- * open the index relations and initialize
- * relation and scan descriptors.
- * ----------------
- */
- for (i=0; i < numIndices; i++) {
- Oid indexOid;
-
- indexOid = (Oid)nthi(i, indxid);
-
- if (indexOid != 0) {
- ExecOpenScanR(indexOid, /* relation */
- numScanKeys[ i ], /* nkeys */
- scanKeys[ i ], /* scan key */
- true, /* is index */
- direction, /* scan direction */
- timeQual, /* time qual */
- &(relationDescs[ i ]), /* return: rel desc */
- (Pointer *) &(scanDescs[ i ]));
- /* return: scan desc */
+
+ /* ----------------
+ * get the range table and direction information
+ * from the execution state (these are needed to
+ * open the relations).
+ * ----------------
+ */
+ rangeTable = estate->es_range_table;
+ direction = estate->es_direction;
+
+ /* ----------------
+ * open the base relation
+ * ----------------
+ */
+ relid = node->scan.scanrelid;
+ rtentry = rt_fetch(relid, rangeTable);
+ reloid = rtentry->relid;
+ timeQual = rtentry->timeQual;
+
+ ExecOpenScanR(reloid, /* relation */
+ 0, /* nkeys */
+ (ScanKey) NULL, /* scan key */
+ 0, /* is index */
+ direction, /* scan direction */
+ timeQual, /* time qual */
+ &currentRelation, /* return: rel desc */
+ (Pointer *) & currentScanDesc); /* return: scan desc */
+
+ scanstate->css_currentRelation = currentRelation;
+ scanstate->css_currentScanDesc = currentScanDesc;
+
+
+ /* ----------------
+ * get the scan type from the relation descriptor.
+ * ----------------
+ */
+ ExecAssignScanType(scanstate, RelationGetTupleDescriptor(currentRelation));
+ ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
+
+ /* ----------------
+ * index scans don't have subtrees..
+ * ----------------
+ */
+/* scanstate->ss_ProcOuterFlag = false; */
+
+ /* ----------------
+ * open the index relations and initialize
+ * relation and scan descriptors.
+ * ----------------
+ */
+ for (i = 0; i < numIndices; i++)
+ {
+ Oid indexOid;
+
+ indexOid = (Oid) nthi(i, indxid);
+
+ if (indexOid != 0)
+ {
+ ExecOpenScanR(indexOid, /* relation */
+ numScanKeys[i], /* nkeys */
+ scanKeys[i], /* scan key */
+ true, /* is index */
+ direction, /* scan direction */
+ timeQual, /* time qual */
+ &(relationDescs[i]), /* return: rel desc */
+ (Pointer *) & (scanDescs[i]));
+ /* return: scan desc */
+ }
}
- }
- indexstate->iss_RelationDescs = relationDescs;
- indexstate->iss_ScanDescs = scanDescs;
+ indexstate->iss_RelationDescs = relationDescs;
+ indexstate->iss_ScanDescs = scanDescs;
- indexstate->cstate.cs_TupFromTlist = false;
+ indexstate->cstate.cs_TupFromTlist = false;
- /* ----------------
- * all done.
- * ----------------
- */
- return TRUE;
+ /* ----------------
+ * all done.
+ * ----------------
+ */
+ return TRUE;
}
int
-ExecCountSlotsIndexScan(IndexScan *node)
+ExecCountSlotsIndexScan(IndexScan * node)
{
- return ExecCountSlotsNode(outerPlan((Plan *)node)) +
- ExecCountSlotsNode(innerPlan((Plan *)node)) +
- INDEXSCAN_NSLOTS;
+ return ExecCountSlotsNode(outerPlan((Plan *) node)) +
+ ExecCountSlotsNode(innerPlan((Plan *) node)) +
+ INDEXSCAN_NSLOTS;
}
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index daf324bb77a..49ba73d3bf0 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* nodeMaterial.c--
- * Routines to handle materialization nodes.
+ * Routines to handle materialization nodes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.6 1997/08/20 14:53:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.7 1997/09/07 04:41:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecMaterial - generate a temporary relation
- * ExecInitMaterial - initialize node and subnodes..
- * ExecEndMaterial - shutdown node and subnodes
+ * ExecMaterial - generate a temporary relation
+ * ExecInitMaterial - initialize node and subnodes..
+ * ExecEndMaterial - shutdown node and subnodes
*
*/
#include "postgres.h"
@@ -29,368 +29,373 @@
#include "access/heapam.h"
/* ----------------------------------------------------------------
- * ExecMaterial
+ * ExecMaterial
*
- * The first time this is called, ExecMaterial retrieves tuples
- * this node's outer subplan and inserts them into a temporary
- * relation. After this is done, a flag is set indicating that
- * the subplan has been materialized. Once the relation is
- * materialized, the first tuple is then returned. Successive
- * calls to ExecMaterial return successive tuples from the temp
- * relation.
+ * The first time this is called, ExecMaterial retrieves tuples
+ * this node's outer subplan and inserts them into a temporary
+ * relation. After this is done, a flag is set indicating that
+ * the subplan has been materialized. Once the relation is
+ * materialized, the first tuple is then returned. Successive
+ * calls to ExecMaterial return successive tuples from the temp
+ * relation.
*
- * Initial State:
+ * Initial State:
*
- * ExecMaterial assumes the temporary relation has been
- * created and openend by ExecInitMaterial during the prior
- * InitPlan() phase.
+ * ExecMaterial assumes the temporary relation has been
+ * created and openend by ExecInitMaterial during the prior
+ * InitPlan() phase.
*
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* result tuple from subplan */
-ExecMaterial(Material *node)
+TupleTableSlot * /* result tuple from subplan */
+ExecMaterial(Material * node)
{
- EState *estate;
- MaterialState *matstate;
- Plan *outerNode;
- ScanDirection dir;
- Relation tempRelation;
- Relation currentRelation;
- HeapScanDesc currentScanDesc;
- HeapTuple heapTuple;
- TupleTableSlot *slot;
- Buffer buffer;
-
- /* ----------------
- * get state info from node
- * ----------------
- */
- matstate = node->matstate;
- estate = node->plan.state;
- dir = estate->es_direction;
-
- /* ----------------
- * the first time we call this, we retrieve all tuples
- * from the subplan into a temporary relation and then
- * we sort the relation. Subsequent calls return tuples
- * from the temporary relation.
- * ----------------
- */
-
- if (matstate->mat_Flag == false) {
+ EState *estate;
+ MaterialState *matstate;
+ Plan *outerNode;
+ ScanDirection dir;
+ Relation tempRelation;
+ Relation currentRelation;
+ HeapScanDesc currentScanDesc;
+ HeapTuple heapTuple;
+ TupleTableSlot *slot;
+ Buffer buffer;
+
/* ----------------
- * set all relations to be scanned in the forward direction
- * while creating the temporary relation.
+ * get state info from node
* ----------------
*/
- estate->es_direction = ForwardScanDirection;
-
+ matstate = node->matstate;
+ estate = node->plan.state;
+ dir = estate->es_direction;
+
/* ----------------
- * if we couldn't create the temp or current relations then
- * we print a warning and return NULL.
+ * the first time we call this, we retrieve all tuples
+ * from the subplan into a temporary relation and then
+ * we sort the relation. Subsequent calls return tuples
+ * from the temporary relation.
* ----------------
*/
- tempRelation = matstate->mat_TempRelation;
- if (tempRelation == NULL) {
- elog(DEBUG, "ExecMaterial: temp relation is NULL! aborting...");
- return NULL;
- }
-
- currentRelation = matstate->csstate.css_currentRelation;
- if (currentRelation == NULL) {
- elog(DEBUG, "ExecMaterial: current relation is NULL! aborting...");
- return NULL;
+
+ if (matstate->mat_Flag == false)
+ {
+ /* ----------------
+ * set all relations to be scanned in the forward direction
+ * while creating the temporary relation.
+ * ----------------
+ */
+ estate->es_direction = ForwardScanDirection;
+
+ /* ----------------
+ * if we couldn't create the temp or current relations then
+ * we print a warning and return NULL.
+ * ----------------
+ */
+ tempRelation = matstate->mat_TempRelation;
+ if (tempRelation == NULL)
+ {
+ elog(DEBUG, "ExecMaterial: temp relation is NULL! aborting...");
+ return NULL;
+ }
+
+ currentRelation = matstate->csstate.css_currentRelation;
+ if (currentRelation == NULL)
+ {
+ elog(DEBUG, "ExecMaterial: current relation is NULL! aborting...");
+ return NULL;
+ }
+
+ /* ----------------
+ * retrieve tuples from the subplan and
+ * insert them in the temporary relation
+ * ----------------
+ */
+ outerNode = outerPlan((Plan *) node);
+ for (;;)
+ {
+ slot = ExecProcNode(outerNode, (Plan *) node);
+
+ heapTuple = slot->val;
+ if (heapTuple == NULL)
+ break;
+
+ heap_insert(tempRelation, /* relation desc */
+ heapTuple); /* heap tuple to insert */
+
+ ExecClearTuple(slot);
+ }
+ currentRelation = tempRelation;
+
+ /* ----------------
+ * restore to user specified direction
+ * ----------------
+ */
+ estate->es_direction = dir;
+
+ /* ----------------
+ * now initialize the scan descriptor to scan the
+ * sorted relation and update the sortstate information
+ * ----------------
+ */
+ currentScanDesc = heap_beginscan(currentRelation, /* relation */
+ ScanDirectionIsBackward(dir),
+ /* bkwd flag */
+ NowTimeQual, /* time qual */
+ 0, /* num scan keys */
+ NULL); /* scan keys */
+ matstate->csstate.css_currentRelation = currentRelation;
+ matstate->csstate.css_currentScanDesc = currentScanDesc;
+
+ ExecAssignScanType(&matstate->csstate,
+ RelationGetTupleDescriptor(currentRelation));
+
+ /* ----------------
+ * finally set the sorted flag to true
+ * ----------------
+ */
+ matstate->mat_Flag = true;
}
-
+
/* ----------------
- * retrieve tuples from the subplan and
- * insert them in the temporary relation
+ * at this point we know we have a sorted relation so
+ * we preform a simple scan on it with amgetnext()..
* ----------------
*/
- outerNode = outerPlan((Plan *) node);
- for (;;) {
- slot = ExecProcNode(outerNode, (Plan*) node);
-
- heapTuple = slot->val;
- if (heapTuple == NULL)
- break;
-
- heap_insert(tempRelation, /* relation desc */
- heapTuple); /* heap tuple to insert */
-
- ExecClearTuple( slot);
- }
- currentRelation = tempRelation;
-
+ currentScanDesc = matstate->csstate.css_currentScanDesc;
+
+ heapTuple = heap_getnext(currentScanDesc, /* scan desc */
+ ScanDirectionIsBackward(dir),
+ /* bkwd flag */
+ &buffer); /* return: buffer */
+
/* ----------------
- * restore to user specified direction
+ * put the tuple into the scan tuple slot and return the slot.
+ * Note: since the tuple is really a pointer to a page, we don't want
+ * to call pfree() on it..
* ----------------
*/
- estate->es_direction = dir;
-
+ slot = (TupleTableSlot *) matstate->csstate.css_ScanTupleSlot;
+
+ return ExecStoreTuple(heapTuple, /* tuple to store */
+ slot, /* slot to store in */
+ buffer, /* buffer for this tuple */
+ false); /* don't pfree this pointer */
+
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitMaterial
+ * ----------------------------------------------------------------
+ */
+bool /* initialization status */
+ExecInitMaterial(Material * node, EState * estate, Plan * parent)
+{
+ MaterialState *matstate;
+ Plan *outerPlan;
+ TupleDesc tupType;
+ Relation tempDesc;
+
+ /* int len; */
+
/* ----------------
- * now initialize the scan descriptor to scan the
- * sorted relation and update the sortstate information
+ * assign the node's execution state
* ----------------
*/
- currentScanDesc = heap_beginscan(currentRelation, /* relation */
- ScanDirectionIsBackward(dir),
- /* bkwd flag */
- NowTimeQual, /* time qual */
- 0, /* num scan keys */
- NULL); /* scan keys */
- matstate->csstate.css_currentRelation = currentRelation;
- matstate->csstate.css_currentScanDesc = currentScanDesc;
-
- ExecAssignScanType(&matstate->csstate,
- RelationGetTupleDescriptor(currentRelation));
-
+ node->plan.state = estate;
+
/* ----------------
- * finally set the sorted flag to true
+ * create state structure
* ----------------
*/
- matstate->mat_Flag = true;
- }
-
- /* ----------------
- * at this point we know we have a sorted relation so
- * we preform a simple scan on it with amgetnext()..
- * ----------------
- */
- currentScanDesc = matstate->csstate.css_currentScanDesc;
-
- heapTuple = heap_getnext(currentScanDesc, /* scan desc */
- ScanDirectionIsBackward(dir),
- /* bkwd flag */
- &buffer); /* return: buffer */
-
- /* ----------------
- * put the tuple into the scan tuple slot and return the slot.
- * Note: since the tuple is really a pointer to a page, we don't want
- * to call pfree() on it..
- * ----------------
- */
- slot = (TupleTableSlot *)matstate->csstate.css_ScanTupleSlot;
-
- return ExecStoreTuple(heapTuple, /* tuple to store */
- slot, /* slot to store in */
- buffer, /* buffer for this tuple */
- false); /* don't pfree this pointer */
-
-}
+ matstate = makeNode(MaterialState);
+ matstate->mat_Flag = false;
+ matstate->mat_TempRelation = NULL;
+ node->matstate = matstate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ * + assign result tuple slot
+ *
+ * Materialization nodes don't need ExprContexts because
+ * they never call ExecQual or ExecTargetList.
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &matstate->csstate.cstate, parent);
-/* ----------------------------------------------------------------
- * ExecInitMaterial
- * ----------------------------------------------------------------
- */
-bool /* initialization status */
-ExecInitMaterial(Material *node, EState *estate, Plan *parent)
-{
- MaterialState *matstate;
- Plan *outerPlan;
- TupleDesc tupType;
- Relation tempDesc;
- /* int len; */
-
- /* ----------------
- * assign the node's execution state
- * ----------------
- */
- node->plan.state = estate;
-
- /* ----------------
- * create state structure
- * ----------------
- */
- matstate = makeNode(MaterialState);
- matstate->mat_Flag = false;
- matstate->mat_TempRelation = NULL;
- node->matstate = matstate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + assign result tuple slot
- *
- * Materialization nodes don't need ExprContexts because
- * they never call ExecQual or ExecTargetList.
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &matstate->csstate.cstate, parent);
-
#define MATERIAL_NSLOTS 1
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitScanTupleSlot(estate, &matstate->csstate);
-
- /* ----------------
- * initializes child nodes
- * ----------------
- */
- outerPlan = outerPlan((Plan *) node);
- ExecInitNode(outerPlan, estate, (Plan *) node);
-
- /* ----------------
- * initialize matstate information
- * ----------------
- */
- matstate->mat_Flag = false;
-
- /* ----------------
- * initialize tuple type. no need to initialize projection
- * info because this node doesn't do projections.
- * ----------------
- */
- ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
- matstate->csstate.cstate.cs_ProjInfo = NULL;
-
- /* ----------------
- * get type information needed for ExecCreatR
- * ----------------
- */
- tupType = ExecGetScanType(&matstate->csstate);
-
- /* ----------------
- * ExecCreatR wants it's second argument to be an object id of
- * a relation in the range table or a _TEMP_RELATION_ID
- * indicating that the relation is not in the range table.
- *
- * In the second case ExecCreatR creates a temp relation.
- * (currently this is the only case we support -cim 10/16/89)
- * ----------------
- */
- /* ----------------
- * create the temporary relation
- * ----------------
- */
-/* len = ExecTargetListLength(node->plan.targetlist); */
- tempDesc = ExecCreatR(tupType, _TEMP_RELATION_ID_);
-
- /* ----------------
- * save the relation descriptor in the sortstate
- * ----------------
- */
- matstate->mat_TempRelation = tempDesc;
- matstate->csstate.css_currentRelation = tempDesc;
-
- /* ----------------
- * return relation oid of temporary relation in a list
- * (someday -- for now we return LispTrue... cim 10/12/89)
- * ----------------
- */
- return TRUE;
+ /* ----------------
+ * tuple table initialization
+ * ----------------
+ */
+ ExecInitScanTupleSlot(estate, &matstate->csstate);
+
+ /* ----------------
+ * initializes child nodes
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * initialize matstate information
+ * ----------------
+ */
+ matstate->mat_Flag = false;
+
+ /* ----------------
+ * initialize tuple type. no need to initialize projection
+ * info because this node doesn't do projections.
+ * ----------------
+ */
+ ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
+ matstate->csstate.cstate.cs_ProjInfo = NULL;
+
+ /* ----------------
+ * get type information needed for ExecCreatR
+ * ----------------
+ */
+ tupType = ExecGetScanType(&matstate->csstate);
+
+ /* ----------------
+ * ExecCreatR wants it's second argument to be an object id of
+ * a relation in the range table or a _TEMP_RELATION_ID
+ * indicating that the relation is not in the range table.
+ *
+ * In the second case ExecCreatR creates a temp relation.
+ * (currently this is the only case we support -cim 10/16/89)
+ * ----------------
+ */
+ /* ----------------
+ * create the temporary relation
+ * ----------------
+ */
+/* len = ExecTargetListLength(node->plan.targetlist); */
+ tempDesc = ExecCreatR(tupType, _TEMP_RELATION_ID_);
+
+ /* ----------------
+ * save the relation descriptor in the sortstate
+ * ----------------
+ */
+ matstate->mat_TempRelation = tempDesc;
+ matstate->csstate.css_currentRelation = tempDesc;
+
+ /* ----------------
+ * return relation oid of temporary relation in a list
+ * (someday -- for now we return LispTrue... cim 10/12/89)
+ * ----------------
+ */
+ return TRUE;
}
int
-ExecCountSlotsMaterial(Material *node)
+ExecCountSlotsMaterial(Material * node)
{
- return ExecCountSlotsNode(outerPlan((Plan *)node)) +
- ExecCountSlotsNode(innerPlan((Plan *)node)) +
- MATERIAL_NSLOTS;
+ return ExecCountSlotsNode(outerPlan((Plan *) node)) +
+ ExecCountSlotsNode(innerPlan((Plan *) node)) +
+ MATERIAL_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndMaterial
+ * ExecEndMaterial
*
* old comments
- * destroys the temporary relation.
+ * destroys the temporary relation.
* ----------------------------------------------------------------
*/
void
-ExecEndMaterial(Material *node)
+ExecEndMaterial(Material * node)
{
- MaterialState *matstate;
- Relation tempRelation;
- Plan *outerPlan;
-
- /* ----------------
- * get info from the material state
- * ----------------
- */
- matstate = node->matstate;
- tempRelation = matstate->mat_TempRelation;
-
- heap_destroyr(tempRelation);
-
- /* ----------------
- * close the temp relation and shut down the scan.
- * ----------------
- */
- ExecCloseR((Plan *) node);
-
- /* ----------------
- * shut down the subplan
- * ----------------
- */
- outerPlan = outerPlan((Plan *) node);
- ExecEndNode(outerPlan, (Plan*) node);
-
- /* ----------------
- * clean out the tuple table
- * ----------------
- */
- ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
-}
-
-#ifdef NOT_USED /* not used */
+ MaterialState *matstate;
+ Relation tempRelation;
+ Plan *outerPlan;
+
+ /* ----------------
+ * get info from the material state
+ * ----------------
+ */
+ matstate = node->matstate;
+ tempRelation = matstate->mat_TempRelation;
+
+ heap_destroyr(tempRelation);
+
+ /* ----------------
+ * close the temp relation and shut down the scan.
+ * ----------------
+ */
+ ExecCloseR((Plan *) node);
+
+ /* ----------------
+ * shut down the subplan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecEndNode(outerPlan, (Plan *) node);
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
+}
+
+#ifdef NOT_USED /* not used */
/* ----------------------------------------------------------------
- * ExecMaterialMarkPos
+ * ExecMaterialMarkPos
* ----------------------------------------------------------------
*/
-List /* nothing of interest */
+List /* nothing of interest */
ExecMaterialMarkPos(Material node)
{
- MaterialState matstate;
- HeapScanDesc sdesc;
-
- /* ----------------
- * if we haven't materialized yet, just return NIL.
- * ----------------
- */
- matstate = get_matstate(node);
- if (get_mat_Flag(matstate) == false)
+ MaterialState matstate;
+ HeapScanDesc sdesc;
+
+ /* ----------------
+ * if we haven't materialized yet, just return NIL.
+ * ----------------
+ */
+ matstate = get_matstate(node);
+ if (get_mat_Flag(matstate) == false)
+ return NIL;
+
+ /* ----------------
+ * XXX access methods don't return positions yet so
+ * for now we return NIL. It's possible that
+ * they will never return positions for all I know -cim 10/16/89
+ * ----------------
+ */
+ sdesc = get_css_currentScanDesc((CommonScanState) matstate);
+ heap_markpos(sdesc);
+
return NIL;
-
- /* ----------------
- * XXX access methods don't return positions yet so
- * for now we return NIL. It's possible that
- * they will never return positions for all I know -cim 10/16/89
- * ----------------
- */
- sdesc = get_css_currentScanDesc((CommonScanState)matstate);
- heap_markpos(sdesc);
-
- return NIL;
}
/* ----------------------------------------------------------------
- * ExecMaterialRestrPos
+ * ExecMaterialRestrPos
* ----------------------------------------------------------------
*/
void
ExecMaterialRestrPos(Material node)
{
- MaterialState matstate;
- HeapScanDesc sdesc;
-
- /* ----------------
- * if we haven't materialized yet, just return.
- * ----------------
- */
- matstate = get_matstate(node);
- if (get_mat_Flag(matstate) == false)
- return;
-
- /* ----------------
- * restore the scan to the previously marked position
- * ----------------
- */
- sdesc = get_css_currentScanDesc((CommonScanState)matstate);
- heap_restrpos(sdesc);
+ MaterialState matstate;
+ HeapScanDesc sdesc;
+
+ /* ----------------
+ * if we haven't materialized yet, just return.
+ * ----------------
+ */
+ matstate = get_matstate(node);
+ if (get_mat_Flag(matstate) == false)
+ return;
+
+ /* ----------------
+ * restore the scan to the previously marked position
+ * ----------------
+ */
+ sdesc = get_css_currentScanDesc((CommonScanState) matstate);
+ heap_restrpos(sdesc);
}
-#endif
+#endif
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 9151479d306..348d3fa1e00 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -1,78 +1,78 @@
/*-------------------------------------------------------------------------
*
* nodeMergejoin.c--
- * routines supporting merge joins
+ * routines supporting merge joins
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.8 1997/08/19 21:31:10 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.9 1997/09/07 04:41:37 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecMergeJoin mergejoin outer and inner relations.
- * ExecInitMergeJoin creates and initializes run time states
- * ExecEndMergeJoin cleand up the node.
+ * ExecMergeJoin mergejoin outer and inner relations.
+ * ExecInitMergeJoin creates and initializes run time states
+ * ExecEndMergeJoin cleand up the node.
*
* NOTES
- * Essential operation of the merge join algorithm is as follows:
- * (** indicates the tuples satisify the merge clause).
+ * Essential operation of the merge join algorithm is as follows:
+ * (** indicates the tuples satisify the merge clause).
*
- * Join { -
- * get initial outer and inner tuples INITIALIZE
- * Skip Inner SKIPINNER
- * mark inner position JOINMARK
- * do forever { -
- * while (outer ** inner) { JOINTEST
- * join tuples JOINTUPLES
- * advance inner position NEXTINNER
- * } -
- * advance outer position NEXTOUTER
- * if (outer ** mark) { TESTOUTER
- * restore inner position to mark TESTOUTER
- * continue -
- * } else { -
- * Skip Outer SKIPOUTER
- * mark inner position JOINMARK
- * } -
- * } -
- * } -
+ * Join { -
+ * get initial outer and inner tuples INITIALIZE
+ * Skip Inner SKIPINNER
+ * mark inner position JOINMARK
+ * do forever { -
+ * while (outer ** inner) { JOINTEST
+ * join tuples JOINTUPLES
+ * advance inner position NEXTINNER
+ * } -
+ * advance outer position NEXTOUTER
+ * if (outer ** mark) { TESTOUTER
+ * restore inner position to mark TESTOUTER
+ * continue -
+ * } else { -
+ * Skip Outer SKIPOUTER
+ * mark inner position JOINMARK
+ * } -
+ * } -
+ * } -
*
- * Skip Outer { SKIPOUTER
- * if (inner ** outer) Join Tuples JOINTUPLES
- * while (outer < inner) SKIPOUTER
- * advance outer SKIPOUTER
- * if (outer > inner) SKIPOUTER
- * Skip Inner SKIPINNER
- * } -
+ * Skip Outer { SKIPOUTER
+ * if (inner ** outer) Join Tuples JOINTUPLES
+ * while (outer < inner) SKIPOUTER
+ * advance outer SKIPOUTER
+ * if (outer > inner) SKIPOUTER
+ * Skip Inner SKIPINNER
+ * } -
*
- * Skip Inner { SKIPINNER
- * if (inner ** outer) Join Tuples JOINTUPLES
- * while (outer > inner) SKIPINNER
- * advance inner SKIPINNER
- * if (outer < inner) SKIPINNER
- * Skip Outer SKIPOUTER
- * } -
+ * Skip Inner { SKIPINNER
+ * if (inner ** outer) Join Tuples JOINTUPLES
+ * while (outer > inner) SKIPINNER
+ * advance inner SKIPINNER
+ * if (outer < inner) SKIPINNER
+ * Skip Outer SKIPOUTER
+ * } -
*
- * Currently, the merge join operation is coded in the fashion
- * of a state machine. At each state, we do something and then
- * proceed to another state. This state is stored in the node's
- * execution state information and is preserved across calls to
- * ExecMergeJoin. -cim 10/31/89
+ * Currently, the merge join operation is coded in the fashion
+ * of a state machine. At each state, we do something and then
+ * proceed to another state. This state is stored in the node's
+ * execution state information and is preserved across calls to
+ * ExecMergeJoin. -cim 10/31/89
*
- * Warning: This code is known to fail for inequality operations
- * and is being redesigned. Specifically, = and > work
- * but the logic is not correct for <. Since mergejoins
- * are no better then nestloops for inequalitys, the planner
- * should not plan them anyways. Alternatively, the
- * planner could just exchange the inner/outer relations
- * if it ever sees a <... -cim 7/1/90
+ * Warning: This code is known to fail for inequality operations
+ * and is being redesigned. Specifically, = and > work
+ * but the logic is not correct for <. Since mergejoins
+ * are no better then nestloops for inequalitys, the planner
+ * should not plan them anyways. Alternatively, the
+ * planner could just exchange the inner/outer relations
+ * if it ever sees a <... -cim 7/1/90
*
- * Update: The executor tuple table has long since alleviated the
- * problem described above -cim 4/23/91
+ * Update: The executor tuple table has long since alleviated the
+ * problem described above -cim 4/23/91
*
*/
#include "postgres.h"
@@ -84,1134 +84,1151 @@
#include "utils/lsyscache.h"
#include "utils/psort.h"
-static bool MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext);
+static bool MergeCompare(List * eqQual, List * compareQual, ExprContext * econtext);
/* ----------------------------------------------------------------
- * MarkInnerTuple and RestoreInnerTuple macros
+ * MarkInnerTuple and RestoreInnerTuple macros
*
- * when we "mark" a tuple, we place a pointer to it
- * in the marked tuple slot. now there are two pointers
- * to this tuple and we don't want it to be freed until
- * next time we mark a tuple, so we move the policy to
- * the marked tuple slot and set the inner tuple slot policy
- * to false.
+ * when we "mark" a tuple, we place a pointer to it
+ * in the marked tuple slot. now there are two pointers
+ * to this tuple and we don't want it to be freed until
+ * next time we mark a tuple, so we move the policy to
+ * the marked tuple slot and set the inner tuple slot policy
+ * to false.
*
- * But, when we restore the inner tuple, the marked tuple
- * retains the policy. Basically once a tuple is marked, it
- * should only be freed when we mark another tuple. -cim 9/27/90
+ * But, when we restore the inner tuple, the marked tuple
+ * retains the policy. Basically once a tuple is marked, it
+ * should only be freed when we mark another tuple. -cim 9/27/90
*
- * Note: now that we store buffers in the tuple table,
- * we have to also increment buffer reference counts
- * correctly whenever we propagate an additional pointer
- * to a buffer item. Later, when ExecStoreTuple() is
- * called again on this slot, the refcnt is decremented
- * when the old tuple is replaced.
+ * Note: now that we store buffers in the tuple table,
+ * we have to also increment buffer reference counts
+ * correctly whenever we propagate an additional pointer
+ * to a buffer item. Later, when ExecStoreTuple() is
+ * called again on this slot, the refcnt is decremented
+ * when the old tuple is replaced.
* ----------------------------------------------------------------
*/
#define MarkInnerTuple(innerTupleSlot, mergestate) \
{ \
- bool shouldFree; \
- shouldFree = ExecSetSlotPolicy(innerTupleSlot, false); \
- ExecStoreTuple(innerTupleSlot->val, \
- mergestate->mj_MarkedTupleSlot, \
- innerTupleSlot->ttc_buffer, \
- shouldFree); \
- ExecIncrSlotBufferRefcnt(innerTupleSlot); \
+ bool shouldFree; \
+ shouldFree = ExecSetSlotPolicy(innerTupleSlot, false); \
+ ExecStoreTuple(innerTupleSlot->val, \
+ mergestate->mj_MarkedTupleSlot, \
+ innerTupleSlot->ttc_buffer, \
+ shouldFree); \
+ ExecIncrSlotBufferRefcnt(innerTupleSlot); \
}
#define RestoreInnerTuple(innerTupleSlot, markedTupleSlot) \
- ExecStoreTuple(markedTupleSlot->val, \
- innerTupleSlot, \
- markedTupleSlot->ttc_buffer, \
- false); \
- ExecIncrSlotBufferRefcnt(innerTupleSlot)
+ ExecStoreTuple(markedTupleSlot->val, \
+ innerTupleSlot, \
+ markedTupleSlot->ttc_buffer, \
+ false); \
+ ExecIncrSlotBufferRefcnt(innerTupleSlot)
/* ----------------------------------------------------------------
- * MJFormOSortopI
+ * MJFormOSortopI
*
- * This takes the mergeclause which is a qualification of the
- * form ((= expr expr) (= expr expr) ...) and forms a new
- * qualification like ((> expr expr) (> expr expr) ...) which
- * is used by ExecMergeJoin() in order to determine if we should
- * skip tuples.
+ * This takes the mergeclause which is a qualification of the
+ * form ((= expr expr) (= expr expr) ...) and forms a new
+ * qualification like ((> expr expr) (> expr expr) ...) which
+ * is used by ExecMergeJoin() in order to determine if we should
+ * skip tuples.
*
* old comments
- * The 'qual' must be of the form:
- * {(= outerkey1 innerkey1)(= outerkey2 innerkey2) ...}
- * The "sortOp outerkey innerkey" is formed by substituting the "="
- * by "sortOp".
+ * The 'qual' must be of the form:
+ * {(= outerkey1 innerkey1)(= outerkey2 innerkey2) ...}
+ * The "sortOp outerkey innerkey" is formed by substituting the "="
+ * by "sortOp".
* ----------------------------------------------------------------
*/
-static List *
-MJFormOSortopI(List *qualList, Oid sortOp)
+static List *
+MJFormOSortopI(List * qualList, Oid sortOp)
{
- List *qualCopy;
- List *qualcdr;
- Expr *qual;
- Oper *op;
-
- /* ----------------
- * qualList is a list: ((op .. ..) ...)
- * first we make a copy of it. copyObject() makes a deep copy
- * so let's use it instead of the old fashoned lispCopy()...
- * ----------------
- */
- qualCopy = (List*) copyObject((Node*) qualList);
-
- foreach (qualcdr, qualCopy) {
- /* ----------------
- * first get the current (op .. ..) list
- * ----------------
- */
- qual = lfirst(qualcdr);
-
+ List *qualCopy;
+ List *qualcdr;
+ Expr *qual;
+ Oper *op;
+
/* ----------------
- * now get at the op
+ * qualList is a list: ((op .. ..) ...)
+ * first we make a copy of it. copyObject() makes a deep copy
+ * so let's use it instead of the old fashoned lispCopy()...
* ----------------
*/
- op = (Oper*)qual->oper;
- if (!IsA(op,Oper)) {
- elog(DEBUG, "MJFormOSortopI: op not an Oper!");
- return NIL;
+ qualCopy = (List *) copyObject((Node *) qualList);
+
+ foreach(qualcdr, qualCopy)
+ {
+ /* ----------------
+ * first get the current (op .. ..) list
+ * ----------------
+ */
+ qual = lfirst(qualcdr);
+
+ /* ----------------
+ * now get at the op
+ * ----------------
+ */
+ op = (Oper *) qual->oper;
+ if (!IsA(op, Oper))
+ {
+ elog(DEBUG, "MJFormOSortopI: op not an Oper!");
+ return NIL;
+ }
+
+ /* ----------------
+ * change it's opid and since Op nodes now carry around a
+ * cached pointer to the associated op function, we have
+ * to make sure we invalidate this. Otherwise you get bizarre
+ * behavior when someone runs a mergejoin with _exec_repeat_ > 1
+ * -cim 4/23/91
+ * ----------------
+ */
+ op->opid = sortOp;
+ op->op_fcache = NULL;
}
-
- /* ----------------
- * change it's opid and since Op nodes now carry around a
- * cached pointer to the associated op function, we have
- * to make sure we invalidate this. Otherwise you get bizarre
- * behavior when someone runs a mergejoin with _exec_repeat_ > 1
- * -cim 4/23/91
- * ----------------
- */
- op->opid = sortOp;
- op->op_fcache = NULL;
- }
-
- return qualCopy;
+
+ return qualCopy;
}
-
+
/* ----------------------------------------------------------------
- * MJFormISortopO
+ * MJFormISortopO
*
- * This does the same thing as MJFormOSortopI() except that
- * it also reverses the expressions in the qualifications.
- * For example: ((= expr1 expr2)) produces ((> expr2 expr1))
+ * This does the same thing as MJFormOSortopI() except that
+ * it also reverses the expressions in the qualifications.
+ * For example: ((= expr1 expr2)) produces ((> expr2 expr1))
*
* old comments
- * The 'qual' must be of the form:
- * {(= outerkey1 innerkey1) (= outerkey2 innerkey2) ...}
- * The 'sortOp innerkey1 outerkey" is formed by substituting the "="
- * by "sortOp" and reversing the positions of the keys.
- * ----------------------------------------------------------------
+ * The 'qual' must be of the form:
+ * {(= outerkey1 innerkey1) (= outerkey2 innerkey2) ...}
+ * The 'sortOp innerkey1 outerkey" is formed by substituting the "="
+ * by "sortOp" and reversing the positions of the keys.
+ * ----------------------------------------------------------------
*/
-static List *
-MJFormISortopO(List *qualList, Oid sortOp)
+static List *
+MJFormISortopO(List * qualList, Oid sortOp)
{
- List *ISortopO;
- List *qualcdr;
-
- /* ----------------
- * first generate OSortopI, a list of the form
- * ((op outer inner) (op outer inner) ... )
- * ----------------
- */
- ISortopO = MJFormOSortopI(qualList, sortOp);
-
- /* ----------------
- * now swap the cadr and caddr of each qual to form ISortopO,
- * ((op inner outer) (op inner outer) ... )
- * ----------------
- */
- foreach (qualcdr, ISortopO) {
- Expr *qual;
- List *inner;
- List *outer;
- qual = lfirst(qualcdr);
-
- inner = lfirst(qual->args);
- outer = lfirst(lnext(qual->args));
- lfirst(qual->args) = outer;
- lfirst(lnext(qual->args)) = inner;
- }
-
- return ISortopO;
+ List *ISortopO;
+ List *qualcdr;
+
+ /* ----------------
+ * first generate OSortopI, a list of the form
+ * ((op outer inner) (op outer inner) ... )
+ * ----------------
+ */
+ ISortopO = MJFormOSortopI(qualList, sortOp);
+
+ /* ----------------
+ * now swap the cadr and caddr of each qual to form ISortopO,
+ * ((op inner outer) (op inner outer) ... )
+ * ----------------
+ */
+ foreach(qualcdr, ISortopO)
+ {
+ Expr *qual;
+ List *inner;
+ List *outer;
+
+ qual = lfirst(qualcdr);
+
+ inner = lfirst(qual->args);
+ outer = lfirst(lnext(qual->args));
+ lfirst(qual->args) = outer;
+ lfirst(lnext(qual->args)) = inner;
+ }
+
+ return ISortopO;
}
-
+
/* ----------------------------------------------------------------
- * MergeCompare
- *
- * Compare the keys according to 'compareQual' which is of the
- * form: {(key1a > key2a)(key1b > key2b) ...}.
+ * MergeCompare
*
- * (actually, it could also be the form (key1a < key2a)..)
- *
- * This is different from calling ExecQual because ExecQual returns
- * true only if ALL the comparisions clauses are satisfied.
- * However, there is an order of significance among the keys with
- * the first keys being most significant. Therefore, the clauses
- * are evaluated in order and the 'compareQual' is satisfied
- * if (key1i > key2i) is true and (key1j = key2j) for 0 < j < i.
+ * Compare the keys according to 'compareQual' which is of the
+ * form: {(key1a > key2a)(key1b > key2b) ...}.
+ *
+ * (actually, it could also be the form (key1a < key2a)..)
+ *
+ * This is different from calling ExecQual because ExecQual returns
+ * true only if ALL the comparisions clauses are satisfied.
+ * However, there is an order of significance among the keys with
+ * the first keys being most significant. Therefore, the clauses
+ * are evaluated in order and the 'compareQual' is satisfied
+ * if (key1i > key2i) is true and (key1j = key2j) for 0 < j < i.
* ----------------------------------------------------------------
*/
-static bool
-MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
+static bool
+MergeCompare(List * eqQual, List * compareQual, ExprContext * econtext)
{
- List *clause;
- List *eqclause;
- Datum const_value;
- bool isNull;
- bool isDone;
-
- /* ----------------
- * if we have no compare qualification, return nil
- * ----------------
- */
- if (compareQual == NIL)
- return false;
-
- /* ----------------
- * for each pair of clauses, test them until
- * our compare conditions are satisified
- * ----------------
- */
- eqclause = eqQual;
- foreach (clause, compareQual) {
+ List *clause;
+ List *eqclause;
+ Datum const_value;
+ bool isNull;
+ bool isDone;
+
/* ----------------
- * first test if our compare clause is satisified.
- * if so then return true. ignore isDone, don't iterate in
- * quals.
+ * if we have no compare qualification, return nil
* ----------------
*/
- const_value = (Datum)
- ExecEvalExpr((Node*) lfirst(clause), econtext, &isNull, &isDone);
-
- if (DatumGetInt32(const_value) != 0)
- return true;
-
+ if (compareQual == NIL)
+ return false;
+
/* ----------------
- * ok, the compare clause failed so we test if the keys
- * are equal... if key1 != key2, we return false.
- * otherwise key1 = key2 so we move on to the next pair of keys.
- *
- * ignore isDone, don't iterate in quals.
+ * for each pair of clauses, test them until
+ * our compare conditions are satisified
* ----------------
*/
- const_value = ExecEvalExpr((Node*) lfirst(eqclause),
- econtext,
- &isNull,
- &isDone);
-
- if (DatumGetInt32(const_value) == 0)
- return false;
- eqclause = lnext(eqclause);
- }
-
- /* ----------------
- * if we get here then it means none of our key greater-than
- * conditions were satisified so we return false.
- * ----------------
- */
- return false;
+ eqclause = eqQual;
+ foreach(clause, compareQual)
+ {
+ /* ----------------
+ * first test if our compare clause is satisified.
+ * if so then return true. ignore isDone, don't iterate in
+ * quals.
+ * ----------------
+ */
+ const_value = (Datum)
+ ExecEvalExpr((Node *) lfirst(clause), econtext, &isNull, &isDone);
+
+ if (DatumGetInt32(const_value) != 0)
+ return true;
+
+ /* ----------------
+ * ok, the compare clause failed so we test if the keys
+ * are equal... if key1 != key2, we return false.
+ * otherwise key1 = key2 so we move on to the next pair of keys.
+ *
+ * ignore isDone, don't iterate in quals.
+ * ----------------
+ */
+ const_value = ExecEvalExpr((Node *) lfirst(eqclause),
+ econtext,
+ &isNull,
+ &isDone);
+
+ if (DatumGetInt32(const_value) == 0)
+ return false;
+ eqclause = lnext(eqclause);
+ }
+
+ /* ----------------
+ * if we get here then it means none of our key greater-than
+ * conditions were satisified so we return false.
+ * ----------------
+ */
+ return false;
}
-
+
/* ----------------------------------------------------------------
- * ExecMergeTupleDump
+ * ExecMergeTupleDump
*
- * This function is called through the MJ_dump() macro
- * when EXEC_MERGEJOINDEBUG is defined
+ * This function is called through the MJ_dump() macro
+ * when EXEC_MERGEJOINDEBUG is defined
* ----------------------------------------------------------------
*/
#ifdef EXEC_MERGEJOINDEBUG
void
-ExecMergeTupleDumpInner(ExprContext *econtext)
+ExecMergeTupleDumpInner(ExprContext * econtext)
{
- TupleTableSlot *innerSlot;
-
- printf("==== inner tuple ====\n");
- innerSlot = econtext->ecxt_innertuple;
- if (TupIsNull(innerSlot))
- printf("(nil)\n");
- else
- debugtup(innerSlot->val,
- innerSlot->ttc_tupleDescriptor);
+ TupleTableSlot *innerSlot;
+
+ printf("==== inner tuple ====\n");
+ innerSlot = econtext->ecxt_innertuple;
+ if (TupIsNull(innerSlot))
+ printf("(nil)\n");
+ else
+ debugtup(innerSlot->val,
+ innerSlot->ttc_tupleDescriptor);
}
void
-ExecMergeTupleDumpOuter(ExprContext *econtext)
+ExecMergeTupleDumpOuter(ExprContext * econtext)
{
- TupleTableSlot *outerSlot;
-
- printf("==== outer tuple ====\n");
- outerSlot = econtext->ecxt_outertuple;
- if (TupIsNull(outerSlot))
- printf("(nil)\n");
- else
- debugtup(outerSlot->val,
- outerSlot->ttc_tupleDescriptor);
+ TupleTableSlot *outerSlot;
+
+ printf("==== outer tuple ====\n");
+ outerSlot = econtext->ecxt_outertuple;
+ if (TupIsNull(outerSlot))
+ printf("(nil)\n");
+ else
+ debugtup(outerSlot->val,
+ outerSlot->ttc_tupleDescriptor);
}
void
-ExecMergeTupleDumpMarked(ExprContext *econtext,
- MergeJoinState *mergestate)
+ExecMergeTupleDumpMarked(ExprContext * econtext,
+ MergeJoinState * mergestate)
{
- TupleTableSlot *markedSlot;
+ TupleTableSlot *markedSlot;
- printf("==== marked tuple ====\n");
- markedSlot = mergestate->mj_MarkedTupleSlot;
+ printf("==== marked tuple ====\n");
+ markedSlot = mergestate->mj_MarkedTupleSlot;
- if (TupIsNull(markedSlot))
- printf("(nil)\n");
- else
- debugtup(markedSlot->val,
- markedSlot->ttc_tupleDescriptor);
+ if (TupIsNull(markedSlot))
+ printf("(nil)\n");
+ else
+ debugtup(markedSlot->val,
+ markedSlot->ttc_tupleDescriptor);
}
void
-ExecMergeTupleDump(ExprContext *econtext, MergeJoinState *mergestate)
+ExecMergeTupleDump(ExprContext * econtext, MergeJoinState * mergestate)
{
- printf("******** ExecMergeTupleDump ********\n");
-
- ExecMergeTupleDumpInner(econtext);
- ExecMergeTupleDumpOuter(econtext);
- ExecMergeTupleDumpMarked(econtext, mergestate);
-
- printf("******** \n");
+ printf("******** ExecMergeTupleDump ********\n");
+
+ ExecMergeTupleDumpInner(econtext);
+ ExecMergeTupleDumpOuter(econtext);
+ ExecMergeTupleDumpMarked(econtext, mergestate);
+
+ printf("******** \n");
}
+
#endif
-
+
static void
-CleanUpSort(Plan *plan) {
-
- if (plan == NULL)
- return;
-
- if (plan->type == T_Sort) {
- Sort *sort = (Sort *)plan;
- psort_end(sort);
- }
+CleanUpSort(Plan * plan)
+{
+
+ if (plan == NULL)
+ return;
+
+ if (plan->type == T_Sort)
+ {
+ Sort *sort = (Sort *) plan;
+
+ psort_end(sort);
+ }
}
/* ----------------------------------------------------------------
- * ExecMergeJoin
+ * ExecMergeJoin
*
* old comments
- * Details of the merge-join routines:
- *
- * (1) ">" and "<" operators
- *
- * Merge-join is done by joining the inner and outer tuples satisfying
- * the join clauses of the form ((= outerKey innerKey) ...).
- * The join clauses is provided by the query planner and may contain
- * more than one (= outerKey innerKey) clauses (for composite key).
- *
- * However, the query executor needs to know whether an outer
- * tuple is "greater/smaller" than an inner tuple so that it can
- * "synchronize" the two relations. For e.g., consider the following
- * relations:
- *
- * outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1
- * inner: (1 ^3 5 5 5 5 6) current tuple: 3
- *
- * To continue the merge-join, the executor needs to scan both inner
- * and outer relations till the matching tuples 5. It needs to know
- * that currently inner tuple 3 is "greater" than outer tuple 1 and
- * therefore it should scan the outer relation first to find a
- * matching tuple and so on.
- *
- * Therefore, when initializing the merge-join node, the executor
- * creates the "greater/smaller" clause by substituting the "="
- * operator in the join clauses with the sort operator used to
- * sort the outer and inner relation forming (outerKey sortOp innerKey).
- * The sort operator is "<" if the relations are in ascending order
- * otherwise, it is ">" if the relations are in descending order.
- * The opposite "smaller/greater" clause is formed by reversing the
- * outer and inner keys forming (innerKey sortOp outerKey).
- *
- * (2) repositioning inner "cursor"
- *
- * Consider the above relations and suppose that the executor has
- * just joined the first outer "5" with the last inner "5". The
- * next step is of course to join the second outer "5" with all
- * the inner "5's". This requires repositioning the inner "cursor"
- * to point at the first inner "5". This is done by "marking" the
- * first inner 5 and restore the "cursor" to it before joining
- * with the second outer 5. The access method interface provides
- * routines to mark and restore to a tuple.
+ * Details of the merge-join routines:
+ *
+ * (1) ">" and "<" operators
+ *
+ * Merge-join is done by joining the inner and outer tuples satisfying
+ * the join clauses of the form ((= outerKey innerKey) ...).
+ * The join clauses is provided by the query planner and may contain
+ * more than one (= outerKey innerKey) clauses (for composite key).
+ *
+ * However, the query executor needs to know whether an outer
+ * tuple is "greater/smaller" than an inner tuple so that it can
+ * "synchronize" the two relations. For e.g., consider the following
+ * relations:
+ *
+ * outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1
+ * inner: (1 ^3 5 5 5 5 6) current tuple: 3
+ *
+ * To continue the merge-join, the executor needs to scan both inner
+ * and outer relations till the matching tuples 5. It needs to know
+ * that currently inner tuple 3 is "greater" than outer tuple 1 and
+ * therefore it should scan the outer relation first to find a
+ * matching tuple and so on.
+ *
+ * Therefore, when initializing the merge-join node, the executor
+ * creates the "greater/smaller" clause by substituting the "="
+ * operator in the join clauses with the sort operator used to
+ * sort the outer and inner relation forming (outerKey sortOp innerKey).
+ * The sort operator is "<" if the relations are in ascending order
+ * otherwise, it is ">" if the relations are in descending order.
+ * The opposite "smaller/greater" clause is formed by reversing the
+ * outer and inner keys forming (innerKey sortOp outerKey).
+ *
+ * (2) repositioning inner "cursor"
+ *
+ * Consider the above relations and suppose that the executor has
+ * just joined the first outer "5" with the last inner "5". The
+ * next step is of course to join the second outer "5" with all
+ * the inner "5's". This requires repositioning the inner "cursor"
+ * to point at the first inner "5". This is done by "marking" the
+ * first inner 5 and restore the "cursor" to it before joining
+ * with the second outer 5. The access method interface provides
+ * routines to mark and restore to a tuple.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecMergeJoin(MergeJoin *node)
+ExecMergeJoin(MergeJoin * node)
{
- EState *estate;
- MergeJoinState *mergestate;
- ScanDirection direction;
- List *innerSkipQual;
- List *outerSkipQual;
- List *mergeclauses;
- List *qual;
- bool qualResult;
- bool compareResult;
-
- Plan *innerPlan;
- TupleTableSlot *innerTupleSlot;
-
- Plan *outerPlan;
- TupleTableSlot *outerTupleSlot;
-
- TupleTableSlot *markedTupleSlot;
-
- ExprContext *econtext;
-
- /* ----------------
- * get information from node
- * ----------------
- */
- mergestate = node->mergestate;
- estate = node->join.state;
- direction = estate->es_direction;
- innerPlan = innerPlan((Plan *)node);
- outerPlan = outerPlan((Plan *)node);
- econtext = mergestate->jstate.cs_ExprContext;
- mergeclauses = node->mergeclauses;
- qual = node->join.qual;
-
- if (ScanDirectionIsForward(direction)) {
- outerSkipQual = mergestate->mj_OSortopI;
- innerSkipQual = mergestate->mj_ISortopO;
- } else {
- outerSkipQual = mergestate->mj_ISortopO;
- innerSkipQual = mergestate->mj_OSortopI;
- }
-
- /* ----------------
- * ok, everything is setup.. let's go to work
- * ----------------
- */
- if (mergestate->jstate.cs_TupFromTlist) {
- TupleTableSlot *result;
- ProjectionInfo *projInfo;
- bool isDone;
-
- projInfo = mergestate->jstate.cs_ProjInfo;
- result = ExecProject(projInfo, &isDone);
- if (!isDone)
- return result;
- }
- for (;;) {
+ EState *estate;
+ MergeJoinState *mergestate;
+ ScanDirection direction;
+ List *innerSkipQual;
+ List *outerSkipQual;
+ List *mergeclauses;
+ List *qual;
+ bool qualResult;
+ bool compareResult;
+
+ Plan *innerPlan;
+ TupleTableSlot *innerTupleSlot;
+
+ Plan *outerPlan;
+ TupleTableSlot *outerTupleSlot;
+
+ TupleTableSlot *markedTupleSlot;
+
+ ExprContext *econtext;
+
/* ----------------
- * get the current state of the join and do things accordingly.
- * Note: The join states are highlighted with 32-* comments for
- * improved readability.
+ * get information from node
* ----------------
*/
- MJ_dump(econtext, mergestate);
-
- switch (mergestate->mj_JoinState) {
- /* ********************************
- * EXEC_MJ_INITIALIZE means that this is the first time
- * ExecMergeJoin() has been called and so we have to
- * initialize the inner, outer and marked tuples as well
- * as various stuff in the expression context.
- * ********************************
- */
- case EXEC_MJ_INITIALIZE:
- MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
- /* ----------------
- * Note: at this point, if either of our inner or outer
- * tuples are nil, then the join ends immediately because
- * we know one of the subplans is empty.
- * ----------------
- */
- innerTupleSlot = ExecProcNode(innerPlan, (Plan*)node);
- if (TupIsNull(innerTupleSlot)) {
- MJ_printf("ExecMergeJoin: **** inner tuple is nil ****\n");
- return NULL;
- }
-
- outerTupleSlot = ExecProcNode(outerPlan, (Plan*)node);
- if (TupIsNull(outerTupleSlot)) {
- MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n");
- return NULL;
- }
-
- /* ----------------
- * store the inner and outer tuple in the merge state
- * ----------------
- */
- econtext->ecxt_innertuple = innerTupleSlot;
- econtext->ecxt_outertuple = outerTupleSlot;
-
- /* ----------------
- * set the marked tuple to nil
- * and initialize its tuple descriptor atttributes.
- * -jeff 10 july 1991
- * ----------------
- */
- ExecClearTuple(mergestate->mj_MarkedTupleSlot);
- mergestate->mj_MarkedTupleSlot->ttc_tupleDescriptor =
- innerTupleSlot->ttc_tupleDescriptor;
-/*
- mergestate->mj_MarkedTupleSlot->ttc_execTupDescriptor =
- innerTupleSlot->ttc_execTupDescriptor;
-*/
- /* ----------------
- * initialize merge join state to skip inner tuples.
- * ----------------
- */
- mergestate->mj_JoinState = EXEC_MJ_SKIPINNER;
- break;
-
- /* ********************************
- * EXEC_MJ_JOINMARK means we have just found a new
- * outer tuple and a possible matching inner tuple.
- * This is the case after the INITIALIZE, SKIPOUTER
- * or SKIPINNER states.
- * ********************************
- */
- case EXEC_MJ_JOINMARK:
- MJ_printf("ExecMergeJoin: EXEC_MJ_JOINMARK\n");
- ExecMarkPos(innerPlan);
-
- innerTupleSlot = econtext->ecxt_innertuple;
- MarkInnerTuple(innerTupleSlot, mergestate);
-
- mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
- break;
-
- /* ********************************
- * EXEC_MJ_JOINTEST means we have two tuples which
- * might satisify the merge clause, so we test them.
- *
- * If they do satisify, then we join them and move
- * on to the next inner tuple (EXEC_MJ_JOINTUPLES).
- *
- * If they do not satisify then advance to next outer tuple.
- * ********************************
- */
- case EXEC_MJ_JOINTEST:
- MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n");
-
- qualResult = ExecQual((List*)mergeclauses, econtext);
- MJ_DEBUG_QUAL(mergeclauses, qualResult);
-
- if (qualResult)
- {
- mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
- }
- else
- {
- mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
- }
- break;
-
- /* ********************************
- * EXEC_MJ_JOINTUPLES means we have two tuples which
- * satisified the merge clause so we join them and then
- * proceed to get the next inner tuple (EXEC_NEXT_INNER).
- * ********************************
+ mergestate = node->mergestate;
+ estate = node->join.state;
+ direction = estate->es_direction;
+ innerPlan = innerPlan((Plan *) node);
+ outerPlan = outerPlan((Plan *) node);
+ econtext = mergestate->jstate.cs_ExprContext;
+ mergeclauses = node->mergeclauses;
+ qual = node->join.qual;
+
+ if (ScanDirectionIsForward(direction))
+ {
+ outerSkipQual = mergestate->mj_OSortopI;
+ innerSkipQual = mergestate->mj_ISortopO;
+ }
+ else
+ {
+ outerSkipQual = mergestate->mj_ISortopO;
+ innerSkipQual = mergestate->mj_OSortopI;
+ }
+
+ /* ----------------
+ * ok, everything is setup.. let's go to work
+ * ----------------
*/
- case EXEC_MJ_JOINTUPLES:
- MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
- mergestate->mj_JoinState = EXEC_MJ_NEXTINNER;
-
- qualResult = ExecQual((List*)qual, econtext);
- MJ_DEBUG_QUAL(qual, qualResult);
-
- if (qualResult) {
- /* ----------------
- * qualification succeeded. now form the desired
- * projection tuple and return the slot containing it.
- * ----------------
- */
- ProjectionInfo *projInfo;
+ if (mergestate->jstate.cs_TupFromTlist)
+ {
TupleTableSlot *result;
- bool isDone;
-
- MJ_printf("ExecMergeJoin: **** returning tuple ****\n");
-
+ ProjectionInfo *projInfo;
+ bool isDone;
+
projInfo = mergestate->jstate.cs_ProjInfo;
-
result = ExecProject(projInfo, &isDone);
- mergestate->jstate.cs_TupFromTlist = !isDone;
- return result;
- }
- break;
-
- /* ********************************
- * EXEC_MJ_NEXTINNER means advance the inner scan
- * to the next tuple. If the tuple is not nil, we then
- * proceed to test it against the join qualification.
- * ********************************
- */
- case EXEC_MJ_NEXTINNER:
- MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
-
- /* ----------------
- * now we get the next inner tuple, if any
- * ----------------
- */
- innerTupleSlot = ExecProcNode(innerPlan, (Plan*)node);
- MJ_DEBUG_PROC_NODE(innerTupleSlot);
- econtext->ecxt_innertuple = innerTupleSlot;
-
- if (TupIsNull(innerTupleSlot))
- {
- mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
- }
- else
- {
- mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
- }
- break;
-
- /* ********************************
- * EXEC_MJ_NEXTOUTER means
- *
- * outer inner
- * outer tuple - 5 5 - marked tuple
- * 5 5
- * 6 6 - inner tuple
- * 7 7
- *
- * we know we just bumped into
- * the first inner tuple > current outer tuple
- * so get a new outer tuple and then proceed to test
- * it against the marked tuple (EXEC_MJ_TESTOUTER)
- * ********************************
- */
- case EXEC_MJ_NEXTOUTER:
- MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
-
- outerTupleSlot = ExecProcNode(outerPlan, (Plan*)node);
- MJ_DEBUG_PROC_NODE(outerTupleSlot);
- econtext->ecxt_outertuple = outerTupleSlot;
-
- /* ----------------
- * if the outer tuple is null then we know
- * we are done with the join
- * ----------------
- */
- if (TupIsNull(outerTupleSlot)) {
- MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n");
- CleanUpSort(node->join.lefttree->lefttree);
- CleanUpSort(node->join.righttree->lefttree);
- return NULL;
- }
-
- mergestate->mj_JoinState = EXEC_MJ_TESTOUTER;
- break;
-
- /* ********************************
- * EXEC_MJ_TESTOUTER
- * If the new outer tuple and the marked tuple satisify
- * the merge clause then we know we have duplicates in
- * the outer scan so we have to restore the inner scan
- * to the marked tuple and proceed to join the new outer
- * tuples with the inner tuples (EXEC_MJ_JOINTEST)
- *
- * This is the case when
- *
- * outer inner
- * 4 5 - marked tuple
- * outer tuple - 5 5
- * new outer tuple - 5 5
- * 6 8 - inner tuple
- * 7 12
- *
- * new outer tuple = marked tuple
- *
- * If the outer tuple fails the test, then we know we have
- * to proceed to skip outer tuples until outer >= inner
- * (EXEC_MJ_SKIPOUTER).
- *
- * This is the case when
- *
- * outer inner
- * 5 5 - marked tuple
- * outer tuple - 5 5
- * new outer tuple - 6 8 - inner tuple
- * 7 12
- *
- * new outer tuple > marked tuple
- *
- * ********************************
- */
- case EXEC_MJ_TESTOUTER:
- MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
-
- /* ----------------
- * here we compare the outer tuple with the marked inner tuple
- * by using the marked tuple in place of the inner tuple.
- * ----------------
- */
- innerTupleSlot = econtext->ecxt_innertuple;
- markedTupleSlot = mergestate->mj_MarkedTupleSlot;
- econtext->ecxt_innertuple = markedTupleSlot;
-
- qualResult = ExecQual((List*)mergeclauses, econtext);
- MJ_DEBUG_QUAL(mergeclauses, qualResult);
-
- if (qualResult) {
- /* ----------------
- * the merge clause matched so now we juggle the slots
- * back the way they were and proceed to JOINTEST.
- * ----------------
- */
- econtext->ecxt_innertuple = innerTupleSlot;
-
- RestoreInnerTuple(innerTupleSlot, markedTupleSlot);
-
- ExecRestrPos(innerPlan);
- mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
-
- } else {
- /* ----------------
- * if the inner tuple was nil and the new outer
- * tuple didn't match the marked outer tuple then
- * we may have the case:
- *
- * outer inner
- * 4 4 - marked tuple
- * new outer - 5 4
- * 6 nil - inner tuple
- * 7
- *
- * which means that all subsequent outer tuples will be
- * larger than our inner tuples.
- * ----------------
- */
- if (TupIsNull(innerTupleSlot)) {
- MJ_printf("ExecMergeJoin: **** wierd case 1 ****\n");
- return NULL;
- }
-
- /* ----------------
- * restore the inner tuple and continue on to
- * skip outer tuples.
- * ----------------
- */
- econtext->ecxt_innertuple = innerTupleSlot;
- mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
- }
- break;
-
- /* ********************************
- * EXEC_MJ_SKIPOUTER means skip over tuples in the outer plan
- * until we find an outer tuple > current inner tuple.
- *
- * For example:
- *
- * outer inner
- * 5 5
- * 5 5
- * outer tuple - 6 8 - inner tuple
- * 7 12
- * 8 14
- *
- * we have to advance the outer scan
- * until we find the outer 8.
- *
- * ********************************
- */
- case EXEC_MJ_SKIPOUTER:
- MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER\n");
- /* ----------------
- * before we advance, make sure the current tuples
- * do not satisify the mergeclauses. If they do, then
- * we update the marked tuple and go join them.
- * ----------------
- */
- qualResult = ExecQual((List*)mergeclauses, econtext);
- MJ_DEBUG_QUAL(mergeclauses, qualResult);
-
- if (qualResult) {
- ExecMarkPos(innerPlan);
- innerTupleSlot = econtext->ecxt_innertuple;
-
- MarkInnerTuple(innerTupleSlot, mergestate);
-
- mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
- break;
- }
-
- /* ----------------
- * ok, now test the skip qualification
- * ----------------
- */
- compareResult = MergeCompare(mergeclauses,
- outerSkipQual,
- econtext);
-
- MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
-
- /* ----------------
- * compareResult is true as long as we should
- * continue skipping tuples.
- * ----------------
- */
- if (compareResult) {
-
- outerTupleSlot = ExecProcNode(outerPlan, (Plan*)node);
- MJ_DEBUG_PROC_NODE(outerTupleSlot);
- econtext->ecxt_outertuple = outerTupleSlot;
-
- /* ----------------
- * if the outer tuple is null then we know
- * we are done with the join
- * ----------------
- */
- if (TupIsNull(outerTupleSlot)) {
- MJ_printf("ExecMergeJoin: **** outerTuple is nil ****\n");
- return NULL;
- }
- /* ----------------
- * otherwise test the new tuple against the skip qual.
- * (we remain in the EXEC_MJ_SKIPOUTER state)
- * ----------------
- */
- break;
- }
-
- /* ----------------
- * now check the inner skip qual to see if we
- * should now skip inner tuples... if we fail the
- * inner skip qual, then we know we have a new pair
- * of matching tuples.
- * ----------------
- */
- compareResult = MergeCompare(mergeclauses,
- innerSkipQual,
- econtext);
-
- MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
-
- if (compareResult)
- {
- mergestate->mj_JoinState = EXEC_MJ_SKIPINNER;
- }
- else
- {
- mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
- }
- break;
-
- /* ********************************
- * EXEC_MJ_SKIPINNER means skip over tuples in the inner plan
- * until we find an inner tuple > current outer tuple.
- *
- * For example:
- *
- * outer inner
- * 5 5
- * 5 5
- * outer tuple - 12 8 - inner tuple
- * 14 10
- * 17 12
- *
- * we have to advance the inner scan
- * until we find the inner 12.
- *
- * ********************************
- */
- case EXEC_MJ_SKIPINNER:
- MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER\n");
- /* ----------------
- * before we advance, make sure the current tuples
- * do not satisify the mergeclauses. If they do, then
- * we update the marked tuple and go join them.
- * ----------------
- */
- qualResult = ExecQual((List*)mergeclauses, econtext);
- MJ_DEBUG_QUAL(mergeclauses, qualResult);
-
- if (qualResult) {
- ExecMarkPos(innerPlan);
- innerTupleSlot = econtext->ecxt_innertuple;
-
- MarkInnerTuple(innerTupleSlot, mergestate);
-
- mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
- break;
- }
-
- /* ----------------
- * ok, now test the skip qualification
- * ----------------
- */
- compareResult = MergeCompare(mergeclauses,
- innerSkipQual,
- econtext);
-
- MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
-
- /* ----------------
- * compareResult is true as long as we should
- * continue skipping tuples.
- * ----------------
- */
- if (compareResult) {
- /* ----------------
- * now try and get a new inner tuple
- * ----------------
- */
- innerTupleSlot = ExecProcNode(innerPlan, (Plan*)node);
- MJ_DEBUG_PROC_NODE(innerTupleSlot);
- econtext->ecxt_innertuple = innerTupleSlot;
-
+ if (!isDone)
+ return result;
+ }
+ for (;;)
+ {
/* ----------------
- * if the inner tuple is null then we know
- * we have to restore the inner scan
- * and advance to the next outer tuple
+ * get the current state of the join and do things accordingly.
+ * Note: The join states are highlighted with 32-* comments for
+ * improved readability.
* ----------------
*/
- if (TupIsNull(innerTupleSlot)) {
- /* ----------------
- * this is an interesting case.. all our
- * inner tuples are smaller then our outer
- * tuples so we never found an inner tuple
- * to mark.
- *
- * outer inner
- * outer tuple - 5 4
- * 5 4
- * 6 nil - inner tuple
- * 7
- *
- * This means the join should end.
- * ----------------
- */
- MJ_printf("ExecMergeJoin: **** wierd case 2 ****\n");
- return NULL;
+ MJ_dump(econtext, mergestate);
+
+ switch (mergestate->mj_JoinState)
+ {
+
+ /*
+ * ******************************** EXEC_MJ_INITIALIZE means
+ * that this is the first time ExecMergeJoin() has been called
+ * and so we have to initialize the inner, outer and marked
+ * tuples as well as various stuff in the expression context. ********************************
+ *
+ */
+ case EXEC_MJ_INITIALIZE:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_INITIALIZE\n");
+ /* ----------------
+ * Note: at this point, if either of our inner or outer
+ * tuples are nil, then the join ends immediately because
+ * we know one of the subplans is empty.
+ * ----------------
+ */
+ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
+ if (TupIsNull(innerTupleSlot))
+ {
+ MJ_printf("ExecMergeJoin: **** inner tuple is nil ****\n");
+ return NULL;
+ }
+
+ outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
+ if (TupIsNull(outerTupleSlot))
+ {
+ MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n");
+ return NULL;
+ }
+
+ /* ----------------
+ * store the inner and outer tuple in the merge state
+ * ----------------
+ */
+ econtext->ecxt_innertuple = innerTupleSlot;
+ econtext->ecxt_outertuple = outerTupleSlot;
+
+ /* ----------------
+ * set the marked tuple to nil
+ * and initialize its tuple descriptor atttributes.
+ * -jeff 10 july 1991
+ * ----------------
+ */
+ ExecClearTuple(mergestate->mj_MarkedTupleSlot);
+ mergestate->mj_MarkedTupleSlot->ttc_tupleDescriptor =
+ innerTupleSlot->ttc_tupleDescriptor;
+/*
+ mergestate->mj_MarkedTupleSlot->ttc_execTupDescriptor =
+ innerTupleSlot->ttc_execTupDescriptor;
+*/
+ /* ----------------
+ * initialize merge join state to skip inner tuples.
+ * ----------------
+ */
+ mergestate->mj_JoinState = EXEC_MJ_SKIPINNER;
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_JOINMARK means we
+ * have just found a new outer tuple and a possible matching
+ * inner tuple. This is the case after the INITIALIZE,
+ * SKIPOUTER or SKIPINNER states. ********************************
+ *
+ */
+ case EXEC_MJ_JOINMARK:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_JOINMARK\n");
+ ExecMarkPos(innerPlan);
+
+ innerTupleSlot = econtext->ecxt_innertuple;
+ MarkInnerTuple(innerTupleSlot, mergestate);
+
+ mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_JOINTEST means we
+ * have two tuples which might satisify the merge clause, so
+ * we test them.
+ *
+ * If they do satisify, then we join them and move on to the next
+ * inner tuple (EXEC_MJ_JOINTUPLES).
+ *
+ * If they do not satisify then advance to next outer tuple. ********************************
+ *
+ */
+ case EXEC_MJ_JOINTEST:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTEST\n");
+
+ qualResult = ExecQual((List *) mergeclauses, econtext);
+ MJ_DEBUG_QUAL(mergeclauses, qualResult);
+
+ if (qualResult)
+ {
+ mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ }
+ else
+ {
+ mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
+ }
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_JOINTUPLES means
+ * we have two tuples which satisified the merge clause so we
+ * join them and then proceed to get the next inner tuple
+ * (EXEC_NEXT_INNER). ********************************
+ *
+ */
+ case EXEC_MJ_JOINTUPLES:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_JOINTUPLES\n");
+ mergestate->mj_JoinState = EXEC_MJ_NEXTINNER;
+
+ qualResult = ExecQual((List *) qual, econtext);
+ MJ_DEBUG_QUAL(qual, qualResult);
+
+ if (qualResult)
+ {
+ /* ----------------
+ * qualification succeeded. now form the desired
+ * projection tuple and return the slot containing it.
+ * ----------------
+ */
+ ProjectionInfo *projInfo;
+ TupleTableSlot *result;
+ bool isDone;
+
+ MJ_printf("ExecMergeJoin: **** returning tuple ****\n");
+
+ projInfo = mergestate->jstate.cs_ProjInfo;
+
+ result = ExecProject(projInfo, &isDone);
+ mergestate->jstate.cs_TupFromTlist = !isDone;
+ return result;
+ }
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_NEXTINNER means
+ * advance the inner scan to the next tuple. If the tuple is
+ * not nil, we then proceed to test it against the join
+ * qualification. ********************************
+ *
+ */
+ case EXEC_MJ_NEXTINNER:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTINNER\n");
+
+ /* ----------------
+ * now we get the next inner tuple, if any
+ * ----------------
+ */
+ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
+ MJ_DEBUG_PROC_NODE(innerTupleSlot);
+ econtext->ecxt_innertuple = innerTupleSlot;
+
+ if (TupIsNull(innerTupleSlot))
+ {
+ mergestate->mj_JoinState = EXEC_MJ_NEXTOUTER;
+ }
+ else
+ {
+ mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
+ }
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_NEXTOUTER means
+ *
+ * outer inner outer tuple - 5 5 - marked tuple 5 5 6
+ * 6 - inner tuple 7 7
+ *
+ * we know we just bumped into the first inner tuple > current
+ * outer tuple so get a new outer tuple and then proceed to
+ * test it against the marked tuple (EXEC_MJ_TESTOUTER) ********************************
+ *
+ */
+ case EXEC_MJ_NEXTOUTER:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_NEXTOUTER\n");
+
+ outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
+ MJ_DEBUG_PROC_NODE(outerTupleSlot);
+ econtext->ecxt_outertuple = outerTupleSlot;
+
+ /* ----------------
+ * if the outer tuple is null then we know
+ * we are done with the join
+ * ----------------
+ */
+ if (TupIsNull(outerTupleSlot))
+ {
+ MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n");
+ CleanUpSort(node->join.lefttree->lefttree);
+ CleanUpSort(node->join.righttree->lefttree);
+ return NULL;
+ }
+
+ mergestate->mj_JoinState = EXEC_MJ_TESTOUTER;
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_TESTOUTER If the
+ * new outer tuple and the marked tuple satisify the merge
+ * clause then we know we have duplicates in the outer scan so
+ * we have to restore the inner scan to the marked tuple and
+ * proceed to join the new outer tuples with the inner tuples
+ * (EXEC_MJ_JOINTEST)
+ *
+ * This is the case when
+ *
+ * outer inner 4 5 - marked tuple outer tuple - 5 5 new
+ * outer tuple - 5 5 6 8 - inner tuple 7 12
+ *
+ * new outer tuple = marked tuple
+ *
+ * If the outer tuple fails the test, then we know we have to
+ * proceed to skip outer tuples until outer >= inner
+ * (EXEC_MJ_SKIPOUTER).
+ *
+ * This is the case when
+ *
+ * outer inner 5 5 - marked tuple outer tuple - 5 5 new
+ * outer tuple - 6 8 - inner tuple 7 12
+ *
+ * new outer tuple > marked tuple
+ *
+ ********************************
+ *
+ */
+ case EXEC_MJ_TESTOUTER:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_TESTOUTER\n");
+
+ /* ----------------
+ * here we compare the outer tuple with the marked inner tuple
+ * by using the marked tuple in place of the inner tuple.
+ * ----------------
+ */
+ innerTupleSlot = econtext->ecxt_innertuple;
+ markedTupleSlot = mergestate->mj_MarkedTupleSlot;
+ econtext->ecxt_innertuple = markedTupleSlot;
+
+ qualResult = ExecQual((List *) mergeclauses, econtext);
+ MJ_DEBUG_QUAL(mergeclauses, qualResult);
+
+ if (qualResult)
+ {
+ /* ----------------
+ * the merge clause matched so now we juggle the slots
+ * back the way they were and proceed to JOINTEST.
+ * ----------------
+ */
+ econtext->ecxt_innertuple = innerTupleSlot;
+
+ RestoreInnerTuple(innerTupleSlot, markedTupleSlot);
+
+ ExecRestrPos(innerPlan);
+ mergestate->mj_JoinState = EXEC_MJ_JOINTEST;
+
+ }
+ else
+ {
+ /* ----------------
+ * if the inner tuple was nil and the new outer
+ * tuple didn't match the marked outer tuple then
+ * we may have the case:
+ *
+ * outer inner
+ * 4 4 - marked tuple
+ * new outer - 5 4
+ * 6 nil - inner tuple
+ * 7
+ *
+ * which means that all subsequent outer tuples will be
+ * larger than our inner tuples.
+ * ----------------
+ */
+ if (TupIsNull(innerTupleSlot))
+ {
+ MJ_printf("ExecMergeJoin: **** wierd case 1 ****\n");
+ return NULL;
+ }
+
+ /* ----------------
+ * restore the inner tuple and continue on to
+ * skip outer tuples.
+ * ----------------
+ */
+ econtext->ecxt_innertuple = innerTupleSlot;
+ mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
+ }
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_SKIPOUTER means
+ * skip over tuples in the outer plan until we find an outer
+ * tuple > current inner tuple.
+ *
+ * For example:
+ *
+ * outer inner 5 5 5 5 outer tuple - 6 8 - inner
+ * tuple 7 12 8 14
+ *
+ * we have to advance the outer scan until we find the outer 8.
+ *
+ ********************************
+ *
+ */
+ case EXEC_MJ_SKIPOUTER:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPOUTER\n");
+ /* ----------------
+ * before we advance, make sure the current tuples
+ * do not satisify the mergeclauses. If they do, then
+ * we update the marked tuple and go join them.
+ * ----------------
+ */
+ qualResult = ExecQual((List *) mergeclauses, econtext);
+ MJ_DEBUG_QUAL(mergeclauses, qualResult);
+
+ if (qualResult)
+ {
+ ExecMarkPos(innerPlan);
+ innerTupleSlot = econtext->ecxt_innertuple;
+
+ MarkInnerTuple(innerTupleSlot, mergestate);
+
+ mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ break;
+ }
+
+ /* ----------------
+ * ok, now test the skip qualification
+ * ----------------
+ */
+ compareResult = MergeCompare(mergeclauses,
+ outerSkipQual,
+ econtext);
+
+ MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
+
+ /* ----------------
+ * compareResult is true as long as we should
+ * continue skipping tuples.
+ * ----------------
+ */
+ if (compareResult)
+ {
+
+ outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
+ MJ_DEBUG_PROC_NODE(outerTupleSlot);
+ econtext->ecxt_outertuple = outerTupleSlot;
+
+ /* ----------------
+ * if the outer tuple is null then we know
+ * we are done with the join
+ * ----------------
+ */
+ if (TupIsNull(outerTupleSlot))
+ {
+ MJ_printf("ExecMergeJoin: **** outerTuple is nil ****\n");
+ return NULL;
+ }
+ /* ----------------
+ * otherwise test the new tuple against the skip qual.
+ * (we remain in the EXEC_MJ_SKIPOUTER state)
+ * ----------------
+ */
+ break;
+ }
+
+ /* ----------------
+ * now check the inner skip qual to see if we
+ * should now skip inner tuples... if we fail the
+ * inner skip qual, then we know we have a new pair
+ * of matching tuples.
+ * ----------------
+ */
+ compareResult = MergeCompare(mergeclauses,
+ innerSkipQual,
+ econtext);
+
+ MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
+
+ if (compareResult)
+ {
+ mergestate->mj_JoinState = EXEC_MJ_SKIPINNER;
+ }
+ else
+ {
+ mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
+ }
+ break;
+
+ /*
+ * ******************************** EXEC_MJ_SKIPINNER means
+ * skip over tuples in the inner plan until we find an inner
+ * tuple > current outer tuple.
+ *
+ * For example:
+ *
+ * outer inner 5 5 5 5 outer tuple - 12 8 - inner
+ * tuple 14 10 17 12
+ *
+ * we have to advance the inner scan until we find the inner 12.
+ *
+ ********************************
+ *
+ */
+ case EXEC_MJ_SKIPINNER:
+ MJ_printf("ExecMergeJoin: EXEC_MJ_SKIPINNER\n");
+ /* ----------------
+ * before we advance, make sure the current tuples
+ * do not satisify the mergeclauses. If they do, then
+ * we update the marked tuple and go join them.
+ * ----------------
+ */
+ qualResult = ExecQual((List *) mergeclauses, econtext);
+ MJ_DEBUG_QUAL(mergeclauses, qualResult);
+
+ if (qualResult)
+ {
+ ExecMarkPos(innerPlan);
+ innerTupleSlot = econtext->ecxt_innertuple;
+
+ MarkInnerTuple(innerTupleSlot, mergestate);
+
+ mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
+ break;
+ }
+
+ /* ----------------
+ * ok, now test the skip qualification
+ * ----------------
+ */
+ compareResult = MergeCompare(mergeclauses,
+ innerSkipQual,
+ econtext);
+
+ MJ_DEBUG_MERGE_COMPARE(innerSkipQual, compareResult);
+
+ /* ----------------
+ * compareResult is true as long as we should
+ * continue skipping tuples.
+ * ----------------
+ */
+ if (compareResult)
+ {
+ /* ----------------
+ * now try and get a new inner tuple
+ * ----------------
+ */
+ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
+ MJ_DEBUG_PROC_NODE(innerTupleSlot);
+ econtext->ecxt_innertuple = innerTupleSlot;
+
+ /* ----------------
+ * if the inner tuple is null then we know
+ * we have to restore the inner scan
+ * and advance to the next outer tuple
+ * ----------------
+ */
+ if (TupIsNull(innerTupleSlot))
+ {
+ /* ----------------
+ * this is an interesting case.. all our
+ * inner tuples are smaller then our outer
+ * tuples so we never found an inner tuple
+ * to mark.
+ *
+ * outer inner
+ * outer tuple - 5 4
+ * 5 4
+ * 6 nil - inner tuple
+ * 7
+ *
+ * This means the join should end.
+ * ----------------
+ */
+ MJ_printf("ExecMergeJoin: **** wierd case 2 ****\n");
+ return NULL;
+ }
+
+ /* ----------------
+ * otherwise test the new tuple against the skip qual.
+ * (we remain in the EXEC_MJ_SKIPINNER state)
+ * ----------------
+ */
+ break;
+ }
+
+ /* ----------------
+ * compare finally failed and we have stopped skipping
+ * inner tuples so now check the outer skip qual
+ * to see if we should now skip outer tuples...
+ * ----------------
+ */
+ compareResult = MergeCompare(mergeclauses,
+ outerSkipQual,
+ econtext);
+
+ MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
+
+ if (compareResult)
+ {
+ mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
+ }
+ else
+ {
+ mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
+ }
+
+ break;
+
+ /*
+ * ******************************** if we get here it means
+ * our code is fucked up and so we just end the join
+ * prematurely. ********************************
+ *
+ */
+ default:
+ elog(NOTICE, "ExecMergeJoin: invalid join state. aborting");
+ return NULL;
}
-
- /* ----------------
- * otherwise test the new tuple against the skip qual.
- * (we remain in the EXEC_MJ_SKIPINNER state)
- * ----------------
- */
- break;
- }
-
- /* ----------------
- * compare finally failed and we have stopped skipping
- * inner tuples so now check the outer skip qual
- * to see if we should now skip outer tuples...
- * ----------------
- */
- compareResult = MergeCompare(mergeclauses,
- outerSkipQual,
- econtext);
-
- MJ_DEBUG_MERGE_COMPARE(outerSkipQual, compareResult);
-
- if (compareResult)
- {
- mergestate->mj_JoinState = EXEC_MJ_SKIPOUTER;
- }
- else
- {
- mergestate->mj_JoinState = EXEC_MJ_JOINMARK;
- }
-
- break;
-
- /* ********************************
- * if we get here it means our code is fucked up and
- * so we just end the join prematurely.
- * ********************************
- */
- default:
- elog(NOTICE, "ExecMergeJoin: invalid join state. aborting");
- return NULL;
}
- }
}
-
+
/* ----------------------------------------------------------------
- * ExecInitMergeJoin
+ * ExecInitMergeJoin
*
* old comments
- * Creates the run-time state information for the node and
- * sets the relation id to contain relevant decriptors.
+ * Creates the run-time state information for the node and
+ * sets the relation id to contain relevant decriptors.
* ----------------------------------------------------------------
*/
bool
-ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
+ExecInitMergeJoin(MergeJoin * node, EState * estate, Plan * parent)
{
- MergeJoinState *mergestate;
- List *joinclauses;
- RegProcedure rightsortop;
- RegProcedure leftsortop;
- RegProcedure sortop;
-
- List *OSortopI;
- List *ISortopO;
-
- MJ1_printf("ExecInitMergeJoin: %s\n",
- "initializing node");
-
- /* ----------------
- * assign the node's execution state and
- * get the range table and direction from it
- * ----------------
- */
- node->join.state = estate;
-
- /* ----------------
- * create new merge state for node
- * ----------------
- */
- mergestate = makeNode(MergeJoinState);
- mergestate->mj_OSortopI = NIL;
- mergestate->mj_ISortopO = NIL;
- mergestate->mj_JoinState = 0;
- mergestate->mj_MarkedTupleSlot = NULL;
- node->mergestate = mergestate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &mergestate->jstate, parent);
- ExecAssignExprContext(estate, &mergestate->jstate);
+ MergeJoinState *mergestate;
+ List *joinclauses;
+ RegProcedure rightsortop;
+ RegProcedure leftsortop;
+ RegProcedure sortop;
+
+ List *OSortopI;
+ List *ISortopO;
+
+ MJ1_printf("ExecInitMergeJoin: %s\n",
+ "initializing node");
+
+ /* ----------------
+ * assign the node's execution state and
+ * get the range table and direction from it
+ * ----------------
+ */
+ node->join.state = estate;
+
+ /* ----------------
+ * create new merge state for node
+ * ----------------
+ */
+ mergestate = makeNode(MergeJoinState);
+ mergestate->mj_OSortopI = NIL;
+ mergestate->mj_ISortopO = NIL;
+ mergestate->mj_JoinState = 0;
+ mergestate->mj_MarkedTupleSlot = NULL;
+ node->mergestate = mergestate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &mergestate->jstate, parent);
+ ExecAssignExprContext(estate, &mergestate->jstate);
#define MERGEJOIN_NSLOTS 2
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &mergestate->jstate);
- ExecInitMarkedTupleSlot(estate, mergestate);
-
- /* ----------------
- * get merge sort operators.
- *
- * XXX for now we assume all quals in the joinclauses were
- * sorted with the same operator in both the inner and
- * outer relations. -cim 11/2/89
- * ----------------
- */
- joinclauses = node->mergeclauses;
-
- rightsortop = get_opcode(node->mergerightorder[0]);
- leftsortop = get_opcode(node->mergeleftorder[0]);
-
- if (leftsortop != rightsortop)
- elog(NOTICE, "ExecInitMergeJoin: %s",
- "left and right sortop's are unequal!");
-
- sortop = rightsortop;
-
- /* ----------------
- * form merge skip qualifications
- *
- * XXX MJform routines need to be extended
- * to take a list of sortops.. -cim 11/2/89
- * ----------------
- */
- OSortopI = MJFormOSortopI(joinclauses, sortop);
- ISortopO = MJFormISortopO(joinclauses, sortop);
- mergestate->mj_OSortopI = OSortopI;
- mergestate->mj_ISortopO = ISortopO;
-
- MJ_printf("\nExecInitMergeJoin: OSortopI is ");
- MJ_nodeDisplay(OSortopI);
- MJ_printf("\nExecInitMergeJoin: ISortopO is ");
- MJ_nodeDisplay(ISortopO);
- MJ_printf("\n");
-
- /* ----------------
- * initialize join state
- * ----------------
- */
- mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
-
- /* ----------------
- * initialize subplans
- * ----------------
- */
- ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
- ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
-
- /* ----------------
- * initialize tuple type and projection info
- * ----------------
- */
- ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
- ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
-
- mergestate->jstate.cs_TupFromTlist = false;
- /* ----------------
- * initialization successful
- * ----------------
- */
- MJ1_printf("ExecInitMergeJoin: %s\n",
- "node initialized");
-
- return TRUE;
+ /* ----------------
+ * tuple table initialization
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &mergestate->jstate);
+ ExecInitMarkedTupleSlot(estate, mergestate);
+
+ /* ----------------
+ * get merge sort operators.
+ *
+ * XXX for now we assume all quals in the joinclauses were
+ * sorted with the same operator in both the inner and
+ * outer relations. -cim 11/2/89
+ * ----------------
+ */
+ joinclauses = node->mergeclauses;
+
+ rightsortop = get_opcode(node->mergerightorder[0]);
+ leftsortop = get_opcode(node->mergeleftorder[0]);
+
+ if (leftsortop != rightsortop)
+ elog(NOTICE, "ExecInitMergeJoin: %s",
+ "left and right sortop's are unequal!");
+
+ sortop = rightsortop;
+
+ /* ----------------
+ * form merge skip qualifications
+ *
+ * XXX MJform routines need to be extended
+ * to take a list of sortops.. -cim 11/2/89
+ * ----------------
+ */
+ OSortopI = MJFormOSortopI(joinclauses, sortop);
+ ISortopO = MJFormISortopO(joinclauses, sortop);
+ mergestate->mj_OSortopI = OSortopI;
+ mergestate->mj_ISortopO = ISortopO;
+
+ MJ_printf("\nExecInitMergeJoin: OSortopI is ");
+ MJ_nodeDisplay(OSortopI);
+ MJ_printf("\nExecInitMergeJoin: ISortopO is ");
+ MJ_nodeDisplay(ISortopO);
+ MJ_printf("\n");
+
+ /* ----------------
+ * initialize join state
+ * ----------------
+ */
+ mergestate->mj_JoinState = EXEC_MJ_INITIALIZE;
+
+ /* ----------------
+ * initialize subplans
+ * ----------------
+ */
+ ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
+ ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
+
+ /* ----------------
+ * initialize tuple type and projection info
+ * ----------------
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &mergestate->jstate);
+ ExecAssignProjectionInfo((Plan *) node, &mergestate->jstate);
+
+ mergestate->jstate.cs_TupFromTlist = false;
+ /* ----------------
+ * initialization successful
+ * ----------------
+ */
+ MJ1_printf("ExecInitMergeJoin: %s\n",
+ "node initialized");
+
+ return TRUE;
}
-
+
int
-ExecCountSlotsMergeJoin(MergeJoin *node)
+ExecCountSlotsMergeJoin(MergeJoin * node)
{
- return ExecCountSlotsNode(outerPlan((Plan *)node)) +
- ExecCountSlotsNode(innerPlan((Plan *)node)) +
- MERGEJOIN_NSLOTS;
+ return ExecCountSlotsNode(outerPlan((Plan *) node)) +
+ ExecCountSlotsNode(innerPlan((Plan *) node)) +
+ MERGEJOIN_NSLOTS;
}
-
+
/* ----------------------------------------------------------------
- * ExecEndMergeJoin
+ * ExecEndMergeJoin
*
* old comments
- * frees storage allocated through C routines.
+ * frees storage allocated through C routines.
* ----------------------------------------------------------------
*/
void
-ExecEndMergeJoin(MergeJoin *node)
+ExecEndMergeJoin(MergeJoin * node)
{
- MergeJoinState *mergestate;
-
- MJ1_printf("ExecEndMergeJoin: %s\n",
- "ending node processing");
-
- /* ----------------
- * get state information from the node
- * ----------------
- */
- mergestate = node->mergestate;
-
- /* ----------------
- * Free the projection info and the scan attribute info
- *
- * Note: we don't ExecFreeResultType(mergestate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo(&mergestate->jstate);
-
- /* ----------------
- * shut down the subplans
- * ----------------
- */
- ExecEndNode((Plan*) innerPlan((Plan *) node), (Plan*)node);
- ExecEndNode((Plan*) outerPlan((Plan *) node), (Plan*)node);
-
- /* ----------------
- * clean out the tuple table so that we don't try and
- * pfree the marked tuples.. see HACK ALERT at the top of
- * this file.
- * ----------------
- */
- ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
- ExecClearTuple(mergestate->mj_MarkedTupleSlot);
-
- MJ1_printf("ExecEndMergeJoin: %s\n",
- "node processing ended");
+ MergeJoinState *mergestate;
+
+ MJ1_printf("ExecEndMergeJoin: %s\n",
+ "ending node processing");
+
+ /* ----------------
+ * get state information from the node
+ * ----------------
+ */
+ mergestate = node->mergestate;
+
+ /* ----------------
+ * Free the projection info and the scan attribute info
+ *
+ * Note: we don't ExecFreeResultType(mergestate)
+ * because the rule manager depends on the tupType
+ * returned by ExecMain(). So for now, this
+ * is freed at end-transaction time. -cim 6/2/91
+ * ----------------
+ */
+ ExecFreeProjectionInfo(&mergestate->jstate);
+
+ /* ----------------
+ * shut down the subplans
+ * ----------------
+ */
+ ExecEndNode((Plan *) innerPlan((Plan *) node), (Plan *) node);
+ ExecEndNode((Plan *) outerPlan((Plan *) node), (Plan *) node);
+
+ /* ----------------
+ * clean out the tuple table so that we don't try and
+ * pfree the marked tuples.. see HACK ALERT at the top of
+ * this file.
+ * ----------------
+ */
+ ExecClearTuple(mergestate->jstate.cs_ResultTupleSlot);
+ ExecClearTuple(mergestate->mj_MarkedTupleSlot);
+
+ MJ1_printf("ExecEndMergeJoin: %s\n",
+ "node processing ended");
}
-
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index d83d306bba9..e7cba2e756e 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* nodeNestloop.c--
- * routines to support nest-loop joins
+ * routines to support nest-loop joins
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.3 1996/11/08 05:56:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.4 1997/09/07 04:41:41 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * ExecNestLoop - process a nestloop join of two plans
- * ExecInitNestLoop - initialize the join
- * ExecEndNestLoop - shut down the join
+ * INTERFACE ROUTINES
+ * ExecNestLoop - process a nestloop join of two plans
+ * ExecInitNestLoop - initialize the join
+ * ExecEndNestLoop - shut down the join
*/
#include "postgres.h"
@@ -25,349 +25,363 @@
#include "executor/nodeIndexscan.h"
/* ----------------------------------------------------------------
- * ExecNestLoop(node)
+ * ExecNestLoop(node)
*
* old comments
- * Returns the tuple joined from inner and outer tuples which
- * satisfies the qualification clause.
+ * Returns the tuple joined from inner and outer tuples which
+ * satisfies the qualification clause.
*
- * It scans the inner relation to join with current outer tuple.
+ * It scans the inner relation to join with current outer tuple.
*
- * If none is found, next tuple form the outer relation is retrieved
- * and the inner relation is scanned from the beginning again to join
- * with the outer tuple.
+ * If none is found, next tuple form the outer relation is retrieved
+ * and the inner relation is scanned from the beginning again to join
+ * with the outer tuple.
*
- * Nil is returned if all the remaining outer tuples are tried and
- * all fail to join with the inner tuples.
+ * Nil is returned if all the remaining outer tuples are tried and
+ * all fail to join with the inner tuples.
*
- * Nil is also returned if there is no tuple from inner realtion.
- *
- * Conditions:
- * -- outerTuple contains current tuple from outer relation and
- * the right son(inner realtion) maintains "cursor" at the tuple
- * returned previously.
- * This is achieved by maintaining a scan position on the outer
- * relation.
- *
- * Initial States:
- * -- the outer child and the inner child
- * are prepared to return the first tuple.
+ * Nil is also returned if there is no tuple from inner realtion.
+ *
+ * Conditions:
+ * -- outerTuple contains current tuple from outer relation and
+ * the right son(inner realtion) maintains "cursor" at the tuple
+ * returned previously.
+ * This is achieved by maintaining a scan position on the outer
+ * relation.
+ *
+ * Initial States:
+ * -- the outer child and the inner child
+ * are prepared to return the first tuple.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecNestLoop(NestLoop *node, Plan* parent)
+ExecNestLoop(NestLoop * node, Plan * parent)
{
- NestLoopState *nlstate;
- Plan *innerPlan;
- Plan *outerPlan;
- bool needNewOuterTuple;
-
- TupleTableSlot *outerTupleSlot;
- TupleTableSlot *innerTupleSlot;
-
- List *qual;
- bool qualResult;
- ExprContext *econtext;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- ENL1_printf("getting info from node");
-
- nlstate = node->nlstate;
- qual = node->join.qual;
- outerPlan = outerPlan(&node->join);
- innerPlan = innerPlan(&node->join);
-
- /* ----------------
- * initialize expression context
- * ----------------
- */
- econtext = nlstate->jstate.cs_ExprContext;
-
- /* ---------------- * get the current outer tuple
- * ----------------
- */
- outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
- econtext->ecxt_outertuple = outerTupleSlot;
-
- /* ----------------
- * Ok, everything is setup for the join so now loop until
- * we return a qualifying join tuple..
- * ----------------
- */
-
- if (nlstate->jstate.cs_TupFromTlist) {
- TupleTableSlot *result;
- bool isDone;
-
- result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
- if (!isDone)
- return result;
- }
-
- ENL1_printf("entering main loop");
- for(;;) {
+ NestLoopState *nlstate;
+ Plan *innerPlan;
+ Plan *outerPlan;
+ bool needNewOuterTuple;
+
+ TupleTableSlot *outerTupleSlot;
+ TupleTableSlot *innerTupleSlot;
+
+ List *qual;
+ bool qualResult;
+ ExprContext *econtext;
+
/* ----------------
- * The essential idea now is to get the next inner tuple
- * and join it with the current outer tuple.
+ * get information from the node
* ----------------
*/
- needNewOuterTuple = false;
-
+ ENL1_printf("getting info from node");
+
+ nlstate = node->nlstate;
+ qual = node->join.qual;
+ outerPlan = outerPlan(&node->join);
+ innerPlan = innerPlan(&node->join);
+
/* ----------------
- * If outer tuple is not null then that means
- * we are in the middle of a scan and we should
- * restore our previously saved scan position.
+ * initialize expression context
* ----------------
*/
- if (! TupIsNull(outerTupleSlot)) {
- ENL1_printf("have outer tuple, restoring outer plan");
- ExecRestrPos(outerPlan);
- } else {
- ENL1_printf("outer tuple is nil, need new outer tuple");
- needNewOuterTuple = true;
- }
-
- /* ----------------
- * if we have an outerTuple, try to get the next inner tuple.
+ econtext = nlstate->jstate.cs_ExprContext;
+
+ /* ---------------- * get the current outer tuple
* ----------------
*/
- if (!needNewOuterTuple) {
- ENL1_printf("getting new inner tuple");
-
- innerTupleSlot = ExecProcNode(innerPlan, (Plan*)node);
- econtext->ecxt_innertuple = innerTupleSlot;
-
- if (TupIsNull(innerTupleSlot)) {
- ENL1_printf("no inner tuple, need new outer tuple");
- needNewOuterTuple = true;
- }
- }
-
+ outerTupleSlot = nlstate->jstate.cs_OuterTupleSlot;
+ econtext->ecxt_outertuple = outerTupleSlot;
+
/* ----------------
- * loop until we have a new outer tuple and a new
- * inner tuple.
+ * Ok, everything is setup for the join so now loop until
+ * we return a qualifying join tuple..
* ----------------
*/
- while (needNewOuterTuple) {
- /* ----------------
- * now try to get the next outer tuple
- * ----------------
- */
- ENL1_printf("getting new outer tuple");
- outerTupleSlot = ExecProcNode(outerPlan, (Plan*)node);
- econtext->ecxt_outertuple = outerTupleSlot;
-
- /* ----------------
- * if there are no more outer tuples, then the join
- * is complete..
- * ----------------
- */
- if (TupIsNull(outerTupleSlot)) {
- ENL1_printf("no outer tuple, ending join");
- return NULL;
- }
-
- /* ----------------
- * we have a new outer tuple so we mark our position
- * in the outer scan and save the outer tuple in the
- * NestLoop state
- * ----------------
- */
- ENL1_printf("saving new outer tuple information");
- ExecMarkPos(outerPlan);
- nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
-
- /* ----------------
- * now rescan the inner plan and get a new inner tuple
- * ----------------
- */
-
- ENL1_printf("rescanning inner plan");
- /*
- * The scan key of the inner plan might depend on the current
- * outer tuple (e.g. in index scans), that's why we pass our
- * expr context.
- */
- ExecReScan(innerPlan, econtext, parent);
-
- ENL1_printf("getting new inner tuple");
-
- innerTupleSlot = ExecProcNode(innerPlan, (Plan*)node);
- econtext->ecxt_innertuple = innerTupleSlot;
-
- if (TupIsNull(innerTupleSlot)) {
- ENL1_printf("couldn't get inner tuple - need new outer tuple");
- } else {
- ENL1_printf("got inner and outer tuples");
+
+ if (nlstate->jstate.cs_TupFromTlist)
+ {
+ TupleTableSlot *result;
+ bool isDone;
+
+ result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
+ if (!isDone)
+ return result;
+ }
+
+ ENL1_printf("entering main loop");
+ for (;;)
+ {
+ /* ----------------
+ * The essential idea now is to get the next inner tuple
+ * and join it with the current outer tuple.
+ * ----------------
+ */
needNewOuterTuple = false;
- }
- } /* while (needNewOuterTuple) */
-
+
+ /* ----------------
+ * If outer tuple is not null then that means
+ * we are in the middle of a scan and we should
+ * restore our previously saved scan position.
+ * ----------------
+ */
+ if (!TupIsNull(outerTupleSlot))
+ {
+ ENL1_printf("have outer tuple, restoring outer plan");
+ ExecRestrPos(outerPlan);
+ }
+ else
+ {
+ ENL1_printf("outer tuple is nil, need new outer tuple");
+ needNewOuterTuple = true;
+ }
+
+ /* ----------------
+ * if we have an outerTuple, try to get the next inner tuple.
+ * ----------------
+ */
+ if (!needNewOuterTuple)
+ {
+ ENL1_printf("getting new inner tuple");
+
+ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
+ econtext->ecxt_innertuple = innerTupleSlot;
+
+ if (TupIsNull(innerTupleSlot))
+ {
+ ENL1_printf("no inner tuple, need new outer tuple");
+ needNewOuterTuple = true;
+ }
+ }
+
+ /* ----------------
+ * loop until we have a new outer tuple and a new
+ * inner tuple.
+ * ----------------
+ */
+ while (needNewOuterTuple)
+ {
+ /* ----------------
+ * now try to get the next outer tuple
+ * ----------------
+ */
+ ENL1_printf("getting new outer tuple");
+ outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
+ econtext->ecxt_outertuple = outerTupleSlot;
+
+ /* ----------------
+ * if there are no more outer tuples, then the join
+ * is complete..
+ * ----------------
+ */
+ if (TupIsNull(outerTupleSlot))
+ {
+ ENL1_printf("no outer tuple, ending join");
+ return NULL;
+ }
+
+ /* ----------------
+ * we have a new outer tuple so we mark our position
+ * in the outer scan and save the outer tuple in the
+ * NestLoop state
+ * ----------------
+ */
+ ENL1_printf("saving new outer tuple information");
+ ExecMarkPos(outerPlan);
+ nlstate->jstate.cs_OuterTupleSlot = outerTupleSlot;
+
+ /* ----------------
+ * now rescan the inner plan and get a new inner tuple
+ * ----------------
+ */
+
+ ENL1_printf("rescanning inner plan");
+
+ /*
+ * The scan key of the inner plan might depend on the current
+ * outer tuple (e.g. in index scans), that's why we pass our
+ * expr context.
+ */
+ ExecReScan(innerPlan, econtext, parent);
+
+ ENL1_printf("getting new inner tuple");
+
+ innerTupleSlot = ExecProcNode(innerPlan, (Plan *) node);
+ econtext->ecxt_innertuple = innerTupleSlot;
+
+ if (TupIsNull(innerTupleSlot))
+ {
+ ENL1_printf("couldn't get inner tuple - need new outer tuple");
+ }
+ else
+ {
+ ENL1_printf("got inner and outer tuples");
+ needNewOuterTuple = false;
+ }
+ } /* while (needNewOuterTuple) */
+
+ /* ----------------
+ * at this point we have a new pair of inner and outer
+ * tuples so we test the inner and outer tuples to see
+ * if they satisify the node's qualification.
+ * ----------------
+ */
+ ENL1_printf("testing qualification");
+ qualResult = ExecQual((List *) qual, econtext);
+
+ if (qualResult)
+ {
+ /* ----------------
+ * qualification was satisified so we project and
+ * return the slot containing the result tuple
+ * using ExecProject().
+ * ----------------
+ */
+ ProjectionInfo *projInfo;
+ TupleTableSlot *result;
+ bool isDone;
+
+ ENL1_printf("qualification succeeded, projecting tuple");
+
+ projInfo = nlstate->jstate.cs_ProjInfo;
+ result = ExecProject(projInfo, &isDone);
+ nlstate->jstate.cs_TupFromTlist = !isDone;
+ return result;
+ }
+
+ /* ----------------
+ * qualification failed so we have to try again..
+ * ----------------
+ */
+ ENL1_printf("qualification failed, looping");
+ }
+}
+
+/* ----------------------------------------------------------------
+ * ExecInitNestLoop
+ *
+ * Creates the run-time state information for the nestloop node
+ * produced by the planner and initailizes inner and outer relations
+ * (child nodes).
+ * ----------------------------------------------------------------
+ */
+bool
+ExecInitNestLoop(NestLoop * node, EState * estate, Plan * parent)
+{
+ NestLoopState *nlstate;
+
+ NL1_printf("ExecInitNestLoop: %s\n",
+ "initializing node");
+
/* ----------------
- * at this point we have a new pair of inner and outer
- * tuples so we test the inner and outer tuples to see
- * if they satisify the node's qualification.
+ * assign execution state to node
* ----------------
*/
- ENL1_printf("testing qualification");
- qualResult = ExecQual((List*)qual, econtext);
-
- if (qualResult) {
- /* ----------------
- * qualification was satisified so we project and
- * return the slot containing the result tuple
- * using ExecProject().
- * ----------------
- */
- ProjectionInfo *projInfo;
- TupleTableSlot *result;
- bool isDone;
-
- ENL1_printf("qualification succeeded, projecting tuple");
-
- projInfo = nlstate->jstate.cs_ProjInfo;
- result = ExecProject(projInfo, &isDone);
- nlstate->jstate.cs_TupFromTlist = !isDone;
- return result;
- }
-
+ node->join.state = estate;
+
/* ----------------
- * qualification failed so we have to try again..
+ * create new nest loop state
* ----------------
*/
- ENL1_printf("qualification failed, looping");
- }
-}
+ nlstate = makeNode(NestLoopState);
+ nlstate->nl_PortalFlag = false;
+ node->nlstate = nlstate;
-/* ----------------------------------------------------------------
- * ExecInitNestLoop
- *
- * Creates the run-time state information for the nestloop node
- * produced by the planner and initailizes inner and outer relations
- * (child nodes).
- * ----------------------------------------------------------------
- */
-bool
-ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
-{
- NestLoopState *nlstate;
-
- NL1_printf("ExecInitNestLoop: %s\n",
- "initializing node");
-
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- node->join.state = estate;
-
- /* ----------------
- * create new nest loop state
- * ----------------
- */
- nlstate = makeNode(NestLoopState);
- nlstate->nl_PortalFlag = false;
- node->nlstate = nlstate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
- ExecAssignExprContext(estate, &nlstate->jstate);
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &nlstate->jstate, parent);
+ ExecAssignExprContext(estate, &nlstate->jstate);
#define NESTLOOP_NSLOTS 1
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &nlstate->jstate);
-
- /* ----------------
- * now initialize children
- * ----------------
- */
- ExecInitNode(outerPlan((Plan*)node), estate, (Plan*)node);
- ExecInitNode(innerPlan((Plan*)node), estate, (Plan*)node);
-
- /* ----------------
- * initialize tuple type and projection info
- * ----------------
- */
- ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
- ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
-
- /* ----------------
- * finally, wipe the current outer tuple clean.
- * ----------------
- */
- nlstate->jstate.cs_OuterTupleSlot = NULL;
- nlstate->jstate.cs_TupFromTlist = false;
-
- NL1_printf("ExecInitNestLoop: %s\n",
- "node initialized");
- return TRUE;
+ /* ----------------
+ * tuple table initialization
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &nlstate->jstate);
+
+ /* ----------------
+ * now initialize children
+ * ----------------
+ */
+ ExecInitNode(outerPlan((Plan *) node), estate, (Plan *) node);
+ ExecInitNode(innerPlan((Plan *) node), estate, (Plan *) node);
+
+ /* ----------------
+ * initialize tuple type and projection info
+ * ----------------
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &nlstate->jstate);
+ ExecAssignProjectionInfo((Plan *) node, &nlstate->jstate);
+
+ /* ----------------
+ * finally, wipe the current outer tuple clean.
+ * ----------------
+ */
+ nlstate->jstate.cs_OuterTupleSlot = NULL;
+ nlstate->jstate.cs_TupFromTlist = false;
+
+ NL1_printf("ExecInitNestLoop: %s\n",
+ "node initialized");
+ return TRUE;
}
int
-ExecCountSlotsNestLoop(NestLoop *node)
+ExecCountSlotsNestLoop(NestLoop * node)
{
- return ExecCountSlotsNode(outerPlan(node)) +
- ExecCountSlotsNode(innerPlan(node)) +
- NESTLOOP_NSLOTS;
+ return ExecCountSlotsNode(outerPlan(node)) +
+ ExecCountSlotsNode(innerPlan(node)) +
+ NESTLOOP_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndNestLoop
- *
- * closes down scans and frees allocated storage
+ * ExecEndNestLoop
+ *
+ * closes down scans and frees allocated storage
* ----------------------------------------------------------------
*/
void
-ExecEndNestLoop(NestLoop *node)
+ExecEndNestLoop(NestLoop * node)
{
- NestLoopState *nlstate;
-
- NL1_printf("ExecEndNestLoop: %s\n",
- "ending node processing");
-
- /* ----------------
- * get info from the node
- * ----------------
- */
- nlstate = node->nlstate;
-
- /* ----------------
- * Free the projection info
- *
- * Note: we don't ExecFreeResultType(nlstate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo(&nlstate->jstate);
-
- /* ----------------
- * close down subplans
- * ----------------
- */
- ExecEndNode(outerPlan((Plan *) node), (Plan*)node);
- ExecEndNode(innerPlan((Plan *) node), (Plan*)node);
-
- /* ----------------
- * clean out the tuple table
- * ----------------
- */
- ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
-
- NL1_printf("ExecEndNestLoop: %s\n",
- "node processing ended");
+ NestLoopState *nlstate;
+
+ NL1_printf("ExecEndNestLoop: %s\n",
+ "ending node processing");
+
+ /* ----------------
+ * get info from the node
+ * ----------------
+ */
+ nlstate = node->nlstate;
+
+ /* ----------------
+ * Free the projection info
+ *
+ * Note: we don't ExecFreeResultType(nlstate)
+ * because the rule manager depends on the tupType
+ * returned by ExecMain(). So for now, this
+ * is freed at end-transaction time. -cim 6/2/91
+ * ----------------
+ */
+ ExecFreeProjectionInfo(&nlstate->jstate);
+
+ /* ----------------
+ * close down subplans
+ * ----------------
+ */
+ ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
+ ExecEndNode(innerPlan((Plan *) node), (Plan *) node);
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(nlstate->jstate.cs_ResultTupleSlot);
+
+ NL1_printf("ExecEndNestLoop: %s\n",
+ "node processing ended");
}
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index f4553dcc7b7..743bd73f2b3 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -1,33 +1,33 @@
/*-------------------------------------------------------------------------
*
* nodeResult.c--
- * support for constant nodes needing special code.
+ * support for constant nodes needing special code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
- * DESCRIPTION
+ * DESCRIPTION
*
- * Example: in constant queries where no relations are scanned,
- * the planner generates result nodes. Examples of such queries are:
+ * Example: in constant queries where no relations are scanned,
+ * the planner generates result nodes. Examples of such queries are:
*
- * retrieve (x = 1)
- * and
- * append emp (name = "mike", salary = 15000)
+ * retrieve (x = 1)
+ * and
+ * append emp (name = "mike", salary = 15000)
*
- * Result nodes are also used to optimise queries
- * with tautological qualifications like:
+ * Result nodes are also used to optimise queries
+ * with tautological qualifications like:
*
- * retrieve (emp.all) where 2 > 1
+ * retrieve (emp.all) where 2 > 1
*
- * In this case, the plan generated is
+ * In this case, the plan generated is
*
- * Result (with 2 > 1 qual)
- * /
- * SeqScan (emp.all)
+ * Result (with 2 > 1 qual)
+ * /
+ * SeqScan (emp.all)
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.2 1996/10/31 10:12:18 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.3 1997/09/07 04:41:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,253 +38,259 @@
#include "executor/nodeResult.h"
/* ----------------------------------------------------------------
- * ExecResult(node)
+ * ExecResult(node)
*
- * returns the tuples from the outer plan which satisify the
- * qualification clause. Since result nodes with right
- * subtrees are never planned, we ignore the right subtree
- * entirely (for now).. -cim 10/7/89
+ * returns the tuples from the outer plan which satisify the
+ * qualification clause. Since result nodes with right
+ * subtrees are never planned, we ignore the right subtree
+ * entirely (for now).. -cim 10/7/89
*
- * The qualification containing only constant clauses are
- * checked first before any processing is done. It always returns
- * 'nil' if the constant qualification is not satisfied.
+ * The qualification containing only constant clauses are
+ * checked first before any processing is done. It always returns
+ * 'nil' if the constant qualification is not satisfied.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecResult(Result *node)
+ExecResult(Result * node)
{
- ResultState *resstate;
- TupleTableSlot *outerTupleSlot;
- TupleTableSlot *resultSlot;
- Plan *outerPlan;
- ExprContext *econtext;
- Node *qual;
- bool qualResult;
- bool isDone;
- ProjectionInfo *projInfo;
-
- /* ----------------
- * initialize the result node's state
- * ----------------
- */
- resstate = node->resstate;
-
- /* ----------------
- * get the expression context
- * ----------------
- */
- econtext = resstate->cstate.cs_ExprContext;
-
- /* ----------------
- * check tautological qualifications like (2 > 1)
- * ----------------
- */
- qual = node->resconstantqual;
- if (qual != NULL) {
- qualResult = ExecQual((List*)qual, econtext);
- /* ----------------
- * if we failed the constant qual, then there
- * is no need to continue processing because regardless of
- * what happens, the constant qual will be false..
- * ----------------
- */
- if (qualResult == false)
- return NULL;
-
- /* ----------------
- * our constant qualification succeeded so now we
- * throw away the qual because we know it will always
- * succeed.
- * ----------------
- */
- node->resconstantqual = NULL;
- }
-
- if (resstate->cstate.cs_TupFromTlist) {
+ ResultState *resstate;
+ TupleTableSlot *outerTupleSlot;
+ TupleTableSlot *resultSlot;
+ Plan *outerPlan;
+ ExprContext *econtext;
+ Node *qual;
+ bool qualResult;
+ bool isDone;
ProjectionInfo *projInfo;
-
- projInfo = resstate->cstate.cs_ProjInfo;
- resultSlot = ExecProject(projInfo, &isDone);
- if (!isDone)
- return resultSlot;
- }
-
- /* ----------------
- * retrieve a tuple that satisfy the qual from the outer plan until
- * there are no more.
- *
- * if rs_done is 1 then it means that we were asked to return
- * a constant tuple and we alread did the last time ExecResult()
- * was called, so now we are through.
- * ----------------
- */
- outerPlan = outerPlan(node);
-
- while (!resstate->rs_done) {
/* ----------------
- * get next outer tuple if necessary.
+ * initialize the result node's state
* ----------------
*/
- if (outerPlan != NULL) {
- outerTupleSlot = ExecProcNode(outerPlan, (Plan*)node);
-
- if (TupIsNull(outerTupleSlot))
- return NULL;
-
- resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
- } else {
-
- /* ----------------
- * if we don't have an outer plan, then it's probably
- * the case that we are doing a retrieve or an append
- * with a constant target list, so we should only return
- * the constant tuple once or never if we fail the qual.
- * ----------------
- */
- resstate->rs_done = 1;
- }
-
+ resstate = node->resstate;
+
/* ----------------
- * get the information to place into the expr context
+ * get the expression context
* ----------------
*/
- resstate = node->resstate;
-
- outerTupleSlot = resstate->cstate.cs_OuterTupleSlot;
-
+ econtext = resstate->cstate.cs_ExprContext;
+
/* ----------------
- * fill in the information in the expression context
- * XXX gross hack. use outer tuple as scan tuple
+ * check tautological qualifications like (2 > 1)
* ----------------
*/
- econtext->ecxt_outertuple = outerTupleSlot;
- econtext->ecxt_scantuple = outerTupleSlot;
-
+ qual = node->resconstantqual;
+ if (qual != NULL)
+ {
+ qualResult = ExecQual((List *) qual, econtext);
+ /* ----------------
+ * if we failed the constant qual, then there
+ * is no need to continue processing because regardless of
+ * what happens, the constant qual will be false..
+ * ----------------
+ */
+ if (qualResult == false)
+ return NULL;
+
+ /* ----------------
+ * our constant qualification succeeded so now we
+ * throw away the qual because we know it will always
+ * succeed.
+ * ----------------
+ */
+ node->resconstantqual = NULL;
+ }
+
+ if (resstate->cstate.cs_TupFromTlist)
+ {
+ ProjectionInfo *projInfo;
+
+ projInfo = resstate->cstate.cs_ProjInfo;
+ resultSlot = ExecProject(projInfo, &isDone);
+ if (!isDone)
+ return resultSlot;
+ }
+
/* ----------------
- * form the result tuple and pass it back using ExecProject()
+ * retrieve a tuple that satisfy the qual from the outer plan until
+ * there are no more.
+ *
+ * if rs_done is 1 then it means that we were asked to return
+ * a constant tuple and we alread did the last time ExecResult()
+ * was called, so now we are through.
* ----------------
*/
- projInfo = resstate->cstate.cs_ProjInfo;
- resultSlot = ExecProject(projInfo, &isDone);
- resstate->cstate.cs_TupFromTlist = !isDone;
- return resultSlot;
- }
+ outerPlan = outerPlan(node);
+
+ while (!resstate->rs_done)
+ {
+
+ /* ----------------
+ * get next outer tuple if necessary.
+ * ----------------
+ */
+ if (outerPlan != NULL)
+ {
+ outerTupleSlot = ExecProcNode(outerPlan, (Plan *) node);
+
+ if (TupIsNull(outerTupleSlot))
+ return NULL;
- return NULL;
+ resstate->cstate.cs_OuterTupleSlot = outerTupleSlot;
+ }
+ else
+ {
+
+ /* ----------------
+ * if we don't have an outer plan, then it's probably
+ * the case that we are doing a retrieve or an append
+ * with a constant target list, so we should only return
+ * the constant tuple once or never if we fail the qual.
+ * ----------------
+ */
+ resstate->rs_done = 1;
+ }
+
+ /* ----------------
+ * get the information to place into the expr context
+ * ----------------
+ */
+ resstate = node->resstate;
+
+ outerTupleSlot = resstate->cstate.cs_OuterTupleSlot;
+
+ /* ----------------
+ * fill in the information in the expression context
+ * XXX gross hack. use outer tuple as scan tuple
+ * ----------------
+ */
+ econtext->ecxt_outertuple = outerTupleSlot;
+ econtext->ecxt_scantuple = outerTupleSlot;
+
+ /* ----------------
+ * form the result tuple and pass it back using ExecProject()
+ * ----------------
+ */
+ projInfo = resstate->cstate.cs_ProjInfo;
+ resultSlot = ExecProject(projInfo, &isDone);
+ resstate->cstate.cs_TupFromTlist = !isDone;
+ return resultSlot;
+ }
+
+ return NULL;
}
/* ----------------------------------------------------------------
- * ExecInitResult
- *
- * Creates the run-time state information for the result node
- * produced by the planner and initailizes outer relations
- * (child nodes).
+ * ExecInitResult
+ *
+ * Creates the run-time state information for the result node
+ * produced by the planner and initailizes outer relations
+ * (child nodes).
* ----------------------------------------------------------------
*/
bool
-ExecInitResult(Result *node, EState *estate, Plan *parent)
+ExecInitResult(Result * node, EState * estate, Plan * parent)
{
- ResultState *resstate;
-
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- node->plan.state = estate;
-
- /* ----------------
- * create new ResultState for node
- * ----------------
- */
- resstate = makeNode(ResultState);
- resstate->rs_done = 0;
- node->resstate = resstate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &resstate->cstate, parent);
- ExecAssignExprContext(estate, &resstate->cstate);
-
+ ResultState *resstate;
+
+ /* ----------------
+ * assign execution state to node
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create new ResultState for node
+ * ----------------
+ */
+ resstate = makeNode(ResultState);
+ resstate->rs_done = 0;
+ node->resstate = resstate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &resstate->cstate, parent);
+ ExecAssignExprContext(estate, &resstate->cstate);
+
#define RESULT_NSLOTS 1
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &resstate->cstate);
-
- /* ----------------
- * then initialize children
- * ----------------
- */
- ExecInitNode(outerPlan(node), estate, (Plan*)node);
-
- /*
- * we don't use inner plan
- */
- Assert(innerPlan(node)==NULL);
-
- /* ----------------
- * initialize tuple type and projection info
- * ----------------
- */
- ExecAssignResultTypeFromTL((Plan*)node, &resstate->cstate);
- ExecAssignProjectionInfo((Plan*)node, &resstate->cstate);
-
- /* ----------------
- * set "are we done yet" to false
- * ----------------
- */
- resstate->rs_done = 0;
-
- return TRUE;
+ /* ----------------
+ * tuple table initialization
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &resstate->cstate);
+
+ /* ----------------
+ * then initialize children
+ * ----------------
+ */
+ ExecInitNode(outerPlan(node), estate, (Plan *) node);
+
+ /*
+ * we don't use inner plan
+ */
+ Assert(innerPlan(node) == NULL);
+
+ /* ----------------
+ * initialize tuple type and projection info
+ * ----------------
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &resstate->cstate);
+ ExecAssignProjectionInfo((Plan *) node, &resstate->cstate);
+
+ /* ----------------
+ * set "are we done yet" to false
+ * ----------------
+ */
+ resstate->rs_done = 0;
+
+ return TRUE;
}
int
-ExecCountSlotsResult(Result *node)
+ExecCountSlotsResult(Result * node)
{
- return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
+ return ExecCountSlotsNode(outerPlan(node)) + RESULT_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndResult
- *
- * fees up storage allocated through C routines
+ * ExecEndResult
+ *
+ * fees up storage allocated through C routines
* ----------------------------------------------------------------
*/
void
-ExecEndResult(Result *node)
+ExecEndResult(Result * node)
{
- ResultState *resstate;
-
- resstate = node->resstate;
-
- /* ----------------
- * Free the projection info
- *
- * Note: we don't ExecFreeResultType(resstate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo(&resstate->cstate);
-
- /* ----------------
- * shut down subplans
- * ----------------
- */
- ExecEndNode(outerPlan(node), (Plan*)node);
-
- /* ----------------
- * clean out the tuple table
- * ----------------
- */
- ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
+ ResultState *resstate;
+
+ resstate = node->resstate;
+
+ /* ----------------
+ * Free the projection info
+ *
+ * Note: we don't ExecFreeResultType(resstate)
+ * because the rule manager depends on the tupType
+ * returned by ExecMain(). So for now, this
+ * is freed at end-transaction time. -cim 6/2/91
+ * ----------------
+ */
+ ExecFreeProjectionInfo(&resstate->cstate);
+
+ /* ----------------
+ * shut down subplans
+ * ----------------
+ */
+ ExecEndNode(outerPlan(node), (Plan *) node);
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(resstate->cstate.cs_ResultTupleSlot);
}
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index b94bb58d260..d3451f8026f 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* nodeSeqscan.c--
- * Support routines for sequential scans of relations.
+ * Support routines for sequential scans of relations.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.4 1997/08/19 21:31:12 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.5 1997/09/07 04:41:44 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecSeqScan sequentially scans a relation.
- * ExecSeqNext retrieve next tuple in sequential order.
- * ExecInitSeqScan creates and initializes a seqscan node.
- * ExecEndSeqScan releases any storage allocated.
- * ExecSeqReScan rescans the relation
- * ExecMarkPos marks scan position
- * ExecRestrPos restores scan position
+ * ExecSeqScan sequentially scans a relation.
+ * ExecSeqNext retrieve next tuple in sequential order.
+ * ExecInitSeqScan creates and initializes a seqscan node.
+ * ExecEndSeqScan releases any storage allocated.
+ * ExecSeqReScan rescans the relation
+ * ExecMarkPos marks scan position
+ * ExecRestrPos restores scan position
*
*/
#include "postgres.h"
@@ -30,429 +30,443 @@
#include "access/heapam.h"
#include "parser/parsetree.h"
-static Oid InitScanRelation(SeqScan *node, EState *estate,
- CommonScanState *scanstate, Plan *outerPlan);
+static Oid
+InitScanRelation(SeqScan * node, EState * estate,
+ CommonScanState * scanstate, Plan * outerPlan);
-static TupleTableSlot *SeqNext(SeqScan *node);
+static TupleTableSlot *SeqNext(SeqScan * node);
/* ----------------------------------------------------------------
- * Scan Support
+ * Scan Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
- * SeqNext
+ * SeqNext
*
- * This is a workhorse for ExecSeqScan
+ * This is a workhorse for ExecSeqScan
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-SeqNext(SeqScan *node)
+SeqNext(SeqScan * node)
{
- HeapTuple tuple;
- HeapScanDesc scandesc;
- CommonScanState *scanstate;
- EState *estate;
- ScanDirection direction;
- TupleTableSlot *slot;
- Buffer buffer;
-
- /* ----------------
- * get information from the estate and scan state
- * ----------------
- */
- estate = node->plan.state;
- scanstate = node->scanstate;
- scandesc = scanstate->css_currentScanDesc;
- direction = estate->es_direction;
-
- /* ----------------
- * get the next tuple from the access methods
- * ----------------
- */
- tuple = heap_getnext(scandesc, /* scan desc */
- ScanDirectionIsBackward(direction), /*backward flag*/
- &buffer); /* return: buffer */
-
- /* ----------------
- * save the tuple and the buffer returned to us by the access methods
- * in our scan tuple slot and return the slot. Note: we pass 'false'
- * because tuples returned by heap_getnext() are pointers onto
- * disk pages and were not created with palloc() and so should not
- * be pfree()'d.
- * ----------------
- */
- slot = scanstate->css_ScanTupleSlot;
-
- slot = ExecStoreTuple(tuple, /* tuple to store */
- slot, /* slot to store in */
- buffer, /* buffer associated with this tuple */
- false); /* don't pfree this pointer */
-
- /* ----------------
- * XXX -- mao says: The sequential scan for heap relations will
- * automatically unpin the buffer this tuple is on when we cross
- * a page boundary. The clearslot code also does this. We bump
- * the pin count on the page here, since we actually have two
- * pointers to it -- one in the scan desc and one in the tuple
- * table slot. --mar 20 91
- * ----------------
- */
- ExecIncrSlotBufferRefcnt(slot);
-
- return slot;
+ HeapTuple tuple;
+ HeapScanDesc scandesc;
+ CommonScanState *scanstate;
+ EState *estate;
+ ScanDirection direction;
+ TupleTableSlot *slot;
+ Buffer buffer;
+
+ /* ----------------
+ * get information from the estate and scan state
+ * ----------------
+ */
+ estate = node->plan.state;
+ scanstate = node->scanstate;
+ scandesc = scanstate->css_currentScanDesc;
+ direction = estate->es_direction;
+
+ /* ----------------
+ * get the next tuple from the access methods
+ * ----------------
+ */
+ tuple = heap_getnext(scandesc, /* scan desc */
+ ScanDirectionIsBackward(direction), /* backward flag */
+ &buffer); /* return: buffer */
+
+ /* ----------------
+ * save the tuple and the buffer returned to us by the access methods
+ * in our scan tuple slot and return the slot. Note: we pass 'false'
+ * because tuples returned by heap_getnext() are pointers onto
+ * disk pages and were not created with palloc() and so should not
+ * be pfree()'d.
+ * ----------------
+ */
+ slot = scanstate->css_ScanTupleSlot;
+
+ slot = ExecStoreTuple(tuple,/* tuple to store */
+ slot, /* slot to store in */
+ buffer, /* buffer associated with this
+ * tuple */
+ false); /* don't pfree this pointer */
+
+ /* ----------------
+ * XXX -- mao says: The sequential scan for heap relations will
+ * automatically unpin the buffer this tuple is on when we cross
+ * a page boundary. The clearslot code also does this. We bump
+ * the pin count on the page here, since we actually have two
+ * pointers to it -- one in the scan desc and one in the tuple
+ * table slot. --mar 20 91
+ * ----------------
+ */
+ ExecIncrSlotBufferRefcnt(slot);
+
+ return slot;
}
/* ----------------------------------------------------------------
- * ExecSeqScan(node)
+ * ExecSeqScan(node)
+ *
+ * Scans the relation sequentially and returns the next qualifying
+ * tuple.
+ * It calls the ExecScan() routine and passes it the access method
+ * which retrieve tuples sequentially.
*
- * Scans the relation sequentially and returns the next qualifying
- * tuple.
- * It calls the ExecScan() routine and passes it the access method
- * which retrieve tuples sequentially.
- *
*/
TupleTableSlot *
-ExecSeqScan(SeqScan *node)
+ExecSeqScan(SeqScan * node)
{
- TupleTableSlot *slot;
- Plan *outerPlan;
-
-S_printf("ExecSeqScan: scanning node: "); S_nodeDisplay(node);
-
- /* ----------------
- * if there is an outer subplan, get a tuple from it
- * else, scan the relation
- * ----------------
- */
- outerPlan = outerPlan((Plan *) node);
- if (outerPlan) {
- slot = ExecProcNode(outerPlan, (Plan*) node);
- } else {
- slot = ExecScan(node, SeqNext);
- }
-
-S1_printf("ExecSeqScan: returned tuple slot: %d\n", slot);
-
- return slot;
+ TupleTableSlot *slot;
+ Plan *outerPlan;
+
+ S_printf("ExecSeqScan: scanning node: ");
+ S_nodeDisplay(node);
+
+ /* ----------------
+ * if there is an outer subplan, get a tuple from it
+ * else, scan the relation
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ if (outerPlan)
+ {
+ slot = ExecProcNode(outerPlan, (Plan *) node);
+ }
+ else
+ {
+ slot = ExecScan(node, SeqNext);
+ }
+
+ S1_printf("ExecSeqScan: returned tuple slot: %d\n", slot);
+
+ return slot;
}
/* ----------------------------------------------------------------
- * InitScanRelation
+ * InitScanRelation
*
- * This does the initialization for scan relations and
- * subplans of scans.
+ * This does the initialization for scan relations and
+ * subplans of scans.
* ----------------------------------------------------------------
*/
-static Oid
-InitScanRelation(SeqScan *node, EState *estate,
- CommonScanState *scanstate, Plan *outerPlan)
+static Oid
+InitScanRelation(SeqScan * node, EState * estate,
+ CommonScanState * scanstate, Plan * outerPlan)
{
- Index relid;
- List *rangeTable;
- RangeTblEntry *rtentry;
- Oid reloid;
- TimeQual timeQual;
- ScanDirection direction;
- Relation currentRelation;
- HeapScanDesc currentScanDesc;
- RelationInfo *resultRelationInfo;
-
- if (outerPlan == NULL) {
- /* ----------------
- * if the outer node is nil then we are doing a simple
- * sequential scan of a relation...
- *
- * get the relation object id from the relid'th entry
- * in the range table, open that relation and initialize
- * the scan state...
- * ----------------
- */
- relid = node->scanrelid;
- rangeTable = estate->es_range_table;
- rtentry = rt_fetch(relid, rangeTable);
- reloid = rtentry->relid;
- timeQual = rtentry->timeQual;
- direction = estate->es_direction;
- resultRelationInfo = estate->es_result_relation_info;
-
- ExecOpenScanR(reloid, /* relation */
- 0, /* nkeys */
- NULL, /* scan key */
- 0, /* is index */
- direction, /* scan direction */
- timeQual, /* time qual */
- &currentRelation, /* return: rel desc */
- (Pointer *) &currentScanDesc); /* return: scan desc */
-
- scanstate->css_currentRelation = currentRelation;
- scanstate->css_currentScanDesc = currentScanDesc;
-
- ExecAssignScanType(scanstate,
- RelationGetTupleDescriptor(currentRelation));
- } else {
+ Index relid;
+ List *rangeTable;
+ RangeTblEntry *rtentry;
+ Oid reloid;
+ TimeQual timeQual;
+ ScanDirection direction;
+ Relation currentRelation;
+ HeapScanDesc currentScanDesc;
+ RelationInfo *resultRelationInfo;
+
+ if (outerPlan == NULL)
+ {
+ /* ----------------
+ * if the outer node is nil then we are doing a simple
+ * sequential scan of a relation...
+ *
+ * get the relation object id from the relid'th entry
+ * in the range table, open that relation and initialize
+ * the scan state...
+ * ----------------
+ */
+ relid = node->scanrelid;
+ rangeTable = estate->es_range_table;
+ rtentry = rt_fetch(relid, rangeTable);
+ reloid = rtentry->relid;
+ timeQual = rtentry->timeQual;
+ direction = estate->es_direction;
+ resultRelationInfo = estate->es_result_relation_info;
+
+ ExecOpenScanR(reloid, /* relation */
+ 0, /* nkeys */
+ NULL, /* scan key */
+ 0, /* is index */
+ direction,/* scan direction */
+ timeQual, /* time qual */
+ &currentRelation, /* return: rel desc */
+ (Pointer *) & currentScanDesc); /* return: scan desc */
+
+ scanstate->css_currentRelation = currentRelation;
+ scanstate->css_currentScanDesc = currentScanDesc;
+
+ ExecAssignScanType(scanstate,
+ RelationGetTupleDescriptor(currentRelation));
+ }
+ else
+ {
+ /* ----------------
+ * otherwise we are scanning tuples from the
+ * outer subplan so we initialize the outer plan
+ * and nullify
+ * ----------------
+ */
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ node->scanrelid = 0;
+ scanstate->css_currentRelation = NULL;
+ scanstate->css_currentScanDesc = NULL;
+ ExecAssignScanType(scanstate, NULL);
+ reloid = InvalidOid;
+ }
+
/* ----------------
- * otherwise we are scanning tuples from the
- * outer subplan so we initialize the outer plan
- * and nullify
+ * return the relation
* ----------------
*/
- ExecInitNode(outerPlan, estate, (Plan*)node);
-
- node->scanrelid = 0;
- scanstate->css_currentRelation = NULL;
- scanstate->css_currentScanDesc = NULL;
- ExecAssignScanType(scanstate, NULL);
- reloid = InvalidOid;
- }
-
- /* ----------------
- * return the relation
- * ----------------
- */
- return reloid;
+ return reloid;
}
/* ----------------------------------------------------------------
- * ExecInitSeqScan
+ * ExecInitSeqScan
*
* old comments
- * Creates the run-time state information for the seqscan node
- * and sets the relation id to contain relevant descriptors.
- *
- * If there is a outer subtree (sort), the outer subtree
- * is initialized and the relation id is set to the descriptors
- * returned by the subtree.
+ * Creates the run-time state information for the seqscan node
+ * and sets the relation id to contain relevant descriptors.
+ *
+ * If there is a outer subtree (sort), the outer subtree
+ * is initialized and the relation id is set to the descriptors
+ * returned by the subtree.
* ----------------------------------------------------------------
*/
bool
-ExecInitSeqScan(SeqScan *node, EState *estate, Plan *parent)
+ExecInitSeqScan(SeqScan * node, EState * estate, Plan * parent)
{
- CommonScanState *scanstate;
- Plan *outerPlan;
- Oid reloid;
- HeapScanDesc scandesc;
-
- /* ----------------
- * assign the node's execution state
- * ----------------
- */
- node->plan.state = estate;
-
- /* ----------------
- * create new CommonScanState for node
- * ----------------
- */
- scanstate = makeNode(CommonScanState);
- node->scanstate = scanstate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &scanstate->cstate, parent);
- ExecAssignExprContext(estate, &scanstate->cstate);
+ CommonScanState *scanstate;
+ Plan *outerPlan;
+ Oid reloid;
+ HeapScanDesc scandesc;
+
+ /* ----------------
+ * assign the node's execution state
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create new CommonScanState for node
+ * ----------------
+ */
+ scanstate = makeNode(CommonScanState);
+ node->scanstate = scanstate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &scanstate->cstate, parent);
+ ExecAssignExprContext(estate, &scanstate->cstate);
#define SEQSCAN_NSLOTS 3
- /* ----------------
- * tuple table initialization
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &scanstate->cstate);
- ExecInitScanTupleSlot(estate, scanstate);
-
- /* ----------------
- * initialize scan relation or outer subplan
- * ----------------
- */
- outerPlan = outerPlan((Plan *)node);
-
- reloid = InitScanRelation(node, estate, scanstate, outerPlan);
-
- scandesc = scanstate->css_currentScanDesc;
- scanstate->cstate.cs_TupFromTlist = false;
-
- /* ----------------
- * initialize tuple type
- * ----------------
- */
- ExecAssignResultTypeFromTL((Plan*)node, &scanstate->cstate);
- ExecAssignProjectionInfo((Plan*)node, &scanstate->cstate);
-
- return TRUE;
+ /* ----------------
+ * tuple table initialization
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &scanstate->cstate);
+ ExecInitScanTupleSlot(estate, scanstate);
+
+ /* ----------------
+ * initialize scan relation or outer subplan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+
+ reloid = InitScanRelation(node, estate, scanstate, outerPlan);
+
+ scandesc = scanstate->css_currentScanDesc;
+ scanstate->cstate.cs_TupFromTlist = false;
+
+ /* ----------------
+ * initialize tuple type
+ * ----------------
+ */
+ ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
+ ExecAssignProjectionInfo((Plan *) node, &scanstate->cstate);
+
+ return TRUE;
}
int
-ExecCountSlotsSeqScan(SeqScan *node)
+ExecCountSlotsSeqScan(SeqScan * node)
{
- return ExecCountSlotsNode(outerPlan(node)) +
+ return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
- SEQSCAN_NSLOTS;
+ SEQSCAN_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndSeqScan
- *
- * frees any storage allocated through C routines.
- *| ...and also closes relations and/or shuts down outer subplan
- *| -cim 8/14/89
+ * ExecEndSeqScan
+ *
+ * frees any storage allocated through C routines.
+ *| ...and also closes relations and/or shuts down outer subplan
+ *| -cim 8/14/89
* ----------------------------------------------------------------
*/
void
-ExecEndSeqScan(SeqScan *node)
+ExecEndSeqScan(SeqScan * node)
{
- CommonScanState *scanstate;
- Plan *outerPlan;
-
- /* ----------------
- * get information from node
- * ----------------
- */
- scanstate = node->scanstate;
-
- /* ----------------
- * Free the projection info and the scan attribute info
- *
- * Note: we don't ExecFreeResultType(scanstate)
- * because the rule manager depends on the tupType
- * returned by ExecMain(). So for now, this
- * is freed at end-transaction time. -cim 6/2/91
- * ----------------
- */
- ExecFreeProjectionInfo(&scanstate->cstate);
-
- /* ----------------
- * close scan relation
- * ----------------
- */
- ExecCloseR((Plan*) node);
-
- /* ----------------
- * clean up outer subtree (does nothing if there is no outerPlan)
- * ----------------
- */
- outerPlan = outerPlan((Plan *)node);
- ExecEndNode(outerPlan, (Plan*)node);
-
- /* ----------------
- * clean out the tuple table
- * ----------------
- */
- ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
- ExecClearTuple(scanstate->css_ScanTupleSlot);
+ CommonScanState *scanstate;
+ Plan *outerPlan;
+
+ /* ----------------
+ * get information from node
+ * ----------------
+ */
+ scanstate = node->scanstate;
+
+ /* ----------------
+ * Free the projection info and the scan attribute info
+ *
+ * Note: we don't ExecFreeResultType(scanstate)
+ * because the rule manager depends on the tupType
+ * returned by ExecMain(). So for now, this
+ * is freed at end-transaction time. -cim 6/2/91
+ * ----------------
+ */
+ ExecFreeProjectionInfo(&scanstate->cstate);
+
+ /* ----------------
+ * close scan relation
+ * ----------------
+ */
+ ExecCloseR((Plan *) node);
+
+ /* ----------------
+ * clean up outer subtree (does nothing if there is no outerPlan)
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecEndNode(outerPlan, (Plan *) node);
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(scanstate->cstate.cs_ResultTupleSlot);
+ ExecClearTuple(scanstate->css_ScanTupleSlot);
}
/* ----------------------------------------------------------------
- * Join Support
+ * Join Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
- * ExecSeqReScan
- *
- * Rescans the relation.
+ * ExecSeqReScan
+ *
+ * Rescans the relation.
* ----------------------------------------------------------------
*/
void
-ExecSeqReScan(SeqScan *node, ExprContext *exprCtxt, Plan* parent)
+ExecSeqReScan(SeqScan * node, ExprContext * exprCtxt, Plan * parent)
{
- CommonScanState *scanstate;
- EState *estate;
- Plan *outerPlan;
- Relation rdesc;
- HeapScanDesc sdesc;
- ScanDirection direction;
-
- scanstate = node->scanstate;
- estate = node->plan.state;
-
- outerPlan = outerPlan((Plan*)node);
- if (outerPlan) {
- /* we are scanning a subplan */
- outerPlan = outerPlan((Plan *)node);
- ExecReScan(outerPlan, exprCtxt, parent);
- } else {
- /* otherwise, we are scanning a relation */
- rdesc = scanstate->css_currentRelation;
- sdesc = scanstate->css_currentScanDesc;
- direction = estate->es_direction;
- sdesc = ExecReScanR(rdesc, sdesc, direction, 0, NULL);
- scanstate->css_currentScanDesc = sdesc;
- }
+ CommonScanState *scanstate;
+ EState *estate;
+ Plan *outerPlan;
+ Relation rdesc;
+ HeapScanDesc sdesc;
+ ScanDirection direction;
+
+ scanstate = node->scanstate;
+ estate = node->plan.state;
+
+ outerPlan = outerPlan((Plan *) node);
+ if (outerPlan)
+ {
+ /* we are scanning a subplan */
+ outerPlan = outerPlan((Plan *) node);
+ ExecReScan(outerPlan, exprCtxt, parent);
+ }
+ else
+ {
+ /* otherwise, we are scanning a relation */
+ rdesc = scanstate->css_currentRelation;
+ sdesc = scanstate->css_currentScanDesc;
+ direction = estate->es_direction;
+ sdesc = ExecReScanR(rdesc, sdesc, direction, 0, NULL);
+ scanstate->css_currentScanDesc = sdesc;
+ }
}
/* ----------------------------------------------------------------
- * ExecSeqMarkPos(node)
- *
- * Marks scan position.
+ * ExecSeqMarkPos(node)
+ *
+ * Marks scan position.
* ----------------------------------------------------------------
*/
void
-ExecSeqMarkPos(SeqScan *node)
+ExecSeqMarkPos(SeqScan * node)
{
- CommonScanState *scanstate;
- Plan *outerPlan;
- HeapScanDesc sdesc;
-
- scanstate = node->scanstate;
-
- /* ----------------
- * if we are scanning a subplan then propagate
- * the ExecMarkPos() request to the subplan
- * ----------------
- */
- outerPlan = outerPlan((Plan*)node);
- if (outerPlan) {
- ExecMarkPos(outerPlan);
+ CommonScanState *scanstate;
+ Plan *outerPlan;
+ HeapScanDesc sdesc;
+
+ scanstate = node->scanstate;
+
+ /* ----------------
+ * if we are scanning a subplan then propagate
+ * the ExecMarkPos() request to the subplan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ if (outerPlan)
+ {
+ ExecMarkPos(outerPlan);
+ return;
+ }
+
+ /* ----------------
+ * otherwise we are scanning a relation so mark the
+ * position using the access methods..
+ *
+ * ----------------
+ */
+ sdesc = scanstate->css_currentScanDesc;
+ heap_markpos(sdesc);
+
return;
- }
-
- /* ----------------
- * otherwise we are scanning a relation so mark the
- * position using the access methods..
- *
- * ----------------
- */
- sdesc = scanstate->css_currentScanDesc;
- heap_markpos(sdesc);
-
- return;
}
/* ----------------------------------------------------------------
- * ExecSeqRestrPos
- *
- * Restores scan position.
+ * ExecSeqRestrPos
+ *
+ * Restores scan position.
* ----------------------------------------------------------------
*/
void
-ExecSeqRestrPos(SeqScan *node)
+ExecSeqRestrPos(SeqScan * node)
{
- CommonScanState *scanstate;
- Plan *outerPlan;
- HeapScanDesc sdesc;
-
- scanstate = node->scanstate;
-
- /* ----------------
- * if we are scanning a subplan then propagate
- * the ExecRestrPos() request to the subplan
- * ----------------
- */
- outerPlan = outerPlan((Plan*)node);
- if (outerPlan) {
- ExecRestrPos(outerPlan);
- return;
- }
-
- /* ----------------
- * otherwise we are scanning a relation so restore the
- * position using the access methods..
- * ----------------
- */
- sdesc = scanstate->css_currentScanDesc;
- heap_restrpos(sdesc);
+ CommonScanState *scanstate;
+ Plan *outerPlan;
+ HeapScanDesc sdesc;
+
+ scanstate = node->scanstate;
+
+ /* ----------------
+ * if we are scanning a subplan then propagate
+ * the ExecRestrPos() request to the subplan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ if (outerPlan)
+ {
+ ExecRestrPos(outerPlan);
+ return;
+ }
+
+ /* ----------------
+ * otherwise we are scanning a relation so restore the
+ * position using the access methods..
+ * ----------------
+ */
+ sdesc = scanstate->css_currentScanDesc;
+ heap_restrpos(sdesc);
}
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 0955108b2fb..eb2e2e7b180 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* nodeSort.c--
- * Routines to handle sorting of relations.
+ * Routines to handle sorting of relations.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.6 1997/08/21 02:28:06 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.7 1997/09/07 04:41:45 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,383 +25,389 @@
#include "optimizer/internal.h" /* for _TEMP_RELATION_ID_ */
/* ----------------------------------------------------------------
- * FormSortKeys(node)
- *
- * Forms the structure containing information used to sort the relation.
- *
- * Returns an array of ScanKeyData.
+ * FormSortKeys(node)
+ *
+ * Forms the structure containing information used to sort the relation.
+ *
+ * Returns an array of ScanKeyData.
* ----------------------------------------------------------------
*/
-static ScanKey
-FormSortKeys(Sort *sortnode)
+static ScanKey
+FormSortKeys(Sort * sortnode)
{
- ScanKey sortkeys;
- List *targetList;
- List *tl;
- int keycount;
- Resdom *resdom;
- AttrNumber resno;
- Index reskey;
- Oid reskeyop;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- targetList = sortnode->plan.targetlist;
- keycount = sortnode->keycount;
-
- /* ----------------
- * first allocate space for scan keys
- * ----------------
- */
- if (keycount <= 0)
- elog(WARN, "FormSortKeys: keycount <= 0");
- sortkeys = (ScanKey) palloc(keycount * sizeof(ScanKeyData));
-
- /* ----------------
- * form each scan key from the resdom info in the target list
- * ----------------
- */
- foreach(tl, targetList) {
- TargetEntry *target = (TargetEntry *)lfirst(tl);
- resdom = target->resdom;
- resno = resdom->resno;
- reskey = resdom->reskey;
- reskeyop = resdom->reskeyop;
-
- if (reskey > 0) {
- ScanKeyEntryInitialize(&sortkeys[reskey-1],
- 0,
- resno,
- (RegProcedure) DatumGetInt32(reskeyop),
- (Datum) 0);
+ ScanKey sortkeys;
+ List *targetList;
+ List *tl;
+ int keycount;
+ Resdom *resdom;
+ AttrNumber resno;
+ Index reskey;
+ Oid reskeyop;
+
+ /* ----------------
+ * get information from the node
+ * ----------------
+ */
+ targetList = sortnode->plan.targetlist;
+ keycount = sortnode->keycount;
+
+ /* ----------------
+ * first allocate space for scan keys
+ * ----------------
+ */
+ if (keycount <= 0)
+ elog(WARN, "FormSortKeys: keycount <= 0");
+ sortkeys = (ScanKey) palloc(keycount * sizeof(ScanKeyData));
+
+ /* ----------------
+ * form each scan key from the resdom info in the target list
+ * ----------------
+ */
+ foreach(tl, targetList)
+ {
+ TargetEntry *target = (TargetEntry *) lfirst(tl);
+
+ resdom = target->resdom;
+ resno = resdom->resno;
+ reskey = resdom->reskey;
+ reskeyop = resdom->reskeyop;
+
+ if (reskey > 0)
+ {
+ ScanKeyEntryInitialize(&sortkeys[reskey - 1],
+ 0,
+ resno,
+ (RegProcedure) DatumGetInt32(reskeyop),
+ (Datum) 0);
+ }
}
- }
-
- return sortkeys;
+
+ return sortkeys;
}
/* ----------------------------------------------------------------
- * ExecSort
+ * ExecSort
*
* old comments
- * Sorts tuples from the outer subtree of the node in psort,
- * which saves the results in a temporary file or memory. After the
- * initial call, returns a tuple from the file with each call.
- * Assumes that heap access method is used.
- *
- * Conditions:
- * -- none.
- *
- * Initial States:
- * -- the outer child is prepared to return the first tuple.
+ * Sorts tuples from the outer subtree of the node in psort,
+ * which saves the results in a temporary file or memory. After the
+ * initial call, returns a tuple from the file with each call.
+ * Assumes that heap access method is used.
+ *
+ * Conditions:
+ * -- none.
+ *
+ * Initial States:
+ * -- the outer child is prepared to return the first tuple.
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecSort(Sort *node)
+ExecSort(Sort * node)
{
- EState *estate;
- SortState *sortstate;
- Plan *outerNode;
- ScanDirection dir;
- int keycount;
- ScanKey sortkeys;
- HeapTuple heapTuple;
- TupleTableSlot *slot;
-
- /* ----------------
- * get state info from node
- * ----------------
- */
- SO1_printf("ExecSort: %s\n",
- "entering routine");
-
- sortstate = node->sortstate;
- estate = node->plan.state;
- dir = estate->es_direction;
-
- /* ----------------
- * the first time we call this, psort sorts this into a file.
- * Subsequent calls return tuples from psort.
- * ----------------
- */
-
- if (sortstate->sort_Flag == false) {
- SO1_printf("ExecSort: %s\n",
- "sortstate == false -> sorting subplan");
+ EState *estate;
+ SortState *sortstate;
+ Plan *outerNode;
+ ScanDirection dir;
+ int keycount;
+ ScanKey sortkeys;
+ HeapTuple heapTuple;
+ TupleTableSlot *slot;
+
/* ----------------
- * set all relations to be scanned in the forward direction
- * while creating the temporary relation.
+ * get state info from node
* ----------------
*/
- estate->es_direction = ForwardScanDirection;
+ SO1_printf("ExecSort: %s\n",
+ "entering routine");
+
+ sortstate = node->sortstate;
+ estate = node->plan.state;
+ dir = estate->es_direction;
/* ----------------
- * prepare information for psort_begin()
+ * the first time we call this, psort sorts this into a file.
+ * Subsequent calls return tuples from psort.
* ----------------
*/
- outerNode = outerPlan((Plan *) node);
- keycount = node->keycount;
- sortkeys = (ScanKey)sortstate->sort_Keys;
- SO1_printf("ExecSort: %s\n",
- "calling psort_begin");
-
- if (!psort_begin(node, /* this node */
- keycount, /* number keys */
- sortkeys)) /* keys */
+ if (sortstate->sort_Flag == false)
{
- /* Psort says, there are no tuples to be sorted */
- return NULL;
- }
-
- /* ----------------
- * restore to user specified direction
- * ----------------
- */
- estate->es_direction = dir;
-
- /* ----------------
- * make sure the tuple descriptor is up to date
- * ----------------
- */
- slot = (TupleTableSlot*)sortstate->csstate.cstate.cs_ResultTupleSlot;
- /* *** get_cs_ResultTupleSlot((CommonState) sortstate); */
+ SO1_printf("ExecSort: %s\n",
+ "sortstate == false -> sorting subplan");
+ /* ----------------
+ * set all relations to be scanned in the forward direction
+ * while creating the temporary relation.
+ * ----------------
+ */
+ estate->es_direction = ForwardScanDirection;
+
+ /* ----------------
+ * prepare information for psort_begin()
+ * ----------------
+ */
+ outerNode = outerPlan((Plan *) node);
+
+ keycount = node->keycount;
+ sortkeys = (ScanKey) sortstate->sort_Keys;
+ SO1_printf("ExecSort: %s\n",
+ "calling psort_begin");
+
+ if (!psort_begin(node, /* this node */
+ keycount, /* number keys */
+ sortkeys)) /* keys */
+ {
+ /* Psort says, there are no tuples to be sorted */
+ return NULL;
+ }
+
+ /* ----------------
+ * restore to user specified direction
+ * ----------------
+ */
+ estate->es_direction = dir;
- slot->ttc_tupleDescriptor = ExecGetTupType(outerNode);
+ /* ----------------
+ * make sure the tuple descriptor is up to date
+ * ----------------
+ */
+ slot = (TupleTableSlot *) sortstate->csstate.cstate.cs_ResultTupleSlot;
+ /* *** get_cs_ResultTupleSlot((CommonState) sortstate); */
+
+ slot->ttc_tupleDescriptor = ExecGetTupType(outerNode);
#if 0
- slot->ttc_execTupDescriptor = ExecGetExecTupDesc(outerNode);
+ slot->ttc_execTupDescriptor = ExecGetExecTupDesc(outerNode);
#endif
+ /* ----------------
+ * finally set the sorted flag to true
+ * ----------------
+ */
+ sortstate->sort_Flag = true;
+ SO1_printf(stderr, "ExecSort: sorting done.\n");
+ }
+ else
+ {
+ slot = (TupleTableSlot *) sortstate->csstate.cstate.cs_ResultTupleSlot;
+ /* *** get_cs_ResultTupleSlot((CommonState) sortstate); */
+/* slot = sortstate->csstate.css_ScanTupleSlot; orig */
+ }
+
+ SO1_printf("ExecSort: %s\n",
+ "retrieving tuple from sorted relation");
+
/* ----------------
- * finally set the sorted flag to true
+ * at this point we grab a tuple from psort
* ----------------
*/
- sortstate->sort_Flag = true;
- SO1_printf(stderr, "ExecSort: sorting done.\n");
- }
- else {
- slot = (TupleTableSlot*)sortstate->csstate.cstate.cs_ResultTupleSlot;
- /* *** get_cs_ResultTupleSlot((CommonState) sortstate); */
-/* slot = sortstate->csstate.css_ScanTupleSlot; orig */
- }
-
- SO1_printf("ExecSort: %s\n",
- "retrieving tuple from sorted relation");
-
- /* ----------------
- * at this point we grab a tuple from psort
- * ----------------
- */
- heapTuple = psort_grabtuple(node);
-
- if (heapTuple == NULL) {
-/* psort_end(node); */
- return (ExecClearTuple(slot));
- }
-
- ExecStoreTuple(heapTuple, /* tuple to store */
- slot, /* slot to store in */
- InvalidBuffer, /* no buffer */
- true); /* free the palloc'd tuple */
-/* printf("ExecSort: (%x)",node);print_slot(slot);printf("\n");*/
- return slot;
+ heapTuple = psort_grabtuple(node);
+
+ if (heapTuple == NULL)
+ {
+/* psort_end(node); */
+ return (ExecClearTuple(slot));
+ }
+
+ ExecStoreTuple(heapTuple, /* tuple to store */
+ slot, /* slot to store in */
+ InvalidBuffer, /* no buffer */
+ true); /* free the palloc'd tuple */
+/* printf("ExecSort: (%x)",node);print_slot(slot);printf("\n");*/
+ return slot;
#if 0
- return ExecStoreTuple(heapTuple, /* tuple to store */
- slot, /* slot to store in */
- InvalidBuffer, /* no buffer */
- true); /* free the palloc'd tuple */
+ return ExecStoreTuple(heapTuple, /* tuple to store */
+ slot, /* slot to store in */
+ InvalidBuffer, /* no buffer */
+ true);/* free the palloc'd tuple */
#endif
}
/* ----------------------------------------------------------------
- * ExecInitSort
+ * ExecInitSort
*
* old comments
- * Creates the run-time state information for the sort node
- * produced by the planner and initailizes its outer subtree.
+ * Creates the run-time state information for the sort node
+ * produced by the planner and initailizes its outer subtree.
* ----------------------------------------------------------------
*/
bool
-ExecInitSort(Sort *node, EState *estate, Plan *parent)
+ExecInitSort(Sort * node, EState * estate, Plan * parent)
{
- SortState *sortstate;
- Plan *outerPlan;
- ScanKey sortkeys;
-
- SO1_printf("ExecInitSort: %s\n",
- "initializing sort node");
-
- /* ----------------
- * assign the node's execution state
- * ----------------
- */
- node->plan.state = estate;
-
- /* ----------------
- * create state structure
- * ----------------
- */
- sortstate = makeNode(SortState);
- sortstate->sort_Flag = 0;
- sortstate->sort_Keys = NULL;
- node->cleaned = FALSE;
-
- node->sortstate = sortstate;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks
- *
- * Sort nodes don't initialize their ExprContexts because
- * they never call ExecQual or ExecTargetList.
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &sortstate->csstate.cstate, parent);
-
+ SortState *sortstate;
+ Plan *outerPlan;
+ ScanKey sortkeys;
+
+ SO1_printf("ExecInitSort: %s\n",
+ "initializing sort node");
+
+ /* ----------------
+ * assign the node's execution state
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create state structure
+ * ----------------
+ */
+ sortstate = makeNode(SortState);
+ sortstate->sort_Flag = 0;
+ sortstate->sort_Keys = NULL;
+ node->cleaned = FALSE;
+
+ node->sortstate = sortstate;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks
+ *
+ * Sort nodes don't initialize their ExprContexts because
+ * they never call ExecQual or ExecTargetList.
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &sortstate->csstate.cstate, parent);
+
#define SORT_NSLOTS 1
- /* ----------------
- * tuple table initialization
- *
- * sort nodes only return scan tuples from their sorted
- * relation.
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
- ExecInitScanTupleSlot(estate, &sortstate->csstate);
-
- /* ----------------
- * initializes child nodes
- * ----------------
- */
- outerPlan = outerPlan((Plan *) node);
- ExecInitNode(outerPlan, estate, (Plan *) node);
-
- /* ----------------
- * initialize sortstate information
- * ----------------
- */
- sortkeys = FormSortKeys(node);
- sortstate->sort_Keys = sortkeys;
- sortstate->sort_Flag = false;
-
- /* ----------------
- * initialize tuple type. no need to initialize projection
- * info because this node doesn't do projections.
- * ----------------
- */
- ExecAssignResultTypeFromOuterPlan((Plan *)node, &sortstate->csstate.cstate);
- ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
- sortstate->csstate.cstate.cs_ProjInfo = NULL;
-
- SO1_printf("ExecInitSort: %s\n",
- "sort node initialized");
-
- /* ----------------
- * return relation oid of temporary sort relation in a list
- * (someday -- for now we return LispTrue... cim 10/12/89)
- * ----------------
- */
- return TRUE;
+ /* ----------------
+ * tuple table initialization
+ *
+ * sort nodes only return scan tuples from their sorted
+ * relation.
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
+ ExecInitScanTupleSlot(estate, &sortstate->csstate);
+
+ /* ----------------
+ * initializes child nodes
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * initialize sortstate information
+ * ----------------
+ */
+ sortkeys = FormSortKeys(node);
+ sortstate->sort_Keys = sortkeys;
+ sortstate->sort_Flag = false;
+
+ /* ----------------
+ * initialize tuple type. no need to initialize projection
+ * info because this node doesn't do projections.
+ * ----------------
+ */
+ ExecAssignResultTypeFromOuterPlan((Plan *) node, &sortstate->csstate.cstate);
+ ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
+ sortstate->csstate.cstate.cs_ProjInfo = NULL;
+
+ SO1_printf("ExecInitSort: %s\n",
+ "sort node initialized");
+
+ /* ----------------
+ * return relation oid of temporary sort relation in a list
+ * (someday -- for now we return LispTrue... cim 10/12/89)
+ * ----------------
+ */
+ return TRUE;
}
int
-ExecCountSlotsSort(Sort *node)
+ExecCountSlotsSort(Sort * node)
{
- return ExecCountSlotsNode(outerPlan((Plan *)node)) +
- ExecCountSlotsNode(innerPlan((Plan *)node)) +
- SORT_NSLOTS;
+ return ExecCountSlotsNode(outerPlan((Plan *) node)) +
+ ExecCountSlotsNode(innerPlan((Plan *) node)) +
+ SORT_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndSort(node)
+ * ExecEndSort(node)
*
* old comments
* ----------------------------------------------------------------
*/
void
-ExecEndSort(Sort *node)
+ExecEndSort(Sort * node)
{
- SortState *sortstate;
- Plan *outerPlan;
-
- /* ----------------
- * get info from the sort state
- * ----------------
- */
- SO1_printf("ExecEndSort: %s\n",
- "shutting down sort node");
-
- sortstate = node->sortstate;
-
- /* ----------------
- * shut down the subplan
- * ----------------
- */
- outerPlan = outerPlan((Plan *) node);
- ExecEndNode(outerPlan, (Plan*)node);
-
- /* ----------------
- * clean out the tuple table
- * ----------------
- */
- ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
-
- /* Clean up after psort */
- psort_end(node);
-
- SO1_printf("ExecEndSort: %s\n",
- "sort node shutdown");
-}
+ SortState *sortstate;
+ Plan *outerPlan;
+
+ /* ----------------
+ * get info from the sort state
+ * ----------------
+ */
+ SO1_printf("ExecEndSort: %s\n",
+ "shutting down sort node");
+
+ sortstate = node->sortstate;
+
+ /* ----------------
+ * shut down the subplan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecEndNode(outerPlan, (Plan *) node);
+
+ /* ----------------
+ * clean out the tuple table
+ * ----------------
+ */
+ ExecClearTuple(sortstate->csstate.css_ScanTupleSlot);
+
+ /* Clean up after psort */
+ psort_end(node);
+
+ SO1_printf("ExecEndSort: %s\n",
+ "sort node shutdown");
+}
/* ----------------------------------------------------------------
- * ExecSortMarkPos
+ * ExecSortMarkPos
*
- * Calls psort to save the current position in the sorted file.
+ * Calls psort to save the current position in the sorted file.
* ----------------------------------------------------------------
*/
void
-ExecSortMarkPos(Sort *node)
+ExecSortMarkPos(Sort * node)
{
- SortState *sortstate;
-
- /* ----------------
- * if we haven't sorted yet, just return
- * ----------------
- */
- sortstate = node->sortstate;
- if (sortstate->sort_Flag == false)
- return;
-
- psort_markpos(node);
-
- return;
+ SortState *sortstate;
+
+ /* ----------------
+ * if we haven't sorted yet, just return
+ * ----------------
+ */
+ sortstate = node->sortstate;
+ if (sortstate->sort_Flag == false)
+ return;
+
+ psort_markpos(node);
+
+ return;
}
/* ----------------------------------------------------------------
- * ExecSortRestrPos
+ * ExecSortRestrPos
*
- * Calls psort to restore the last saved sort file position.
+ * Calls psort to restore the last saved sort file position.
* ----------------------------------------------------------------
*/
void
-ExecSortRestrPos(Sort *node)
+ExecSortRestrPos(Sort * node)
{
- SortState *sortstate;
-
- /* ----------------
- * if we haven't sorted yet, just return.
- * ----------------
- */
- sortstate = node->sortstate;
- if (sortstate->sort_Flag == false)
- return;
-
- /* ----------------
- * restore the scan to the previously marked position
- * ----------------
- */
- psort_restorepos(node);
+ SortState *sortstate;
+
+ /* ----------------
+ * if we haven't sorted yet, just return.
+ * ----------------
+ */
+ sortstate = node->sortstate;
+ if (sortstate->sort_Flag == false)
+ return;
+
+ /* ----------------
+ * restore the scan to the previously marked position
+ * ----------------
+ */
+ psort_restorepos(node);
}
diff --git a/src/backend/executor/nodeTee.c b/src/backend/executor/nodeTee.c
index 6ddbecc3a49..8a1e233125a 100644
--- a/src/backend/executor/nodeTee.c
+++ b/src/backend/executor/nodeTee.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* nodeTee.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
- * DESCRIPTION
- * This code provides support for a tee node, which allows multiple
- * parent in a megaplan.
- *
- * INTERFACE ROUTINES
- * ExecTee
- * ExecInitTee
- * ExecEndTee
+ * DESCRIPTION
+ * This code provides support for a tee node, which allows multiple
+ * parent in a megaplan.
+ *
+ * INTERFACE ROUTINES
+ * ExecTee
+ * ExecInitTee
+ * ExecEndTee
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/Attic/nodeTee.c,v 1.6 1997/07/28 00:54:11 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/Attic/nodeTee.c,v 1.7 1997/09/07 04:41:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,9 +25,9 @@
#include "postgres.h"
#include "utils/palloc.h"
-#include "utils/relcache.h"
+#include "utils/relcache.h"
#include "utils/mcxt.h"
-#include "storage/bufmgr.h" /* for IncrBufferRefCount */
+#include "storage/bufmgr.h" /* for IncrBufferRefCount */
#include "storage/smgr.h"
#include "optimizer/internal.h"
#include "executor/executor.h"
@@ -38,475 +38,520 @@
#include "access/heapam.h"
/* ------------------------------------------------------------------
- * ExecInitTee
+ * ExecInitTee
*
- * Create tee state
+ * Create tee state
*
* ------------------------------------------------------------------
*/
bool
-ExecInitTee(Tee* node, EState *currentEstate, Plan * parent)
+ExecInitTee(Tee * node, EState * currentEstate, Plan * parent)
{
- TeeState *teeState;
- Plan *outerPlan;
- int len;
- Relation bufferRel;
- TupleDesc tupType;
- EState *estate;
-
- /* it is possible that the Tee has already been initialized
- since it can be reached by multiple parents.
- If it is already initialized, simply return and do
- not initialize the children nodes again
- */
- if (node->plan.state)
- return TRUE;
-
- /* ----------------
- * assign the node's execution state
- * ----------------
- */
- /* make a new executor state, because we have a different
- es_range_table */
-
-/* node->plan.state = estate;*/
-
- estate = CreateExecutorState();
- estate->es_direction = currentEstate->es_direction;
- estate->es_BaseId = currentEstate->es_BaseId;
- estate->es_BaseId = currentEstate->es_BaseId;
- estate->es_tupleTable = currentEstate->es_tupleTable;
- estate->es_refcount = currentEstate->es_refcount;
- estate->es_junkFilter = currentEstate->es_junkFilter;
-
- /* use the range table for Tee subplan since the range tables
- for the two parents may be different */
- if (node->rtentries)
- estate->es_range_table = node->rtentries;
- else
- estate->es_range_table = currentEstate->es_range_table;
-
- node->plan.state = estate;
-
-
- /* ----------------
- * create teeState structure
- * ----------------
- */
- teeState = makeNode(TeeState);
- teeState->tee_leftPlace = 0;
- teeState->tee_rightPlace = 0;
- teeState->tee_lastPlace = 0;
- teeState->tee_bufferRel = NULL;
- teeState->tee_leftScanDesc = NULL;
- teeState->tee_rightScanDesc = NULL;
-
-
- node->teestate = teeState;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- * + create expression context for node
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, &(teeState->cstate), parent);
- ExecAssignExprContext(estate, &(teeState->cstate));
+ TeeState *teeState;
+ Plan *outerPlan;
+ int len;
+ Relation bufferRel;
+ TupleDesc tupType;
+ EState *estate;
+
+ /*
+ * it is possible that the Tee has already been initialized since it
+ * can be reached by multiple parents. If it is already initialized,
+ * simply return and do not initialize the children nodes again
+ */
+ if (node->plan.state)
+ return TRUE;
+
+ /* ----------------
+ * assign the node's execution state
+ * ----------------
+ */
+
+ /*
+ * make a new executor state, because we have a different
+ * es_range_table
+ */
+
+/* node->plan.state = estate;*/
+
+ estate = CreateExecutorState();
+ estate->es_direction = currentEstate->es_direction;
+ estate->es_BaseId = currentEstate->es_BaseId;
+ estate->es_BaseId = currentEstate->es_BaseId;
+ estate->es_tupleTable = currentEstate->es_tupleTable;
+ estate->es_refcount = currentEstate->es_refcount;
+ estate->es_junkFilter = currentEstate->es_junkFilter;
+
+ /*
+ * use the range table for Tee subplan since the range tables for the
+ * two parents may be different
+ */
+ if (node->rtentries)
+ estate->es_range_table = node->rtentries;
+ else
+ estate->es_range_table = currentEstate->es_range_table;
+
+ node->plan.state = estate;
+
+
+ /* ----------------
+ * create teeState structure
+ * ----------------
+ */
+ teeState = makeNode(TeeState);
+ teeState->tee_leftPlace = 0;
+ teeState->tee_rightPlace = 0;
+ teeState->tee_lastPlace = 0;
+ teeState->tee_bufferRel = NULL;
+ teeState->tee_leftScanDesc = NULL;
+ teeState->tee_rightScanDesc = NULL;
+
+
+ node->teestate = teeState;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ * + create expression context for node
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, &(teeState->cstate), parent);
+ ExecAssignExprContext(estate, &(teeState->cstate));
#define TEE_NSLOTS 2
- /* ----------------
- * initialize tuple slots
- * ----------------
- */
- ExecInitResultTupleSlot(estate, &(teeState->cstate));
-
- /* initialize child nodes */
- outerPlan = outerPlan((Plan*) node);
- ExecInitNode(outerPlan, estate, (Plan*) node);
-
- /* ----------------
- * the tuple type info is from the outer plan of this node
- * the result type is also the same as the outerplan
- */
- ExecAssignResultTypeFromOuterPlan((Plan*) node, &(teeState->cstate));
- ExecAssignProjectionInfo((Plan*)node, &teeState->cstate);
-
- /* ---------------------------------------
- initialize temporary relation to buffer tuples
- */
- tupType = ExecGetResultType(&(teeState->cstate));
- len = ExecTargetListLength(((Plan*)node)->targetlist);
-
-/* bufferRel = ExecCreatR(len, tupType, _TEMP_RELATION_ID_); */
-
- /* create a catalogued relation even though this is a temporary relation */
- /* cleanup of catalogued relations is easier to do */
-
- if (node->teeTableName[0] != '\0') {
- Relation r;
-
- teeState->tee_bufferRelname = pstrdup(node->teeTableName);
-
- /* we are given an tee table name,
- if a relation by that name exists, then we open it,
- else we create it and then open it */
- r = RelationNameGetRelation(teeState->tee_bufferRelname);
-
- if (RelationIsValid(r))
- bufferRel = heap_openr(teeState->tee_bufferRelname);
+ /* ----------------
+ * initialize tuple slots
+ * ----------------
+ */
+ ExecInitResultTupleSlot(estate, &(teeState->cstate));
+
+ /* initialize child nodes */
+ outerPlan = outerPlan((Plan *) node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * the tuple type info is from the outer plan of this node
+ * the result type is also the same as the outerplan
+ */
+ ExecAssignResultTypeFromOuterPlan((Plan *) node, &(teeState->cstate));
+ ExecAssignProjectionInfo((Plan *) node, &teeState->cstate);
+
+ /* ---------------------------------------
+ initialize temporary relation to buffer tuples
+ */
+ tupType = ExecGetResultType(&(teeState->cstate));
+ len = ExecTargetListLength(((Plan *) node)->targetlist);
+
+/* bufferRel = ExecCreatR(len, tupType, _TEMP_RELATION_ID_); */
+
+ /*
+ * create a catalogued relation even though this is a temporary
+ * relation
+ */
+ /* cleanup of catalogued relations is easier to do */
+
+ if (node->teeTableName[0] != '\0')
+ {
+ Relation r;
+
+ teeState->tee_bufferRelname = pstrdup(node->teeTableName);
+
+ /*
+ * we are given an tee table name, if a relation by that name
+ * exists, then we open it, else we create it and then open it
+ */
+ r = RelationNameGetRelation(teeState->tee_bufferRelname);
+
+ if (RelationIsValid(r))
+ bufferRel = heap_openr(teeState->tee_bufferRelname);
+ else
+ bufferRel = heap_open(heap_create(teeState->tee_bufferRelname,
+ /*FIX */ NULL,
+ 'n',
+ DEFAULT_SMGR,
+ tupType));
+ }
else
- bufferRel = heap_open(heap_create(teeState->tee_bufferRelname,
-/*FIX */ NULL,
- 'n',
- DEFAULT_SMGR,
- tupType));
- }
- else {
- sprintf(teeState->tee_bufferRelname,
- "ttemp_%d", /* 'ttemp' for 'tee' temporary*/
- newoid());
-/* bufferRel = ExecCreatR(len, tupType, _TEMP_RELATION_ID); */
- bufferRel = heap_open(heap_create(teeState->tee_bufferRelname,
- NULL, /*XXX */
- 'n',
- DEFAULT_SMGR,
- tupType));
- }
-
- teeState->tee_bufferRel = bufferRel;
-
- /*initialize a memory context for allocating thing like scan descriptors */
- /* we do this so that on cleanup of the tee, we can free things.
- if we didn't have our own memory context, we would be in the memory
- context of the portal that we happen to be using at the moment */
-
- teeState->tee_mcxt = (MemoryContext)CreateGlobalMemory(teeState->tee_bufferRelname);
-
- /* don't initialize the scan descriptors here
- because it's not good to initialize scan descriptors on empty
- rels. Wait until the scan descriptors are needed
- before initializing them. */
-
- teeState->tee_leftScanDesc = NULL;
- teeState->tee_rightScanDesc = NULL;
-
- return TRUE;
+ {
+ sprintf(teeState->tee_bufferRelname,
+ "ttemp_%d", /* 'ttemp' for 'tee' temporary */
+ newoid());
+/* bufferRel = ExecCreatR(len, tupType, _TEMP_RELATION_ID); */
+ bufferRel = heap_open(heap_create(teeState->tee_bufferRelname,
+ NULL, /* XXX */
+ 'n',
+ DEFAULT_SMGR,
+ tupType));
+ }
+
+ teeState->tee_bufferRel = bufferRel;
+
+ /*
+ * initialize a memory context for allocating thing like scan
+ * descriptors
+ */
+
+ /*
+ * we do this so that on cleanup of the tee, we can free things. if we
+ * didn't have our own memory context, we would be in the memory
+ * context of the portal that we happen to be using at the moment
+ */
+
+ teeState->tee_mcxt = (MemoryContext) CreateGlobalMemory(teeState->tee_bufferRelname);
+
+ /*
+ * don't initialize the scan descriptors here because it's not good to
+ * initialize scan descriptors on empty rels. Wait until the scan
+ * descriptors are needed before initializing them.
+ */
+
+ teeState->tee_leftScanDesc = NULL;
+ teeState->tee_rightScanDesc = NULL;
+
+ return TRUE;
}
-int
-ExecCountSlotsTee(Tee *node)
+int
+ExecCountSlotsTee(Tee * node)
{
- /* Tee nodes can't have innerPlans */
- return ExecCountSlotsNode(outerPlan(node)) + TEE_NSLOTS;
+ /* Tee nodes can't have innerPlans */
+ return ExecCountSlotsNode(outerPlan(node)) + TEE_NSLOTS;
}
/* ----------------------------------------------------------------
initTeeScanDescs
- initializes the left and right scandescs on the temporary
- relation of a Tee node
+ initializes the left and right scandescs on the temporary
+ relation of a Tee node
- must open two separate scan descriptors,
- because the left and right scans may be at different points
+ must open two separate scan descriptors,
+ because the left and right scans may be at different points
* ----------------------------------------------------------------
*/
-static void
-initTeeScanDescs(Tee* node)
+static void
+initTeeScanDescs(Tee * node)
{
- TeeState *teeState;
- Relation bufferRel;
- ScanDirection dir;
- MemoryContext orig;
-
- teeState = node->teestate;
- if (teeState->tee_leftScanDesc && teeState->tee_rightScanDesc)
- return;
-
- orig = CurrentMemoryContext;
- MemoryContextSwitchTo(teeState->tee_mcxt);
-
- bufferRel = teeState->tee_bufferRel;
- dir = ((Plan*)node)->state->es_direction; /* backwards not handled yet XXX */
-
- if (teeState->tee_leftScanDesc == NULL)
- {
- teeState->tee_leftScanDesc = heap_beginscan(bufferRel,
- ScanDirectionIsBackward(dir),
- NowTimeQual, /* time qual */
- 0, /* num scan keys */
- NULL /* scan keys */
- );
- }
- if (teeState->tee_rightScanDesc == NULL)
- {
- teeState->tee_rightScanDesc = heap_beginscan(bufferRel,
- ScanDirectionIsBackward(dir),
- NowTimeQual, /* time qual */
- 0, /* num scan keys */
- NULL /* scan keys */
- );
- }
-
- MemoryContextSwitchTo(orig);
+ TeeState *teeState;
+ Relation bufferRel;
+ ScanDirection dir;
+ MemoryContext orig;
+
+ teeState = node->teestate;
+ if (teeState->tee_leftScanDesc && teeState->tee_rightScanDesc)
+ return;
+
+ orig = CurrentMemoryContext;
+ MemoryContextSwitchTo(teeState->tee_mcxt);
+
+ bufferRel = teeState->tee_bufferRel;
+ dir = ((Plan *) node)->state->es_direction; /* backwards not handled
+ * yet XXX */
+
+ if (teeState->tee_leftScanDesc == NULL)
+ {
+ teeState->tee_leftScanDesc = heap_beginscan(bufferRel,
+ ScanDirectionIsBackward(dir),
+ NowTimeQual, /* time qual */
+ 0, /* num scan keys */
+ NULL /* scan keys */
+ );
+ }
+ if (teeState->tee_rightScanDesc == NULL)
+ {
+ teeState->tee_rightScanDesc = heap_beginscan(bufferRel,
+ ScanDirectionIsBackward(dir),
+ NowTimeQual, /* time qual */
+ 0, /* num scan keys */
+ NULL /* scan keys */
+ );
+ }
+
+ MemoryContextSwitchTo(orig);
}
/* ----------------------------------------------------------------
- * ExecTee(node)
+ * ExecTee(node)
+ *
*
+ * A Tee serves to connect a subplan to multiple parents.
+ * the subplan is always the outplan of the Tee node.
*
- * A Tee serves to connect a subplan to multiple parents.
- * the subplan is always the outplan of the Tee node.
- *
- * The Tee gets requests from either leftParent or rightParent,
- * fetches the result tuple from the child, and then
- * stored the result into a temporary relation (serving as a queue).
- * leftPlace and rightPlace keep track of where the left and rightParents
- * are.
- * If a parent requests a tuple and that parent is not at the end
- * of the temporary relation, then the request is satisfied from
- * the queue instead of by executing the child plan
+ * The Tee gets requests from either leftParent or rightParent,
+ * fetches the result tuple from the child, and then
+ * stored the result into a temporary relation (serving as a queue).
+ * leftPlace and rightPlace keep track of where the left and rightParents
+ * are.
+ * If a parent requests a tuple and that parent is not at the end
+ * of the temporary relation, then the request is satisfied from
+ * the queue instead of by executing the child plan
*
* ----------------------------------------------------------------
*/
-TupleTableSlot*
-ExecTee(Tee *node, Plan *parent)
+TupleTableSlot *
+ExecTee(Tee * node, Plan * parent)
{
- EState *estate;
- TeeState *teeState;
- int leftPlace, rightPlace, lastPlace;
- int branch;
- TupleTableSlot* result;
- TupleTableSlot* slot;
- Plan *childNode;
- ScanDirection dir;
- HeapTuple heapTuple;
- Relation bufferRel;
- HeapScanDesc scanDesc;
- Buffer buffer;
-
- estate = ((Plan*)node)->state;
- teeState = node->teestate;
- leftPlace = teeState->tee_leftPlace;
- rightPlace = teeState->tee_rightPlace;
- lastPlace = teeState->tee_lastPlace;
- bufferRel = teeState->tee_bufferRel;
-
- childNode = outerPlan(node);
-
- dir = estate->es_direction;
-
- /* XXX doesn't handle backwards direction yet */
-
- if (parent == node->leftParent) {
- branch = leftPlace;
- }
- else
- if ( (parent == node->rightParent) || (parent == (Plan*) node))
- /* the tee node could be the root node of the plan,
- in which case, we treat it like a right-parent pull*/
+ EState *estate;
+ TeeState *teeState;
+ int leftPlace,
+ rightPlace,
+ lastPlace;
+ int branch;
+ TupleTableSlot *result;
+ TupleTableSlot *slot;
+ Plan *childNode;
+ ScanDirection dir;
+ HeapTuple heapTuple;
+ Relation bufferRel;
+ HeapScanDesc scanDesc;
+ Buffer buffer;
+
+ estate = ((Plan *) node)->state;
+ teeState = node->teestate;
+ leftPlace = teeState->tee_leftPlace;
+ rightPlace = teeState->tee_rightPlace;
+ lastPlace = teeState->tee_lastPlace;
+ bufferRel = teeState->tee_bufferRel;
+
+ childNode = outerPlan(node);
+
+ dir = estate->es_direction;
+
+ /* XXX doesn't handle backwards direction yet */
+
+ if (parent == node->leftParent)
+ {
+ branch = leftPlace;
+ }
+ else if ((parent == node->rightParent) || (parent == (Plan *) node))
+
+ /*
+ * the tee node could be the root node of the plan, in which case,
+ * we treat it like a right-parent pull
+ */
+ {
+ branch = rightPlace;
+ }
+ else
+ {
+ elog(WARN, "A Tee node can only be executed from its left or right parent\n");
+ return NULL;
+ }
+
+ if (branch == lastPlace)
+ { /* we're at the end of the queue already,
+ * - get a new tuple from the child plan,
+ * - store it in the queue, - increment
+ * lastPlace, - increment leftPlace or
+ * rightPlace as appropriate, - and return
+ * result */
+ slot = ExecProcNode(childNode, (Plan *) node);
+ if (!TupIsNull(slot))
+ {
+ heapTuple = slot->val;
+
+ /* insert into temporary relation */
+ heap_insert(bufferRel, heapTuple);
+
+ /*
+ * once there is data in the temporary relation, ensure that
+ * the left and right scandescs are initialized
+ */
+ initTeeScanDescs(node);
+
+ scanDesc = (parent == node->leftParent) ?
+ teeState->tee_leftScanDesc : teeState->tee_rightScanDesc;
+
+ {
+
+ /*
+ * move the scandesc forward so we don't re-read this
+ * tuple later
+ */
+ HeapTuple throwAway;
+
+ /* Buffer buffer; */
+ throwAway = heap_getnext(scanDesc,
+ ScanDirectionIsBackward(dir),
+ /* &buffer */
+ (Buffer *) NULL);
+ }
+
+ /*
+ * set the shouldFree field of the child's slot so that when
+ * the child's slot is free'd, this tuple isn't free'd also
+ */
+
+ /*
+ * does this mean this tuple has to be garbage collected
+ * later??
+ */
+ slot->ttc_shouldFree = false;
+
+ teeState->tee_lastPlace = lastPlace + 1;
+ }
+ result = slot;
+ }
+ else
+ { /* the desired data already exists in the
+ * temporary relation */
+ scanDesc = (parent == node->leftParent) ?
+ teeState->tee_leftScanDesc : teeState->tee_rightScanDesc;
+
+ heapTuple = heap_getnext(scanDesc,
+ ScanDirectionIsBackward(dir),
+ &buffer);
+
+ /*
+ * Increase the pin count on the buffer page, because the tuple
+ * stored in the slot also points to it (as well as the scan
+ * descriptor). If we don't, ExecStoreTuple will decrease the pin
+ * count on the next iteration.
+ */
+
+ if (buffer != InvalidBuffer)
+ IncrBufferRefCount(buffer);
+
+ slot = teeState->cstate.cs_ResultTupleSlot;
+ slot->ttc_tupleDescriptor = RelationGetTupleDescriptor(bufferRel);
+
+ result = ExecStoreTuple(heapTuple, /* tuple to store */
+ slot, /* slot to store in */
+ buffer, /* this tuple's buffer */
+ false); /* don't free stuff from
+ * heap_getnext */
+
+ }
+
+ if (parent == node->leftParent)
{
- branch = rightPlace;
- }
- else
- {
- elog(WARN,"A Tee node can only be executed from its left or right parent\n");
- return NULL;
- }
-
- if (branch == lastPlace)
- { /* we're at the end of the queue already,
- - get a new tuple from the child plan,
- - store it in the queue,
- - increment lastPlace,
- - increment leftPlace or rightPlace as appropriate,
- - and return result
- */
- slot = ExecProcNode(childNode, (Plan*)node);
- if (!TupIsNull(slot))
- {
- heapTuple = slot->val;
-
- /* insert into temporary relation */
- heap_insert(bufferRel, heapTuple);
-
- /* once there is data in the temporary relation,
- ensure that the left and right scandescs are initialized */
- initTeeScanDescs(node);
-
- scanDesc = (parent == node->leftParent) ?
- teeState->tee_leftScanDesc : teeState->tee_rightScanDesc;
-
- {
- /* move the scandesc forward so we don't re-read this tuple later */
- HeapTuple throwAway;
- /* Buffer buffer;*/
- throwAway = heap_getnext(scanDesc,
- ScanDirectionIsBackward(dir),
- /* &buffer */
- (Buffer*)NULL);
- }
-
- /* set the shouldFree field of the child's slot so that
- when the child's slot is free'd, this tuple isn't free'd also */
- /* does this mean this tuple has to be garbage collected later??*/
- slot->ttc_shouldFree = false;
-
- teeState->tee_lastPlace = lastPlace + 1;
- }
- result = slot;
- }
- else
- {/* the desired data already exists in the temporary relation */
- scanDesc = (parent == node->leftParent) ?
- teeState->tee_leftScanDesc : teeState->tee_rightScanDesc;
-
- heapTuple = heap_getnext(scanDesc,
- ScanDirectionIsBackward(dir),
- &buffer);
-
- /* Increase the pin count on the buffer page, because the
- tuple stored in the slot also points to it (as well as
- the scan descriptor). If we don't, ExecStoreTuple will
- decrease the pin count on the next iteration. */
-
- if (buffer != InvalidBuffer)
- IncrBufferRefCount(buffer);
-
- slot = teeState->cstate.cs_ResultTupleSlot;
- slot->ttc_tupleDescriptor = RelationGetTupleDescriptor(bufferRel);
-
- result = ExecStoreTuple(heapTuple,/* tuple to store */
- slot, /* slot to store in */
- buffer,/* this tuple's buffer */
- false); /* don't free stuff from heap_getnext */
-
- }
-
- if (parent == node->leftParent)
- {
- teeState->tee_leftPlace = leftPlace+1;
- }
- else
- {
- teeState->tee_rightPlace = rightPlace+1;
- }
-
- return result;
+ teeState->tee_leftPlace = leftPlace + 1;
+ }
+ else
+ {
+ teeState->tee_rightPlace = rightPlace + 1;
+ }
+
+ return result;
}
/* ----------------------------------------------------------------
- * ExecTeeReScan(node)
- *
- * Rescans the relation.
+ * ExecTeeReScan(node)
+ *
+ * Rescans the relation.
* ----------------------------------------------------------------
*/
void
-ExecTeeReScan(Tee *node, ExprContext *exprCtxt, Plan *parent)
+ExecTeeReScan(Tee * node, ExprContext * exprCtxt, Plan * parent)
{
- EState *estate;
- TeeState *teeState;
- ScanDirection dir;
+ EState *estate;
+ TeeState *teeState;
+ ScanDirection dir;
- estate = ((Plan*)node)->state;
- teeState = node->teestate;
+ estate = ((Plan *) node)->state;
+ teeState = node->teestate;
- dir = estate->es_direction;
-
- /* XXX doesn't handle backwards direction yet */
+ dir = estate->es_direction;
- if (parent == node->leftParent) {
- if (teeState->tee_leftScanDesc)
+ /* XXX doesn't handle backwards direction yet */
+
+ if (parent == node->leftParent)
+ {
+ if (teeState->tee_leftScanDesc)
+ {
+ heap_rescan(teeState->tee_leftScanDesc,
+ ScanDirectionIsBackward(dir),
+ NULL);
+ teeState->tee_leftPlace = 0;
+ }
+ }
+ else
{
- heap_rescan(teeState->tee_leftScanDesc,
- ScanDirectionIsBackward(dir),
- NULL);
- teeState->tee_leftPlace = 0;
+ if (teeState->tee_rightScanDesc)
+ {
+ heap_rescan(teeState->tee_leftScanDesc,
+ ScanDirectionIsBackward(dir),
+ NULL);
+ teeState->tee_rightPlace = 0;
+ }
}
- }
- else
- {
- if (teeState->tee_rightScanDesc)
- {
- heap_rescan(teeState->tee_leftScanDesc,
- ScanDirectionIsBackward(dir),
- NULL);
- teeState->tee_rightPlace = 0;
- }
- }
}
/* ---------------------------------------------------------------------
- * ExecEndTee
+ * ExecEndTee
*
- * End the Tee node, and free up any storage
+ * End the Tee node, and free up any storage
* since a Tee node can be downstream of multiple parent nodes,
* only free when both parents are done
* --------------------------------------------------------------------
*/
-void
-ExecEndTee(Tee* node, Plan* parent)
+void
+ExecEndTee(Tee * node, Plan * parent)
{
- EState *estate;
- TeeState *teeState;
- int leftPlace, rightPlace, lastPlace;
- Relation bufferRel;
- MemoryContext orig;
-
- estate = ((Plan*)node)->state;
- teeState = node->teestate;
- leftPlace = teeState->tee_leftPlace;
- rightPlace = teeState->tee_rightPlace;
- lastPlace = teeState->tee_lastPlace;
-
- if (!node->leftParent || parent == node->leftParent)
- leftPlace = -1;
-
- if (!node->rightParent || parent == node->rightParent)
- rightPlace = -1;
-
- if (parent == (Plan*)node)
- rightPlace = leftPlace = -1;
-
- teeState->tee_leftPlace = leftPlace;
- teeState->tee_rightPlace = rightPlace;
- if ( (leftPlace == -1) && (rightPlace == -1) )
- {
- /* remove the temporary relations */
- /* and close the scan descriptors */
-
- bufferRel = teeState->tee_bufferRel;
- if (bufferRel) {
- heap_destroyr(bufferRel);
- teeState->tee_bufferRel = NULL;
- if (teeState->tee_mcxt) {
- orig = CurrentMemoryContext;
- MemoryContextSwitchTo(teeState->tee_mcxt);
- }
- else
- orig = 0;
-
- if (teeState->tee_leftScanDesc)
- {
- heap_endscan(teeState->tee_leftScanDesc);
- teeState->tee_leftScanDesc = NULL;
- }
- if (teeState->tee_rightScanDesc)
- {
- heap_endscan(teeState->tee_rightScanDesc);
- teeState->tee_rightScanDesc = NULL;
- }
-
- if (teeState->tee_mcxt) {
- MemoryContextSwitchTo(orig);
- teeState->tee_mcxt = NULL;
- }
+ EState *estate;
+ TeeState *teeState;
+ int leftPlace,
+ rightPlace,
+ lastPlace;
+ Relation bufferRel;
+ MemoryContext orig;
+
+ estate = ((Plan *) node)->state;
+ teeState = node->teestate;
+ leftPlace = teeState->tee_leftPlace;
+ rightPlace = teeState->tee_rightPlace;
+ lastPlace = teeState->tee_lastPlace;
+
+ if (!node->leftParent || parent == node->leftParent)
+ leftPlace = -1;
+
+ if (!node->rightParent || parent == node->rightParent)
+ rightPlace = -1;
+
+ if (parent == (Plan *) node)
+ rightPlace = leftPlace = -1;
+
+ teeState->tee_leftPlace = leftPlace;
+ teeState->tee_rightPlace = rightPlace;
+ if ((leftPlace == -1) && (rightPlace == -1))
+ {
+ /* remove the temporary relations */
+ /* and close the scan descriptors */
+
+ bufferRel = teeState->tee_bufferRel;
+ if (bufferRel)
+ {
+ heap_destroyr(bufferRel);
+ teeState->tee_bufferRel = NULL;
+ if (teeState->tee_mcxt)
+ {
+ orig = CurrentMemoryContext;
+ MemoryContextSwitchTo(teeState->tee_mcxt);
+ }
+ else
+ orig = 0;
+
+ if (teeState->tee_leftScanDesc)
+ {
+ heap_endscan(teeState->tee_leftScanDesc);
+ teeState->tee_leftScanDesc = NULL;
+ }
+ if (teeState->tee_rightScanDesc)
+ {
+ heap_endscan(teeState->tee_rightScanDesc);
+ teeState->tee_rightScanDesc = NULL;
+ }
+
+ if (teeState->tee_mcxt)
+ {
+ MemoryContextSwitchTo(orig);
+ teeState->tee_mcxt = NULL;
+ }
+ }
}
- }
-
-}
+}
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 65c3bea76e0..75e40ccad96 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* nodeUnique.c--
- * Routines to handle unique'ing of queries where appropriate
+ * Routines to handle unique'ing of queries where appropriate
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.7 1997/08/26 23:31:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.8 1997/09/07 04:41:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * ExecUnique - generate a unique'd temporary relation
- * ExecInitUnique - initialize node and subnodes..
- * ExecEndUnique - shutdown node and subnodes
+ * ExecUnique - generate a unique'd temporary relation
+ * ExecInitUnique - initialize node and subnodes..
+ * ExecEndUnique - shutdown node and subnodes
*
* NOTES
- * Assumes tuples returned from subplan arrive in
- * sorted order.
+ * Assumes tuples returned from subplan arrive in
+ * sorted order.
*
*/
#include <string.h>
@@ -31,296 +31,318 @@
#include "executor/nodeUnique.h"
#include "optimizer/clauses.h"
#include "access/heapam.h"
-#include "access/printtup.h" /* for typtoout() */
-#include "utils/builtins.h" /* for namecpy()*/
+#include "access/printtup.h" /* for typtoout() */
+#include "utils/builtins.h" /* for namecpy() */
/* ----------------------------------------------------------------
- * ExecIdenticalTuples
+ * ExecIdenticalTuples
*
- * This is a hack function used by ExecUnique to see if
- * two tuples are identical. This should be provided
- * by the heap tuple code but isn't. The real problem
- * is that we assume we can byte compare tuples to determine
- * if they are "equal". In fact, if we have user defined
- * types there may be problems because it's possible that
- * an ADT may have multiple representations with the
- * same ADT value. -cim
+ * This is a hack function used by ExecUnique to see if
+ * two tuples are identical. This should be provided
+ * by the heap tuple code but isn't. The real problem
+ * is that we assume we can byte compare tuples to determine
+ * if they are "equal". In fact, if we have user defined
+ * types there may be problems because it's possible that
+ * an ADT may have multiple representations with the
+ * same ADT value. -cim
* ----------------------------------------------------------------
*/
-static bool /* true if tuples are identical, false otherwise */
-ExecIdenticalTuples(TupleTableSlot *t1, TupleTableSlot *t2)
+static bool /* true if tuples are identical, false
+ * otherwise */
+ExecIdenticalTuples(TupleTableSlot * t1, TupleTableSlot * t2)
{
- HeapTuple h1;
- HeapTuple h2;
- char *d1;
- char *d2;
- int len;
-
- h1 = t1->val;
- h2 = t2->val;
-
- /* ----------------
- * if tuples aren't the same length then they are
- * obviously different (one may have null attributes).
- * ----------------
- */
- if (h1->t_len != h2->t_len)
- return false;
-
- /* ----------------
- * if the tuples have different header offsets then
- * they are different. This will prevent us from returning
- * true when comparing tuples of one attribute where one of
- * two we're looking at is null (t_len - t_hoff == 0).
- * THE t_len FIELDS CAN BE THE SAME IN THIS CASE!!
- * ----------------
- */
- if (h1->t_hoff != h2->t_hoff)
- return false;
-
- /* ----------------
- * ok, now get the pointers to the data and the
- * size of the attribute portion of the tuple.
- * ----------------
- */
- d1 = (char *) GETSTRUCT(h1);
- d2 = (char *) GETSTRUCT(h2);
- len = (int) h1->t_len - (int) h1->t_hoff;
-
- /* ----------------
- * byte compare the data areas and return the result.
- * ----------------
- */
- if (memcmp(d1, d2, len) != 0)
- return false;
-
- return true;
+ HeapTuple h1;
+ HeapTuple h2;
+ char *d1;
+ char *d2;
+ int len;
+
+ h1 = t1->val;
+ h2 = t2->val;
+
+ /* ----------------
+ * if tuples aren't the same length then they are
+ * obviously different (one may have null attributes).
+ * ----------------
+ */
+ if (h1->t_len != h2->t_len)
+ return false;
+
+ /* ----------------
+ * if the tuples have different header offsets then
+ * they are different. This will prevent us from returning
+ * true when comparing tuples of one attribute where one of
+ * two we're looking at is null (t_len - t_hoff == 0).
+ * THE t_len FIELDS CAN BE THE SAME IN THIS CASE!!
+ * ----------------
+ */
+ if (h1->t_hoff != h2->t_hoff)
+ return false;
+
+ /* ----------------
+ * ok, now get the pointers to the data and the
+ * size of the attribute portion of the tuple.
+ * ----------------
+ */
+ d1 = (char *) GETSTRUCT(h1);
+ d2 = (char *) GETSTRUCT(h2);
+ len = (int) h1->t_len - (int) h1->t_hoff;
+
+ /* ----------------
+ * byte compare the data areas and return the result.
+ * ----------------
+ */
+ if (memcmp(d1, d2, len) != 0)
+ return false;
+
+ return true;
}
/* ----------------------------------------------------------------
- * ExecUnique
+ * ExecUnique
*
- * This is a very simple node which filters out duplicate
- * tuples from a stream of sorted tuples from a subplan.
+ * This is a very simple node which filters out duplicate
+ * tuples from a stream of sorted tuples from a subplan.
*
- * XXX see comments below regarding freeing tuples.
+ * XXX see comments below regarding freeing tuples.
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecUnique(Unique *node)
+TupleTableSlot * /* return: a tuple or NULL */
+ExecUnique(Unique * node)
{
- UniqueState *uniquestate;
- TupleTableSlot *resultTupleSlot;
- TupleTableSlot *slot;
- Plan *outerPlan;
- char *uniqueAttr;
- AttrNumber uniqueAttrNum;
- TupleDesc tupDesc;
- Oid typoutput;
-
- /* ----------------
- * get information from the node
- * ----------------
- */
- uniquestate = node->uniquestate;
- outerPlan = outerPlan((Plan *) node);
- resultTupleSlot = uniquestate->cs_ResultTupleSlot;
- uniqueAttr = node->uniqueAttr;
- uniqueAttrNum = node->uniqueAttrNum;
-
- if (uniqueAttr) {
- tupDesc = ExecGetResultType(uniquestate);
- typoutput = typtoout((Oid)tupDesc->attrs[uniqueAttrNum-1]->atttypid);
- }
- else { /* keep compiler quiet */
- tupDesc = NULL;
- typoutput = 0;
- }
-
- /* ----------------
- * now loop, returning only non-duplicate tuples.
- * We assume that the tuples arrive in sorted order
- * so we can detect duplicates easily.
- * ----------------
- */
- for (;;) {
+ UniqueState *uniquestate;
+ TupleTableSlot *resultTupleSlot;
+ TupleTableSlot *slot;
+ Plan *outerPlan;
+ char *uniqueAttr;
+ AttrNumber uniqueAttrNum;
+ TupleDesc tupDesc;
+ Oid typoutput;
+
/* ----------------
- * fetch a tuple from the outer subplan
+ * get information from the node
* ----------------
*/
- slot = ExecProcNode(outerPlan, (Plan*)node);
- if (TupIsNull(slot))
- return NULL;
-
+ uniquestate = node->uniquestate;
+ outerPlan = outerPlan((Plan *) node);
+ resultTupleSlot = uniquestate->cs_ResultTupleSlot;
+ uniqueAttr = node->uniqueAttr;
+ uniqueAttrNum = node->uniqueAttrNum;
+
+ if (uniqueAttr)
+ {
+ tupDesc = ExecGetResultType(uniquestate);
+ typoutput = typtoout((Oid) tupDesc->attrs[uniqueAttrNum - 1]->atttypid);
+ }
+ else
+ { /* keep compiler quiet */
+ tupDesc = NULL;
+ typoutput = 0;
+ }
+
/* ----------------
- * we use the result tuple slot to hold our saved tuples.
- * if we haven't a saved tuple to compare our new tuple with,
- * then we exit the loop. This new tuple as the saved tuple
- * the next time we get here.
+ * now loop, returning only non-duplicate tuples.
+ * We assume that the tuples arrive in sorted order
+ * so we can detect duplicates easily.
* ----------------
*/
- if (TupIsNull(resultTupleSlot))
- break;
-
+ for (;;)
+ {
+ /* ----------------
+ * fetch a tuple from the outer subplan
+ * ----------------
+ */
+ slot = ExecProcNode(outerPlan, (Plan *) node);
+ if (TupIsNull(slot))
+ return NULL;
+
+ /* ----------------
+ * we use the result tuple slot to hold our saved tuples.
+ * if we haven't a saved tuple to compare our new tuple with,
+ * then we exit the loop. This new tuple as the saved tuple
+ * the next time we get here.
+ * ----------------
+ */
+ if (TupIsNull(resultTupleSlot))
+ break;
+
+ /* ----------------
+ * now test if the new tuple and the previous
+ * tuple match. If so then we loop back and fetch
+ * another new tuple from the subplan.
+ * ----------------
+ */
+
+ if (uniqueAttr)
+ {
+
+ /*
+ * to check equality, we check to see if the typoutput of the
+ * attributes are equal
+ */
+ bool isNull1,
+ isNull2;
+ char *attr1,
+ *attr2;
+ char *val1,
+ *val2;
+
+ attr1 = heap_getattr(slot->val, InvalidBuffer,
+ uniqueAttrNum, tupDesc, &isNull1);
+ attr2 = heap_getattr(resultTupleSlot->val, InvalidBuffer,
+ uniqueAttrNum, tupDesc, &isNull2);
+
+ if (isNull1 == isNull2)
+ {
+ if (isNull1) /* both are null, they are equal */
+ continue;
+ val1 = fmgr(typoutput, attr1, gettypelem(tupDesc->attrs[uniqueAttrNum - 1]->atttypid));
+ val2 = fmgr(typoutput, attr2, gettypelem(tupDesc->attrs[uniqueAttrNum - 1]->atttypid));
+
+ /*
+ * now, val1 and val2 are ascii representations so we can
+ * use strcmp for comparison
+ */
+ if (strcmp(val1, val2) == 0) /* they are equal */
+ continue;
+ else
+ break;
+ }
+ else
+/* one is null and the other isn't, they aren't equal */
+ break;
+
+ }
+ else
+ {
+ if (!ExecIdenticalTuples(slot, resultTupleSlot))
+ break;
+ }
+
+ }
+
/* ----------------
- * now test if the new tuple and the previous
- * tuple match. If so then we loop back and fetch
- * another new tuple from the subplan.
+ * we have a new tuple different from the previous saved tuple
+ * so we save it in the saved tuple slot. We copy the tuple
+ * so we don't increment the buffer ref count.
* ----------------
*/
+ ExecStoreTuple(heap_copytuple(slot->val),
+ resultTupleSlot,
+ InvalidBuffer,
+ true);
- if (uniqueAttr) {
- /* to check equality, we check to see if the typoutput
- of the attributes are equal */
- bool isNull1,isNull2;
- char *attr1, *attr2;
- char *val1, *val2;
-
- attr1 = heap_getattr(slot->val, InvalidBuffer,
- uniqueAttrNum, tupDesc,&isNull1);
- attr2 = heap_getattr(resultTupleSlot->val, InvalidBuffer,
- uniqueAttrNum, tupDesc,&isNull2);
-
- if (isNull1 == isNull2) {
- if (isNull1) /* both are null, they are equal */
- continue;
- val1 = fmgr(typoutput, attr1, gettypelem(tupDesc->attrs[uniqueAttrNum-1]->atttypid));
- val2 = fmgr(typoutput, attr2, gettypelem(tupDesc->attrs[uniqueAttrNum-1]->atttypid));
- /* now, val1 and val2 are ascii representations so we can
- use strcmp for comparison */
- if (strcmp(val1,val2) == 0) /* they are equal */
- continue;
- else
- break;
- }
- else /* one is null and the other isn't, they aren't equal */
- break;
-
- }
- else {
- if (! ExecIdenticalTuples(slot, resultTupleSlot))
- break;
- }
-
- }
-
- /* ----------------
- * we have a new tuple different from the previous saved tuple
- * so we save it in the saved tuple slot. We copy the tuple
- * so we don't increment the buffer ref count.
- * ----------------
- */
- ExecStoreTuple(heap_copytuple(slot->val),
- resultTupleSlot,
- InvalidBuffer,
- true);
-
- return resultTupleSlot;
+ return resultTupleSlot;
}
/* ----------------------------------------------------------------
- * ExecInitUnique
+ * ExecInitUnique
*
- * This initializes the unique node state structures and
- * the node's subplan.
+ * This initializes the unique node state structures and
+ * the node's subplan.
* ----------------------------------------------------------------
*/
-bool /* return: initialization status */
-ExecInitUnique(Unique *node, EState *estate, Plan *parent)
+bool /* return: initialization status */
+ExecInitUnique(Unique * node, EState * estate, Plan * parent)
{
- UniqueState *uniquestate;
- Plan *outerPlan;
- char *uniqueAttr;
-
- /* ----------------
- * assign execution state to node
- * ----------------
- */
- node->plan.state = estate;
-
- /* ----------------
- * create new UniqueState for node
- * ----------------
- */
- uniquestate = makeNode(UniqueState);
- node->uniquestate = uniquestate;
- uniqueAttr = node->uniqueAttr;
-
- /* ----------------
- * Miscellanious initialization
- *
- * + assign node's base_id
- * + assign debugging hooks and
- *
- * Unique nodes have no ExprContext initialization because
- * they never call ExecQual or ExecTargetList.
- * ----------------
- */
- ExecAssignNodeBaseInfo(estate, uniquestate, parent);
-
+ UniqueState *uniquestate;
+ Plan *outerPlan;
+ char *uniqueAttr;
+
+ /* ----------------
+ * assign execution state to node
+ * ----------------
+ */
+ node->plan.state = estate;
+
+ /* ----------------
+ * create new UniqueState for node
+ * ----------------
+ */
+ uniquestate = makeNode(UniqueState);
+ node->uniquestate = uniquestate;
+ uniqueAttr = node->uniqueAttr;
+
+ /* ----------------
+ * Miscellanious initialization
+ *
+ * + assign node's base_id
+ * + assign debugging hooks and
+ *
+ * Unique nodes have no ExprContext initialization because
+ * they never call ExecQual or ExecTargetList.
+ * ----------------
+ */
+ ExecAssignNodeBaseInfo(estate, uniquestate, parent);
+
#define UNIQUE_NSLOTS 1
- /* ------------
- * Tuple table initialization
- * ------------
- */
- ExecInitResultTupleSlot(estate, uniquestate);
-
- /* ----------------
- * then initialize outer plan
- * ----------------
- */
- outerPlan = outerPlan((Plan *) node);
- ExecInitNode(outerPlan, estate, (Plan *) node);
-
- /* ----------------
- * unique nodes do no projections, so initialize
- * projection info for this node appropriately
- * ----------------
- */
- ExecAssignResultTypeFromOuterPlan((Plan *)node,uniquestate);
- uniquestate->cs_ProjInfo = NULL;
-
- if (uniqueAttr) {
- TupleDesc tupDesc;
- int i = 0;
-
- tupDesc = ExecGetResultType(uniquestate);
- /* the parser should have ensured that uniqueAttr is a legal attribute name*/
- while ( strcmp((tupDesc->attrs[i]->attname).data, uniqueAttr) != 0)
- i++;
- node->uniqueAttrNum = i+1; /* attribute numbers start from 1 */
- }
- else
- node->uniqueAttrNum = InvalidAttrNumber;
-
- /* ----------------
- * all done.
- * ----------------
- */
- return TRUE;
+ /* ------------
+ * Tuple table initialization
+ * ------------
+ */
+ ExecInitResultTupleSlot(estate, uniquestate);
+
+ /* ----------------
+ * then initialize outer plan
+ * ----------------
+ */
+ outerPlan = outerPlan((Plan *) node);
+ ExecInitNode(outerPlan, estate, (Plan *) node);
+
+ /* ----------------
+ * unique nodes do no projections, so initialize
+ * projection info for this node appropriately
+ * ----------------
+ */
+ ExecAssignResultTypeFromOuterPlan((Plan *) node, uniquestate);
+ uniquestate->cs_ProjInfo = NULL;
+
+ if (uniqueAttr)
+ {
+ TupleDesc tupDesc;
+ int i = 0;
+
+ tupDesc = ExecGetResultType(uniquestate);
+
+ /*
+ * the parser should have ensured that uniqueAttr is a legal
+ * attribute name
+ */
+ while (strcmp((tupDesc->attrs[i]->attname).data, uniqueAttr) != 0)
+ i++;
+ node->uniqueAttrNum = i + 1; /* attribute numbers start from 1 */
+ }
+ else
+ node->uniqueAttrNum = InvalidAttrNumber;
+
+ /* ----------------
+ * all done.
+ * ----------------
+ */
+ return TRUE;
}
int
-ExecCountSlotsUnique(Unique *node)
+ExecCountSlotsUnique(Unique * node)
{
- return ExecCountSlotsNode(outerPlan(node)) +
+ return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
- UNIQUE_NSLOTS;
+ UNIQUE_NSLOTS;
}
/* ----------------------------------------------------------------
- * ExecEndUnique
+ * ExecEndUnique
*
- * This shuts down the subplan and frees resources allocated
- * to this node.
+ * This shuts down the subplan and frees resources allocated
+ * to this node.
* ----------------------------------------------------------------
*/
void
-ExecEndUnique(Unique *node)
+ExecEndUnique(Unique * node)
{
- UniqueState *uniquestate;
-
- uniquestate = node->uniquestate;
- ExecEndNode(outerPlan((Plan *) node), (Plan*)node);
- ExecClearTuple(uniquestate->cs_ResultTupleSlot);
-}
+ UniqueState *uniquestate;
+
+ uniquestate = node->uniquestate;
+ ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
+ ExecClearTuple(uniquestate->cs_ResultTupleSlot);
+}
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 74ace81171a..1d05a752d24 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* spi.c--
- * Server Programming Interface
+ * Server Programming Interface
*
*-------------------------------------------------------------------------
*/
@@ -9,440 +9,447 @@
#include "access/printtup.h"
#include "fmgr.h"
-typedef struct {
- QueryTreeList *qtlist; /* malloced */
- uint32 processed; /* by Executor */
- SPITupleTable *tuptable;
- Portal portal; /* portal per procedure */
- MemoryContext savedcxt;
- CommandId savedId;
-} _SPI_connection;
-
-static Portal _SPI_portal = (Portal) NULL;
+typedef struct
+{
+ QueryTreeList *qtlist; /* malloced */
+ uint32 processed; /* by Executor */
+ SPITupleTable *tuptable;
+ Portal portal; /* portal per procedure */
+ MemoryContext savedcxt;
+ CommandId savedId;
+} _SPI_connection;
+
+static Portal _SPI_portal = (Portal) NULL;
static _SPI_connection *_SPI_stack = NULL;
static _SPI_connection *_SPI_current = NULL;
-static int _SPI_connected = -1;
-static int _SPI_curid = -1;
+static int _SPI_connected = -1;
+static int _SPI_curid = -1;
+
+uint32 SPI_processed = 0;
+SPITupleTable *SPI_tuptable;
+int SPI_result;
-uint32 SPI_processed = 0;
-SPITupleTable *SPI_tuptable;
-int SPI_result;
+void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
-void spi_printtup (HeapTuple tuple, TupleDesc tupdesc);
+typedef struct
+{
+ QueryTreeList *qtlist;
+ List *ptlist;
+ int nargs;
+ Oid *argtypes;
+} _SPI_plan;
-typedef struct {
- QueryTreeList *qtlist;
- List *ptlist;
- int nargs;
- Oid *argtypes;
-} _SPI_plan;
+static int _SPI_execute(char *src, int tcount, _SPI_plan * plan);
+static int _SPI_pquery(QueryDesc * queryDesc, EState * state, int tcount);
-static int _SPI_execute (char *src, int tcount, _SPI_plan *plan);
-static int _SPI_pquery (QueryDesc *queryDesc, EState *state, int tcount);
#if 0
-static void _SPI_fetch (FetchStmt *stmt);
+static void _SPI_fetch(FetchStmt * stmt);
+
#endif
-static int _SPI_execute_plan (_SPI_plan *plan,
- char **Values, char *Nulls, int tcount);
+static int
+_SPI_execute_plan(_SPI_plan * plan,
+ char **Values, char *Nulls, int tcount);
-static _SPI_plan *_SPI_copy_plan (_SPI_plan *plan, bool local);
+static _SPI_plan *_SPI_copy_plan(_SPI_plan * plan, bool local);
-static int _SPI_begin_call (bool execmem);
-static int _SPI_end_call (bool procmem);
-static MemoryContext _SPI_execmem (void);
-static MemoryContext _SPI_procmem (void);
-static bool _SPI_checktuples (bool isRetrieveIntoRelation);
+static int _SPI_begin_call(bool execmem);
+static int _SPI_end_call(bool procmem);
+static MemoryContext _SPI_execmem(void);
+static MemoryContext _SPI_procmem(void);
+static bool _SPI_checktuples(bool isRetrieveIntoRelation);
#ifdef SPI_EXECUTOR_STATS
-extern int ShowExecutorStats;
-extern void ResetUsage (void);
-extern void ShowUsage (void);
+extern int ShowExecutorStats;
+extern void ResetUsage(void);
+extern void ShowUsage(void);
+
#endif
int
-SPI_connect ()
+SPI_connect()
{
- char pname[64];
- PortalVariableMemory pvmem;
-
- /*
- * It's possible on startup and after commit/abort.
- * In future we'll catch commit/abort in some way...
- */
- strcpy (pname, "<SPI manager>");
- _SPI_portal = GetPortalByName (pname);
- if ( !PortalIsValid (_SPI_portal) )
- {
- if ( _SPI_stack != NULL ) /* there was abort */
- free (_SPI_stack);
- _SPI_current = _SPI_stack = NULL;
- _SPI_connected = _SPI_curid = -1;
- SPI_processed = 0;
- SPI_tuptable = NULL;
- _SPI_portal = CreatePortal (pname);
- if ( !PortalIsValid (_SPI_portal) )
- elog (FATAL, "SPI_connect: global initialization failed");
- }
-
- /*
- * When procedure called by Executor _SPI_curid expected to be
- * equal to _SPI_connected
- */
- if ( _SPI_curid != _SPI_connected )
- return (SPI_ERROR_CONNECT);
-
- if ( _SPI_stack == NULL )
- {
- if ( _SPI_connected != -1 )
- elog (FATAL, "SPI_connect: no connection(s) expected");
- _SPI_stack = (_SPI_connection *) malloc (sizeof (_SPI_connection));
- }
- else
- {
- if ( _SPI_connected <= -1 )
- elog (FATAL, "SPI_connect: some connection(s) expected");
- _SPI_stack = (_SPI_connection *) realloc (_SPI_stack,
- (_SPI_connected + 1) * sizeof (_SPI_connection));
- }
- /*
- * We' returning to procedure where _SPI_curid == _SPI_connected - 1
- */
- _SPI_connected++;
-
- _SPI_current = &(_SPI_stack[_SPI_connected]);
- _SPI_current->qtlist = NULL;
- _SPI_current->processed = 0;
- _SPI_current->tuptable = NULL;
-
- /* Create Portal for this procedure ... */
- sprintf (pname, "<SPI %d>", _SPI_connected);
- _SPI_current->portal = CreatePortal (pname);
- if ( !PortalIsValid (_SPI_current->portal) )
- elog (FATAL, "SPI_connect: initialization failed");
-
- /* ... and switch to Portal' Variable memory - procedure' context */
- pvmem = PortalGetVariableMemory (_SPI_current->portal);
- _SPI_current->savedcxt = MemoryContextSwitchTo ((MemoryContext)pvmem);
-
- _SPI_current->savedId = GetScanCommandId ();
- SetScanCommandId (GetCurrentCommandId ());
-
- return (SPI_OK_CONNECT);
-
+ char pname[64];
+ PortalVariableMemory pvmem;
+
+ /*
+ * It's possible on startup and after commit/abort. In future we'll
+ * catch commit/abort in some way...
+ */
+ strcpy(pname, "<SPI manager>");
+ _SPI_portal = GetPortalByName(pname);
+ if (!PortalIsValid(_SPI_portal))
+ {
+ if (_SPI_stack != NULL) /* there was abort */
+ free(_SPI_stack);
+ _SPI_current = _SPI_stack = NULL;
+ _SPI_connected = _SPI_curid = -1;
+ SPI_processed = 0;
+ SPI_tuptable = NULL;
+ _SPI_portal = CreatePortal(pname);
+ if (!PortalIsValid(_SPI_portal))
+ elog(FATAL, "SPI_connect: global initialization failed");
+ }
+
+ /*
+ * When procedure called by Executor _SPI_curid expected to be equal
+ * to _SPI_connected
+ */
+ if (_SPI_curid != _SPI_connected)
+ return (SPI_ERROR_CONNECT);
+
+ if (_SPI_stack == NULL)
+ {
+ if (_SPI_connected != -1)
+ elog(FATAL, "SPI_connect: no connection(s) expected");
+ _SPI_stack = (_SPI_connection *) malloc(sizeof(_SPI_connection));
+ }
+ else
+ {
+ if (_SPI_connected <= -1)
+ elog(FATAL, "SPI_connect: some connection(s) expected");
+ _SPI_stack = (_SPI_connection *) realloc(_SPI_stack,
+ (_SPI_connected + 1) * sizeof(_SPI_connection));
+ }
+
+ /*
+ * We' returning to procedure where _SPI_curid == _SPI_connected - 1
+ */
+ _SPI_connected++;
+
+ _SPI_current = &(_SPI_stack[_SPI_connected]);
+ _SPI_current->qtlist = NULL;
+ _SPI_current->processed = 0;
+ _SPI_current->tuptable = NULL;
+
+ /* Create Portal for this procedure ... */
+ sprintf(pname, "<SPI %d>", _SPI_connected);
+ _SPI_current->portal = CreatePortal(pname);
+ if (!PortalIsValid(_SPI_current->portal))
+ elog(FATAL, "SPI_connect: initialization failed");
+
+ /* ... and switch to Portal' Variable memory - procedure' context */
+ pvmem = PortalGetVariableMemory(_SPI_current->portal);
+ _SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
+
+ _SPI_current->savedId = GetScanCommandId();
+ SetScanCommandId(GetCurrentCommandId());
+
+ return (SPI_OK_CONNECT);
+
}
int
-SPI_finish ()
+SPI_finish()
{
- int res;
-
- res = _SPI_begin_call (false); /* live in procedure memory */
- if ( res < 0 )
- return (res);
-
- /* Restore memory context as it was before procedure call */
- MemoryContextSwitchTo (_SPI_current->savedcxt);
- PortalDestroy (&(_SPI_current->portal));
-
- SetScanCommandId (_SPI_current->savedId);
-
- /*
- * After _SPI_begin_call _SPI_connected == _SPI_curid.
- * Now we are closing connection to SPI and returning to upper
- * Executor and so _SPI_connected must be equal to _SPI_curid.
- */
- _SPI_connected--;
- _SPI_curid--;
- if ( _SPI_connected == -1 )
- {
- free (_SPI_stack);
- _SPI_stack = NULL;
- }
- else
- {
- _SPI_stack = (_SPI_connection *) realloc (_SPI_stack,
- (_SPI_connected + 1) * sizeof (_SPI_connection));
- _SPI_current = &(_SPI_stack[_SPI_connected]);
- }
-
- return (SPI_OK_FINISH);
-
+ int res;
+
+ res = _SPI_begin_call(false); /* live in procedure memory */
+ if (res < 0)
+ return (res);
+
+ /* Restore memory context as it was before procedure call */
+ MemoryContextSwitchTo(_SPI_current->savedcxt);
+ PortalDestroy(&(_SPI_current->portal));
+
+ SetScanCommandId(_SPI_current->savedId);
+
+ /*
+ * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are
+ * closing connection to SPI and returning to upper Executor and so
+ * _SPI_connected must be equal to _SPI_curid.
+ */
+ _SPI_connected--;
+ _SPI_curid--;
+ if (_SPI_connected == -1)
+ {
+ free(_SPI_stack);
+ _SPI_stack = NULL;
+ }
+ else
+ {
+ _SPI_stack = (_SPI_connection *) realloc(_SPI_stack,
+ (_SPI_connected + 1) * sizeof(_SPI_connection));
+ _SPI_current = &(_SPI_stack[_SPI_connected]);
+ }
+
+ return (SPI_OK_FINISH);
+
}
int
-SPI_exec (char *src, int tcount)
+SPI_exec(char *src, int tcount)
{
- int res;
-
- if ( src == NULL || tcount < 0 )
- return (SPI_ERROR_ARGUMENT);
-
- res = _SPI_begin_call (true);
- if ( res < 0 )
- return (res);
-
- res = _SPI_execute (src, tcount, NULL);
-
- _SPI_end_call (true);
- return (res);
+ int res;
+
+ if (src == NULL || tcount < 0)
+ return (SPI_ERROR_ARGUMENT);
+
+ res = _SPI_begin_call(true);
+ if (res < 0)
+ return (res);
+
+ res = _SPI_execute(src, tcount, NULL);
+
+ _SPI_end_call(true);
+ return (res);
}
-int
-SPI_execp (void *plan, char **Values, char *Nulls, int tcount)
+int
+SPI_execp(void *plan, char **Values, char *Nulls, int tcount)
{
- int res;
-
- if ( plan == NULL || tcount < 0 )
- return (SPI_ERROR_ARGUMENT);
-
- if ( ((_SPI_plan *)plan)->nargs > 0 &&
- ( Values == NULL || Nulls == NULL ) )
- return (SPI_ERROR_PARAM);
-
- res = _SPI_begin_call (true);
- if ( res < 0 )
- return (res);
-
- res = _SPI_execute_plan ((_SPI_plan *)plan, Values, Nulls, tcount);
-
- _SPI_end_call (true);
- return (res);
+ int res;
+
+ if (plan == NULL || tcount < 0)
+ return (SPI_ERROR_ARGUMENT);
+
+ if (((_SPI_plan *) plan)->nargs > 0 &&
+ (Values == NULL || Nulls == NULL))
+ return (SPI_ERROR_PARAM);
+
+ res = _SPI_begin_call(true);
+ if (res < 0)
+ return (res);
+
+ res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, tcount);
+
+ _SPI_end_call(true);
+ return (res);
}
-void *
-SPI_prepare (char *src, int nargs, Oid *argtypes)
+void *
+SPI_prepare(char *src, int nargs, Oid * argtypes)
{
- _SPI_plan *plan;
-
- if ( nargs < 0 || ( nargs > 0 && argtypes == NULL ) )
- {
- SPI_result = SPI_ERROR_ARGUMENT;
- return (NULL);
- }
-
- SPI_result = _SPI_begin_call (true);
- if ( SPI_result < 0 )
- return (NULL);
-
- plan = (_SPI_plan *) palloc (sizeof (_SPI_plan)); /* Executor context */
- plan->argtypes = argtypes;
- plan->nargs = nargs;
-
- SPI_result = _SPI_execute (src, 0, plan);
-
- if ( SPI_result >= 0 ) /* copy plan to local space */
- plan = _SPI_copy_plan (plan, true);
- else
- plan = NULL;
-
- _SPI_end_call (true);
-
- return ((void *)plan);
-
+ _SPI_plan *plan;
+
+ if (nargs < 0 || (nargs > 0 && argtypes == NULL))
+ {
+ SPI_result = SPI_ERROR_ARGUMENT;
+ return (NULL);
+ }
+
+ SPI_result = _SPI_begin_call(true);
+ if (SPI_result < 0)
+ return (NULL);
+
+ plan = (_SPI_plan *) palloc(sizeof(_SPI_plan)); /* Executor context */
+ plan->argtypes = argtypes;
+ plan->nargs = nargs;
+
+ SPI_result = _SPI_execute(src, 0, plan);
+
+ if (SPI_result >= 0) /* copy plan to local space */
+ plan = _SPI_copy_plan(plan, true);
+ else
+ plan = NULL;
+
+ _SPI_end_call(true);
+
+ return ((void *) plan);
+
}
-void *
-SPI_saveplan (void *plan)
+void *
+SPI_saveplan(void *plan)
{
- _SPI_plan *newplan;
-
- if ( plan == NULL )
- {
- SPI_result = SPI_ERROR_ARGUMENT;
- return (NULL);
- }
-
- SPI_result = _SPI_begin_call (false); /* don't change context */
- if ( SPI_result < 0 )
- return (NULL);
-
- newplan = _SPI_copy_plan ((_SPI_plan *)plan, false);
-
- _SPI_curid--;
- SPI_result = 0;
-
- return ((void *)newplan);
-
+ _SPI_plan *newplan;
+
+ if (plan == NULL)
+ {
+ SPI_result = SPI_ERROR_ARGUMENT;
+ return (NULL);
+ }
+
+ SPI_result = _SPI_begin_call(false); /* don't change context */
+ if (SPI_result < 0)
+ return (NULL);
+
+ newplan = _SPI_copy_plan((_SPI_plan *) plan, false);
+
+ _SPI_curid--;
+ SPI_result = 0;
+
+ return ((void *) newplan);
+
}
int
-SPI_fnumber (TupleDesc tupdesc, char *fname)
+SPI_fnumber(TupleDesc tupdesc, char *fname)
{
- int res;
-
- if ( _SPI_curid + 1 != _SPI_connected )
- return (SPI_ERROR_UNCONNECTED);
-
- for (res = 0; res < tupdesc->natts; res++)
- {
- if ( strcmp (tupdesc->attrs[res]->attname.data, fname) == 0 )
- return (res + 1);
- }
-
- return (SPI_ERROR_NOATTRIBUTE);
+ int res;
+
+ if (_SPI_curid + 1 != _SPI_connected)
+ return (SPI_ERROR_UNCONNECTED);
+
+ for (res = 0; res < tupdesc->natts; res++)
+ {
+ if (strcmp(tupdesc->attrs[res]->attname.data, fname) == 0)
+ return (res + 1);
+ }
+
+ return (SPI_ERROR_NOATTRIBUTE);
}
-char *
-SPI_getvalue (HeapTuple tuple, TupleDesc tupdesc, int fnumber)
+char *
+SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
{
- char *val;
- bool isnull;
- Oid foutoid;
-
- SPI_result = 0;
- if ( _SPI_curid + 1 != _SPI_connected )
- {
- SPI_result = SPI_ERROR_UNCONNECTED;
- return (NULL);
- }
-
- if ( tuple->t_natts < fnumber || fnumber <= 0 )
- return (NULL);
-
- val = heap_getattr (tuple, InvalidBuffer, fnumber, tupdesc, &isnull);
- if ( isnull )
- return (NULL);
- foutoid = typtoout ((Oid) tupdesc->attrs[fnumber - 1]->atttypid);
- if ( !OidIsValid (foutoid) )
- {
- SPI_result = SPI_ERROR_NOOUTFUNC;
- return (NULL);
- }
-
- return (fmgr (foutoid, val, gettypelem (tupdesc->attrs[fnumber - 1]->atttypid)));
+ char *val;
+ bool isnull;
+ Oid foutoid;
+
+ SPI_result = 0;
+ if (_SPI_curid + 1 != _SPI_connected)
+ {
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ return (NULL);
+ }
+
+ if (tuple->t_natts < fnumber || fnumber <= 0)
+ return (NULL);
+
+ val = heap_getattr(tuple, InvalidBuffer, fnumber, tupdesc, &isnull);
+ if (isnull)
+ return (NULL);
+ foutoid = typtoout((Oid) tupdesc->attrs[fnumber - 1]->atttypid);
+ if (!OidIsValid(foutoid))
+ {
+ SPI_result = SPI_ERROR_NOOUTFUNC;
+ return (NULL);
+ }
+
+ return (fmgr(foutoid, val, gettypelem(tupdesc->attrs[fnumber - 1]->atttypid)));
}
-char *
-SPI_getbinval (HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
+char *
+SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool * isnull)
{
- char *val;
-
- *isnull = true;
- SPI_result = 0;
- if ( _SPI_curid + 1 != _SPI_connected )
- {
- SPI_result = SPI_ERROR_UNCONNECTED;
- return (NULL);
- }
-
- if ( tuple->t_natts < fnumber || fnumber <= 0 )
- return (NULL);
-
- val = heap_getattr (tuple, InvalidBuffer, fnumber, tupdesc, isnull);
-
- return (val);
+ char *val;
+
+ *isnull = true;
+ SPI_result = 0;
+ if (_SPI_curid + 1 != _SPI_connected)
+ {
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ return (NULL);
+ }
+
+ if (tuple->t_natts < fnumber || fnumber <= 0)
+ return (NULL);
+
+ val = heap_getattr(tuple, InvalidBuffer, fnumber, tupdesc, isnull);
+
+ return (val);
}
-char *
-SPI_gettype (TupleDesc tupdesc, int fnumber)
+char *
+SPI_gettype(TupleDesc tupdesc, int fnumber)
{
- HeapTuple typeTuple;
-
- SPI_result = 0;
- if ( _SPI_curid + 1 != _SPI_connected )
- {
- SPI_result = SPI_ERROR_UNCONNECTED;
- return (NULL);
- }
-
- if ( tupdesc->natts < fnumber || fnumber <= 0 )
- {
- SPI_result = SPI_ERROR_NOATTRIBUTE;
- return (NULL);
- }
-
- typeTuple = SearchSysCacheTuple (TYPOID,
- ObjectIdGetDatum (tupdesc->attrs[fnumber - 1]->atttypid),
- 0, 0, 0);
-
- if ( !HeapTupleIsValid (typeTuple) )
- {
- SPI_result = SPI_ERROR_TYPUNKNOWN;
- return (NULL);
- }
-
- return (pstrdup (((TypeTupleForm) GETSTRUCT (typeTuple))->typname.data));
+ HeapTuple typeTuple;
+
+ SPI_result = 0;
+ if (_SPI_curid + 1 != _SPI_connected)
+ {
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ return (NULL);
+ }
+
+ if (tupdesc->natts < fnumber || fnumber <= 0)
+ {
+ SPI_result = SPI_ERROR_NOATTRIBUTE;
+ return (NULL);
+ }
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(tupdesc->attrs[fnumber - 1]->atttypid),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(typeTuple))
+ {
+ SPI_result = SPI_ERROR_TYPUNKNOWN;
+ return (NULL);
+ }
+
+ return (pstrdup(((TypeTupleForm) GETSTRUCT(typeTuple))->typname.data));
}
Oid
-SPI_gettypeid (TupleDesc tupdesc, int fnumber)
+SPI_gettypeid(TupleDesc tupdesc, int fnumber)
{
-
- SPI_result = 0;
- if ( _SPI_curid + 1 != _SPI_connected )
- {
- SPI_result = SPI_ERROR_UNCONNECTED;
- return (InvalidOid);
- }
-
- if ( tupdesc->natts < fnumber || fnumber <= 0 )
- {
- SPI_result = SPI_ERROR_NOATTRIBUTE;
- return (InvalidOid);
- }
-
- return (tupdesc->attrs[fnumber - 1]->atttypid);
+
+ SPI_result = 0;
+ if (_SPI_curid + 1 != _SPI_connected)
+ {
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ return (InvalidOid);
+ }
+
+ if (tupdesc->natts < fnumber || fnumber <= 0)
+ {
+ SPI_result = SPI_ERROR_NOATTRIBUTE;
+ return (InvalidOid);
+ }
+
+ return (tupdesc->attrs[fnumber - 1]->atttypid);
}
-char *
-SPI_getrelname (Relation rel)
+char *
+SPI_getrelname(Relation rel)
{
-
- SPI_result = 0;
- if ( _SPI_curid + 1 != _SPI_connected )
- {
- SPI_result = SPI_ERROR_UNCONNECTED;
- return (NULL);
- }
-
- return (pstrdup (rel->rd_rel->relname.data));
+
+ SPI_result = 0;
+ if (_SPI_curid + 1 != _SPI_connected)
+ {
+ SPI_result = SPI_ERROR_UNCONNECTED;
+ return (NULL);
+ }
+
+ return (pstrdup(rel->rd_rel->relname.data));
}
/*
* spi_printtup --
- * store tuple retrieved by Executor into SPITupleTable
- * of current SPI procedure
+ * store tuple retrieved by Executor into SPITupleTable
+ * of current SPI procedure
*
*/
void
-spi_printtup (HeapTuple tuple, TupleDesc tupdesc)
+spi_printtup(HeapTuple tuple, TupleDesc tupdesc)
{
- SPITupleTable *tuptable;
- MemoryContext oldcxt;
-
- /*
- * When called by Executor _SPI_curid expected to be
- * equal to _SPI_connected
- */
- if ( _SPI_curid != _SPI_connected || _SPI_connected < 0 )
- elog (FATAL, "SPI: improper call to spi_printtup");
- if ( _SPI_current != &(_SPI_stack[_SPI_curid]) )
- elog (FATAL, "SPI: stack corrupted in spi_printtup");
-
- oldcxt = _SPI_procmem (); /* switch to procedure memory context */
-
- tuptable = _SPI_current->tuptable;
- if ( tuptable == NULL )
- {
- _SPI_current->tuptable = tuptable = (SPITupleTable *)
- palloc (sizeof (SPITupleTable));
- tuptable->alloced = tuptable->free = 128;
- tuptable->vals = (HeapTuple *) palloc (tuptable->alloced * sizeof (HeapTuple));
- tuptable->tupdesc = CreateTupleDescCopy (tupdesc);
- }
- else if ( tuptable->free == 0 )
- {
- tuptable->free = 256;
- tuptable->alloced += tuptable->free;
- tuptable->vals = (HeapTuple *) repalloc (tuptable->vals,
- tuptable->alloced * sizeof (HeapTuple));
- }
-
- tuptable->vals[tuptable->alloced - tuptable->free] = heap_copytuple (tuple);
- (tuptable->free)--;
-
- MemoryContextSwitchTo (oldcxt);
- return;
+ SPITupleTable *tuptable;
+ MemoryContext oldcxt;
+
+ /*
+ * When called by Executor _SPI_curid expected to be equal to
+ * _SPI_connected
+ */
+ if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
+ elog(FATAL, "SPI: improper call to spi_printtup");
+ if (_SPI_current != &(_SPI_stack[_SPI_curid]))
+ elog(FATAL, "SPI: stack corrupted in spi_printtup");
+
+ oldcxt = _SPI_procmem(); /* switch to procedure memory context */
+
+ tuptable = _SPI_current->tuptable;
+ if (tuptable == NULL)
+ {
+ _SPI_current->tuptable = tuptable = (SPITupleTable *)
+ palloc(sizeof(SPITupleTable));
+ tuptable->alloced = tuptable->free = 128;
+ tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
+ tuptable->tupdesc = CreateTupleDescCopy(tupdesc);
+ }
+ else if (tuptable->free == 0)
+ {
+ tuptable->free = 256;
+ tuptable->alloced += tuptable->free;
+ tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
+ tuptable->alloced * sizeof(HeapTuple));
+ }
+
+ tuptable->vals[tuptable->alloced - tuptable->free] = heap_copytuple(tuple);
+ (tuptable->free)--;
+
+ MemoryContextSwitchTo(oldcxt);
+ return;
}
/*
@@ -450,330 +457,334 @@ spi_printtup (HeapTuple tuple, TupleDesc tupdesc)
*/
static int
-_SPI_execute (char *src, int tcount, _SPI_plan *plan)
+_SPI_execute(char *src, int tcount, _SPI_plan * plan)
{
- QueryTreeList *queryTree_list;
- List *planTree_list;
- List *ptlist;
- QueryDesc *qdesc;
- Query *queryTree;
- Plan *planTree;
- EState *state;
- int qlen;
- int nargs = 0;
- Oid *argtypes = NULL;
- int res;
- int i;
-
- /* Increment CommandCounter to see changes made by now */
- CommandCounterIncrement ();
-
- SPI_processed = 0;
- SPI_tuptable = NULL;
- _SPI_current->tuptable = NULL;
- _SPI_current->qtlist = NULL;
-
- if ( plan )
- {
- nargs = plan->nargs;
- argtypes = plan->argtypes;
- }
- ptlist = planTree_list = (List *)
- pg_plan (src, argtypes, nargs, &queryTree_list, None);
-
- _SPI_current->qtlist = queryTree_list;
-
- qlen = queryTree_list->len;
- for (i=0; ;i++)
- {
- queryTree = (Query*) (queryTree_list->qtrees[i]);
- planTree = lfirst(planTree_list);
-
- planTree_list = lnext (planTree_list);
-
- if ( queryTree->commandType == CMD_UTILITY )
- {
- if ( nodeTag (queryTree->utilityStmt ) == T_CopyStmt )
- {
- CopyStmt *stmt = (CopyStmt *)(queryTree->utilityStmt);
-
- if ( stmt->filename == NULL )
- return (SPI_ERROR_COPY);
- }
- else if ( nodeTag (queryTree->utilityStmt ) == T_ClosePortalStmt ||
- nodeTag (queryTree->utilityStmt ) == T_FetchStmt )
- return (SPI_ERROR_CURSOR);
- else if ( nodeTag (queryTree->utilityStmt ) == T_TransactionStmt )
- return (SPI_ERROR_TRANSACTION);
- res = SPI_OK_UTILITY;
- if ( plan == NULL )
- {
- ProcessUtility (queryTree->utilityStmt, None);
- if ( i < qlen - 1 )
- CommandCounterIncrement ();
- else
- return (res);
- }
- else if ( i >= qlen - 1 )
- break;
- }
- else if ( plan == NULL )
- {
- qdesc = CreateQueryDesc (queryTree, planTree,
- ( i < qlen - 1 ) ? None : SPI);
- state = CreateExecutorState();
- res = _SPI_pquery (qdesc, state, ( i < qlen - 1 ) ? 0 : tcount);
- if ( res < 0 || i >= qlen - 1 )
- return (res);
- CommandCounterIncrement ();
+ QueryTreeList *queryTree_list;
+ List *planTree_list;
+ List *ptlist;
+ QueryDesc *qdesc;
+ Query *queryTree;
+ Plan *planTree;
+ EState *state;
+ int qlen;
+ int nargs = 0;
+ Oid *argtypes = NULL;
+ int res;
+ int i;
+
+ /* Increment CommandCounter to see changes made by now */
+ CommandCounterIncrement();
+
+ SPI_processed = 0;
+ SPI_tuptable = NULL;
+ _SPI_current->tuptable = NULL;
+ _SPI_current->qtlist = NULL;
+
+ if (plan)
+ {
+ nargs = plan->nargs;
+ argtypes = plan->argtypes;
}
- else
+ ptlist = planTree_list = (List *)
+ pg_plan(src, argtypes, nargs, &queryTree_list, None);
+
+ _SPI_current->qtlist = queryTree_list;
+
+ qlen = queryTree_list->len;
+ for (i = 0;; i++)
{
- qdesc = CreateQueryDesc (queryTree, planTree,
- ( i < qlen - 1 ) ? None : SPI);
- res = _SPI_pquery (qdesc, NULL, ( i < qlen - 1 ) ? 0 : tcount);
- if ( res < 0 )
- return (res);
- if ( i >= qlen - 1 )
- break;
- }
- }
-
- plan->qtlist = queryTree_list;
- plan->ptlist = ptlist;
-
- return (res);
-
+ queryTree = (Query *) (queryTree_list->qtrees[i]);
+ planTree = lfirst(planTree_list);
+
+ planTree_list = lnext(planTree_list);
+
+ if (queryTree->commandType == CMD_UTILITY)
+ {
+ if (nodeTag(queryTree->utilityStmt) == T_CopyStmt)
+ {
+ CopyStmt *stmt = (CopyStmt *) (queryTree->utilityStmt);
+
+ if (stmt->filename == NULL)
+ return (SPI_ERROR_COPY);
+ }
+ else if (nodeTag(queryTree->utilityStmt) == T_ClosePortalStmt ||
+ nodeTag(queryTree->utilityStmt) == T_FetchStmt)
+ return (SPI_ERROR_CURSOR);
+ else if (nodeTag(queryTree->utilityStmt) == T_TransactionStmt)
+ return (SPI_ERROR_TRANSACTION);
+ res = SPI_OK_UTILITY;
+ if (plan == NULL)
+ {
+ ProcessUtility(queryTree->utilityStmt, None);
+ if (i < qlen - 1)
+ CommandCounterIncrement();
+ else
+ return (res);
+ }
+ else if (i >= qlen - 1)
+ break;
+ }
+ else if (plan == NULL)
+ {
+ qdesc = CreateQueryDesc(queryTree, planTree,
+ (i < qlen - 1) ? None : SPI);
+ state = CreateExecutorState();
+ res = _SPI_pquery(qdesc, state, (i < qlen - 1) ? 0 : tcount);
+ if (res < 0 || i >= qlen - 1)
+ return (res);
+ CommandCounterIncrement();
+ }
+ else
+ {
+ qdesc = CreateQueryDesc(queryTree, planTree,
+ (i < qlen - 1) ? None : SPI);
+ res = _SPI_pquery(qdesc, NULL, (i < qlen - 1) ? 0 : tcount);
+ if (res < 0)
+ return (res);
+ if (i >= qlen - 1)
+ break;
+ }
+ }
+
+ plan->qtlist = queryTree_list;
+ plan->ptlist = ptlist;
+
+ return (res);
+
}
static int
-_SPI_execute_plan (_SPI_plan *plan, char **Values, char *Nulls, int tcount)
+_SPI_execute_plan(_SPI_plan * plan, char **Values, char *Nulls, int tcount)
{
- QueryTreeList *queryTree_list = plan->qtlist;
- List *planTree_list = plan->ptlist;
- QueryDesc *qdesc;
- Query *queryTree;
- Plan *planTree;
- EState *state;
- int nargs = plan->nargs;
- int qlen = queryTree_list->len;
- int res;
- int i, k;
-
- /* Increment CommandCounter to see changes made by now */
- CommandCounterIncrement ();
-
- SPI_processed = 0;
- SPI_tuptable = NULL;
- _SPI_current->tuptable = NULL;
- _SPI_current->qtlist = NULL;
-
- for (i=0; ;i++)
- {
- queryTree = (Query*) (queryTree_list->qtrees[i]);
- planTree = lfirst(planTree_list);
-
- planTree_list = lnext (planTree_list);
-
- if ( queryTree->commandType == CMD_UTILITY )
- {
- ProcessUtility (queryTree->utilityStmt, None);
- if ( i < qlen - 1 )
- CommandCounterIncrement ();
- else
- return (SPI_OK_UTILITY);
- }
- else
+ QueryTreeList *queryTree_list = plan->qtlist;
+ List *planTree_list = plan->ptlist;
+ QueryDesc *qdesc;
+ Query *queryTree;
+ Plan *planTree;
+ EState *state;
+ int nargs = plan->nargs;
+ int qlen = queryTree_list->len;
+ int res;
+ int i,
+ k;
+
+ /* Increment CommandCounter to see changes made by now */
+ CommandCounterIncrement();
+
+ SPI_processed = 0;
+ SPI_tuptable = NULL;
+ _SPI_current->tuptable = NULL;
+ _SPI_current->qtlist = NULL;
+
+ for (i = 0;; i++)
{
- qdesc = CreateQueryDesc (queryTree, planTree,
- ( i < qlen - 1 ) ? None : SPI);
- state = CreateExecutorState();
- if ( nargs > 0 )
- {
- ParamListInfo paramLI = (ParamListInfo) palloc ((nargs + 1) *
- sizeof (ParamListInfoData));
- state->es_param_list_info = paramLI;
- for (k = 0; k < plan->nargs; paramLI++, k++)
- {
- paramLI->kind = PARAM_NUM;
- paramLI->id = k+1;
- paramLI->isnull = (Nulls[k] != 0);
- paramLI->value = (Datum) Values[k];
- }
- paramLI->kind = PARAM_INVALID;
- }
- else
- state->es_param_list_info = NULL;
- res = _SPI_pquery (qdesc, state, ( i < qlen - 1 ) ? 0 : tcount);
- if ( res < 0 || i >= qlen - 1 )
- return (res);
- CommandCounterIncrement ();
- }
- }
-
- return (res);
-
+ queryTree = (Query *) (queryTree_list->qtrees[i]);
+ planTree = lfirst(planTree_list);
+
+ planTree_list = lnext(planTree_list);
+
+ if (queryTree->commandType == CMD_UTILITY)
+ {
+ ProcessUtility(queryTree->utilityStmt, None);
+ if (i < qlen - 1)
+ CommandCounterIncrement();
+ else
+ return (SPI_OK_UTILITY);
+ }
+ else
+ {
+ qdesc = CreateQueryDesc(queryTree, planTree,
+ (i < qlen - 1) ? None : SPI);
+ state = CreateExecutorState();
+ if (nargs > 0)
+ {
+ ParamListInfo paramLI = (ParamListInfo) palloc((nargs + 1) *
+ sizeof(ParamListInfoData));
+
+ state->es_param_list_info = paramLI;
+ for (k = 0; k < plan->nargs; paramLI++, k++)
+ {
+ paramLI->kind = PARAM_NUM;
+ paramLI->id = k + 1;
+ paramLI->isnull = (Nulls[k] != 0);
+ paramLI->value = (Datum) Values[k];
+ }
+ paramLI->kind = PARAM_INVALID;
+ }
+ else
+ state->es_param_list_info = NULL;
+ res = _SPI_pquery(qdesc, state, (i < qlen - 1) ? 0 : tcount);
+ if (res < 0 || i >= qlen - 1)
+ return (res);
+ CommandCounterIncrement();
+ }
+ }
+
+ return (res);
+
}
static int
-_SPI_pquery (QueryDesc *queryDesc, EState *state, int tcount)
+_SPI_pquery(QueryDesc * queryDesc, EState * state, int tcount)
{
- Query *parseTree;
- Plan *plan;
- int operation;
- TupleDesc tupdesc;
- bool isRetrieveIntoPortal = false;
- bool isRetrieveIntoRelation = false;
- char* intoName = NULL;
- int res;
-
- parseTree = queryDesc->parsetree;
- plan = queryDesc->plantree;
- operation = queryDesc->operation;
-
- switch (operation)
- {
- case CMD_SELECT:
- res = SPI_OK_SELECT;
- if (parseTree->isPortal)
- {
- isRetrieveIntoPortal = true;
- intoName = parseTree->into;
- parseTree->isBinary = false; /* */
-
- return (SPI_ERROR_CURSOR);
-
- }
- else if (parseTree->into != NULL) /* select into table */
- {
- res = SPI_OK_SELINTO;
- isRetrieveIntoRelation = true;
- }
- break;
- case CMD_INSERT:
- res = SPI_OK_INSERT;
- break;
- case CMD_DELETE:
- res = SPI_OK_DELETE;
- break;
- case CMD_UPDATE:
- res = SPI_OK_UPDATE;
- break;
- default:
- return (SPI_ERROR_OPUNKNOWN);
- }
-
- if ( state == NULL ) /* plan preparation */
- return (res);
+ Query *parseTree;
+ Plan *plan;
+ int operation;
+ TupleDesc tupdesc;
+ bool isRetrieveIntoPortal = false;
+ bool isRetrieveIntoRelation = false;
+ char *intoName = NULL;
+ int res;
+
+ parseTree = queryDesc->parsetree;
+ plan = queryDesc->plantree;
+ operation = queryDesc->operation;
+
+ switch (operation)
+ {
+ case CMD_SELECT:
+ res = SPI_OK_SELECT;
+ if (parseTree->isPortal)
+ {
+ isRetrieveIntoPortal = true;
+ intoName = parseTree->into;
+ parseTree->isBinary = false; /* */
+
+ return (SPI_ERROR_CURSOR);
+
+ }
+ else if (parseTree->into != NULL) /* select into table */
+ {
+ res = SPI_OK_SELINTO;
+ isRetrieveIntoRelation = true;
+ }
+ break;
+ case CMD_INSERT:
+ res = SPI_OK_INSERT;
+ break;
+ case CMD_DELETE:
+ res = SPI_OK_DELETE;
+ break;
+ case CMD_UPDATE:
+ res = SPI_OK_UPDATE;
+ break;
+ default:
+ return (SPI_ERROR_OPUNKNOWN);
+ }
+
+ if (state == NULL) /* plan preparation */
+ return (res);
#ifdef SPI_EXECUTOR_STATS
- if ( ShowExecutorStats )
- ResetUsage ();
+ if (ShowExecutorStats)
+ ResetUsage();
#endif
- tupdesc = ExecutorStart (queryDesc, state);
-
- /* Don't work currently */
- if (isRetrieveIntoPortal)
- {
- ProcessPortal(intoName,
- parseTree,
- plan,
- state,
- tupdesc,
- None);
- return (SPI_OK_CURSOR);
- }
-
- ExecutorRun (queryDesc, state, EXEC_RUN, tcount);
-
- _SPI_current->processed = state->es_processed;
- if ( operation == CMD_SELECT && queryDesc->dest == SPI )
- {
- if ( _SPI_checktuples (isRetrieveIntoRelation) )
- elog (FATAL, "SPI_select: # of processed tuples check failed");
- }
-
- ExecutorEnd (queryDesc, state);
-
+ tupdesc = ExecutorStart(queryDesc, state);
+
+ /* Don't work currently */
+ if (isRetrieveIntoPortal)
+ {
+ ProcessPortal(intoName,
+ parseTree,
+ plan,
+ state,
+ tupdesc,
+ None);
+ return (SPI_OK_CURSOR);
+ }
+
+ ExecutorRun(queryDesc, state, EXEC_RUN, tcount);
+
+ _SPI_current->processed = state->es_processed;
+ if (operation == CMD_SELECT && queryDesc->dest == SPI)
+ {
+ if (_SPI_checktuples(isRetrieveIntoRelation))
+ elog(FATAL, "SPI_select: # of processed tuples check failed");
+ }
+
+ ExecutorEnd(queryDesc, state);
+
#ifdef SPI_EXECUTOR_STATS
- if ( ShowExecutorStats )
- {
- fprintf (stderr, "! Executor Stats:\n");
- ShowUsage ();
- }
+ if (ShowExecutorStats)
+ {
+ fprintf(stderr, "! Executor Stats:\n");
+ ShowUsage();
+ }
#endif
-
- if ( queryDesc->dest == SPI )
- {
- SPI_processed = _SPI_current->processed;
- SPI_tuptable = _SPI_current->tuptable;
- }
-
- return (res);
+
+ if (queryDesc->dest == SPI)
+ {
+ SPI_processed = _SPI_current->processed;
+ SPI_tuptable = _SPI_current->tuptable;
+ }
+
+ return (res);
}
#if 0
static void
-_SPI_fetch (FetchStmt *stmt)
+_SPI_fetch(FetchStmt * stmt)
{
- char *name = stmt->portalname;
- int feature = ( stmt->direction == FORWARD ) ? EXEC_FOR : EXEC_BACK;
- int count = stmt->howMany;
- Portal portal;
- QueryDesc *queryDesc;
- EState *state;
- MemoryContext context;
-
- if ( name == NULL)
- elog (FATAL, "SPI_fetch from blank portal unsupported");
-
- portal = GetPortalByName (name);
- if ( !PortalIsValid (portal) )
- elog (FATAL, "SPI_fetch: portal \"%s\" not found", name);
-
- context = MemoryContextSwitchTo((MemoryContext)PortalGetHeapMemory(portal));
-
- queryDesc = PortalGetQueryDesc(portal);
- state = PortalGetState(portal);
-
- ExecutorRun(queryDesc, state, feature, count);
-
- MemoryContextSwitchTo (context); /* switch to the normal Executor context */
-
- _SPI_current->processed = state->es_processed;
- if ( _SPI_checktuples (false) )
- elog (FATAL, "SPI_fetch: # of processed tuples check failed");
-
- SPI_processed = _SPI_current->processed;
- SPI_tuptable = _SPI_current->tuptable;
-
+ char *name = stmt->portalname;
+ int feature = (stmt->direction == FORWARD) ? EXEC_FOR : EXEC_BACK;
+ int count = stmt->howMany;
+ Portal portal;
+ QueryDesc *queryDesc;
+ EState *state;
+ MemoryContext context;
+
+ if (name == NULL)
+ elog(FATAL, "SPI_fetch from blank portal unsupported");
+
+ portal = GetPortalByName(name);
+ if (!PortalIsValid(portal))
+ elog(FATAL, "SPI_fetch: portal \"%s\" not found", name);
+
+ context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
+
+ queryDesc = PortalGetQueryDesc(portal);
+ state = PortalGetState(portal);
+
+ ExecutorRun(queryDesc, state, feature, count);
+
+ MemoryContextSwitchTo(context); /* switch to the normal Executor
+ * context */
+
+ _SPI_current->processed = state->es_processed;
+ if (_SPI_checktuples(false))
+ elog(FATAL, "SPI_fetch: # of processed tuples check failed");
+
+ SPI_processed = _SPI_current->processed;
+ SPI_tuptable = _SPI_current->tuptable;
+
}
+
#endif
-static MemoryContext
-_SPI_execmem ()
+static MemoryContext
+_SPI_execmem()
{
- MemoryContext oldcxt;
- PortalHeapMemory phmem;
-
- phmem = PortalGetHeapMemory (_SPI_current->portal);
- oldcxt = MemoryContextSwitchTo ((MemoryContext)phmem);
-
- return (oldcxt);
-
+ MemoryContext oldcxt;
+ PortalHeapMemory phmem;
+
+ phmem = PortalGetHeapMemory(_SPI_current->portal);
+ oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
+
+ return (oldcxt);
+
}
-static MemoryContext
-_SPI_procmem ()
+static MemoryContext
+_SPI_procmem()
{
- MemoryContext oldcxt;
- PortalVariableMemory pvmem;
-
- pvmem = PortalGetVariableMemory (_SPI_current->portal);
- oldcxt = MemoryContextSwitchTo ((MemoryContext)pvmem);
-
- return (oldcxt);
-
+ MemoryContext oldcxt;
+ PortalVariableMemory pvmem;
+
+ pvmem = PortalGetVariableMemory(_SPI_current->portal);
+ oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
+
+ return (oldcxt);
+
}
/*
@@ -781,108 +792,110 @@ _SPI_procmem ()
*
*/
static int
-_SPI_begin_call (bool execmem)
+_SPI_begin_call(bool execmem)
{
- if ( _SPI_curid + 1 != _SPI_connected )
- return (SPI_ERROR_UNCONNECTED);
- _SPI_curid++;
- if ( _SPI_current != &(_SPI_stack[_SPI_curid]) )
- elog (FATAL, "SPI: stack corrupted");
-
- if ( execmem ) /* switch to the Executor memory context */
- {
- _SPI_execmem ();
- StartPortalAllocMode (DefaultAllocMode, 0);
- }
-
- return (0);
+ if (_SPI_curid + 1 != _SPI_connected)
+ return (SPI_ERROR_UNCONNECTED);
+ _SPI_curid++;
+ if (_SPI_current != &(_SPI_stack[_SPI_curid]))
+ elog(FATAL, "SPI: stack corrupted");
+
+ if (execmem) /* switch to the Executor memory context */
+ {
+ _SPI_execmem();
+ StartPortalAllocMode(DefaultAllocMode, 0);
+ }
+
+ return (0);
}
static int
-_SPI_end_call (bool procmem)
+_SPI_end_call(bool procmem)
{
- /*
- * We' returning to procedure where _SPI_curid == _SPI_connected - 1
- */
- _SPI_curid--;
-
- if ( _SPI_current->qtlist) /* free _SPI_plan allocations */
- {
- free (_SPI_current->qtlist->qtrees);
- free (_SPI_current->qtlist);
- _SPI_current->qtlist = NULL;
- }
-
- if ( procmem ) /* switch to the procedure memory context */
- { /* but free Executor memory before */
- EndPortalAllocMode ();
- _SPI_procmem ();
- }
-
- return (0);
+
+ /*
+ * We' returning to procedure where _SPI_curid == _SPI_connected - 1
+ */
+ _SPI_curid--;
+
+ if (_SPI_current->qtlist) /* free _SPI_plan allocations */
+ {
+ free(_SPI_current->qtlist->qtrees);
+ free(_SPI_current->qtlist);
+ _SPI_current->qtlist = NULL;
+ }
+
+ if (procmem) /* switch to the procedure memory context */
+ { /* but free Executor memory before */
+ EndPortalAllocMode();
+ _SPI_procmem();
+ }
+
+ return (0);
}
-static bool
-_SPI_checktuples (bool isRetrieveIntoRelation)
+static bool
+_SPI_checktuples(bool isRetrieveIntoRelation)
{
- uint32 processed = _SPI_current->processed;
- SPITupleTable *tuptable = _SPI_current->tuptable;
- bool failed = false;
-
- if ( processed == 0 )
- {
- if ( tuptable != NULL )
- failed = true;
- }
- else /* some tuples were processed */
- {
- if ( tuptable == NULL ) /* spi_printtup was not called */
- {
- if ( !isRetrieveIntoRelation )
- failed = true;
- }
- else if ( isRetrieveIntoRelation )
- failed = true;
- else if ( processed != ( tuptable->alloced - tuptable->free ) )
- failed = true;
- }
-
- return (failed);
+ uint32 processed = _SPI_current->processed;
+ SPITupleTable *tuptable = _SPI_current->tuptable;
+ bool failed = false;
+
+ if (processed == 0)
+ {
+ if (tuptable != NULL)
+ failed = true;
+ }
+ else
+/* some tuples were processed */
+ {
+ if (tuptable == NULL) /* spi_printtup was not called */
+ {
+ if (!isRetrieveIntoRelation)
+ failed = true;
+ }
+ else if (isRetrieveIntoRelation)
+ failed = true;
+ else if (processed != (tuptable->alloced - tuptable->free))
+ failed = true;
+ }
+
+ return (failed);
}
-
+
static _SPI_plan *
-_SPI_copy_plan (_SPI_plan *plan, bool local)
+_SPI_copy_plan(_SPI_plan * plan, bool local)
{
- _SPI_plan *newplan;
- MemoryContext oldcxt;
- int i;
-
- if ( local )
- oldcxt = MemoryContextSwitchTo ((MemoryContext)
- PortalGetVariableMemory (_SPI_current->portal));
- else
- oldcxt = MemoryContextSwitchTo (TopMemoryContext);
-
- newplan = (_SPI_plan *) palloc (sizeof (_SPI_plan));
- newplan->qtlist = (QueryTreeList*) palloc (sizeof (QueryTreeList));
- newplan->qtlist->len = plan->qtlist->len;
- newplan->qtlist->qtrees = (Query**) palloc (plan->qtlist->len *
- sizeof (Query*));
- for (i = 0; i < plan->qtlist->len; i++)
- newplan->qtlist->qtrees[i] = (Query *)
- copyObject (plan->qtlist->qtrees[i]);
-
- newplan->ptlist = (List *) copyObject (plan->ptlist);
- newplan->nargs = plan->nargs;
- if ( plan->nargs > 0 )
- {
- newplan->argtypes = (Oid *) palloc (plan->nargs * sizeof (Oid));
- memcpy (newplan->argtypes, plan->argtypes, plan->nargs * sizeof (Oid));
- }
- else
- newplan->argtypes = NULL;
-
- MemoryContextSwitchTo (oldcxt);
-
- return (newplan);
+ _SPI_plan *newplan;
+ MemoryContext oldcxt;
+ int i;
+
+ if (local)
+ oldcxt = MemoryContextSwitchTo((MemoryContext)
+ PortalGetVariableMemory(_SPI_current->portal));
+ else
+ oldcxt = MemoryContextSwitchTo(TopMemoryContext);
+
+ newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
+ newplan->qtlist = (QueryTreeList *) palloc(sizeof(QueryTreeList));
+ newplan->qtlist->len = plan->qtlist->len;
+ newplan->qtlist->qtrees = (Query **) palloc(plan->qtlist->len *
+ sizeof(Query *));
+ for (i = 0; i < plan->qtlist->len; i++)
+ newplan->qtlist->qtrees[i] = (Query *)
+ copyObject(plan->qtlist->qtrees[i]);
+
+ newplan->ptlist = (List *) copyObject(plan->ptlist);
+ newplan->nargs = plan->nargs;
+ if (plan->nargs > 0)
+ {
+ newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
+ memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
+ }
+ else
+ newplan->argtypes = NULL;
+
+ MemoryContextSwitchTo(oldcxt);
+
+ return (newplan);
}
diff --git a/src/backend/lib/bit.c b/src/backend/lib/bit.c
index 680f349a520..439566c0b75 100644
--- a/src/backend/lib/bit.c
+++ b/src/backend/lib/bit.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* bit.c--
- * Standard bit array code.
+ * Standard bit array code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/lib/Attic/bit.c,v 1.4 1996/11/06 08:27:09 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/lib/Attic/bit.c,v 1.5 1997/09/07 04:41:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,27 +22,26 @@
void
BitArraySetBit(BitArray bitArray, BitIndex bitIndex)
-{
- bitArray[bitIndex/BitsPerByte]
+{
+ bitArray[bitIndex / BitsPerByte]
|= (1 << (BitsPerByte - (bitIndex % BitsPerByte) - 1));
- return;
+ return;
}
void
BitArrayClearBit(BitArray bitArray, BitIndex bitIndex)
{
- bitArray[bitIndex/BitsPerByte]
+ bitArray[bitIndex / BitsPerByte]
&= ~(1 << (BitsPerByte - (bitIndex % BitsPerByte) - 1));
- return;
+ return;
}
bool
BitArrayBitIsSet(BitArray bitArray, BitIndex bitIndex)
-{
- return( (bool) (((bitArray[bitIndex / BitsPerByte] &
- (1 << (BitsPerByte - (bitIndex % BitsPerByte)
- - 1)
- )
- ) != 0 ) ? 1 : 0) );
+{
+ return ((bool) (((bitArray[bitIndex / BitsPerByte] &
+ (1 << (BitsPerByte - (bitIndex % BitsPerByte)
+ - 1)
+ )
+ ) != 0) ? 1 : 0));
}
-
diff --git a/src/backend/lib/dllist.c b/src/backend/lib/dllist.c
index b8dd14a231b..70feee02bb9 100644
--- a/src/backend/lib/dllist.c
+++ b/src/backend/lib/dllist.c
@@ -1,15 +1,15 @@
/*-------------------------------------------------------------------------
*
* dllist.c--
- * this is a simple doubly linked list implementation
- * replaces the old simplelists stuff
- * the elements of the lists are void*
+ * this is a simple doubly linked list implementation
+ * replaces the old simplelists stuff
+ * the elements of the lists are void*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/lib/dllist.c,v 1.5 1997/08/19 21:31:16 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/lib/dllist.c,v 1.6 1997/09/07 04:41:56 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,191 +18,197 @@
#include <lib/dllist.h>
-Dllist*
+Dllist *
DLNewList(void)
{
- Dllist* l;
+ Dllist *l;
- l = malloc(sizeof(Dllist));
- l->dll_head = 0;
- l->dll_tail = 0;
+ l = malloc(sizeof(Dllist));
+ l->dll_head = 0;
+ l->dll_tail = 0;
- return l;
+ return l;
}
- /* free up a list and all the nodes in it*/
+ /* free up a list and all the nodes in it */
void
-DLFreeList(Dllist* l)
+DLFreeList(Dllist * l)
{
- Dlelem* curr;
+ Dlelem *curr;
- while ( (curr = DLRemHead(l)) != 0)
- free(curr);
+ while ((curr = DLRemHead(l)) != 0)
+ free(curr);
- free(l);
+ free(l);
}
-Dlelem*
-DLNewElem(void* val)
+Dlelem *
+DLNewElem(void *val)
{
- Dlelem* e;
- e = malloc(sizeof(Dlelem));
- e->dle_next = 0;
- e->dle_prev = 0;
- e->dle_val = val;
- e->dle_list = 0;
- return e;
+ Dlelem *e;
+
+ e = malloc(sizeof(Dlelem));
+ e->dle_next = 0;
+ e->dle_prev = 0;
+ e->dle_val = val;
+ e->dle_list = 0;
+ return e;
}
void
-DLFreeElem(Dlelem* e)
+DLFreeElem(Dlelem * e)
{
- free(e);
+ free(e);
}
-Dlelem*
-DLGetHead(Dllist* l)
+Dlelem *
+DLGetHead(Dllist * l)
{
- return (l ? l->dll_head : 0);
+ return (l ? l->dll_head : 0);
}
/* get the value stored in the first element */
#ifdef NOT_USED
-void*
-DLGetHeadVal(Dllist* l)
+void *
+DLGetHeadVal(Dllist * l)
{
- Dlelem* e = DLGetHead(l);
-
- return (e ? e->dle_val : 0);
+ Dlelem *e = DLGetHead(l);
+
+ return (e ? e->dle_val : 0);
}
+
#endif
-Dlelem*
-DLGetTail(Dllist* l)
+Dlelem *
+DLGetTail(Dllist * l)
{
- return (l ? l->dll_tail : 0);
+ return (l ? l->dll_tail : 0);
}
/* get the value stored in the first element */
#ifdef NOT_USED
-void*
-DLGetTailVal(Dllist* l)
+void *
+DLGetTailVal(Dllist * l)
{
- Dlelem* e = DLGetTail(l);
-
- return (e ? e->dle_val : 0);
+ Dlelem *e = DLGetTail(l);
+
+ return (e ? e->dle_val : 0);
}
+
#endif
-Dlelem*
-DLGetPred(Dlelem* e) /* get predecessor */
+Dlelem *
+DLGetPred(Dlelem * e) /* get predecessor */
{
- return (e ? e->dle_prev : 0);
+ return (e ? e->dle_prev : 0);
}
-Dlelem*
-DLGetSucc(Dlelem* e) /* get successor */
+Dlelem *
+DLGetSucc(Dlelem * e) /* get successor */
{
- return (e ? e->dle_next : 0);
+ return (e ? e->dle_next : 0);
}
void
-DLRemove(Dlelem* e)
+DLRemove(Dlelem * e)
{
- Dllist* l;
+ Dllist *l;
- if (e->dle_prev)
- e->dle_prev->dle_next = e->dle_next;
- if (e->dle_next)
- e->dle_next->dle_prev = e->dle_prev;
+ if (e->dle_prev)
+ e->dle_prev->dle_next = e->dle_next;
+ if (e->dle_next)
+ e->dle_next->dle_prev = e->dle_prev;
- /* check to see if we're removing the head or tail */
- l = e->dle_list;
- if (e == l->dll_head)
- DLRemHead(l);
- if (e == l->dll_tail)
- DLRemTail(l);
+ /* check to see if we're removing the head or tail */
+ l = e->dle_list;
+ if (e == l->dll_head)
+ DLRemHead(l);
+ if (e == l->dll_tail)
+ DLRemTail(l);
}
-void
-DLAddHead(Dllist* l, Dlelem* e)
+void
+DLAddHead(Dllist * l, Dlelem * e)
{
- e->dle_list = l;
-
- if (l->dll_head) {
- l->dll_head->dle_prev = e;
- e->dle_next = l->dll_head;
- }
- e->dle_prev = 0;
- l->dll_head = e;
-
- if (l->dll_tail == 0) /* if this is first element added */
- l->dll_tail = l->dll_head;
+ e->dle_list = l;
+
+ if (l->dll_head)
+ {
+ l->dll_head->dle_prev = e;
+ e->dle_next = l->dll_head;
+ }
+ e->dle_prev = 0;
+ l->dll_head = e;
+
+ if (l->dll_tail == 0) /* if this is first element added */
+ l->dll_tail = l->dll_head;
}
void
-DLAddTail(Dllist* l, Dlelem* e)
+DLAddTail(Dllist * l, Dlelem * e)
{
- e->dle_list = l;
-
- if (l->dll_tail) {
- l->dll_tail->dle_next = e;
- e->dle_prev = l->dll_tail;
- }
- e->dle_next = 0;
- l->dll_tail = e;
-
- if (l->dll_head == 0) /* if this is first element added */
- l->dll_head = l->dll_tail;
+ e->dle_list = l;
+
+ if (l->dll_tail)
+ {
+ l->dll_tail->dle_next = e;
+ e->dle_prev = l->dll_tail;
+ }
+ e->dle_next = 0;
+ l->dll_tail = e;
+
+ if (l->dll_head == 0) /* if this is first element added */
+ l->dll_head = l->dll_tail;
}
-Dlelem*
-DLRemHead(Dllist* l)
+Dlelem *
+DLRemHead(Dllist * l)
{
- /* remove and return the head */
- Dlelem* result;
+ /* remove and return the head */
+ Dlelem *result;
- if (l->dll_head == 0)
- return 0;
+ if (l->dll_head == 0)
+ return 0;
- result = l->dll_head;
- if (l->dll_head->dle_next) {
- l->dll_head->dle_next->dle_prev = 0;
- }
+ result = l->dll_head;
+ if (l->dll_head->dle_next)
+ {
+ l->dll_head->dle_next->dle_prev = 0;
+ }
- l->dll_head = l->dll_head->dle_next;
+ l->dll_head = l->dll_head->dle_next;
- result->dle_next = 0;
- result->dle_list = 0;
-
- if (result == l->dll_tail) /* if the head is also the tail */
- l->dll_tail = 0;
+ result->dle_next = 0;
+ result->dle_list = 0;
- return result;
+ if (result == l->dll_tail) /* if the head is also the tail */
+ l->dll_tail = 0;
+
+ return result;
}
-Dlelem*
-DLRemTail(Dllist* l)
+Dlelem *
+DLRemTail(Dllist * l)
{
- /* remove and return the tail */
- Dlelem* result;
+ /* remove and return the tail */
+ Dlelem *result;
- if (l->dll_tail == 0 )
- return 0;
+ if (l->dll_tail == 0)
+ return 0;
- result = l->dll_tail;
- if (l->dll_tail->dle_prev) {
- l->dll_tail->dle_prev->dle_next = 0;
- }
- l->dll_tail = l->dll_tail->dle_prev;
+ result = l->dll_tail;
+ if (l->dll_tail->dle_prev)
+ {
+ l->dll_tail->dle_prev->dle_next = 0;
+ }
+ l->dll_tail = l->dll_tail->dle_prev;
- result->dle_prev = 0;
- result->dle_list = 0;
+ result->dle_prev = 0;
+ result->dle_list = 0;
- if (result == l->dll_head) /* if the tail is also the head */
- l->dll_head = 0;
+ if (result == l->dll_head) /* if the tail is also the head */
+ l->dll_head = 0;
- return result;
+ return result;
}
-
diff --git a/src/backend/lib/fstack.c b/src/backend/lib/fstack.c
index 68f1505b167..f97d467fe92 100644
--- a/src/backend/lib/fstack.c
+++ b/src/backend/lib/fstack.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* fstack.c--
- * Fixed format stack definitions.
+ * Fixed format stack definitions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.4 1997/06/06 22:02:37 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.5 1997/09/07 04:42:00 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,25 +21,25 @@
/*
* FixedItemIsValid --
- * True iff item is valid.
+ * True iff item is valid.
*/
#define FixedItemIsValid(item) PointerIsValid(item)
/*
* FixedStackGetItemBase --
- * Returns base of enclosing structure.
+ * Returns base of enclosing structure.
*/
#define FixedStackGetItemBase(stack, item) \
- ((Pointer)((char *)(item) - (stack)->offset))
+ ((Pointer)((char *)(item) - (stack)->offset))
/*
* FixedStackGetItem --
- * Returns item of given pointer to enclosing structure.
+ * Returns item of given pointer to enclosing structure.
*/
#define FixedStackGetItem(stack, pointer) \
- ((FixedItem)((char *)(pointer) + (stack)->offset))
+ ((FixedItem)((char *)(pointer) + (stack)->offset))
-#define FixedStackIsValid(stack) ((bool)PointerIsValid(stack))
+#define FixedStackIsValid(stack) ((bool)PointerIsValid(stack))
/*
* External functions
@@ -48,99 +48,105 @@
void
FixedStackInit(FixedStack stack, Offset offset)
{
- AssertArg(PointerIsValid(stack));
-
- stack->top = NULL;
- stack->offset = offset;
+ AssertArg(PointerIsValid(stack));
+
+ stack->top = NULL;
+ stack->offset = offset;
}
Pointer
FixedStackPop(FixedStack stack)
{
- Pointer pointer;
-
- AssertArg(FixedStackIsValid(stack));
-
- if (!PointerIsValid(stack->top)) {
- return (NULL);
- }
-
- pointer = FixedStackGetItemBase(stack, stack->top);
- stack->top = stack->top->next;
-
- return (pointer);
+ Pointer pointer;
+
+ AssertArg(FixedStackIsValid(stack));
+
+ if (!PointerIsValid(stack->top))
+ {
+ return (NULL);
+ }
+
+ pointer = FixedStackGetItemBase(stack, stack->top);
+ stack->top = stack->top->next;
+
+ return (pointer);
}
void
FixedStackPush(FixedStack stack, Pointer pointer)
{
- FixedItem item = FixedStackGetItem(stack, pointer);
-
- AssertArg(FixedStackIsValid(stack));
- AssertArg(PointerIsValid(pointer));
-
- item->next = stack->top;
- stack->top = item;
+ FixedItem item = FixedStackGetItem(stack, pointer);
+
+ AssertArg(FixedStackIsValid(stack));
+ AssertArg(PointerIsValid(pointer));
+
+ item->next = stack->top;
+ stack->top = item;
}
-#ifndef NO_ASSERT_CHECKING
+#ifndef NO_ASSERT_CHECKING
/*
* FixedStackContains --
- * True iff ordered stack contains given element.
+ * True iff ordered stack contains given element.
*
* Note:
- * This is inefficient. It is intended for debugging use only.
+ * This is inefficient. It is intended for debugging use only.
*
* Exceptions:
- * BadArg if stack is invalid.
- * BadArg if pointer is invalid.
+ * BadArg if stack is invalid.
+ * BadArg if pointer is invalid.
*/
-static bool
+static bool
FixedStackContains(FixedStack stack, Pointer pointer)
{
- FixedItem next;
- FixedItem item;
-
- AssertArg(FixedStackIsValid(stack));
- AssertArg(PointerIsValid(pointer));
-
- item = FixedStackGetItem(stack, pointer);
-
- for (next = stack->top; FixedItemIsValid(next); next = next->next) {
- if (next == item) {
- return (true);
+ FixedItem next;
+ FixedItem item;
+
+ AssertArg(FixedStackIsValid(stack));
+ AssertArg(PointerIsValid(pointer));
+
+ item = FixedStackGetItem(stack, pointer);
+
+ for (next = stack->top; FixedItemIsValid(next); next = next->next)
+ {
+ if (next == item)
+ {
+ return (true);
+ }
}
- }
- return (false);
+ return (false);
}
+
#endif
Pointer
FixedStackGetTop(FixedStack stack)
{
- AssertArg(FixedStackIsValid(stack));
-
- if (!PointerIsValid(stack->top)) {
- return (NULL);
- }
-
- return (FixedStackGetItemBase(stack, stack->top));
+ AssertArg(FixedStackIsValid(stack));
+
+ if (!PointerIsValid(stack->top))
+ {
+ return (NULL);
+ }
+
+ return (FixedStackGetItemBase(stack, stack->top));
}
Pointer
FixedStackGetNext(FixedStack stack, Pointer pointer)
{
- FixedItem item;
-
- /* AssertArg(FixedStackIsValid(stack)); */
- /* AssertArg(PointerIsValid(pointer)); */
- AssertArg(FixedStackContains(stack, pointer));
-
- item = FixedStackGetItem(stack, pointer)->next;
-
- if (!PointerIsValid(item)) {
- return (NULL);
- }
-
- return(FixedStackGetItemBase(stack, item));
+ FixedItem item;
+
+ /* AssertArg(FixedStackIsValid(stack)); */
+ /* AssertArg(PointerIsValid(pointer)); */
+ AssertArg(FixedStackContains(stack, pointer));
+
+ item = FixedStackGetItem(stack, pointer)->next;
+
+ if (!PointerIsValid(item))
+ {
+ return (NULL);
+ }
+
+ return (FixedStackGetItemBase(stack, item));
}
diff --git a/src/backend/lib/hasht.c b/src/backend/lib/hasht.c
index baceabfcf7a..4e12dcf30eb 100644
--- a/src/backend/lib/hasht.c
+++ b/src/backend/lib/hasht.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* hasht.c--
- * hash table related functions that are not directly supported
- * by the hashing packages under utils/hash.
+ * hash table related functions that are not directly supported
+ * by the hashing packages under utils/hash.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/lib/Attic/hasht.c,v 1.4 1997/08/12 22:52:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/lib/Attic/hasht.c,v 1.5 1997/09/07 04:42:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,29 +19,31 @@
#include <lib/hasht.h>
/* -----------------------------------
- * HashTableWalk
+ * HashTableWalk
*
- * call function on every element in hashtable
- * one extra argument, arg may be supplied
+ * call function on every element in hashtable
+ * one extra argument, arg may be supplied
* -----------------------------------
*/
void
-HashTableWalk(HTAB *hashtable, HashtFunc function, int arg)
+HashTableWalk(HTAB * hashtable, HashtFunc function, int arg)
{
- long *hashent;
- long *data;
- int keysize;
-
- keysize = hashtable->hctl->keysize;
- hash_seq((HTAB *)NULL);
- while ((hashent = hash_seq(hashtable)) != (long *) TRUE) {
- if (hashent == NULL)
- elog(FATAL, "error in HashTableWalk.");
- /*
- * XXX the corresponding hash table insertion does NOT
- * LONGALIGN -- make sure the keysize is ok
- */
- data = (long *) LONGALIGN((char*) hashent + keysize);
- (*function)(data, arg);
- }
+ long *hashent;
+ long *data;
+ int keysize;
+
+ keysize = hashtable->hctl->keysize;
+ hash_seq((HTAB *) NULL);
+ while ((hashent = hash_seq(hashtable)) != (long *) TRUE)
+ {
+ if (hashent == NULL)
+ elog(FATAL, "error in HashTableWalk.");
+
+ /*
+ * XXX the corresponding hash table insertion does NOT LONGALIGN
+ * -- make sure the keysize is ok
+ */
+ data = (long *) LONGALIGN((char *) hashent + keysize);
+ (*function) (data, arg);
+ }
}
diff --git a/src/backend/lib/lispsort.c b/src/backend/lib/lispsort.c
index 11acc5683b2..bf346ecc1a6 100644
--- a/src/backend/lib/lispsort.c
+++ b/src/backend/lib/lispsort.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/lib/Attic/lispsort.c,v 1.4 1997/08/19 21:31:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/lib/Attic/lispsort.c,v 1.5 1997/09/07 04:42:05 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,38 +24,41 @@
#ifdef NOT_USED
/*
-** lisp_qsort: Takes a lisp list as input, copies it into an array of lisp
-** nodes which it sorts via qsort() with the comparison function
-** as passed into lisp_qsort(), and returns a new list with
-** the nodes sorted. The old list is *not* freed or modified (?)
+** lisp_qsort: Takes a lisp list as input, copies it into an array of lisp
+** nodes which it sorts via qsort() with the comparison function
+** as passed into lisp_qsort(), and returns a new list with
+** the nodes sorted. The old list is *not* freed or modified (?)
*/
-List *lisp_qsort(List *the_list, /* the list to be sorted */
- int (*compare)()) /* function to compare two nodes */
+List *
+lisp_qsort(List * the_list, /* the list to be sorted */
+ int (*compare) ()) /* function to compare two nodes */
{
- int i;
- size_t num;
- List **nodearray;
- List *tmp, *output;
-
- /* find size of list */
- num = length(the_list);
- if (num < 2)
- return(copyObject(the_list));
-
- /* copy elements of the list into an array */
- nodearray = (List **) palloc(num * sizeof(List *));
-
- for (tmp = the_list, i = 0; tmp != NIL; tmp = lnext(tmp), i++)
- nodearray[i] = copyObject(lfirst(tmp));
-
- /* sort the array */
- pg_qsort(nodearray, num, sizeof(List *), compare);
-
- /* lcons together the array elements */
- output = NIL;
- for (i = num - 1; i >= 0; i--)
- output = lcons(nodearray[i], output);
-
- return(output);
+ int i;
+ size_t num;
+ List **nodearray;
+ List *tmp,
+ *output;
+
+ /* find size of list */
+ num = length(the_list);
+ if (num < 2)
+ return (copyObject(the_list));
+
+ /* copy elements of the list into an array */
+ nodearray = (List **) palloc(num * sizeof(List *));
+
+ for (tmp = the_list, i = 0; tmp != NIL; tmp = lnext(tmp), i++)
+ nodearray[i] = copyObject(lfirst(tmp));
+
+ /* sort the array */
+ pg_qsort(nodearray, num, sizeof(List *), compare);
+
+ /* lcons together the array elements */
+ output = NIL;
+ for (i = num - 1; i >= 0; i--)
+ output = lcons(nodearray[i], output);
+
+ return (output);
}
+
#endif
diff --git a/src/backend/lib/qsort.c b/src/backend/lib/qsort.c
index e0f3cbbb2c2..ff2bbfa16d9 100644
--- a/src/backend/lib/qsort.c
+++ b/src/backend/lib/qsort.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* qsort.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/lib/Attic/qsort.c,v 1.2 1996/11/06 08:27:15 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/lib/Attic/qsort.c,v 1.3 1997/09/07 04:42:06 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,22 +19,22 @@
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -45,8 +45,9 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)qsort.c 5.9 (Berkeley) 2/23/91";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)qsort.c 5.9 (Berkeley) 2/23/91";
+
+#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
@@ -58,21 +59,22 @@ static char sccsid[] = "@(#)qsort.c 5.9 (Berkeley) 2/23/91";
* MTHRESH is the smallest partition for which we compare for a median
* value instead of using the middle value.
*/
-#define MTHRESH 6
+#define MTHRESH 6
/*
* THRESH is the minimum number of entries in a partition for continued
* partitioning.
*/
-#define THRESH 4
+#define THRESH 4
-static void insertion_sort(char* bot, int nmemb, int size, int (*compar)());
-static void quick_sort(char* bot, int nmemb, int size, int (*compar)());
+static void insertion_sort(char *bot, int nmemb, int size, int (*compar) ());
+static void quick_sort(char *bot, int nmemb, int size, int (*compar) ());
-void pg_qsort(void *bot,
- size_t nmemb,
- size_t size,
- int (*compar)(void *, void *))
+void
+pg_qsort(void *bot,
+ size_t nmemb,
+ size_t size,
+ int (*compar) (void *, void *))
{
if (nmemb <= 1)
@@ -85,19 +87,19 @@ void pg_qsort(void *bot,
}
/*
- * Swap two areas of size number of bytes. Although qsort(3) permits random
+ * Swap two areas of size number of bytes. Although qsort(3) permits random
* blocks of memory to be sorted, sorting pointers is almost certainly the
* common case (and, were it not, could easily be made so). Regardless, it
* isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
* arithmetic gets lost in the time required for comparison function calls.
*/
-#define SWAP(a, b) { \
- cnt = size; \
- do { \
- ch = *a; \
- *a++ = *b; \
- *b++ = ch; \
- } while (--cnt); \
+#define SWAP(a, b) { \
+ cnt = size; \
+ do { \
+ ch = *a; \
+ *a++ = *b; \
+ *b++ = ch; \
+ } while (--cnt); \
}
/*
@@ -114,24 +116,28 @@ void pg_qsort(void *bot,
* Knuth, page 122, equation 26), since the quicksort algorithm does less
* comparisons than the insertion sort.
*/
-#define SORT(bot, n) { \
- if (n > 1) \
- if (n == 2) { \
- t1 = bot + size; \
- if (compar(t1, bot) < 0) \
- SWAP(t1, bot); \
- } else \
- insertion_sort(bot, n, size, compar); \
+#define SORT(bot, n) { \
+ if (n > 1) \
+ if (n == 2) { \
+ t1 = bot + size; \
+ if (compar(t1, bot) < 0) \
+ SWAP(t1, bot); \
+ } else \
+ insertion_sort(bot, n, size, compar); \
}
static void
-quick_sort(char* bot, int nmemb, int size, int (*compar)())
+quick_sort(char *bot, int nmemb, int size, int (*compar) ())
{
- register int cnt;
+ register int cnt;
register u_char ch;
- register char *top, *mid, *t1, *t2;
- register int n1, n2;
- char *bsv;
+ register char *top,
+ *mid,
+ *t1,
+ *t2;
+ register int n1,
+ n2;
+ char *bsv;
/* bot and nmemb must already be set. */
partition:
@@ -145,7 +151,8 @@ partition:
* Vol. 3, page 123, Eq. 28). This test order gets the equalities
* right.
*/
- if (nmemb >= MTHRESH) {
+ if (nmemb >= MTHRESH)
+ {
n1 = compar(bot, mid);
n2 = compar(mid, top);
if (n1 < 0 && n2 > 0)
@@ -156,28 +163,33 @@ partition:
t1 = mid;
/* if mid element not selected, swap selection there */
- if (t1 != mid) {
+ if (t1 != mid)
+ {
SWAP(t1, mid);
mid -= size;
}
}
/* Standard quicksort, Knuth, Vol. 3, page 116, Algorithm Q. */
-#define didswap n1
-#define newbot t1
-#define replace t2
+#define didswap n1
+#define newbot t1
+#define replace t2
didswap = 0;
- for (bsv = bot;;) {
+ for (bsv = bot;;)
+ {
for (; bot < mid && compar(bot, mid) <= 0; bot += size);
- while (top > mid) {
- if (compar(mid, top) <= 0) {
+ while (top > mid)
+ {
+ if (compar(mid, top) <= 0)
+ {
top -= size;
continue;
}
- newbot = bot + size; /* value of bot after swap */
+ newbot = bot + size;/* value of bot after swap */
if (bot == mid) /* top <-> mid, mid == top */
replace = mid = top;
- else { /* bot <-> top */
+ else
+ { /* bot <-> top */
replace = top;
top -= size;
}
@@ -191,7 +203,7 @@ partition:
newbot = mid = bot; /* value of bot after swap */
top -= size;
-swap: SWAP(bot, replace);
+swap: SWAP(bot, replace);
bot = newbot;
didswap = 1;
}
@@ -200,14 +212,15 @@ swap: SWAP(bot, replace);
* Quicksort behaves badly in the presence of data which is already
* sorted (see Knuth, Vol. 3, page 119) going from O N lg N to O N^2.
* To avoid this worst case behavior, if a re-partitioning occurs
- * without swapping any elements, it is not further partitioned and
- * is insert sorted. This wins big with almost sorted data sets and
- * only loses if the data set is very strangely partitioned. A fix
- * for those data sets would be to return prematurely if the insertion
+ * without swapping any elements, it is not further partitioned and is
+ * insert sorted. This wins big with almost sorted data sets and only
+ * loses if the data set is very strangely partitioned. A fix for
+ * those data sets would be to return prematurely if the insertion
* sort routine is forced to make an excessive number of swaps, and
* continue the partitioning.
*/
- if (!didswap) {
+ if (!didswap)
+ {
insertion_sort(bsv, nmemb, size, compar);
return;
}
@@ -216,34 +229,41 @@ swap: SWAP(bot, replace);
* Re-partition or sort as necessary. Note that the mid element
* itself is correctly positioned and can be ignored.
*/
-#define nlower n1
-#define nupper n2
+#define nlower n1
+#define nupper n2
bot = bsv;
- nlower = (mid - bot) / size; /* size of lower partition */
+ nlower = (mid - bot) / size;/* size of lower partition */
mid += size;
- nupper = nmemb - nlower - 1; /* size of upper partition */
+ nupper = nmemb - nlower - 1;/* size of upper partition */
/*
* If must call recursively, do it on the smaller partition; this
* bounds the stack to lg N entries.
*/
- if (nlower > nupper) {
+ if (nlower > nupper)
+ {
if (nupper >= THRESH)
quick_sort(mid, nupper, size, compar);
- else {
+ else
+ {
SORT(mid, nupper);
- if (nlower < THRESH) {
+ if (nlower < THRESH)
+ {
SORT(bot, nlower);
return;
}
}
nmemb = nlower;
- } else {
+ }
+ else
+ {
if (nlower >= THRESH)
quick_sort(bot, nlower, size, compar);
- else {
+ else
+ {
SORT(bot, nlower);
- if (nupper < THRESH) {
+ if (nupper < THRESH)
+ {
SORT(mid, nupper);
return;
}
@@ -255,30 +275,38 @@ swap: SWAP(bot, replace);
}
static void
-insertion_sort(char* bot, int nmemb, int size, int (*compar)())
+insertion_sort(char *bot, int nmemb, int size, int (*compar) ())
{
- register int cnt;
+ register int cnt;
register u_char ch;
- register char *s1, *s2, *t1, *t2, *top;
+ register char *s1,
+ *s2,
+ *t1,
+ *t2,
+ *top;
/*
- * A simple insertion sort (see Knuth, Vol. 3, page 81, Algorithm
- * S). Insertion sort has the same worst case as most simple sorts
- * (O N^2). It gets used here because it is (O N) in the case of
- * sorted data.
+ * A simple insertion sort (see Knuth, Vol. 3, page 81, Algorithm S).
+ * Insertion sort has the same worst case as most simple sorts (O
+ * N^2). It gets used here because it is (O N) in the case of sorted
+ * data.
*/
top = bot + nmemb * size;
- for (t1 = bot + size; t1 < top;) {
+ for (t1 = bot + size; t1 < top;)
+ {
for (t2 = t1; (t2 -= size) >= bot && compar(t1, t2) < 0;);
- if (t1 != (t2 += size)) {
+ if (t1 != (t2 += size))
+ {
/* Bubble bytes up through each element. */
- for (cnt = size; cnt--; ++t1) {
+ for (cnt = size; cnt--; ++t1)
+ {
ch = *t1;
for (s1 = s2 = t1; (s2 -= size) >= t2; s1 = s2)
*s1 = *s2;
*s1 = ch;
}
- } else
+ }
+ else
t1 += size;
}
}
diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c
index 18cfc89f982..34108c04c72 100644
--- a/src/backend/lib/stringinfo.c
+++ b/src/backend/lib/stringinfo.c
@@ -1,15 +1,15 @@
/*-------------------------------------------------------------------------
*
* stringinfo.c--
- * These are routines that can be used to write informations to a string,
- * without having to worry about string lengths, space allocation etc.
- * Ideally the interface should look like the file i/o interface,
+ * These are routines that can be used to write informations to a string,
+ * without having to worry about string lengths, space allocation etc.
+ * Ideally the interface should look like the file i/o interface,
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/lib/stringinfo.c,v 1.3 1997/08/12 20:15:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/lib/stringinfo.c,v 1.4 1997/09/07 04:42:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,30 +30,33 @@
StringInfo
makeStringInfo()
{
- StringInfo res;
- long size;
-
- res = (StringInfo) palloc(sizeof(StringInfoData));
- if (res == NULL) {
- elog(WARN, "makeStringInfo: Out of memory!");
- }
-
- size = 100;
- res->data = palloc(size);
- if (res->data == NULL) {
- elog(WARN,
- "makeStringInfo: Out of memory! (%ld bytes requested)", size);
- }
- res->maxlen = size;
- res->len = 0;
- /*
- * NOTE: we must initialize `res->data' to the empty string because
- * we use 'strcat' in 'appendStringInfo', which of course it always
- * expects a null terminated string.
- */
- res->data[0] = '\0';
-
- return(res);
+ StringInfo res;
+ long size;
+
+ res = (StringInfo) palloc(sizeof(StringInfoData));
+ if (res == NULL)
+ {
+ elog(WARN, "makeStringInfo: Out of memory!");
+ }
+
+ size = 100;
+ res->data = palloc(size);
+ if (res->data == NULL)
+ {
+ elog(WARN,
+ "makeStringInfo: Out of memory! (%ld bytes requested)", size);
+ }
+ res->maxlen = size;
+ res->len = 0;
+
+ /*
+ * NOTE: we must initialize `res->data' to the empty string because we
+ * use 'strcat' in 'appendStringInfo', which of course it always
+ * expects a null terminated string.
+ */
+ res->data[0] = '\0';
+
+ return (res);
}
/*---------------------------------------------------------------------
@@ -69,48 +72,53 @@ makeStringInfo()
void
appendStringInfo(StringInfo str, char *buffer)
{
- int buflen, newlen;
- char *s;
-
- Assert((str!=NULL));
-
- /*
- * do we have enough space to append the new string?
- * (don't forget to count the null string terminating char!)
- * If no, then reallocate some more.
- */
- buflen = strlen(buffer);
- if (buflen + str->len >= str->maxlen-1) {
+ int buflen,
+ newlen;
+ char *s;
+
+ Assert((str != NULL));
+
/*
- * how much more space to allocate ?
- * Let's say double the current space...
- * However we must check if this is enough!
+ * do we have enough space to append the new string? (don't forget to
+ * count the null string terminating char!) If no, then reallocate
+ * some more.
*/
- newlen = 2 * str->len;
- while (buflen + str->len >= newlen-1) {
- newlen = 2 * newlen;
+ buflen = strlen(buffer);
+ if (buflen + str->len >= str->maxlen - 1)
+ {
+
+ /*
+ * how much more space to allocate ? Let's say double the current
+ * space... However we must check if this is enough!
+ */
+ newlen = 2 * str->len;
+ while (buflen + str->len >= newlen - 1)
+ {
+ newlen = 2 * newlen;
+ }
+
+ /*
+ * allocate enough space.
+ */
+ s = palloc(newlen);
+ if (s == NULL)
+ {
+ elog(WARN,
+ "appendStringInfo: Out of memory (%d bytes requested)",
+ newlen);
+ }
+ memmove(s, str->data, str->len + 1);
+ pfree(str->data);
+ str->maxlen = newlen;
+ str->data = s;
}
+
/*
- * allocate enough space.
+ * OK, we have enough space now, append 'buffer' at the end of the
+ * string & update the string length. NOTE: this is a text string
+ * (i.e. printable characters) so 'strcat' will do the job (no need to
+ * use 'bcopy' et all...)
*/
- s = palloc(newlen);
- if (s==NULL) {
- elog(WARN,
- "appendStringInfo: Out of memory (%d bytes requested)",
- newlen);
- }
- memmove(s, str->data, str->len+1);
- pfree(str->data);
- str->maxlen = newlen;
- str->data = s;
- }
-
- /*
- * OK, we have enough space now, append 'buffer' at the
- * end of the string & update the string length.
- * NOTE: this is a text string (i.e. printable characters)
- * so 'strcat' will do the job (no need to use 'bcopy' et all...)
- */
- strcat(str->data, buffer);
- str->len += buflen;
+ strcat(str->data, buffer);
+ str->len += buflen;
}
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index abf59e25b17..ff6711d3b5c 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -1,65 +1,65 @@
/*-------------------------------------------------------------------------
*
* auth.c--
- * Routines to handle network authentication
+ * Routines to handle network authentication
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.14 1997/08/19 21:31:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.15 1997/09/07 04:42:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
*
- * backend (postmaster) routines:
- * be_recvauth receive authentication information
- * be_setauthsvc do/do not permit an authentication service
- * be_getauthsvc is an authentication service permitted?
+ * backend (postmaster) routines:
+ * be_recvauth receive authentication information
+ * be_setauthsvc do/do not permit an authentication service
+ * be_getauthsvc is an authentication service permitted?
*
- * NOTES
- * To add a new authentication system:
- * 0. If you can't do your authentication over an existing socket,
- * you lose -- get ready to hack around this framework instead of
- * using it. Otherwise, you can assume you have an initialized
- * and empty connection to work with. (Please don't leave leftover
- * gunk in the connection after the authentication transactions, or
- * the POSTGRES routines that follow will be very unhappy.)
- * 1. Write a set of routines that:
- * let a client figure out what user/principal name to use
- * send authentication information (client side)
- * receive authentication information (server side)
- * You can include both routines in this file, using #ifdef FRONTEND
- * to separate them.
- * 2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
- * 3. Edit the static "struct authsvc" array and the generic
- * {be,fe}_{get,set}auth{name,svc} routines in this file to reflect
- * the new service. You may have to change the arguments of these
- * routines; they basically just reflect what Kerberos v4 needs.
- * 4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
- * to add library and CFLAGS hooks -- basically, grep the Makefile
- * hierarchy for KRBVERS to see where you need to add things.
+ * NOTES
+ * To add a new authentication system:
+ * 0. If you can't do your authentication over an existing socket,
+ * you lose -- get ready to hack around this framework instead of
+ * using it. Otherwise, you can assume you have an initialized
+ * and empty connection to work with. (Please don't leave leftover
+ * gunk in the connection after the authentication transactions, or
+ * the POSTGRES routines that follow will be very unhappy.)
+ * 1. Write a set of routines that:
+ * let a client figure out what user/principal name to use
+ * send authentication information (client side)
+ * receive authentication information (server side)
+ * You can include both routines in this file, using #ifdef FRONTEND
+ * to separate them.
+ * 2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
+ * 3. Edit the static "struct authsvc" array and the generic
+ * {be,fe}_{get,set}auth{name,svc} routines in this file to reflect
+ * the new service. You may have to change the arguments of these
+ * routines; they basically just reflect what Kerberos v4 needs.
+ * 4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
+ * to add library and CFLAGS hooks -- basically, grep the Makefile
+ * hierarchy for KRBVERS to see where you need to add things.
*
- * Send mail to [email protected] if you have to make
- * any changes to arguments, etc. Context diffs would be nice, too.
+ * Send mail to [email protected] if you have to make
+ * any changes to arguments, etc. Context diffs would be nice, too.
*
- * Someday, this cruft will go away and magically be replaced by a
- * nice interface based on the GSS API or something. For now, though,
- * there's no (stable) UNIX security API to work with...
+ * Someday, this cruft will go away and magically be replaced by a
+ * nice interface based on the GSS API or something. For now, though,
+ * there's no (stable) UNIX security API to work with...
*
*/
#include <stdio.h>
#include <string.h>
-#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#ifndef MAXHOSTNAMELEN
-#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
#include <pwd.h>
-#include <ctype.h> /* isspace() declaration */
+#include <ctype.h> /* isspace() declaration */
-#include <sys/types.h> /* needed by in.h on Ultrix */
+#include <sys/types.h> /* needed by in.h on Ultrix */
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -72,19 +72,19 @@
#include <libpq/hba.h>
#include <libpq/password.h>
-static int be_getauthsvc(MsgType msgtype);
+static int be_getauthsvc(MsgType msgtype);
/*----------------------------------------------------------------
* common definitions for generic fe/be routines
*----------------------------------------------------------------
*/
-struct authsvc {
- char name[16]; /* service nickname (for command line) */
- MsgType msgtype; /* startup packet header type */
- int allowed; /* initially allowed (before command line
- * option parsing)?
- */
+struct authsvc
+{
+ char name[16]; /* service nickname (for command line) */
+ MsgType msgtype; /* startup packet header type */
+ int allowed; /* initially allowed (before command line
+ * option parsing)? */
};
/*
@@ -99,9 +99,11 @@ struct authsvc {
*/
#if defined(HBA)
-static int useHostBasedAuth = 1;
+static int useHostBasedAuth = 1;
+
#else
-static int useHostBasedAuth = 0;
+static int useHostBasedAuth = 0;
+
#endif
#if defined(KRB4) || defined(KRB5) || defined(HBA)
@@ -111,19 +113,19 @@ static int useHostBasedAuth = 0;
#endif
static struct authsvc authsvcs[] = {
- { "unauth", STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED },
- { "hba", STARTUP_HBA_MSG, 1 },
- { "krb4", STARTUP_KRB4_MSG, 1 },
- { "krb5", STARTUP_KRB5_MSG, 1 },
-#if defined(KRB5)
- { "kerberos", STARTUP_KRB5_MSG, 1 },
+ {"unauth", STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED},
+ {"hba", STARTUP_HBA_MSG, 1},
+ {"krb4", STARTUP_KRB4_MSG, 1},
+ {"krb5", STARTUP_KRB5_MSG, 1},
+#if defined(KRB5)
+ {"kerberos", STARTUP_KRB5_MSG, 1},
#else
- { "kerberos", STARTUP_KRB4_MSG, 1 },
+ {"kerberos", STARTUP_KRB4_MSG, 1},
#endif
- { "password", STARTUP_PASSWORD_MSG, 1 }
+ {"password", STARTUP_PASSWORD_MSG, 1}
};
-static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
+static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
#ifdef KRB4
/* This has to be ifdef'd out because krb.h does exist. This needs
@@ -138,11 +140,11 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
#ifdef FRONTEND
/* moves to src/libpq/fe-auth.c */
-#else /* !FRONTEND */
+#else /* !FRONTEND */
/*
* pg_krb4_recvauth -- server routine to receive authentication information
- * from the client
+ * from the client
*
* Nothing unusual here, except that we compare the username obtained from
* the client's setup packet to the authenticated name. (We have to retain
@@ -151,77 +153,82 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
*/
static int
pg_krb4_recvauth(int sock,
- struct sockaddr_in *laddr,
- struct sockaddr_in *raddr,
- char *username)
+ struct sockaddr_in * laddr,
+ struct sockaddr_in * raddr,
+ char *username)
{
- long krbopts = 0; /* one-way authentication */
- KTEXT_ST clttkt;
- char instance[INST_SZ];
- AUTH_DAT auth_data;
- Key_schedule key_sched;
- char version[KRB_SENDAUTH_VLEN];
- int status;
-
- strcpy(instance, "*"); /* don't care, but arg gets expanded anyway */
- status = krb_recvauth(krbopts,
- sock,
- &clttkt,
- PG_KRB_SRVNAM,
- instance,
- raddr,
- laddr,
- &auth_data,
- PG_KRB_SRVTAB,
- key_sched,
- version);
- if (status != KSUCCESS) {
- sprintf(PQerrormsg,
- "pg_krb4_recvauth: kerberos error: %s\n",
- krb_err_txt[status]);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN)) {
- sprintf(PQerrormsg,
- "pg_krb4_recvauth: protocol version != \"%s\"\n",
- PG_KRB4_VERSION);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- if (username && *username &&
- strncmp(username, auth_data.pname, NAMEDATALEN)) {
- sprintf(PQerrormsg,
- "pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
- username,
- auth_data.pname);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- return(STATUS_OK);
+ long krbopts = 0;/* one-way authentication */
+ KTEXT_ST clttkt;
+ char instance[INST_SZ];
+ AUTH_DAT auth_data;
+ Key_schedule key_sched;
+ char version[KRB_SENDAUTH_VLEN];
+ int status;
+
+ strcpy(instance, "*"); /* don't care, but arg gets expanded
+ * anyway */
+ status = krb_recvauth(krbopts,
+ sock,
+ &clttkt,
+ PG_KRB_SRVNAM,
+ instance,
+ raddr,
+ laddr,
+ &auth_data,
+ PG_KRB_SRVTAB,
+ key_sched,
+ version);
+ if (status != KSUCCESS)
+ {
+ sprintf(PQerrormsg,
+ "pg_krb4_recvauth: kerberos error: %s\n",
+ krb_err_txt[status]);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ if (strncmp(version, PG_KRB4_VERSION, KRB_SENDAUTH_VLEN))
+ {
+ sprintf(PQerrormsg,
+ "pg_krb4_recvauth: protocol version != \"%s\"\n",
+ PG_KRB4_VERSION);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ if (username && *username &&
+ strncmp(username, auth_data.pname, NAMEDATALEN))
+ {
+ sprintf(PQerrormsg,
+ "pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
+ username,
+ auth_data.pname);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ return (STATUS_OK);
}
-#endif /* !FRONTEND */
+#endif /* !FRONTEND */
#else
static int
pg_krb4_recvauth(int sock,
- struct sockaddr_in *laddr,
- struct sockaddr_in *raddr,
- char *username)
+ struct sockaddr_in * laddr,
+ struct sockaddr_in * raddr,
+ char *username)
{
- sprintf(PQerrormsg,
- "pg_krb4_recvauth: Kerberos not implemented on this "
- "server.\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
+ sprintf(PQerrormsg,
+ "pg_krb4_recvauth: Kerberos not implemented on this "
+ "server.\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
-return(STATUS_ERROR);
+ return (STATUS_ERROR);
}
-#endif /* KRB4 */
+
+#endif /* KRB4 */
#ifdef KRB5
@@ -237,37 +244,37 @@ return(STATUS_ERROR);
/*
* pg_an_to_ln -- return the local name corresponding to an authentication
- * name
+ * name
*
* XXX Assumes that the first aname component is the user name. This is NOT
- * necessarily so, since an aname can actually be something out of your
- * worst X.400 nightmare, like
- * ORGANIZATION=U. C. Berkeley/NAME=Paul M. [email protected]
- * Note that the MIT an_to_ln code does the same thing if you don't
- * provide an aname mapping database...it may be a better idea to use
- * krb5_an_to_ln, except that it punts if multiple components are found,
- * and we can't afford to punt.
+ * necessarily so, since an aname can actually be something out of your
+ * worst X.400 nightmare, like
+ * ORGANIZATION=U. C. Berkeley/NAME=Paul M. [email protected]
+ * Note that the MIT an_to_ln code does the same thing if you don't
+ * provide an aname mapping database...it may be a better idea to use
+ * krb5_an_to_ln, except that it punts if multiple components are found,
+ * and we can't afford to punt.
*/
-static char *
+static char *
pg_an_to_ln(char *aname)
{
- char *p;
-
- if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
- *p = '\0';
- return(aname);
+ char *p;
+
+ if ((p = strchr(aname, '/')) || (p = strchr(aname, '@')))
+ *p = '\0';
+ return (aname);
}
#ifdef FRONTEND
/* moves to src/libpq/fe-auth.c */
-#else /* !FRONTEND */
+#else /* !FRONTEND */
/*
* pg_krb5_recvauth -- server routine to receive authentication information
- * from the client
+ * from the client
*
* We still need to compare the username obtained from the client's setup
- * packet to the authenticated name, as described in pg_krb4_recvauth. This
+ * packet to the authenticated name, as described in pg_krb4_recvauth. This
* is a bit more problematic in v5, as described above in pg_an_to_ln.
*
* In addition, as described above in pg_krb5_sendauth, we still need to
@@ -286,315 +293,348 @@ pg_an_to_ln(char *aname)
*/
static int
pg_krb5_recvauth(int sock,
- struct sockaddr_in *laddr,
- struct sockaddr_in *raddr,
- char *username)
+ struct sockaddr_in * laddr,
+ struct sockaddr_in * raddr,
+ char *username)
{
- char servbuf[MAXHOSTNAMELEN + 1 +
- sizeof(PG_KRB_SRVNAM)];
- char *hostp, *kusername = (char *) NULL;
- krb5_error_code code;
- krb5_principal client, server;
- krb5_address sender_addr;
- krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc) NULL;
- krb5_pointer keyprocarg = (krb5_pointer) NULL;
-
- /*
- * Set up server side -- since we have no ticket file to make this
- * easy, we construct our own name and parse it. See note on
- * canonicalization above.
- */
- strcpy(servbuf, PG_KRB_SRVNAM);
- *(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
- if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
- strcpy(hostp, "localhost");
- if (hostp = strchr(hostp, '.'))
- *hostp = '\0';
- if (code = krb5_parse_name(servbuf, &server)) {
- sprintf(PQerrormsg,
- "pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n",
- code);
- com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
- return(STATUS_ERROR);
- }
-
- /*
- * krb5_sendauth needs this to verify the address in the client
- * authenticator.
- */
- sender_addr.addrtype = raddr->sin_family;
- sender_addr.length = sizeof(raddr->sin_addr);
- sender_addr.contents = (krb5_octet *) &(raddr->sin_addr);
-
- if (strcmp(PG_KRB_SRVTAB, "")) {
- keyproc = krb5_kt_read_service_key;
- keyprocarg = PG_KRB_SRVTAB;
- }
-
- if (code = krb5_recvauth((krb5_pointer) &sock,
- PG_KRB5_VERSION,
- server,
- &sender_addr,
- (krb5_pointer) NULL,
- keyproc,
- keyprocarg,
- (char *) NULL,
- (krb5_int32 *) NULL,
- &client,
- (krb5_ticket **) NULL,
- (krb5_authenticator **) NULL)) {
- sprintf(PQerrormsg,
- "pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n",
- code);
- com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
+ char servbuf[MAXHOSTNAMELEN + 1 +
+ sizeof(PG_KRB_SRVNAM)];
+ char *hostp,
+ *kusername = (char *) NULL;
+ krb5_error_code code;
+ krb5_principal client,
+ server;
+ krb5_address sender_addr;
+ krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc) NULL;
+ krb5_pointer keyprocarg = (krb5_pointer) NULL;
+
+ /*
+ * Set up server side -- since we have no ticket file to make this
+ * easy, we construct our own name and parse it. See note on
+ * canonicalization above.
+ */
+ strcpy(servbuf, PG_KRB_SRVNAM);
+ *(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
+ if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
+ strcpy(hostp, "localhost");
+ if (hostp = strchr(hostp, '.'))
+ *hostp = '\0';
+ if (code = krb5_parse_name(servbuf, &server))
+ {
+ sprintf(PQerrormsg,
+ "pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n",
+ code);
+ com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
+ return (STATUS_ERROR);
+ }
+
+ /*
+ * krb5_sendauth needs this to verify the address in the client
+ * authenticator.
+ */
+ sender_addr.addrtype = raddr->sin_family;
+ sender_addr.length = sizeof(raddr->sin_addr);
+ sender_addr.contents = (krb5_octet *) & (raddr->sin_addr);
+
+ if (strcmp(PG_KRB_SRVTAB, ""))
+ {
+ keyproc = krb5_kt_read_service_key;
+ keyprocarg = PG_KRB_SRVTAB;
+ }
+
+ if (code = krb5_recvauth((krb5_pointer) & sock,
+ PG_KRB5_VERSION,
+ server,
+ &sender_addr,
+ (krb5_pointer) NULL,
+ keyproc,
+ keyprocarg,
+ (char *) NULL,
+ (krb5_int32 *) NULL,
+ &client,
+ (krb5_ticket **) NULL,
+ (krb5_authenticator **) NULL))
+ {
+ sprintf(PQerrormsg,
+ "pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n",
+ code);
+ com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
+ krb5_free_principal(server);
+ return (STATUS_ERROR);
+ }
krb5_free_principal(server);
- return(STATUS_ERROR);
- }
- krb5_free_principal(server);
-
- /*
- * The "client" structure comes out of the ticket and is therefore
- * authenticated. Use it to check the username obtained from the
- * postmaster startup packet.
- */
- if ((code = krb5_unparse_name(client, &kusername))) {
- sprintf(PQerrormsg,
- "pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n",
- code);
- com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
+
+ /*
+ * The "client" structure comes out of the ticket and is therefore
+ * authenticated. Use it to check the username obtained from the
+ * postmaster startup packet.
+ */
+ if ((code = krb5_unparse_name(client, &kusername)))
+ {
+ sprintf(PQerrormsg,
+ "pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n",
+ code);
+ com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
+ krb5_free_principal(client);
+ return (STATUS_ERROR);
+ }
krb5_free_principal(client);
- return(STATUS_ERROR);
- }
- krb5_free_principal(client);
- if (!kusername) {
- sprintf(PQerrormsg,
- "pg_krb5_recvauth: could not decode username\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- kusername = pg_an_to_ln(kusername);
- if (username && strncmp(username, kusername, NAMEDATALEN)) {
- sprintf(PQerrormsg,
- "pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
- username, kusername);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
+ if (!kusername)
+ {
+ sprintf(PQerrormsg,
+ "pg_krb5_recvauth: could not decode username\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ kusername = pg_an_to_ln(kusername);
+ if (username && strncmp(username, kusername, NAMEDATALEN))
+ {
+ sprintf(PQerrormsg,
+ "pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
+ username, kusername);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ free(kusername);
+ return (STATUS_ERROR);
+ }
free(kusername);
- return(STATUS_ERROR);
- }
- free(kusername);
- return(STATUS_OK);
+ return (STATUS_OK);
}
-#endif /* !FRONTEND */
+#endif /* !FRONTEND */
#else
static int
pg_krb5_recvauth(int sock,
- struct sockaddr_in *laddr,
- struct sockaddr_in *raddr,
- char *username)
+ struct sockaddr_in * laddr,
+ struct sockaddr_in * raddr,
+ char *username)
{
- sprintf(PQerrormsg,
- "pg_krb5_recvauth: Kerberos not implemented on this "
- "server.\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
+ sprintf(PQerrormsg,
+ "pg_krb5_recvauth: Kerberos not implemented on this "
+ "server.\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
-return(STATUS_ERROR);
+ return (STATUS_ERROR);
}
-#endif /* KRB5 */
+
+#endif /* KRB5 */
static int
-pg_password_recvauth(Port *port, char *database, char *DataDir)
+pg_password_recvauth(Port * port, char *database, char *DataDir)
{
- PacketBuf buf;
- char *user, *password;
-
- if(PacketReceive(port, &buf, BLOCKING) != STATUS_OK) {
- sprintf(PQerrormsg,
- "pg_password_recvauth: failed to receive authentication packet.\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
+ PacketBuf buf;
+ char *user,
+ *password;
+
+ if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
+ {
+ sprintf(PQerrormsg,
+ "pg_password_recvauth: failed to receive authentication packet.\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return STATUS_ERROR;
+ }
- user = buf.data;
- password = buf.data + strlen(user) + 1;
+ user = buf.data;
+ password = buf.data + strlen(user) + 1;
- return verify_password(user, password, port, database, DataDir);
+ return verify_password(user, password, port, database, DataDir);
}
/*
* be_recvauth -- server demux routine for incoming authentication information
*/
int
-be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo* sp)
+be_recvauth(MsgType msgtype_arg, Port * port, char *username, StartupInfo * sp)
{
- MsgType msgtype;
-
- /* A message type of STARTUP_MSG (which once upon a time was the only
- startup message type) means user wants us to choose. "unauth" is
- what used to be the only choice, but installation may choose "hba"
- instead.
- */
- if (msgtype_arg == STARTUP_MSG) {
- if(useHostBasedAuth)
- msgtype = STARTUP_HBA_MSG;
- else
- msgtype = STARTUP_UNAUTH_MSG;
- } else
- msgtype = msgtype_arg;
-
-
- if (!username) {
- sprintf(PQerrormsg,
- "be_recvauth: no user name passed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- if (!port) {
- sprintf(PQerrormsg,
- "be_recvauth: no port structure passed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
-
- switch (msgtype) {
- case STARTUP_KRB4_MSG:
- if (!be_getauthsvc(msgtype)) {
- sprintf(PQerrormsg,
- "be_recvauth: krb4 authentication disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- if (pg_krb4_recvauth(port->sock, &port->laddr, &port->raddr,
- username) != STATUS_OK) {
- sprintf(PQerrormsg,
- "be_recvauth: krb4 authentication failed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- break;
- case STARTUP_KRB5_MSG:
- if (!be_getauthsvc(msgtype)) {
- sprintf(PQerrormsg,
- "be_recvauth: krb5 authentication disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
- username) != STATUS_OK) {
- sprintf(PQerrormsg,
- "be_recvauth: krb5 authentication failed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- break;
- case STARTUP_UNAUTH_MSG:
- if (!be_getauthsvc(msgtype)) {
- sprintf(PQerrormsg,
- "be_recvauth: "
- "unauthenticated connections disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- break;
- case STARTUP_HBA_MSG:
- if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK) {
- sprintf(PQerrormsg,
- "be_recvauth: host-based authentication failed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- break;
- case STARTUP_PASSWORD_MSG:
- if(!be_getauthsvc(msgtype)) {
- sprintf(PQerrormsg,
- "be_recvauth: "
- "plaintext password authentication disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
+ MsgType msgtype;
+
+ /*
+ * A message type of STARTUP_MSG (which once upon a time was the only
+ * startup message type) means user wants us to choose. "unauth" is
+ * what used to be the only choice, but installation may choose "hba"
+ * instead.
+ */
+ if (msgtype_arg == STARTUP_MSG)
+ {
+ if (useHostBasedAuth)
+ msgtype = STARTUP_HBA_MSG;
+ else
+ msgtype = STARTUP_UNAUTH_MSG;
+ }
+ else
+ msgtype = msgtype_arg;
+
+
+ if (!username)
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: no user name passed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ if (!port)
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: no port structure passed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
}
- if(pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK) {
- /* pg_password_recvauth or lower-level routines have already set */
- /* the error message */
- return(STATUS_ERROR);
+
+ switch (msgtype)
+ {
+ case STARTUP_KRB4_MSG:
+ if (!be_getauthsvc(msgtype))
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: krb4 authentication disallowed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ if (pg_krb4_recvauth(port->sock, &port->laddr, &port->raddr,
+ username) != STATUS_OK)
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: krb4 authentication failed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ break;
+ case STARTUP_KRB5_MSG:
+ if (!be_getauthsvc(msgtype))
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: krb5 authentication disallowed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
+ username) != STATUS_OK)
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: krb5 authentication failed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ break;
+ case STARTUP_UNAUTH_MSG:
+ if (!be_getauthsvc(msgtype))
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: "
+ "unauthenticated connections disallowed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ break;
+ case STARTUP_HBA_MSG:
+ if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK)
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: host-based authentication failed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ break;
+ case STARTUP_PASSWORD_MSG:
+ if (!be_getauthsvc(msgtype))
+ {
+ sprintf(PQerrormsg,
+ "be_recvauth: "
+ "plaintext password authentication disallowed\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ if (pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK)
+ {
+
+ /*
+ * pg_password_recvauth or lower-level routines have already
+ * set
+ */
+ /* the error message */
+ return (STATUS_ERROR);
+ }
+ break;
+ default:
+ sprintf(PQerrormsg,
+ "be_recvauth: unrecognized message type: %d\n",
+ msgtype);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
}
- break;
- default:
- sprintf(PQerrormsg,
- "be_recvauth: unrecognized message type: %d\n",
- msgtype);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- return(STATUS_OK);
+ return (STATUS_OK);
}
/*
* be_setauthsvc -- enable/disable the authentication services currently
- * selected for use by the backend
+ * selected for use by the backend
* be_getauthsvc -- returns whether a particular authentication system
- * (indicated by its message type) is permitted by the
- * current selections
+ * (indicated by its message type) is permitted by the
+ * current selections
*
* be_setauthsvc encodes the command-line syntax that
- * -a "<service-name>"
+ * -a "<service-name>"
* enables a service, whereas
- * -a "no<service-name>"
+ * -a "no<service-name>"
* disables it.
*/
void
be_setauthsvc(char *name)
{
- int i, j;
- int turnon = 1;
-
- if (!name)
- return;
- if (!strncmp("no", name, 2)) {
- turnon = 0;
- name += 2;
- }
- if (name[0] == '\0')
- return;
- for (i = 0; i < n_authsvcs; ++i)
- if (!strcmp(name, authsvcs[i].name)) {
- for (j = 0; j < n_authsvcs; ++j)
- if (authsvcs[j].msgtype == authsvcs[i].msgtype)
- authsvcs[j].allowed = turnon;
- break;
+ int i,
+ j;
+ int turnon = 1;
+
+ if (!name)
+ return;
+ if (!strncmp("no", name, 2))
+ {
+ turnon = 0;
+ name += 2;
}
- if (i == n_authsvcs) {
- sprintf(PQerrormsg,
- "be_setauthsvc: invalid name %s, ignoring...\n",
- name);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- }
- return;
+ if (name[0] == '\0')
+ return;
+ for (i = 0; i < n_authsvcs; ++i)
+ if (!strcmp(name, authsvcs[i].name))
+ {
+ for (j = 0; j < n_authsvcs; ++j)
+ if (authsvcs[j].msgtype == authsvcs[i].msgtype)
+ authsvcs[j].allowed = turnon;
+ break;
+ }
+ if (i == n_authsvcs)
+ {
+ sprintf(PQerrormsg,
+ "be_setauthsvc: invalid name %s, ignoring...\n",
+ name);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ }
+ return;
}
static int
be_getauthsvc(MsgType msgtype)
{
- int i;
-
- for (i = 0; i < n_authsvcs; ++i)
- if (msgtype == authsvcs[i].msgtype)
- return(authsvcs[i].allowed);
- return(0);
+ int i;
+
+ for (i = 0; i < n_authsvcs; ++i)
+ if (msgtype == authsvcs[i].msgtype)
+ return (authsvcs[i].allowed);
+ return (0);
}
diff --git a/src/backend/libpq/be-dumpdata.c b/src/backend/libpq/be-dumpdata.c
index b47e79fa65c..db0a99141d6 100644
--- a/src/backend/libpq/be-dumpdata.c
+++ b/src/backend/libpq/be-dumpdata.c
@@ -1,32 +1,32 @@
/*-------------------------------------------------------------------------
*
* be-dumpdata.c--
- * support for collection of returned tuples from an internal
- * PQ call into a backend buffer.
+ * support for collection of returned tuples from an internal
+ * PQ call into a backend buffer.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.5 1997/08/18 20:52:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.6 1997/09/07 04:42:12 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * be_portalinit - initialize backend portal administration
- * be_portalpush - add a portal to the top of the portal stack
- * be_portalpop - remove portal on the top of the stack & return it
- * be_currentportal - return the top portal on the portal stack
- * be_newportal - return a new portal.
- * be_portalinit - initialize backend portal expected to hold results.
- * be_printtup - add a tuple to a backend portal
+ * be_portalinit - initialize backend portal administration
+ * be_portalpush - add a portal to the top of the portal stack
+ * be_portalpop - remove portal on the top of the stack & return it
+ * be_currentportal - return the top portal on the portal stack
+ * be_newportal - return a new portal.
+ * be_portalinit - initialize backend portal expected to hold results.
+ * be_printtup - add a tuple to a backend portal
*
* NOTES
- * Since backend user-defined operators can call queries
- * which in turn call user-defined operators can call queries...
- * we have to keep track of portals on a stack. BeginCommand()
- * puts portals on the stack and the PQ functions remove them.
+ * Since backend user-defined operators can call queries
+ * which in turn call user-defined operators can call queries...
+ * we have to keep track of portals on a stack. BeginCommand()
+ * puts portals on the stack and the PQ functions remove them.
*
*/
#include <string.h>
@@ -48,274 +48,288 @@
#include <access/printtup.h>
/* ----------------
- * backend portal stack for recursive PQexec calls
+ * backend portal stack for recursive PQexec calls
* ----------------
*/
-static Dllist *be_portalstack;
+static Dllist *be_portalstack;
/* ----------------
- * be_portalinit - initialize backend portal administration
+ * be_portalinit - initialize backend portal administration
*
- * This is called once from InitPostgres() to initialize
- * the portal stack.
+ * This is called once from InitPostgres() to initialize
+ * the portal stack.
* ----------------
*/
void
be_portalinit(void)
{
- be_portalstack = DLNewList();
+ be_portalstack = DLNewList();
}
/* ----------------
- * be_portalpush - add a portal to the top of the portal stack
+ * be_portalpush - add a portal to the top of the portal stack
*
- * used by BeginCommand()
+ * used by BeginCommand()
* ----------------
*/
void
-be_portalpush(PortalEntry *entry)
+be_portalpush(PortalEntry * entry)
{
- DLAddTail(be_portalstack, DLNewElem(entry));
+ DLAddTail(be_portalstack, DLNewElem(entry));
}
/* ----------------
- * be_portalpop - remove the portal on the top of the stack & return it
+ * be_portalpop - remove the portal on the top of the stack & return it
*
- * used by PQexec()
+ * used by PQexec()
* ----------------
*/
-PortalEntry *
+PortalEntry *
be_portalpop(void)
{
- PortalEntry *p;
- Dlelem* elt;
- elt = DLRemTail(be_portalstack);
+ PortalEntry *p;
+ Dlelem *elt;
+
+ elt = DLRemTail(be_portalstack);
+
+ p = (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
+ DLFreeElem(elt);
+ return p;
- p = (elt ? (PortalEntry*)DLE_VAL(elt) : NULL);
- DLFreeElem(elt);
- return p;
-
}
/* ----------------
- * be_currentportal - return the top portal on the portal stack
+ * be_currentportal - return the top portal on the portal stack
*
- * used by be_printtup()
+ * used by be_printtup()
* ----------------
*/
-PortalEntry *
+PortalEntry *
be_currentportal(void)
{
- Dlelem* elt;
- elt = DLGetTail(be_portalstack);
- return (elt ? (PortalEntry*)DLE_VAL(elt) : NULL);
+ Dlelem *elt;
+
+ elt = DLGetTail(be_portalstack);
+ return (elt ? (PortalEntry *) DLE_VAL(elt) : NULL);
}
/* ----------------
- * be_newportal - return a new portal.
+ * be_newportal - return a new portal.
*
- * If the user-defined function does not specify a portal name,
- * we generate a unique one. Names are generated from a combination
- * of a postgres oid and an integer counter which is incremented
- * every time we ask for a local portal.
+ * If the user-defined function does not specify a portal name,
+ * we generate a unique one. Names are generated from a combination
+ * of a postgres oid and an integer counter which is incremented
+ * every time we ask for a local portal.
*
- * used by BeginCommand()
+ * used by BeginCommand()
* ----------------
*/
-static Oid be_portaloid;
+static Oid be_portaloid;
static u_int be_portalcnt = 0;
-PortalEntry *
-be_newportal(void)
+PortalEntry *
+be_newportal(void)
{
- PortalEntry *entry;
- char buf[PortalNameLength];
-
- /* ----------------
- * generate a new name
- * ----------------
- */
- if (be_portalcnt == 0)
- be_portaloid = newoid();
- be_portalcnt++;
- sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt);
-
- /* ----------------
- * initialize the new portal entry and keep track
- * of the current memory context for be_printtup().
- * This is important - otherwise whatever we allocate
- * will go away and the contents of the portal after
- * PQexec() returns will be meaningless.
- * ----------------
- */
- entry = pbuf_setup(buf);
- entry->portalcxt = (Pointer) CurrentMemoryContext;
-
- return entry;
+ PortalEntry *entry;
+ char buf[PortalNameLength];
+
+ /* ----------------
+ * generate a new name
+ * ----------------
+ */
+ if (be_portalcnt == 0)
+ be_portaloid = newoid();
+ be_portalcnt++;
+ sprintf(buf, "be_%d_%d", be_portaloid, be_portalcnt);
+
+ /* ----------------
+ * initialize the new portal entry and keep track
+ * of the current memory context for be_printtup().
+ * This is important - otherwise whatever we allocate
+ * will go away and the contents of the portal after
+ * PQexec() returns will be meaningless.
+ * ----------------
+ */
+ entry = pbuf_setup(buf);
+ entry->portalcxt = (Pointer) CurrentMemoryContext;
+
+ return entry;
}
/* ----------------
- * be_typeinit - initialize backend portal expected to hold
- * query results.
+ * be_typeinit - initialize backend portal expected to hold
+ * query results.
*
- * used by BeginCommand()
+ * used by BeginCommand()
* ----------------
*/
void
-be_typeinit(PortalEntry *entry,
- TupleDesc tupDesc,
- int natts)
+be_typeinit(PortalEntry * entry,
+ TupleDesc tupDesc,
+ int natts)
{
- PortalBuffer *portal;
- GroupBuffer *group;
- int i;
- AttributeTupleForm *attrs = tupDesc->attrs;
-
- /* ----------------
- * add a new portal group to the portal
- * ----------------
- */
- portal = entry->portal;
- portal->no_groups++;
- portal->groups = group = pbuf_addGroup(portal);
- group->no_fields = natts;
-
- /* ----------------
- * initialize portal group type info
- * ----------------
- */
- if (natts > 0) {
- group->types = pbuf_addTypes(natts);
- for (i = 0; i < natts; ++i) {
- strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN);
- group->types[i].adtid = attrs[i]->atttypid;
- group->types[i].adtsize = attrs[i]->attlen;
+ PortalBuffer *portal;
+ GroupBuffer *group;
+ int i;
+ AttributeTupleForm *attrs = tupDesc->attrs;
+
+ /* ----------------
+ * add a new portal group to the portal
+ * ----------------
+ */
+ portal = entry->portal;
+ portal->no_groups++;
+ portal->groups = group = pbuf_addGroup(portal);
+ group->no_fields = natts;
+
+ /* ----------------
+ * initialize portal group type info
+ * ----------------
+ */
+ if (natts > 0)
+ {
+ group->types = pbuf_addTypes(natts);
+ for (i = 0; i < natts; ++i)
+ {
+ strncpy(group->types[i].name, attrs[i]->attname.data, NAMEDATALEN);
+ group->types[i].adtid = attrs[i]->atttypid;
+ group->types[i].adtsize = attrs[i]->attlen;
+ }
}
- }
}
/* ----------------
- * be_printtup - add a tuple to a backend portal
+ * be_printtup - add a tuple to a backend portal
*
- * used indirectly by ExecRetrieve()
+ * used indirectly by ExecRetrieve()
*
- * This code is pretty much copied from printtup(), dump_type()
- * and dump_data(). -cim 2/12/91
+ * This code is pretty much copied from printtup(), dump_type()
+ * and dump_data(). -cim 2/12/91
* ----------------
*/
void
be_printtup(HeapTuple tuple, TupleDesc typeinfo)
{
- int i;
- char *attr;
- bool isnull;
- Oid typoutput;
-
- PortalEntry *entry = NULL;
- PortalBuffer *portal = NULL;
- GroupBuffer *group = NULL ;
- TupleBlock *tuples = NULL;
- char **values;
- int *lengths;
-
- MemoryContext savecxt;
-
- /* ----------------
- * get the current portal and group
- * ----------------
- */
- entry = be_currentportal();
- portal = entry->portal;
- group = portal->groups;
-
- /* ----------------
- * switch to the portal's memory context so that
- * the tuples we allocate are returned to the user.
- * ----------------
- */
- savecxt = MemoryContextSwitchTo((MemoryContext)entry->portalcxt);
-
- /* ----------------
- * If no tuple block yet, allocate one.
- * If the current block is full, allocate another one.
- * ----------------
- */
- if (group->tuples == NULL) {
- tuples = group->tuples = pbuf_addTuples();
- tuples->tuple_index = 0;
- } else {
- tuples = group->tuples;
- /* walk to the end of the linked list of TupleBlocks */
- while (tuples->next)
- tuples = tuples->next;
- /* now, tuples is the last TupleBlock, check to see if it is full.
- If so, allocate a new TupleBlock and add it to the end of
- the chain */
-
- if (tuples->tuple_index == TupleBlockSize) {
- tuples->next = pbuf_addTuples();
- tuples = tuples->next;
- tuples->tuple_index = 0;
+ int i;
+ char *attr;
+ bool isnull;
+ Oid typoutput;
+
+ PortalEntry *entry = NULL;
+ PortalBuffer *portal = NULL;
+ GroupBuffer *group = NULL;
+ TupleBlock *tuples = NULL;
+ char **values;
+ int *lengths;
+
+ MemoryContext savecxt;
+
+ /* ----------------
+ * get the current portal and group
+ * ----------------
+ */
+ entry = be_currentportal();
+ portal = entry->portal;
+ group = portal->groups;
+
+ /* ----------------
+ * switch to the portal's memory context so that
+ * the tuples we allocate are returned to the user.
+ * ----------------
+ */
+ savecxt = MemoryContextSwitchTo((MemoryContext) entry->portalcxt);
+
+ /* ----------------
+ * If no tuple block yet, allocate one.
+ * If the current block is full, allocate another one.
+ * ----------------
+ */
+ if (group->tuples == NULL)
+ {
+ tuples = group->tuples = pbuf_addTuples();
+ tuples->tuple_index = 0;
}
- }
-
- /* ----------------
- * Allocate space for a tuple.
- * ----------------
- */
- tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_natts);
- tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts);
- /* ----------------
- * copy printable representations of the tuple's attributes
- * to the portal.
- *
- * This seems silly, because the user's function which is calling
- * PQexec() or PQfn() will probably just convert this back into the
- * internal form anyways, but the point here is to provide a uniform
- * libpq interface and this is how the fe libpq interface currently
- * works. Pretty soon we'll have to add code to let the fe or be
- * select the desired data representation and then deal with that.
- * This should not be too hard, as there already exist typrecieve()
- * and typsend() procedures for user-defined types (see pg_type.h)
- * -cim 2/11/91
- * ----------------
- */
-
- values = tuples->values[tuples->tuple_index];
- lengths = tuples->lengths[tuples->tuple_index];
-
- for (i = 0; i < tuple->t_natts; i++) {
- attr = heap_getattr(tuple, InvalidBuffer, i+1, typeinfo, &isnull);
- typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
-
- lengths[i] = typeinfo->attrs[i]->attlen;
-
- if (lengths[i] == -1) /* variable length attribute */
- if (!isnull)
- lengths[i] = VARSIZE(attr)-VARHDRSZ;
- else
- lengths[i] = 0;
-
- if (!isnull && OidIsValid(typoutput)) {
- values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid));
- } else
- values[i] = NULL;
-
- }
-
- /* ----------------
- * increment tuple group counters
- * ----------------
- */
- portal->no_tuples++;
- group->no_tuples++;
- tuples->tuple_index++;
-
- /* ----------------
- * return to the original memory context
- * ----------------
- */
- MemoryContextSwitchTo(savecxt);
+ else
+ {
+ tuples = group->tuples;
+ /* walk to the end of the linked list of TupleBlocks */
+ while (tuples->next)
+ tuples = tuples->next;
+
+ /*
+ * now, tuples is the last TupleBlock, check to see if it is full.
+ * If so, allocate a new TupleBlock and add it to the end of the
+ * chain
+ */
+
+ if (tuples->tuple_index == TupleBlockSize)
+ {
+ tuples->next = pbuf_addTuples();
+ tuples = tuples->next;
+ tuples->tuple_index = 0;
+ }
+ }
+
+ /* ----------------
+ * Allocate space for a tuple.
+ * ----------------
+ */
+ tuples->values[tuples->tuple_index] = pbuf_addTuple(tuple->t_natts);
+ tuples->lengths[tuples->tuple_index] = pbuf_addTupleValueLengths(tuple->t_natts);
+ /* ----------------
+ * copy printable representations of the tuple's attributes
+ * to the portal.
+ *
+ * This seems silly, because the user's function which is calling
+ * PQexec() or PQfn() will probably just convert this back into the
+ * internal form anyways, but the point here is to provide a uniform
+ * libpq interface and this is how the fe libpq interface currently
+ * works. Pretty soon we'll have to add code to let the fe or be
+ * select the desired data representation and then deal with that.
+ * This should not be too hard, as there already exist typrecieve()
+ * and typsend() procedures for user-defined types (see pg_type.h)
+ * -cim 2/11/91
+ * ----------------
+ */
+
+ values = tuples->values[tuples->tuple_index];
+ lengths = tuples->lengths[tuples->tuple_index];
+
+ for (i = 0; i < tuple->t_natts; i++)
+ {
+ attr = heap_getattr(tuple, InvalidBuffer, i + 1, typeinfo, &isnull);
+ typoutput = typtoout((Oid) typeinfo->attrs[i]->atttypid);
+
+ lengths[i] = typeinfo->attrs[i]->attlen;
+
+ if (lengths[i] == -1) /* variable length attribute */
+ if (!isnull)
+ lengths[i] = VARSIZE(attr) - VARHDRSZ;
+ else
+ lengths[i] = 0;
+
+ if (!isnull && OidIsValid(typoutput))
+ {
+ values[i] = fmgr(typoutput, attr, gettypelem(typeinfo->attrs[i]->atttypid));
+ }
+ else
+ values[i] = NULL;
+
+ }
+
+ /* ----------------
+ * increment tuple group counters
+ * ----------------
+ */
+ portal->no_tuples++;
+ group->no_tuples++;
+ tuples->tuple_index++;
+
+ /* ----------------
+ * return to the original memory context
+ * ----------------
+ */
+ MemoryContextSwitchTo(savecxt);
}
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index 58a827838db..e3a464b087f 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -1,24 +1,24 @@
/*-------------------------------------------------------------------------
*
* be-fsstubs.c--
- * support for filesystem operations on large objects
+ * support for filesystem operations on large objects
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.12 1997/08/12 22:52:48 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.13 1997/09/07 04:42:15 momjian Exp $
*
* NOTES
- * This should be moved to a more appropriate place. It is here
- * for lack of a better place.
+ * This should be moved to a more appropriate place. It is here
+ * for lack of a better place.
*
- * Builtin functions for open/close/read/write operations on large objects.
+ * Builtin functions for open/close/read/write operations on large objects.
*
- * These functions operate in the current portal variable context, which
- * means the large object descriptors hang around between transactions and
- * are not deallocated until explicitly closed, or until the portal is
- * closed.
+ * These functions operate in the current portal variable context, which
+ * means the large object descriptors hang around between transactions and
+ * are not deallocated until explicitly closed, or until the portal is
+ * closed.
*-------------------------------------------------------------------------
*/
@@ -37,340 +37,364 @@
#include <utils/memutils.h>
#include <lib/fstack.h>
#include <utils/mcxt.h>
-#include <storage/fd.h> /* for O_ */
+#include <storage/fd.h> /* for O_ */
#include <storage/large_object.h>
#include <libpq/be-fsstubs.h>
/*#define FSDB 1*/
#define MAX_LOBJ_FDS 256
-static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
+static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
static GlobalMemory fscxt = NULL;
-static int newLOfd(LargeObjectDesc *lobjCookie);
-static void deleteLOfd(int fd);
+static int newLOfd(LargeObjectDesc * lobjCookie);
+static void deleteLOfd(int fd);
/*****************************************************************************
- * File Interfaces for Large Objects
+ * File Interfaces for Large Objects
*****************************************************************************/
int
lo_open(Oid lobjId, int mode)
{
- LargeObjectDesc *lobjDesc;
- int fd;
- MemoryContext currentContext;
-
+ LargeObjectDesc *lobjDesc;
+ int fd;
+ MemoryContext currentContext;
+
#if FSDB
- elog(NOTICE,"LOopen(%d,%d)",lobjId,mode);
+ elog(NOTICE, "LOopen(%d,%d)", lobjId, mode);
#endif
- if (fscxt == NULL) {
- fscxt = CreateGlobalMemory("Filesystem");
- }
- currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
+ if (fscxt == NULL)
+ {
+ fscxt = CreateGlobalMemory("Filesystem");
+ }
+ currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
- lobjDesc = inv_open(lobjId, mode);
-
- if (lobjDesc == NULL) { /* lookup failed */
- MemoryContextSwitchTo(currentContext);
-#if FSDB
- elog(NOTICE,"cannot open large object %d", lobjId);
+ lobjDesc = inv_open(lobjId, mode);
+
+ if (lobjDesc == NULL)
+ { /* lookup failed */
+ MemoryContextSwitchTo(currentContext);
+#if FSDB
+ elog(NOTICE, "cannot open large object %d", lobjId);
#endif
- return -1;
- }
-
- fd = newLOfd(lobjDesc);
+ return -1;
+ }
+
+ fd = newLOfd(lobjDesc);
- /* switch context back to orig. */
- MemoryContextSwitchTo(currentContext);
+ /* switch context back to orig. */
+ MemoryContextSwitchTo(currentContext);
- return fd;
+ return fd;
}
int
lo_close(int fd)
{
- MemoryContext currentContext;
-
- if (fd >= MAX_LOBJ_FDS) {
- elog(WARN,"lo_close: large obj descriptor (%d) out of range", fd);
- return -2;
- }
- if (cookies[fd] == NULL) {
- elog(WARN,"lo_close: invalid large obj descriptor (%d)", fd);
- return -3;
- }
+ MemoryContext currentContext;
+
+ if (fd >= MAX_LOBJ_FDS)
+ {
+ elog(WARN, "lo_close: large obj descriptor (%d) out of range", fd);
+ return -2;
+ }
+ if (cookies[fd] == NULL)
+ {
+ elog(WARN, "lo_close: invalid large obj descriptor (%d)", fd);
+ return -3;
+ }
#if FSDB
- elog(NOTICE,"LOclose(%d)",fd);
+ elog(NOTICE, "LOclose(%d)", fd);
#endif
- Assert(fscxt != NULL);
- currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
+ Assert(fscxt != NULL);
+ currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
- inv_close(cookies[fd]);
+ inv_close(cookies[fd]);
- MemoryContextSwitchTo(currentContext);
+ MemoryContextSwitchTo(currentContext);
- deleteLOfd(fd);
- return 0;
+ deleteLOfd(fd);
+ return 0;
}
/*
- * We assume the large object supports byte oriented reads and seeks so
- * that our work is easier.
+ * We assume the large object supports byte oriented reads and seeks so
+ * that our work is easier.
*/
int
lo_read(int fd, char *buf, int len)
{
- Assert(cookies[fd]!=NULL);
- return inv_read(cookies[fd], buf, len);
+ Assert(cookies[fd] != NULL);
+ return inv_read(cookies[fd], buf, len);
}
int
lo_write(int fd, char *buf, int len)
{
- Assert(cookies[fd]!=NULL);
- return inv_write(cookies[fd], buf, len);
+ Assert(cookies[fd] != NULL);
+ return inv_write(cookies[fd], buf, len);
}
int
lo_lseek(int fd, int offset, int whence)
{
- MemoryContext currentContext;
- int ret;
+ MemoryContext currentContext;
+ int ret;
- if (fd >= MAX_LOBJ_FDS) {
- elog(WARN,"lo_seek: large obj descriptor (%d) out of range", fd);
- return -2;
- }
+ if (fd >= MAX_LOBJ_FDS)
+ {
+ elog(WARN, "lo_seek: large obj descriptor (%d) out of range", fd);
+ return -2;
+ }
- currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
+ currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
- ret = inv_seek(cookies[fd], offset, whence);
+ ret = inv_seek(cookies[fd], offset, whence);
- MemoryContextSwitchTo(currentContext);
+ MemoryContextSwitchTo(currentContext);
- return ret;
+ return ret;
}
Oid
lo_creat(int mode)
{
- LargeObjectDesc *lobjDesc;
- MemoryContext currentContext;
- Oid lobjId;
-
- if (fscxt == NULL) {
- fscxt = CreateGlobalMemory("Filesystem");
- }
-
- currentContext = MemoryContextSwitchTo((MemoryContext)fscxt);
-
- lobjDesc = inv_create(mode);
-
- if (lobjDesc == NULL) {
+ LargeObjectDesc *lobjDesc;
+ MemoryContext currentContext;
+ Oid lobjId;
+
+ if (fscxt == NULL)
+ {
+ fscxt = CreateGlobalMemory("Filesystem");
+ }
+
+ currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+
+ lobjDesc = inv_create(mode);
+
+ if (lobjDesc == NULL)
+ {
+ MemoryContextSwitchTo(currentContext);
+ return InvalidOid;
+ }
+
+ lobjId = lobjDesc->heap_r->rd_id;
+
+ inv_close(lobjDesc);
+
+ /* switch context back to original memory context */
MemoryContextSwitchTo(currentContext);
- return InvalidOid;
- }
-
- lobjId = lobjDesc->heap_r->rd_id;
-
- inv_close(lobjDesc);
-
- /* switch context back to original memory context */
- MemoryContextSwitchTo(currentContext);
-
- return lobjId;
+
+ return lobjId;
}
int
lo_tell(int fd)
{
- if (fd >= MAX_LOBJ_FDS) {
- elog(WARN,"lo_tell: large object descriptor (%d) out of range",fd);
- return -2;
- }
- if (cookies[fd] == NULL) {
- elog(WARN,"lo_tell: invalid large object descriptor (%d)",fd);
- return -3;
- }
- return inv_tell(cookies[fd]);
+ if (fd >= MAX_LOBJ_FDS)
+ {
+ elog(WARN, "lo_tell: large object descriptor (%d) out of range", fd);
+ return -2;
+ }
+ if (cookies[fd] == NULL)
+ {
+ elog(WARN, "lo_tell: invalid large object descriptor (%d)", fd);
+ return -3;
+ }
+ return inv_tell(cookies[fd]);
}
int
lo_unlink(Oid lobjId)
{
- return (inv_destroy(lobjId));
+ return (inv_destroy(lobjId));
}
/*****************************************************************************
- * Read/Write using varlena
+ * Read/Write using varlena
*****************************************************************************/
struct varlena *
loread(int fd, int len)
{
- struct varlena *retval;
- int totalread = 0;
-
- retval = (struct varlena *)palloc(sizeof(int32) + len);
- totalread = lo_read(fd, VARDATA(retval), len);
- VARSIZE(retval) = totalread + sizeof(int32);
-
- return retval;
+ struct varlena *retval;
+ int totalread = 0;
+
+ retval = (struct varlena *) palloc(sizeof(int32) + len);
+ totalread = lo_read(fd, VARDATA(retval), len);
+ VARSIZE(retval) = totalread + sizeof(int32);
+
+ return retval;
}
-int lowrite(int fd, struct varlena *wbuf)
+int
+lowrite(int fd, struct varlena * wbuf)
{
- int totalwritten;
- int bytestowrite;
-
- bytestowrite = VARSIZE(wbuf) - sizeof(int32);
- totalwritten = lo_write(fd, VARDATA(wbuf), bytestowrite);
- return totalwritten;
+ int totalwritten;
+ int bytestowrite;
+
+ bytestowrite = VARSIZE(wbuf) - sizeof(int32);
+ totalwritten = lo_write(fd, VARDATA(wbuf), bytestowrite);
+ return totalwritten;
}
/*****************************************************************************
- * Import/Export of Large Object
+ * Import/Export of Large Object
*****************************************************************************/
/*
* lo_import -
- * imports a file as an (inversion) large object.
+ * imports a file as an (inversion) large object.
*/
Oid
-lo_import(text *filename)
+lo_import(text * filename)
{
- int fd;
- int nbytes, tmp;
-#define BUFSIZE 1024
- char buf[BUFSIZE];
- char fnamebuf[8192];
- LargeObjectDesc *lobj;
- Oid lobjOid;
-
- /*
- * open the file to be read in
- */
- strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
- fd = open(fnamebuf, O_RDONLY, 0666);
- if (fd < 0) { /* error */
- elog(WARN, "be_lo_import: can't open unix file\"%s\"\n",
- fnamebuf);
- }
-
- /*
- * create an inversion "object"
- */
- lobj = inv_create(INV_READ|INV_WRITE);
- if (lobj == NULL) {
- elog(WARN, "lo_import: can't create inv object for \"%s\"",
- fnamebuf);
- }
-
- /*
- * the oid for the large object is just the oid of the relation
- * XInv??? which contains the data.
- */
- lobjOid = lobj->heap_r->rd_id;
-
- /*
- * read in from the Unix file and write to the inversion file
- */
- while ((nbytes = read(fd, buf, BUFSIZE)) > 0) {
- tmp = inv_write(lobj, buf, nbytes);
- if (tmp < nbytes) {
- elog(WARN, "lo_import: error while reading \"%s\"",
- fnamebuf);
+ int fd;
+ int nbytes,
+ tmp;
+
+#define BUFSIZE 1024
+ char buf[BUFSIZE];
+ char fnamebuf[8192];
+ LargeObjectDesc *lobj;
+ Oid lobjOid;
+
+ /*
+ * open the file to be read in
+ */
+ strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
+ fd = open(fnamebuf, O_RDONLY, 0666);
+ if (fd < 0)
+ { /* error */
+ elog(WARN, "be_lo_import: can't open unix file\"%s\"\n",
+ fnamebuf);
}
- }
- close(fd);
- inv_close(lobj);
+ /*
+ * create an inversion "object"
+ */
+ lobj = inv_create(INV_READ | INV_WRITE);
+ if (lobj == NULL)
+ {
+ elog(WARN, "lo_import: can't create inv object for \"%s\"",
+ fnamebuf);
+ }
- return lobjOid;
+ /*
+ * the oid for the large object is just the oid of the relation
+ * XInv??? which contains the data.
+ */
+ lobjOid = lobj->heap_r->rd_id;
+
+ /*
+ * read in from the Unix file and write to the inversion file
+ */
+ while ((nbytes = read(fd, buf, BUFSIZE)) > 0)
+ {
+ tmp = inv_write(lobj, buf, nbytes);
+ if (tmp < nbytes)
+ {
+ elog(WARN, "lo_import: error while reading \"%s\"",
+ fnamebuf);
+ }
+ }
+
+ close(fd);
+ inv_close(lobj);
+
+ return lobjOid;
}
/*
* lo_export -
- * exports an (inversion) large object.
+ * exports an (inversion) large object.
*/
int4
-lo_export(Oid lobjId, text *filename)
+lo_export(Oid lobjId, text * filename)
{
- int fd;
- int nbytes, tmp;
-#define BUFSIZE 1024
- char buf[BUFSIZE];
- char fnamebuf[8192];
- LargeObjectDesc *lobj;
- mode_t oumask;
-
- /*
- * create an inversion "object"
- */
- lobj = inv_open(lobjId, INV_READ);
- if (lobj == NULL) {
- elog(WARN, "lo_export: can't open inv object %d",
- lobjId);
- }
-
- /*
- * open the file to be written to
- */
- oumask = umask((mode_t) 0);
- strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
- fd = open(fnamebuf, O_CREAT|O_WRONLY, 0666);
- umask(oumask);
- if (fd < 0) { /* error */
- elog(WARN, "lo_export: can't open unix file\"%s\"",
- fnamebuf);
- }
-
- /*
- * read in from the Unix file and write to the inversion file
- */
- while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0) {
- tmp = write(fd, buf, nbytes);
- if (tmp < nbytes) {
- elog(WARN, "lo_export: error while writing \"%s\"",
- fnamebuf);
+ int fd;
+ int nbytes,
+ tmp;
+
+#define BUFSIZE 1024
+ char buf[BUFSIZE];
+ char fnamebuf[8192];
+ LargeObjectDesc *lobj;
+ mode_t oumask;
+
+ /*
+ * create an inversion "object"
+ */
+ lobj = inv_open(lobjId, INV_READ);
+ if (lobj == NULL)
+ {
+ elog(WARN, "lo_export: can't open inv object %d",
+ lobjId);
+ }
+
+ /*
+ * open the file to be written to
+ */
+ oumask = umask((mode_t) 0);
+ strNcpy(fnamebuf, VARDATA(filename), VARSIZE(filename) - VARHDRSZ);
+ fd = open(fnamebuf, O_CREAT | O_WRONLY, 0666);
+ umask(oumask);
+ if (fd < 0)
+ { /* error */
+ elog(WARN, "lo_export: can't open unix file\"%s\"",
+ fnamebuf);
}
- }
- inv_close(lobj);
- close(fd);
+ /*
+ * read in from the Unix file and write to the inversion file
+ */
+ while ((nbytes = inv_read(lobj, buf, BUFSIZE)) > 0)
+ {
+ tmp = write(fd, buf, nbytes);
+ if (tmp < nbytes)
+ {
+ elog(WARN, "lo_export: error while writing \"%s\"",
+ fnamebuf);
+ }
+ }
+
+ inv_close(lobj);
+ close(fd);
- return 1;
+ return 1;
}
/*****************************************************************************
- * Support routines for this file
+ * Support routines for this file
*****************************************************************************/
static int
-newLOfd(LargeObjectDesc *lobjCookie)
+newLOfd(LargeObjectDesc * lobjCookie)
{
- int i;
-
- for (i = 0; i < MAX_LOBJ_FDS; i++) {
-
- if (cookies[i] == NULL) {
- cookies[i] = lobjCookie;
- return i;
+ int i;
+
+ for (i = 0; i < MAX_LOBJ_FDS; i++)
+ {
+
+ if (cookies[i] == NULL)
+ {
+ cookies[i] = lobjCookie;
+ return i;
+ }
}
- }
- return -1;
+ return -1;
}
-static void
+static void
deleteLOfd(int fd)
{
- cookies[fd] = NULL;
+ cookies[fd] = NULL;
}
diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c
index caa710129a9..06185e4534f 100644
--- a/src/backend/libpq/be-pqexec.c
+++ b/src/backend/libpq/be-pqexec.c
@@ -1,24 +1,24 @@
/*-------------------------------------------------------------------------
*
* be-pqexec.c--
- * support for executing POSTGRES commands and functions from a
- * user-defined function in a backend.
+ * support for executing POSTGRES commands and functions from a
+ * user-defined function in a backend.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.4 1997/08/19 21:31:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.5 1997/09/07 04:42:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * PQfn - call a POSTGRES function
- * PQexec - execute a POSTGRES query
- *
+ * PQfn - call a POSTGRES function
+ * PQexec - execute a POSTGRES query
+ *
* NOTES
- * These routines are compiled into the postgres backend.
+ * These routines are compiled into the postgres backend.
*/
#include <postgres.h>
@@ -32,356 +32,395 @@
#include <utils/exc.h>
#include <utils/builtins.h>
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static char *strmake(char *str, int len);
+static char *strmake(char *str, int len);
/* ----------------------------------------------------------------
- * PQ interface routines
+ * PQ interface routines
* ----------------------------------------------------------------
*/
/* ----------------
- * PQfn - Send a function call to the POSTGRES backend.
+ * PQfn - Send a function call to the POSTGRES backend.
*
- * fnid : function id
- * result_buf : pointer to result buffer (&int if integer)
- * result_len : length of return value.
- * result_is_int : If the result is an integer, this must be non-zero
- * args : pointer to a NULL terminated arg array.
- * (length, if integer, and result-pointer)
- * nargs : # of arguments in args array.
+ * fnid : function id
+ * result_buf : pointer to result buffer (&int if integer)
+ * result_len : length of return value.
+ * result_is_int : If the result is an integer, this must be non-zero
+ * args : pointer to a NULL terminated arg array.
+ * (length, if integer, and result-pointer)
+ * nargs : # of arguments in args array.
*
- * This code scavanged from HandleFunctionRequest() in tcop/fastpath.h
+ * This code scavanged from HandleFunctionRequest() in tcop/fastpath.h
* ----------------
*/
-char *
+char *
PQfn(int fnid,
- int *result_buf, /* can't use void, dec compiler barfs */
- int result_len,
- int result_is_int,
- PQArgBlock *args,
- int nargs)
+ int *result_buf, /* can't use void, dec compiler barfs */
+ int result_len,
+ int result_is_int,
+ PQArgBlock * args,
+ int nargs)
{
- char *retval; /* XXX - should be datum, maybe ? */
- char *arg[8];
- int i;
-
- /* ----------------
- * fill args[] array
- * ----------------
- */
- for (i = 0; i < nargs; i++) {
- if (args[i].len == VAR_LENGTH_ARG) {
- arg[i] = (char*) args[i].u.ptr;
- } else if (args[i].len > 4) {
- elog(WARN,"arg_length of argument %d too long",i);
- } else {
- arg[i] = (char*)args[i].u.integer;
+ char *retval; /* XXX - should be datum, maybe ? */
+ char *arg[8];
+ int i;
+
+ /* ----------------
+ * fill args[] array
+ * ----------------
+ */
+ for (i = 0; i < nargs; i++)
+ {
+ if (args[i].len == VAR_LENGTH_ARG)
+ {
+ arg[i] = (char *) args[i].u.ptr;
+ }
+ else if (args[i].len > 4)
+ {
+ elog(WARN, "arg_length of argument %d too long", i);
+ }
+ else
+ {
+ arg[i] = (char *) args[i].u.integer;
+ }
}
- }
-
- /* ----------------
- * call the postgres function manager
- * ----------------
- */
- retval = (char *)
- fmgr(fnid, arg[0], arg[1], arg[2], arg[3],
- arg[4], arg[5], arg[6], arg[7]);
-
- /* ----------------
- * put the result in the buffer the user specified and
- * return the proper code.
- * ----------------
- */
- if (retval == (char *) NULL) /* void retval */
- return "0";
-
- if (result_is_int) {
- *result_buf = (int) retval;
- } else {
- memmove(result_buf, retval, result_len);
- }
- return "G";
+
+ /* ----------------
+ * call the postgres function manager
+ * ----------------
+ */
+ retval = (char *)
+ fmgr(fnid, arg[0], arg[1], arg[2], arg[3],
+ arg[4], arg[5], arg[6], arg[7]);
+
+ /* ----------------
+ * put the result in the buffer the user specified and
+ * return the proper code.
+ * ----------------
+ */
+ if (retval == (char *) NULL)/* void retval */
+ return "0";
+
+ if (result_is_int)
+ {
+ *result_buf = (int) retval;
+ }
+ else
+ {
+ memmove(result_buf, retval, result_len);
+ }
+ return "G";
}
/* ----------------
- * PQexec - Send a query to the POSTGRES backend
+ * PQexec - Send a query to the POSTGRES backend
*
- * The return value is a string.
- * If 0 or more tuples fetched from the backend, return "P portal-name".
- * If a query is does not return tuples, return "C query-command".
- * If there is an error: return "E error-message".
+ * The return value is a string.
+ * If 0 or more tuples fetched from the backend, return "P portal-name".
+ * If a query is does not return tuples, return "C query-command".
+ * If there is an error: return "E error-message".
*
- * Note: if we get a serious error or an elog(WARN), then PQexec never
- * returns because the system longjmp's back to the main loop.
+ * Note: if we get a serious error or an elog(WARN), then PQexec never
+ * returns because the system longjmp's back to the main loop.
* ----------------
*/
-char *
+char *
PQexec(char *query)
{
- PortalEntry *entry = NULL;
- char *result = NULL;
-
- /* ----------------
- * create a new portal and put it on top of the portal stack.
- * ----------------
- */
- entry = (PortalEntry *) be_newportal();
- be_portalpush(entry);
-
- /* ----------------
- * pg_eval_dest will put the query results in a portal which will
- * end up on the top of the portal stack.
- * ----------------
- */
- pg_eval_dest(query, (char **) NULL, (Oid *) NULL, 0, Local);
-
- /* ----------------
- * pop the portal off the portal stack and return the
- * result. Note if result is null, we return C.
- * ----------------
- */
- entry = (PortalEntry *) be_portalpop();
- result = entry->result;
- if (result == NULL) {
- char *PQE = "Cnull PQexec result";
- result = pstrdup(PQE);
- }
-
- if (result[0] != 'P')
+ PortalEntry *entry = NULL;
+ char *result = NULL;
+
+ /* ----------------
+ * create a new portal and put it on top of the portal stack.
+ * ----------------
+ */
+ entry = (PortalEntry *) be_newportal();
+ be_portalpush(entry);
+
+ /* ----------------
+ * pg_eval_dest will put the query results in a portal which will
+ * end up on the top of the portal stack.
+ * ----------------
+ */
+ pg_eval_dest(query, (char **) NULL, (Oid *) NULL, 0, Local);
+
+ /* ----------------
+ * pop the portal off the portal stack and return the
+ * result. Note if result is null, we return C.
+ * ----------------
+ */
+ entry = (PortalEntry *) be_portalpop();
+ result = entry->result;
+ if (result == NULL)
{
- /* some successful command was executed,
- but it's not one where we return the portal name so
- here we should be sure to clear out the portal
- (since the caller has no handle on it)
- */
- pbuf_close(entry->name);
-
+ char *PQE = "Cnull PQexec result";
+
+ result = pstrdup(PQE);
}
- return result;
+
+ if (result[0] != 'P')
+ {
+
+ /*
+ * some successful command was executed, but it's not one where we
+ * return the portal name so here we should be sure to clear out
+ * the portal (since the caller has no handle on it)
+ */
+ pbuf_close(entry->name);
+
+ }
+ return result;
}
/* ----------------------------------------------------------------
- * pqtest support
+ * pqtest support
* ----------------------------------------------------------------
*/
/* ----------------
- * pqtest_PQexec takes a text query and returns the number of
- * tuples it returns. Note: there is no need to PQclear()
- * here - the memory will go away at end transaction.
+ * pqtest_PQexec takes a text query and returns the number of
+ * tuples it returns. Note: there is no need to PQclear()
+ * here - the memory will go away at end transaction.
* ----------------
*/
int
pqtest_PQexec(char *q)
{
- PortalBuffer *a;
- char *res;
- int t;
-
- /* ----------------
- * execute the postgres query
- * ----------------
- */
- res = PQexec(q);
-
- /* ----------------
- * return number of tuples in portal or 0 if command returns no tuples.
- * ----------------
- */
- t = 0;
- switch(res[0]) {
- case 'P':
- a = PQparray(&res[1]);
- if (a == NULL)
- elog(WARN, "pqtest_PQexec: PQparray could not find portal %s",
- res);
-
- t = PQntuples(a);
- break;
- case 'C':
- break;
- default:
- elog(NOTICE, "pqtest_PQexec: PQexec(%s) returns %s", q, res);
- break;
- }
-
- return t;
+ PortalBuffer *a;
+ char *res;
+ int t;
+
+ /* ----------------
+ * execute the postgres query
+ * ----------------
+ */
+ res = PQexec(q);
+
+ /* ----------------
+ * return number of tuples in portal or 0 if command returns no tuples.
+ * ----------------
+ */
+ t = 0;
+ switch (res[0])
+ {
+ case 'P':
+ a = PQparray(&res[1]);
+ if (a == NULL)
+ elog(WARN, "pqtest_PQexec: PQparray could not find portal %s",
+ res);
+
+ t = PQntuples(a);
+ break;
+ case 'C':
+ break;
+ default:
+ elog(NOTICE, "pqtest_PQexec: PQexec(%s) returns %s", q, res);
+ break;
+ }
+
+ return t;
}
/* ----------------
- * utilities for pqtest_PQfn()
+ * utilities for pqtest_PQfn()
* ----------------
*/
-static char *
+static char *
strmake(char *str, int len)
{
- char *newstr;
- if (str == NULL) return NULL;
- if (len <= 0) len = strlen(str);
-
- newstr = (char *) palloc((unsigned) len+1);
- strNcpy(newstr, str, len);
- newstr[len] = (char) 0;
- return newstr;
+ char *newstr;
+
+ if (str == NULL)
+ return NULL;
+ if (len <= 0)
+ len = strlen(str);
+
+ newstr = (char *) palloc((unsigned) len + 1);
+ strNcpy(newstr, str, len);
+ newstr[len] = (char) 0;
+ return newstr;
}
#define SKIP 0
#define SCAN 1
-static char spacestr[] = " ";
+static char spacestr[] = " ";
static int
strparse(char *s, char **fields, int *offsets, int maxfields)
{
- int len = strlen(s);
- char *cp = s, *end = cp + len, *ep;
- int parsed = 0;
- int mode = SKIP, i = 0;
-
- if (*(end - 1) == '\n') end--;
-
- for (i=0; i<maxfields; i++)
- fields[i] = spacestr;
-
- i = 0;
- while (!parsed) {
- if (mode == SKIP) {
-
- while ((cp < end) &&
- (*cp == ' ' || *cp == '\t'))
- cp++;
- if (cp < end) mode = SCAN;
- else parsed = 1;
-
- } else {
-
- ep = cp;
- while ((ep < end) && (*ep != ' ' && *ep != '\t'))
- ep++;
-
- if (ep < end) mode = SKIP;
- else parsed = 1;
-
- fields[i] = strmake(cp, ep - cp);
- if (offsets != NULL)
- offsets[i] = cp - s;
-
- i++;
- cp = ep;
- if (i > maxfields)
- parsed = 1;
-
+ int len = strlen(s);
+ char *cp = s,
+ *end = cp + len,
+ *ep;
+ int parsed = 0;
+ int mode = SKIP,
+ i = 0;
+
+ if (*(end - 1) == '\n')
+ end--;
+
+ for (i = 0; i < maxfields; i++)
+ fields[i] = spacestr;
+
+ i = 0;
+ while (!parsed)
+ {
+ if (mode == SKIP)
+ {
+
+ while ((cp < end) &&
+ (*cp == ' ' || *cp == '\t'))
+ cp++;
+ if (cp < end)
+ mode = SCAN;
+ else
+ parsed = 1;
+
+ }
+ else
+ {
+
+ ep = cp;
+ while ((ep < end) && (*ep != ' ' && *ep != '\t'))
+ ep++;
+
+ if (ep < end)
+ mode = SKIP;
+ else
+ parsed = 1;
+
+ fields[i] = strmake(cp, ep - cp);
+ if (offsets != NULL)
+ offsets[i] = cp - s;
+
+ i++;
+ cp = ep;
+ if (i > maxfields)
+ parsed = 1;
+
+ }
}
- }
- return i;
+ return i;
}
/* ----------------
- * pqtest_PQfn converts it's string into a PQArgBlock and
- * calls the specified function, which is assumed to return
- * an integer value.
+ * pqtest_PQfn converts it's string into a PQArgBlock and
+ * calls the specified function, which is assumed to return
+ * an integer value.
* ----------------
*/
int
pqtest_PQfn(char *q)
{
- int k, j, i, v, f, offsets;
- char *fields[8];
- PQArgBlock pqargs[7];
- int res;
- char *pqres;
-
- /* ----------------
- * parse q into fields
- * ----------------
- */
- i = strparse(q, fields, &offsets, 8);
- printf("pqtest_PQfn: strparse returns %d fields\n", i); /* debug */
- if (i == 0)
- return -1;
-
- /* ----------------
- * get the function id
- * ----------------
- */
- f = atoi(fields[0]);
- printf("pqtest_PQfn: func is %d\n", f); /* debug */
- if (f == 0)
- return -1;
-
- /* ----------------
- * build a PQArgBlock
- * ----------------
- */
- for (j=1; j<i && j<8; j++) {
- k = j-1;
- v = atoi(fields[j]);
- if (v != 0 || (v == 0 && fields[j][0] == '0')) {
- pqargs[k].len = 4;
- pqargs[k].u.integer = v;
- printf("pqtest_PQfn: arg %d is int %d\n", k, v); /* debug */
- } else {
- pqargs[k].len = VAR_LENGTH_ARG;
- pqargs[k].u.ptr = (int *) textin(fields[j]);
- printf("pqtest_PQfn: arg %d is text %s\n", k, fields[j]); /*debug*/
+ int k,
+ j,
+ i,
+ v,
+ f,
+ offsets;
+ char *fields[8];
+ PQArgBlock pqargs[7];
+ int res;
+ char *pqres;
+
+ /* ----------------
+ * parse q into fields
+ * ----------------
+ */
+ i = strparse(q, fields, &offsets, 8);
+ printf("pqtest_PQfn: strparse returns %d fields\n", i); /* debug */
+ if (i == 0)
+ return -1;
+
+ /* ----------------
+ * get the function id
+ * ----------------
+ */
+ f = atoi(fields[0]);
+ printf("pqtest_PQfn: func is %d\n", f); /* debug */
+ if (f == 0)
+ return -1;
+
+ /* ----------------
+ * build a PQArgBlock
+ * ----------------
+ */
+ for (j = 1; j < i && j < 8; j++)
+ {
+ k = j - 1;
+ v = atoi(fields[j]);
+ if (v != 0 || (v == 0 && fields[j][0] == '0'))
+ {
+ pqargs[k].len = 4;
+ pqargs[k].u.integer = v;
+ printf("pqtest_PQfn: arg %d is int %d\n", k, v); /* debug */
+ }
+ else
+ {
+ pqargs[k].len = VAR_LENGTH_ARG;
+ pqargs[k].u.ptr = (int *) textin(fields[j]);
+ printf("pqtest_PQfn: arg %d is text %s\n", k, fields[j]); /* debug */
+ }
+ }
+
+ /* ----------------
+ * call PQfn
+ * ----------------
+ */
+ pqres = PQfn(f, &res, 4, 1, pqargs, i - 1);
+ printf("pqtest_PQfn: pqres is %s\n", pqres); /* debug */
+
+ /* ----------------
+ * free memory used
+ * ----------------
+ */
+ for (j = 0; j < i; j++)
+ {
+ pfree(fields[j]);
+ if (pqargs[j].len == VAR_LENGTH_ARG)
+ pfree(pqargs[j].u.ptr);
}
- }
-
- /* ----------------
- * call PQfn
- * ----------------
- */
- pqres = PQfn(f, &res, 4, 1, pqargs, i-1);
- printf("pqtest_PQfn: pqres is %s\n", pqres); /* debug */
-
- /* ----------------
- * free memory used
- * ----------------
- */
- for (j=0; j<i; j++) {
- pfree(fields[j]);
- if (pqargs[j].len == VAR_LENGTH_ARG)
- pfree(pqargs[j].u.ptr);
- }
-
- /* ----------------
- * return result
- * ----------------
- */
- printf("pqtest_PQfn: res is %d\n", res); /* debugg */
- return res;
+
+ /* ----------------
+ * return result
+ * ----------------
+ */
+ printf("pqtest_PQfn: res is %d\n", res); /* debugg */
+ return res;
}
/* ----------------
- * pqtest looks at the first character of it's test argument
- * and decides which of pqtest_PQexec or pqtest_PQfn to call.
+ * pqtest looks at the first character of it's test argument
+ * and decides which of pqtest_PQexec or pqtest_PQfn to call.
* ----------------
*/
int32
-pqtest(struct varlena *vlena)
+pqtest(struct varlena * vlena)
{
- char *q;
-
- /* ----------------
- * get the query
- * ----------------
- */
- q = textout(vlena);
- if (q == NULL)
- return -1;
-
- switch(q[0]) {
- case '%':
- return pqtest_PQfn(&q[1]);
- break;
- default:
- return pqtest_PQexec(q);
- break;
- }
- return(0);
+ char *q;
+
+ /* ----------------
+ * get the query
+ * ----------------
+ */
+ q = textout(vlena);
+ if (q == NULL)
+ return -1;
+
+ switch (q[0])
+ {
+ case '%':
+ return pqtest_PQfn(&q[1]);
+ break;
+ default:
+ return pqtest_PQexec(q);
+ break;
+ }
+ return (0);
}
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 0cc2bbf6ac9..014eca14fa3 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* hba.c--
- * Routines to handle host based authentication (that's the scheme
- * wherein you authenticate a user by seeing what IP address the system
- * says he comes from and possibly using ident).
+ * Routines to handle host based authentication (that's the scheme
+ * wherein you authenticate a user by seeing what IP address the system
+ * says he comes from and possibly using ident).
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.19 1997/08/27 03:48:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.20 1997/09/07 04:42:21 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,263 +27,356 @@
#include <libpq/libpq.h>
#include <libpq/pqcomm.h>
#include <libpq/hba.h>
-#include <port/inet_aton.h> /* For inet_aton() */
+#include <port/inet_aton.h> /* For inet_aton() */
#include <storage/fd.h>
/* Some standard C libraries, including GNU, have an isblank() function.
Others, including Solaris, do not. So we have our own.
*/
-static bool
-isblank(const char c) {
- return(c == ' ' || c == 9 /* tab */);
+static bool
+isblank(const char c)
+{
+ return (c == ' ' || c == 9 /* tab */ );
}
-static void
-next_token(FILE *fp, char *buf, const int bufsz) {
+static void
+next_token(FILE * fp, char *buf, const int bufsz)
+{
/*--------------------------------------------------------------------------
Grab one token out of fp. Tokens are strings of non-blank
characters bounded by blank characters, beginning of line, and end
- of line. Blank means space or tab. Return the token as *buf.
+ of line. Blank means space or tab. Return the token as *buf.
Leave file positioned to character immediately after the token or
EOF, whichever comes first. If no more tokens on line, return null
string as *buf and position file to beginning of next line or EOF,
- whichever comes first.
+ whichever comes first.
--------------------------------------------------------------------------*/
- int c;
- char *eb = buf+(bufsz-1);
-
- /* Move over inital token-delimiting blanks */
- while (isblank(c = getc(fp))) ;
-
- if (c != '\n') {
- /* build a token in buf of next characters up to EOF, eol, or blank. */
- while (c != EOF && c != '\n' && !isblank(c)) {
- if (buf < eb) *buf++ = c;
- c = getc(fp);
- /* Put back the char right after the token (putting back EOF is ok) */
- }
- ungetc(c, fp);
- }
- *buf = '\0';
+ int c;
+ char *eb = buf + (bufsz - 1);
+
+ /* Move over inital token-delimiting blanks */
+ while (isblank(c = getc(fp)));
+
+ if (c != '\n')
+ {
+
+ /*
+ * build a token in buf of next characters up to EOF, eol, or
+ * blank.
+ */
+ while (c != EOF && c != '\n' && !isblank(c))
+ {
+ if (buf < eb)
+ *buf++ = c;
+ c = getc(fp);
+
+ /*
+ * Put back the char right after the token (putting back EOF
+ * is ok)
+ */
+ }
+ ungetc(c, fp);
+ }
+ *buf = '\0';
}
static void
-read_through_eol(FILE *file) {
- int c;
- do
- c = getc(file);
- while (c != '\n' && c != EOF);
+read_through_eol(FILE * file)
+{
+ int c;
+
+ do
+ c = getc(file);
+ while (c != '\n' && c != EOF);
}
static void
-read_hba_entry2(FILE *file, enum Userauth *userauth_p, char usermap_name[],
- bool *error_p, bool *matches_p, bool find_password_entries) {
+read_hba_entry2(FILE * file, enum Userauth * userauth_p, char usermap_name[],
+ bool * error_p, bool * matches_p, bool find_password_entries)
+{
/*--------------------------------------------------------------------------
Read from file FILE the rest of a host record, after the mask field,
and return the interpretation of it as *userauth_p, usermap_name, and
*error_p.
---------------------------------------------------------------------------*/
- char buf[MAX_TOKEN];
-
- bool userauth_valid;
-
- /* Get authentication type token. */
- next_token(file, buf, sizeof(buf));
- userauth_valid = false;
- if (buf[0] == '\0') {
- *error_p = true;
- } else {
- userauth_valid = true;
- if(strcmp(buf, "trust") == 0) {
- *userauth_p = Trust;
- } else if(strcmp(buf, "ident") == 0) {
- *userauth_p = Ident;
- } else if(strcmp(buf, "password") == 0) {
- *userauth_p = Password;
- } else {
- userauth_valid = false;
- }
-
- if((find_password_entries && strcmp(buf, "password") == 0) ||
- (!find_password_entries && strcmp(buf, "password") != 0)) {
- *matches_p = true;
- } else {
- *matches_p = false;
- }
- }
-
- if(!userauth_valid || !*matches_p || *error_p) {
- if (!userauth_valid) {
- *error_p = true;
- }
- read_through_eol(file);
- } else {
- /* Get the map name token, if any */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0') {
- *error_p = false;
- usermap_name[0] = '\0';
- } else {
- strncpy(usermap_name, buf, USERMAP_NAME_SIZE);
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0') {
- *error_p = true;
- read_through_eol(file);
- } else *error_p = false;
- }
- }
+ char buf[MAX_TOKEN];
+
+ bool userauth_valid;
+
+ /* Get authentication type token. */
+ next_token(file, buf, sizeof(buf));
+ userauth_valid = false;
+ if (buf[0] == '\0')
+ {
+ *error_p = true;
+ }
+ else
+ {
+ userauth_valid = true;
+ if (strcmp(buf, "trust") == 0)
+ {
+ *userauth_p = Trust;
+ }
+ else if (strcmp(buf, "ident") == 0)
+ {
+ *userauth_p = Ident;
+ }
+ else if (strcmp(buf, "password") == 0)
+ {
+ *userauth_p = Password;
+ }
+ else
+ {
+ userauth_valid = false;
+ }
+
+ if ((find_password_entries && strcmp(buf, "password") == 0) ||
+ (!find_password_entries && strcmp(buf, "password") != 0))
+ {
+ *matches_p = true;
+ }
+ else
+ {
+ *matches_p = false;
+ }
+ }
+
+ if (!userauth_valid || !*matches_p || *error_p)
+ {
+ if (!userauth_valid)
+ {
+ *error_p = true;
+ }
+ read_through_eol(file);
+ }
+ else
+ {
+ /* Get the map name token, if any */
+ next_token(file, buf, sizeof(buf));
+ if (buf[0] == '\0')
+ {
+ *error_p = false;
+ usermap_name[0] = '\0';
+ }
+ else
+ {
+ strncpy(usermap_name, buf, USERMAP_NAME_SIZE);
+ next_token(file, buf, sizeof(buf));
+ if (buf[0] != '\0')
+ {
+ *error_p = true;
+ read_through_eol(file);
+ }
+ else
+ *error_p = false;
+ }
+ }
}
static void
-process_hba_record(FILE *file,
- const struct in_addr ip_addr, const char database[],
- bool *matches_p, bool *error_p,
- enum Userauth *userauth_p, char usermap_name[],
- bool find_password_entries) {
+process_hba_record(FILE * file,
+ const struct in_addr ip_addr, const char database[],
+ bool * matches_p, bool * error_p,
+ enum Userauth * userauth_p, char usermap_name[],
+ bool find_password_entries)
+{
/*---------------------------------------------------------------------------
Process the non-comment record in the config file that is next on the file.
See if it applies to a connection to a host with IP address "ip_addr"
to a database named "database[]". If so, return *matches_p true
and *userauth_p and usermap_name[] as the values from the entry.
If not, return matches_p false. If the record has a syntax error,
- return *error_p true, after issuing a message to stderr. If no error,
+ return *error_p true, after issuing a message to stderr. If no error,
leave *error_p as it was.
---------------------------------------------------------------------------*/
- char buf[MAX_TOKEN]; /* A token from the record */
-
- /* Read the record type field */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0') *matches_p = false;
- else {
- /* if this isn't a "host" record, it can't match. */
- if (strcmp(buf, "host") != 0) {
- *matches_p = false;
- read_through_eol(file);
- } else {
- /* It's a "host" record. Read the database name field. */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0') *matches_p = false;
- else {
- /* If this record isn't for our database, ignore it. */
- if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0) {
- *matches_p = false;
- read_through_eol(file);
- } else {
- /* Read the IP address field */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0') *matches_p = false;
- else {
- int valid; /* Field is valid dotted decimal */
- /* Remember the IP address field and go get mask field */
- struct in_addr file_ip_addr; /* IP address field value */
-
- valid = inet_aton(buf, &file_ip_addr);
- if (!valid) {
- *matches_p = false;
- read_through_eol(file);
- } else {
- /* Read the mask field */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0') *matches_p = false;
- else {
- struct in_addr mask;
- /* Got mask. Now see if this record is for our host. */
- valid = inet_aton(buf, &mask);
- if (!valid) {
- *matches_p = false;
- read_through_eol(file);
- } else {
- if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr)
- != 0x0000) {
- *matches_p = false;
- read_through_eol(file);
- } else {
- /* This is the record we're looking for. Read
- the rest of the info from it.
- */
- read_hba_entry2(file, userauth_p, usermap_name,
- error_p, matches_p, find_password_entries);
- if (*error_p) {
- sprintf(PQerrormsg,
- "process_hba_record: invalid syntax in "
- "hba config file "
- "for host record for IP address %s\n",
- inet_ntoa(file_ip_addr));
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
+ char buf[MAX_TOKEN]; /* A token from the record */
+
+ /* Read the record type field */
+ next_token(file, buf, sizeof(buf));
+ if (buf[0] == '\0')
+ *matches_p = false;
+ else
+ {
+ /* if this isn't a "host" record, it can't match. */
+ if (strcmp(buf, "host") != 0)
+ {
+ *matches_p = false;
+ read_through_eol(file);
+ }
+ else
+ {
+ /* It's a "host" record. Read the database name field. */
+ next_token(file, buf, sizeof(buf));
+ if (buf[0] == '\0')
+ *matches_p = false;
+ else
+ {
+ /* If this record isn't for our database, ignore it. */
+ if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0)
+ {
+ *matches_p = false;
+ read_through_eol(file);
+ }
+ else
+ {
+ /* Read the IP address field */
+ next_token(file, buf, sizeof(buf));
+ if (buf[0] == '\0')
+ *matches_p = false;
+ else
+ {
+ int valid; /* Field is valid dotted
+ * decimal */
+
+ /*
+ * Remember the IP address field and go get mask
+ * field
+ */
+ struct in_addr file_ip_addr; /* IP address field
+ * value */
+
+ valid = inet_aton(buf, &file_ip_addr);
+ if (!valid)
+ {
+ *matches_p = false;
+ read_through_eol(file);
+ }
+ else
+ {
+ /* Read the mask field */
+ next_token(file, buf, sizeof(buf));
+ if (buf[0] == '\0')
+ *matches_p = false;
+ else
+ {
+ struct in_addr mask;
+
+ /*
+ * Got mask. Now see if this record is
+ * for our host.
+ */
+ valid = inet_aton(buf, &mask);
+ if (!valid)
+ {
+ *matches_p = false;
+ read_through_eol(file);
+ }
+ else
+ {
+ if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr)
+ != 0x0000)
+ {
+ *matches_p = false;
+ read_through_eol(file);
+ }
+ else
+ {
+
+ /*
+ * This is the record we're
+ * looking for. Read the rest of
+ * the info from it.
+ */
+ read_hba_entry2(file, userauth_p, usermap_name,
+ error_p, matches_p, find_password_entries);
+ if (*error_p)
+ {
+ sprintf(PQerrormsg,
+ "process_hba_record: invalid syntax in "
+ "hba config file "
+ "for host record for IP address %s\n",
+ inet_ntoa(file_ip_addr));
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
static void
-process_open_config_file(FILE *file,
- const struct in_addr ip_addr, const char database[],
- bool *host_ok_p, enum Userauth *userauth_p,
- char usermap_name[], bool find_password_entries) {
+process_open_config_file(FILE * file,
+ const struct in_addr ip_addr, const char database[],
+ bool * host_ok_p, enum Userauth * userauth_p,
+ char usermap_name[], bool find_password_entries)
+{
/*---------------------------------------------------------------------------
This function does the same thing as find_hba_entry, only with
the config file already open on stream descriptor "file".
----------------------------------------------------------------------------*/
- bool found_entry;
- /* We've processed a record that applies to our connection */
- bool error;
- /* Said record has invalid syntax. */
- bool eof; /* We've reached the end of the file we're reading */
-
- found_entry = false; /* initial value */
- error = false; /* initial value */
- eof = false; /* initial value */
- while (!eof && !found_entry && !error) {
- /* Process a line from the config file */
-
- int c; /* a character read from the file */
-
- c = getc(file); ungetc(c, file);
- if (c == EOF) eof = true;
- else {
- if (c == '#') read_through_eol(file);
- else {
- process_hba_record(file, ip_addr, database,
- &found_entry, &error, userauth_p, usermap_name,
- find_password_entries);
- }
- }
- }
- if (found_entry) {
- if (error) *host_ok_p = false;
- else *host_ok_p = true;
- } else *host_ok_p = false;
-}
+ bool found_entry;
+
+ /* We've processed a record that applies to our connection */
+ bool error;
+
+ /* Said record has invalid syntax. */
+ bool eof; /* We've reached the end of the file we're
+ * reading */
+
+ found_entry = false; /* initial value */
+ error = false; /* initial value */
+ eof = false; /* initial value */
+ while (!eof && !found_entry && !error)
+ {
+ /* Process a line from the config file */
+
+ int c; /* a character read from the file */
+
+ c = getc(file);
+ ungetc(c, file);
+ if (c == EOF)
+ eof = true;
+ else
+ {
+ if (c == '#')
+ read_through_eol(file);
+ else
+ {
+ process_hba_record(file, ip_addr, database,
+ &found_entry, &error, userauth_p, usermap_name,
+ find_password_entries);
+ }
+ }
+ }
+ if (found_entry)
+ {
+ if (error)
+ *host_ok_p = false;
+ else
+ *host_ok_p = true;
+ }
+ else
+ *host_ok_p = false;
+}
void
-find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
- const char database[],
- bool *host_ok_p, enum Userauth *userauth_p,
- char usermap_name[], bool find_password_entries) {
+find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
+ const char database[],
+ bool * host_ok_p, enum Userauth * userauth_p,
+ char usermap_name[], bool find_password_entries)
+{
/*--------------------------------------------------------------------------
Read the config file and find an entry that allows connection from
- host "ip_addr" to database "database". If not found, return
- *host_ok_p == false. If found, return *userauth_p and *usermap_name
+ host "ip_addr" to database "database". If not found, return
+ *host_ok_p == false. If found, return *userauth_p and *usermap_name
representing the contents of that entry.
When a record has invalid syntax, we either ignore it or reject the
@@ -298,133 +391,167 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
follow directions and just installed his old hba file in the new database
system.
----------------------------------------------------------------------------*/
- int fd;
-
- FILE *file; /* The config file we have to read */
-
- char *old_conf_file;
- /* The name of old config file that better not exist. */
-
- /* Fail if config file by old name exists. */
-
-
- /* put together the full pathname to the old config file */
- old_conf_file = (char *) malloc((strlen(DataDir) +
- strlen(OLD_CONF_FILE)+2)*sizeof(char));
- sprintf(old_conf_file, "%s/%s", DataDir, OLD_CONF_FILE);
-
- if ((fd = open(old_conf_file,O_RDONLY,0)) != -1) {
- /* Old config file exists. Tell this guy he needs to upgrade. */
- close(fd);
- sprintf(PQerrormsg,
- "A file exists by the name used for host-based authentication "
- "in prior releases of Postgres (%s). The name and format of "
- "the configuration file have changed, so this file should be "
- "converted.\n",
- old_conf_file);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- } else {
- char *conf_file; /* The name of the config file we have to read */
-
- /* put together the full pathname to the config file */
- conf_file = (char *) malloc((strlen(DataDir) +
- strlen(CONF_FILE)+2)*sizeof(char));
- sprintf(conf_file, "%s/%s", DataDir, CONF_FILE);
-
- file = AllocateFile(conf_file, "r");
- if (file == NULL) {
- /* The open of the config file failed. */
-
- *host_ok_p = false;
-
- sprintf(PQerrormsg,
- "find_hba_entry: Host-based authentication config file "
- "does not exist or permissions are not setup correctly! "
- "Unable to open file \"%s\".\n",
- conf_file);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- } else {
- process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p,
- usermap_name, find_password_entries);
- FreeFile(file);
- }
- free(conf_file);
- }
- free(old_conf_file);
- return;
+---------------------------------------------------------------------------*/
+ int fd;
+
+ FILE *file; /* The config file we have to read */
+
+ char *old_conf_file;
+
+ /* The name of old config file that better not exist. */
+
+ /* Fail if config file by old name exists. */
+
+
+ /* put together the full pathname to the old config file */
+ old_conf_file = (char *) malloc((strlen(DataDir) +
+ strlen(OLD_CONF_FILE) + 2) * sizeof(char));
+ sprintf(old_conf_file, "%s/%s", DataDir, OLD_CONF_FILE);
+
+ if ((fd = open(old_conf_file, O_RDONLY, 0)) != -1)
+ {
+ /* Old config file exists. Tell this guy he needs to upgrade. */
+ close(fd);
+ sprintf(PQerrormsg,
+ "A file exists by the name used for host-based authentication "
+ "in prior releases of Postgres (%s). The name and format of "
+ "the configuration file have changed, so this file should be "
+ "converted.\n",
+ old_conf_file);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ }
+ else
+ {
+ char *conf_file; /* The name of the config file we
+ * have to read */
+
+ /* put together the full pathname to the config file */
+ conf_file = (char *) malloc((strlen(DataDir) +
+ strlen(CONF_FILE) + 2) * sizeof(char));
+ sprintf(conf_file, "%s/%s", DataDir, CONF_FILE);
+
+ file = AllocateFile(conf_file, "r");
+ if (file == NULL)
+ {
+ /* The open of the config file failed. */
+
+ *host_ok_p = false;
+
+ sprintf(PQerrormsg,
+ "find_hba_entry: Host-based authentication config file "
+ "does not exist or permissions are not setup correctly! "
+ "Unable to open file \"%s\".\n",
+ conf_file);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ }
+ else
+ {
+ process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p,
+ usermap_name, find_password_entries);
+ FreeFile(file);
+ }
+ free(conf_file);
+ }
+ free(old_conf_file);
+ return;
}
static void
-interpret_ident_response(char ident_response[],
- bool *error_p, char ident_username[]) {
+interpret_ident_response(char ident_response[],
+ bool * error_p, char ident_username[])
+{
/*----------------------------------------------------------------------------
Parse the string "ident_response[]" as a response from a query to an Ident
- server. If it's a normal response indicating a username, return
+ server. If it's a normal response indicating a username, return
*error_p == false and the username as ident_username[]. If it's anything
else, return *error_p == true and ident_username[] undefined.
----------------------------------------------------------------------------*/
- char *cursor; /* Cursor into ident_response[] */
-
- cursor = &ident_response[0];
-
- /* Ident's response, in the telnet tradition, should end in crlf (\r\n). */
- if (strlen(ident_response) < 2) *error_p = true;
- else if (ident_response[strlen(ident_response)-2] != '\r') *error_p = true;
- else {
- while (*cursor != ':' && *cursor != '\r') cursor++; /* skip port field */
-
- if (*cursor != ':') *error_p = true;
- else {
- /* We're positioned to colon before response type field */
- char response_type[80];
- int i; /* Index into response_type[] */
- cursor++; /* Go over colon */
- while (isblank(*cursor)) cursor++; /* skip blanks */
- i = 0;
- while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor)
- && i < sizeof(response_type)-1)
- response_type[i++] = *cursor++;
- response_type[i] = '\0';
- while (isblank(*cursor)) cursor++; /* skip blanks */
- if (strcmp(response_type, "USERID") != 0)
- *error_p = true;
- else {
- /* It's a USERID response. Good. "cursor" should be pointing to
- the colon that precedes the operating system type.
- */
- if (*cursor != ':') *error_p = true;
- else {
- cursor++; /* Go over colon */
- /* Skip over operating system field. */
- while (*cursor != ':' && *cursor != '\r') cursor++;
- if (*cursor != ':') *error_p = true;
- else {
- int i; /* Index into ident_username[] */
- cursor ++; /* Go over colon */
- while (isblank(*cursor)) cursor++; /* skip blanks */
- /* Rest of line is username. Copy it over. */
- i = 0;
- while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
- ident_username[i++] = *cursor++;
- ident_username[i] = '\0';
- *error_p = false;
- }
- }
- }
- }
- }
+ char *cursor; /* Cursor into ident_response[] */
+
+ cursor = &ident_response[0];
+
+ /*
+ * Ident's response, in the telnet tradition, should end in crlf
+ * (\r\n).
+ */
+ if (strlen(ident_response) < 2)
+ *error_p = true;
+ else if (ident_response[strlen(ident_response) - 2] != '\r')
+ *error_p = true;
+ else
+ {
+ while (*cursor != ':' && *cursor != '\r')
+ cursor++; /* skip port field */
+
+ if (*cursor != ':')
+ *error_p = true;
+ else
+ {
+ /* We're positioned to colon before response type field */
+ char response_type[80];
+ int i; /* Index into response_type[] */
+
+ cursor++; /* Go over colon */
+ while (isblank(*cursor))
+ cursor++; /* skip blanks */
+ i = 0;
+ while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor)
+ && i < sizeof(response_type) - 1)
+ response_type[i++] = *cursor++;
+ response_type[i] = '\0';
+ while (isblank(*cursor))
+ cursor++; /* skip blanks */
+ if (strcmp(response_type, "USERID") != 0)
+ *error_p = true;
+ else
+ {
+
+ /*
+ * It's a USERID response. Good. "cursor" should be
+ * pointing to the colon that precedes the operating
+ * system type.
+ */
+ if (*cursor != ':')
+ *error_p = true;
+ else
+ {
+ cursor++; /* Go over colon */
+ /* Skip over operating system field. */
+ while (*cursor != ':' && *cursor != '\r')
+ cursor++;
+ if (*cursor != ':')
+ *error_p = true;
+ else
+ {
+ int i; /* Index into
+ * ident_username[] */
+
+ cursor++; /* Go over colon */
+ while (isblank(*cursor))
+ cursor++; /* skip blanks */
+ /* Rest of line is username. Copy it over. */
+ i = 0;
+ while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
+ ident_username[i++] = *cursor++;
+ ident_username[i] = '\0';
+ *error_p = false;
+ }
+ }
+ }
+ }
+ }
}
static void
ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,
- const ushort remote_port, const ushort local_port,
- bool *ident_failed, char ident_username[]) {
+ const ushort remote_port, const ushort local_port,
+ bool * ident_failed, char ident_username[])
+{
/*--------------------------------------------------------------------------
Talk to the ident server on host "remote_ip_addr" and find out who
owns the tcp connection from his port "remote_port" to port
@@ -437,169 +564,204 @@ ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,
*ident_failed == true (and ident_username[] undefined).
----------------------------------------------------------------------------*/
- int sock_fd;
- /* File descriptor for socket on which we talk to Ident */
-
- int rc; /* Return code from a locally called function */
-
- sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
- if (sock_fd == -1) {
- sprintf(PQerrormsg,
- "Failed to create socket on which to talk to Ident server. "
- "socket() returned errno = %s (%d)\n",
- strerror(errno), errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- } else {
- struct sockaddr_in ident_server;
- /* Socket address of Ident server on the system from which client
- is attempting to connect to us.
- */
- ident_server.sin_family = AF_INET;
- ident_server.sin_port = htons(IDENT_PORT);
- ident_server.sin_addr = remote_ip_addr;
- rc = connect(sock_fd,
- (struct sockaddr *) &ident_server, sizeof(ident_server));
- if (rc != 0) {
- sprintf(PQerrormsg,
- "Unable to connect to Ident server on the host which is "
- "trying to connect to Postgres "
- "(IP address %s, Port %d). "
- "errno = %s (%d)\n",
- inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- *ident_failed = true;
- } else {
- char ident_query[80];
- /* The query we send to the Ident server */
- sprintf(ident_query, "%d,%d\n",
- ntohs(remote_port), ntohs(local_port));
- rc = send(sock_fd, ident_query, strlen(ident_query), 0);
- if (rc < 0) {
- sprintf(PQerrormsg,
- "Unable to send query to Ident server on the host which is "
- "trying to connect to Postgres (Host %s, Port %d),"
- "even though we successfully connected to it. "
- "errno = %s (%d)\n",
- inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- *ident_failed = true;
- } else {
- char ident_response[80+IDENT_USERNAME_MAX];
- rc = recv(sock_fd, ident_response, sizeof(ident_response)-1, 0);
- if (rc < 0) {
- sprintf(PQerrormsg,
- "Unable to receive response from Ident server "
- "on the host which is "
- "trying to connect to Postgres (Host %s, Port %d),"
- "even though we successfully sent our query to it. "
- "errno = %s (%d)\n",
- inet_ntoa(remote_ip_addr), IDENT_PORT,
- strerror(errno), errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- *ident_failed = true;
- } else {
- bool error; /* response from Ident is garbage. */
- ident_response[rc] = '\0';
- interpret_ident_response(ident_response, &error, ident_username);
- *ident_failed = error;
- }
- }
- close(sock_fd);
- }
- }
+ int sock_fd;
+
+ /* File descriptor for socket on which we talk to Ident */
+
+ int rc; /* Return code from a locally called
+ * function */
+
+ sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (sock_fd == -1)
+ {
+ sprintf(PQerrormsg,
+ "Failed to create socket on which to talk to Ident server. "
+ "socket() returned errno = %s (%d)\n",
+ strerror(errno), errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ }
+ else
+ {
+ struct sockaddr_in ident_server;
+
+ /*
+ * Socket address of Ident server on the system from which client
+ * is attempting to connect to us.
+ */
+ ident_server.sin_family = AF_INET;
+ ident_server.sin_port = htons(IDENT_PORT);
+ ident_server.sin_addr = remote_ip_addr;
+ rc = connect(sock_fd,
+ (struct sockaddr *) & ident_server, sizeof(ident_server));
+ if (rc != 0)
+ {
+ sprintf(PQerrormsg,
+ "Unable to connect to Ident server on the host which is "
+ "trying to connect to Postgres "
+ "(IP address %s, Port %d). "
+ "errno = %s (%d)\n",
+ inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ *ident_failed = true;
+ }
+ else
+ {
+ char ident_query[80];
+
+ /* The query we send to the Ident server */
+ sprintf(ident_query, "%d,%d\n",
+ ntohs(remote_port), ntohs(local_port));
+ rc = send(sock_fd, ident_query, strlen(ident_query), 0);
+ if (rc < 0)
+ {
+ sprintf(PQerrormsg,
+ "Unable to send query to Ident server on the host which is "
+ "trying to connect to Postgres (Host %s, Port %d),"
+ "even though we successfully connected to it. "
+ "errno = %s (%d)\n",
+ inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ *ident_failed = true;
+ }
+ else
+ {
+ char ident_response[80 + IDENT_USERNAME_MAX];
+
+ rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0);
+ if (rc < 0)
+ {
+ sprintf(PQerrormsg,
+ "Unable to receive response from Ident server "
+ "on the host which is "
+ "trying to connect to Postgres (Host %s, Port %d),"
+ "even though we successfully sent our query to it. "
+ "errno = %s (%d)\n",
+ inet_ntoa(remote_ip_addr), IDENT_PORT,
+ strerror(errno), errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ *ident_failed = true;
+ }
+ else
+ {
+ bool error; /* response from Ident is
+ * garbage. */
+
+ ident_response[rc] = '\0';
+ interpret_ident_response(ident_response, &error, ident_username);
+ *ident_failed = error;
+ }
+ }
+ close(sock_fd);
+ }
+ }
}
static void
-parse_map_record(FILE *file,
- char file_map[], char file_pguser[], char file_iuser[]) {
+parse_map_record(FILE * file,
+ char file_map[], char file_pguser[], char file_iuser[])
+{
/*---------------------------------------------------------------------------
Take the noncomment line which is next on file "file" and interpret
it as a line in a usermap file. Specifically, return the first
- 3 tokens as file_map, file_iuser, and file_pguser, respectively. If
+ 3 tokens as file_map, file_iuser, and file_pguser, respectively. If
there are fewer than 3 tokens, return null strings for the missing
ones.
---------------------------------------------------------------------------*/
- char buf[MAX_TOKEN];
- /* A token read from the file */
-
- /* Set defaults in case fields not in file */
- file_map[0] = '\0';
- file_pguser[0] = '\0';
- file_iuser[0] = '\0';
-
- next_token(file, buf, sizeof(buf));
- if (buf != '\0') {
- strcpy(file_map, buf);
- next_token(file, buf, sizeof(buf));
- if (buf != '\0') {
- strcpy(file_iuser, buf);
- next_token(file, buf, sizeof(buf));
- if (buf != '\0') {
- strcpy(file_pguser, buf);
- read_through_eol(file);
- }
- }
- }
+ char buf[MAX_TOKEN];
+
+ /* A token read from the file */
+
+ /* Set defaults in case fields not in file */
+ file_map[0] = '\0';
+ file_pguser[0] = '\0';
+ file_iuser[0] = '\0';
+
+ next_token(file, buf, sizeof(buf));
+ if (buf != '\0')
+ {
+ strcpy(file_map, buf);
+ next_token(file, buf, sizeof(buf));
+ if (buf != '\0')
+ {
+ strcpy(file_iuser, buf);
+ next_token(file, buf, sizeof(buf));
+ if (buf != '\0')
+ {
+ strcpy(file_pguser, buf);
+ read_through_eol(file);
+ }
+ }
+ }
}
static void
-verify_against_open_usermap(FILE *file,
- const char pguser[],
- const char ident_username[],
- const char usermap_name[],
- bool *checks_out_p) {
+verify_against_open_usermap(FILE * file,
+ const char pguser[],
+ const char ident_username[],
+ const char usermap_name[],
+ bool * checks_out_p)
+{
/*--------------------------------------------------------------------------
This function does the same thing as verify_against_usermap,
only with the config file already open on stream descriptor "file".
---------------------------------------------------------------------------*/
- bool match; /* We found a matching entry in the map file */
- bool eof; /* We've reached the end of the file we're reading */
-
- match = false; /* initial value */
- eof = false; /* initial value */
- while (!eof && !match) {
- /* Process a line from the map file */
-
- int c; /* a character read from the file */
-
- c = getc(file); ungetc(c, file);
- if (c == EOF) eof = true;
- else {
- if (c == '#') read_through_eol(file);
- else {
- /* The following are fields read from a record of the file */
- char file_map[MAX_TOKEN+1];
- char file_pguser[MAX_TOKEN+1];
- char file_iuser[MAX_TOKEN+1];
-
- parse_map_record(file, file_map, file_pguser, file_iuser);
- if (strcmp(file_map, usermap_name) == 0 &&
- strcmp(file_pguser, pguser) == 0 &&
- strcmp(file_iuser, ident_username) == 0)
- match = true;
- }
- }
- }
- *checks_out_p = match;
+ bool match; /* We found a matching entry in the map
+ * file */
+ bool eof; /* We've reached the end of the file we're
+ * reading */
+
+ match = false; /* initial value */
+ eof = false; /* initial value */
+ while (!eof && !match)
+ {
+ /* Process a line from the map file */
+
+ int c; /* a character read from the file */
+
+ c = getc(file);
+ ungetc(c, file);
+ if (c == EOF)
+ eof = true;
+ else
+ {
+ if (c == '#')
+ read_through_eol(file);
+ else
+ {
+ /* The following are fields read from a record of the file */
+ char file_map[MAX_TOKEN + 1];
+ char file_pguser[MAX_TOKEN + 1];
+ char file_iuser[MAX_TOKEN + 1];
+
+ parse_map_record(file, file_map, file_pguser, file_iuser);
+ if (strcmp(file_map, usermap_name) == 0 &&
+ strcmp(file_pguser, pguser) == 0 &&
+ strcmp(file_iuser, ident_username) == 0)
+ match = true;
+ }
+ }
+ }
+ *checks_out_p = match;
}
static void
verify_against_usermap(const char DataDir[],
- const char pguser[],
- const char ident_username[],
- const char usermap_name[],
- bool *checks_out_p) {
+ const char pguser[],
+ const char ident_username[],
+ const char usermap_name[],
+ bool * checks_out_p)
+{
/*--------------------------------------------------------------------------
See if the user with ident username "ident_username" is allowed to act
as Postgres user "pguser" according to usermap "usermap_name". Look
@@ -610,151 +772,194 @@ verify_against_usermap(const char DataDir[],
"ident_username" in order to be authorized.
Iff authorized, return *checks_out_p == true.
-
+
--------------------------------------------------------------------------*/
- if (usermap_name[0] == '\0') {
- *checks_out_p = false;
- sprintf(PQerrormsg,
- "verify_against_usermap: hba configuration file does not "
- "have the usermap field filled in in the entry that pertains "
- "to this connection. That field is essential for Ident-based "
- "authentication.\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- } else if (strcmp(usermap_name, "sameuser") == 0) {
- if (strcmp(ident_username, pguser) == 0) *checks_out_p = true;
- else *checks_out_p = false;
- } else {
- FILE *file; /* The map file we have to read */
-
- char *map_file; /* The name of the map file we have to read */
-
- /* put together the full pathname to the map file */
- map_file = (char *) malloc((strlen(DataDir) +
- strlen(MAP_FILE)+2)*sizeof(char));
- sprintf(map_file, "%s/%s", DataDir, MAP_FILE);
-
- file = AllocateFile(map_file, "r");
- if (file == NULL) {
- /* The open of the map file failed. */
-
- *checks_out_p = false;
-
- sprintf(PQerrormsg,
- "verify_against_usermap: usermap file for Ident-based "
- "authentication "
- "does not exist or permissions are not setup correctly! "
- "Unable to open file \"%s\".\n",
- map_file);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- } else {
- verify_against_open_usermap(file,
- pguser, ident_username, usermap_name,
- checks_out_p);
- FreeFile(file);
- }
- free(map_file);
-
-
- }
+ if (usermap_name[0] == '\0')
+ {
+ *checks_out_p = false;
+ sprintf(PQerrormsg,
+ "verify_against_usermap: hba configuration file does not "
+ "have the usermap field filled in in the entry that pertains "
+ "to this connection. That field is essential for Ident-based "
+ "authentication.\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ }
+ else if (strcmp(usermap_name, "sameuser") == 0)
+ {
+ if (strcmp(ident_username, pguser) == 0)
+ *checks_out_p = true;
+ else
+ *checks_out_p = false;
+ }
+ else
+ {
+ FILE *file; /* The map file we have to read */
+
+ char *map_file; /* The name of the map file we
+ * have to read */
+
+ /* put together the full pathname to the map file */
+ map_file = (char *) malloc((strlen(DataDir) +
+ strlen(MAP_FILE) + 2) * sizeof(char));
+ sprintf(map_file, "%s/%s", DataDir, MAP_FILE);
+
+ file = AllocateFile(map_file, "r");
+ if (file == NULL)
+ {
+ /* The open of the map file failed. */
+
+ *checks_out_p = false;
+
+ sprintf(PQerrormsg,
+ "verify_against_usermap: usermap file for Ident-based "
+ "authentication "
+ "does not exist or permissions are not setup correctly! "
+ "Unable to open file \"%s\".\n",
+ map_file);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ }
+ else
+ {
+ verify_against_open_usermap(file,
+ pguser, ident_username, usermap_name,
+ checks_out_p);
+ FreeFile(file);
+ }
+ free(map_file);
+
+
+ }
}
static void
-authident(const char DataDir[],
- const Port port, const char postgres_username[],
- const char usermap_name[],
- bool *authentic_p) {
+authident(const char DataDir[],
+ const Port port, const char postgres_username[],
+ const char usermap_name[],
+ bool * authentic_p)
+{
/*---------------------------------------------------------------------------
- Talk to the ident server on the remote host and find out who owns the
+ Talk to the ident server on the remote host and find out who owns the
connection described by "port". Then look in the usermap file under
- the usermap usermap_name[] and see if that user is equivalent to
+ the usermap usermap_name[] and see if that user is equivalent to
Postgres user user[].
Return *authentic_p true iff yes.
---------------------------------------------------------------------------*/
- bool ident_failed;
- /* We were unable to get ident to give us a username */
- char ident_username[IDENT_USERNAME_MAX+1];
- /* The username returned by ident */
-
- ident(port.raddr.sin_addr, port.laddr.sin_addr,
- port.raddr.sin_port, port.laddr.sin_port,
- &ident_failed, ident_username);
-
- if (ident_failed) *authentic_p = false;
- else {
- bool checks_out;
- verify_against_usermap(DataDir,
- postgres_username, ident_username, usermap_name,
- &checks_out);
- if (checks_out) *authentic_p = true;
- else *authentic_p = false;
- }
+ bool ident_failed;
+
+ /* We were unable to get ident to give us a username */
+ char ident_username[IDENT_USERNAME_MAX + 1];
+
+ /* The username returned by ident */
+
+ ident(port.raddr.sin_addr, port.laddr.sin_addr,
+ port.raddr.sin_port, port.laddr.sin_port,
+ &ident_failed, ident_username);
+
+ if (ident_failed)
+ *authentic_p = false;
+ else
+ {
+ bool checks_out;
+
+ verify_against_usermap(DataDir,
+ postgres_username, ident_username, usermap_name,
+ &checks_out);
+ if (checks_out)
+ *authentic_p = true;
+ else
+ *authentic_p = false;
+ }
}
extern int
-hba_recvauth(const Port *port, const char database[], const char user[],
- const char DataDir[]) {
+hba_recvauth(const Port * port, const char database[], const char user[],
+ const char DataDir[])
+{
/*---------------------------------------------------------------------------
Determine if the TCP connection described by "port" is with someone
allowed to act as user "user" and access database "database". Return
STATUS_OK if yes; STATUS_ERROR if not.
-----------------------------------------------------------------------------*/
- bool host_ok;
- /* There's an entry for this database and remote host in the pg_hba file */
- char usermap_name[USERMAP_NAME_SIZE+1];
- /* The name of the map pg_hba specifies for this connection (or special
- value "SAMEUSER")
- */
- enum Userauth userauth;
- /* The type of user authentication pg_hba specifies for this connection */
- int retvalue;
- /* Our eventual return value */
-
-
- find_hba_entry(DataDir, port->raddr.sin_addr, database,
- &host_ok, &userauth, usermap_name,
- false /* don't find password entries of type 'password' */);
-
- if (!host_ok) retvalue = STATUS_ERROR;
- else {
- switch (userauth) {
- case Trust:
- retvalue = STATUS_OK;
- break;
- case Ident: {
- /* Here's where we need to call up ident and authenticate the user */
-
- bool authentic; /* He is who he says he is. */
-
- authident(DataDir, *port, user, usermap_name, &authentic);
-
- if (authentic) retvalue = STATUS_OK;
- else retvalue = STATUS_ERROR;
- }
- break;
- default:
- retvalue = STATUS_ERROR;
- Assert(false);
- }
- }
- return(retvalue);
+----------------------------------------------------------------------------*/
+ bool host_ok;
+
+ /*
+ * There's an entry for this database and remote host in the pg_hba
+ * file
+ */
+ char usermap_name[USERMAP_NAME_SIZE + 1];
+
+ /*
+ * The name of the map pg_hba specifies for this connection (or
+ * special value "SAMEUSER")
+ */
+ enum Userauth userauth;
+
+ /*
+ * The type of user authentication pg_hba specifies for this
+ * connection
+ */
+ int retvalue;
+
+ /* Our eventual return value */
+
+
+ find_hba_entry(DataDir, port->raddr.sin_addr, database,
+ &host_ok, &userauth, usermap_name,
+ false /* don't find password entries of type
+ 'password' */ );
+
+ if (!host_ok)
+ retvalue = STATUS_ERROR;
+ else
+ {
+ switch (userauth)
+ {
+ case Trust:
+ retvalue = STATUS_OK;
+ break;
+ case Ident:
+ {
+
+ /*
+ * Here's where we need to call up ident and authenticate
+ * the user
+ */
+
+ bool authentic; /* He is who he says he
+ * is. */
+
+ authident(DataDir, *port, user, usermap_name, &authentic);
+
+ if (authentic)
+ retvalue = STATUS_OK;
+ else
+ retvalue = STATUS_ERROR;
+ }
+ break;
+ default:
+ retvalue = STATUS_ERROR;
+ Assert(false);
+ }
+ }
+ return (retvalue);
}
/*----------------------------------------------------------------
* This version of hba was written by Bryan Henderson
- * in September 1996 for Release 6.0. It changed the format of the
+ * in September 1996 for Release 6.0. It changed the format of the
* hba file and added ident function.
*
* Here are some notes about the original host based authentication
- * the preceded this one.
+ * the preceded this one.
*
* based on the securelib package originally written by William
* LeFebvre, EECS Department, Northwestern University
@@ -765,4 +970,3 @@ hba_recvauth(const Port *port, const char database[], const char user[],
*
-----------------------------------------------------------------*/
-
diff --git a/src/backend/libpq/password.c b/src/backend/libpq/password.c
index 346d59e8bf6..1efc2e668a3 100644
--- a/src/backend/libpq/password.c
+++ b/src/backend/libpq/password.c
@@ -6,106 +6,116 @@
#include <string.h>
#include <unistd.h>
#ifdef HAVE_CRYPT_H
-# include <crypt.h>
+#include <crypt.h>
#endif
int
-verify_password(char *user, char *password, Port *port,
- char *database, char *DataDir)
+verify_password(char *user, char *password, Port * port,
+ char *database, char *DataDir)
{
- bool host_ok;
- enum Userauth userauth;
- char pw_file_name[PWFILE_NAME_SIZE+1];
-
- char *pw_file_fullname;
- FILE *pw_file;
-
- char pw_file_line[255];
- char *p, *test_user, *test_pw;
- char salt[3];
-
- find_hba_entry(DataDir, port->raddr.sin_addr, database,
- &host_ok, &userauth, pw_file_name, true);
+ bool host_ok;
+ enum Userauth userauth;
+ char pw_file_name[PWFILE_NAME_SIZE + 1];
+
+ char *pw_file_fullname;
+ FILE *pw_file;
+
+ char pw_file_line[255];
+ char *p,
+ *test_user,
+ *test_pw;
+ char salt[3];
+
+ find_hba_entry(DataDir, port->raddr.sin_addr, database,
+ &host_ok, &userauth, pw_file_name, true);
+
+ if (!host_ok)
+ {
+ sprintf(PQerrormsg,
+ "verify_password: couldn't find entry for connecting host\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return STATUS_ERROR;
+ }
- if(!host_ok) {
- sprintf(PQerrormsg,
- "verify_password: couldn't find entry for connecting host\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
+ if (userauth != Password)
+ {
+ sprintf(PQerrormsg,
+ "verify_password: couldn't find entry of type 'password' "
+ "for this host\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return STATUS_ERROR;
+ }
- if(userauth != Password) {
- sprintf(PQerrormsg,
- "verify_password: couldn't find entry of type 'password' "
- "for this host\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
+ if (!pw_file_name || pw_file_name[0] == '\0')
+ {
+ sprintf(PQerrormsg,
+ "verify_password: no password file specified\n");
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return STATUS_ERROR;
+ }
- if(!pw_file_name || pw_file_name[0] == '\0') {
- sprintf(PQerrormsg,
- "verify_password: no password file specified\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
+ pw_file_fullname = (char *) malloc(strlen(DataDir) + strlen(pw_file_name) + 2);
+ strcpy(pw_file_fullname, DataDir);
+ strcat(pw_file_fullname, "/");
+ strcat(pw_file_fullname, pw_file_name);
+
+ pw_file = AllocateFile(pw_file_fullname, "r");
+ if (!pw_file)
+ {
+ sprintf(PQerrormsg,
+ "verify_password: couldn't open password file '%s'\n",
+ pw_file_fullname);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return STATUS_ERROR;
+ }
- pw_file_fullname = (char *)malloc(strlen(DataDir) + strlen(pw_file_name) + 2);
- strcpy(pw_file_fullname, DataDir);
- strcat(pw_file_fullname, "/");
- strcat(pw_file_fullname, pw_file_name);
+ while (!feof(pw_file))
+ {
+ fgets(pw_file_line, 255, pw_file);
+ p = pw_file_line;
+
+ test_user = strtok(p, ":");
+ test_pw = strtok(NULL, ":");
+ if (!test_user || !test_pw ||
+ test_user[0] == '\0' || test_pw[0] == '\0')
+ {
+ continue;
+ }
+
+ /* kill the newline */
+ if (test_pw[strlen(test_pw) - 1] == '\n')
+ test_pw[strlen(test_pw) - 1] = '\0';
+
+ strNcpy(salt, test_pw, 2);
+
+ if (strcmp(user, test_user) == 0)
+ {
+ /* we're outta here one way or the other. */
+ FreeFile(pw_file);
+
+ if (strcmp(crypt(password, salt), test_pw) == 0)
+ {
+ /* it matched. */
+ return STATUS_OK;
+ }
+
+ sprintf(PQerrormsg,
+ "verify_password: password mismatch for '%s'.\n",
+ user);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return STATUS_ERROR;
+ }
+ }
- pw_file = AllocateFile(pw_file_fullname, "r");
- if(!pw_file) {
sprintf(PQerrormsg,
- "verify_password: couldn't open password file '%s'\n",
- pw_file_fullname);
+ "verify_password: user '%s' not found in password file.\n",
+ user);
fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
+ pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
- }
-
- while(!feof(pw_file)) {
- fgets(pw_file_line, 255, pw_file);
- p = pw_file_line;
-
- test_user = strtok(p, ":");
- test_pw = strtok(NULL, ":");
- if(!test_user || !test_pw ||
- test_user[0] == '\0' || test_pw[0] == '\0') {
- continue;
- }
-
- /* kill the newline */
- if (test_pw[strlen(test_pw)-1] == '\n')
- test_pw[strlen(test_pw)-1] = '\0';
-
- strNcpy(salt, test_pw, 2);
-
- if(strcmp(user, test_user) == 0) {
- /* we're outta here one way or the other. */
- FreeFile(pw_file);
-
- if(strcmp(crypt(password, salt), test_pw) == 0) {
- /* it matched. */
- return STATUS_OK;
- }
-
- sprintf(PQerrormsg,
- "verify_password: password mismatch for '%s'.\n",
- user);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
- }
-
- sprintf(PQerrormsg,
- "verify_password: user '%s' not found in password file.\n",
- user);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
}
diff --git a/src/backend/libpq/portal.c b/src/backend/libpq/portal.c
index 301773be9f5..c3c8fe55e38 100644
--- a/src/backend/libpq/portal.c
+++ b/src/backend/libpq/portal.c
@@ -1,642 +1,655 @@
/*-------------------------------------------------------------------------
*
* portal.c--
- * generalized portal support routines
+ * generalized portal support routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portal.c,v 1.6 1997/08/12 22:52:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portal.c,v 1.7 1997/09/07 04:42:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * PQnportals - Return the number of open portals.
- * PQpnames - Return all the portal names
- * PQparray - Return the portal buffer given a portal name
- * PQrulep - Return 1 if an asynchronous portal
- * PQntuples - Return the number of tuples in a portal buffer
- * PQninstances - same as PQntuples using object terminology
- * PQngroups - Return the number of tuple groups in a portal buffer
- * PQntuplesGroup - Return the number of tuples in a tuple group
- * PQninstancesGroup - same as PQntuplesGroup using object terminology
- * PQnfieldsGroup - Return the number of fields in a tuple group
- * PQfnumberGroup - Return field number given (group index, field name)
- * PQftypeGroup - Return field type given (group index, field index)
- * PQfsizeGroup - Return field size given (group index, field index)
- * PQfnameGroup - Return field name given (group index, field index)
- * PQgroup - Return the tuple group that a particular tuple is in
- * PQgetgroup - Return the index of the group that a tuple is in
- * PQnfields - Return the number of fields in a tuple
- * PQfnumber - Return the field index of a field name in a tuple
- * PQfname - Return the name of a field
- * PQftype - Return the type of a field
- * PQfsize - Return the size of a field
- * PQftype - Return the type of a field
- * PQsametype - Return 1 if the two tuples have the same type
- * PQgetvalue - Return an attribute (field) value
- * PQgetlength - Return an attribute (field) length
- * PQclear - free storage claimed by named portal
- * PQnotifies - Return a list of relations on which notification
- * has occurred.
- * PQremoveNotify - Remove this notification from the list.
+ * INTERFACE ROUTINES
+ * PQnportals - Return the number of open portals.
+ * PQpnames - Return all the portal names
+ * PQparray - Return the portal buffer given a portal name
+ * PQrulep - Return 1 if an asynchronous portal
+ * PQntuples - Return the number of tuples in a portal buffer
+ * PQninstances - same as PQntuples using object terminology
+ * PQngroups - Return the number of tuple groups in a portal buffer
+ * PQntuplesGroup - Return the number of tuples in a tuple group
+ * PQninstancesGroup - same as PQntuplesGroup using object terminology
+ * PQnfieldsGroup - Return the number of fields in a tuple group
+ * PQfnumberGroup - Return field number given (group index, field name)
+ * PQftypeGroup - Return field type given (group index, field index)
+ * PQfsizeGroup - Return field size given (group index, field index)
+ * PQfnameGroup - Return field name given (group index, field index)
+ * PQgroup - Return the tuple group that a particular tuple is in
+ * PQgetgroup - Return the index of the group that a tuple is in
+ * PQnfields - Return the number of fields in a tuple
+ * PQfnumber - Return the field index of a field name in a tuple
+ * PQfname - Return the name of a field
+ * PQftype - Return the type of a field
+ * PQfsize - Return the size of a field
+ * PQftype - Return the type of a field
+ * PQsametype - Return 1 if the two tuples have the same type
+ * PQgetvalue - Return an attribute (field) value
+ * PQgetlength - Return an attribute (field) length
+ * PQclear - free storage claimed by named portal
+ * PQnotifies - Return a list of relations on which notification
+ * has occurred.
+ * PQremoveNotify - Remove this notification from the list.
*
- * NOTES
- * These functions may be used by both frontend routines which
- * communicate with a backend or by user-defined functions which
- * are compiled or dynamically loaded into a backend.
+ * NOTES
+ * These functions may be used by both frontend routines which
+ * communicate with a backend or by user-defined functions which
+ * are compiled or dynamically loaded into a backend.
*
- * the portals[] array should be organized as a hash table for
- * quick portal-by-name lookup.
+ * the portals[] array should be organized as a hash table for
+ * quick portal-by-name lookup.
*
- * Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
- * see utils/mmgr/portalmem.c for why. -cim 2/22/91
+ * Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
+ * see utils/mmgr/portalmem.c for why. -cim 2/22/91
*
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <postgres.h>
#include <lib/dllist.h>
-#include <libpq/libpq.h> /* where the declarations go */
+#include <libpq/libpq.h> /* where the declarations go */
#include <utils/exc.h>
/* ----------------------------------------------------------------
- * Helper routines for PQ portal interface routines below
+ * Helper routines for PQ portal interface routines below
* ----------------------------------------------------------------
*/
static int
in_range(char *msg, int value, int min, int max)
{
- if (value < min || value >= max) {
- sprintf(PQerrormsg, "FATAL: %s, %d is not in range [%d,%d)\n",
- msg, value, min, max);
- pqdebug("%s", PQerrormsg);
- fputs(PQerrormsg, stderr);
- return(0);
- }
- return(1);
+ if (value < min || value >= max)
+ {
+ sprintf(PQerrormsg, "FATAL: %s, %d is not in range [%d,%d)\n",
+ msg, value, min, max);
+ pqdebug("%s", PQerrormsg);
+ fputs(PQerrormsg, stderr);
+ return (0);
+ }
+ return (1);
}
static int
valid_pointer(char *msg, void *ptr)
{
- if (!ptr) {
- sprintf(PQerrormsg, "FATAL: %s\n", msg);
- pqdebug("%s", PQerrormsg);
- fputs(PQerrormsg, stderr);
- return(0);
- }
- return(1);
+ if (!ptr)
+ {
+ sprintf(PQerrormsg, "FATAL: %s\n", msg);
+ pqdebug("%s", PQerrormsg);
+ fputs(PQerrormsg, stderr);
+ return (0);
+ }
+ return (1);
}
/* ----------------------------------------------------------------
- * PQ portal interface routines
+ * PQ portal interface routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * PQnportals - Return the number of open portals.
- * If rule_p, only return asynchronous portals.
+ * PQnportals - Return the number of open portals.
+ * If rule_p, only return asynchronous portals.
* --------------------------------
*/
int
PQnportals(int rule_p)
{
- int i, n = 0;
-
- for (i = 0; i < portals_array_size; ++i) {
- if (portals[i] && portals[i]->portal) {
- if (!rule_p || portals[i]->portal->rule_p) {
- ++n;
- }
+ int i,
+ n = 0;
+
+ for (i = 0; i < portals_array_size; ++i)
+ {
+ if (portals[i] && portals[i]->portal)
+ {
+ if (!rule_p || portals[i]->portal->rule_p)
+ {
+ ++n;
+ }
+ }
}
- }
- return(n);
+ return (n);
}
/* --------------------------------
- * PQpnames - Return all the portal names
- * If rule_p, only return asynchronous portals.
+ * PQpnames - Return all the portal names
+ * If rule_p, only return asynchronous portals.
*
- * the caller must have allocated sufficient memory for char** pnames
- * (an array of PQnportals strings of length PortalNameLength).
+ * the caller must have allocated sufficient memory for char** pnames
+ * (an array of PQnportals strings of length PortalNameLength).
*
- * notice that this assumes that the user is calling PQnportals and
- * PQpnames with the same rule_p argument, and with no intervening
- * portal closures. if not, you can get in heap big trouble..
+ * notice that this assumes that the user is calling PQnportals and
+ * PQpnames with the same rule_p argument, and with no intervening
+ * portal closures. if not, you can get in heap big trouble..
* --------------------------------
*/
void
PQpnames(char **pnames, int rule_p)
{
- int i, cur_pname = 0;
-
- if (!valid_pointer("PQpnames: invalid name buffer", pnames))
- return;
-
- for (i = 0; i < portals_array_size; ++i) {
- if (portals[i] && portals[i]->portal) {
- if (!rule_p || portals[i]->portal->rule_p) {
- strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength);
- ++cur_pname;
- }
+ int i,
+ cur_pname = 0;
+
+ if (!valid_pointer("PQpnames: invalid name buffer", pnames))
+ return;
+
+ for (i = 0; i < portals_array_size; ++i)
+ {
+ if (portals[i] && portals[i]->portal)
+ {
+ if (!rule_p || portals[i]->portal->rule_p)
+ {
+ strncpy(pnames[cur_pname], portals[i]->name, PortalNameLength);
+ ++cur_pname;
+ }
+ }
}
- }
}
/* --------------------------------
- * PQparray - Return the portal buffer given a portal name
+ * PQparray - Return the portal buffer given a portal name
* --------------------------------
*/
-PortalBuffer *
+PortalBuffer *
PQparray(char *pname)
{
- int i;
-
- if (!valid_pointer("PQparray: invalid name buffer", pname))
- return NULL;
-
- if ((i = pbuf_getIndex(pname)) < 0)
- return((PortalBuffer *) NULL);
- return(portals[i]->portal);
+ int i;
+
+ if (!valid_pointer("PQparray: invalid name buffer", pname))
+ return NULL;
+
+ if ((i = pbuf_getIndex(pname)) < 0)
+ return ((PortalBuffer *) NULL);
+ return (portals[i]->portal);
}
/* --------------------------------
- * PQrulep - Return 1 if an asynchronous portal
+ * PQrulep - Return 1 if an asynchronous portal
* --------------------------------
*/
int
-PQrulep(PortalBuffer *portal)
+PQrulep(PortalBuffer * portal)
{
- if (!valid_pointer("PQrulep: invalid portal pointer", portal))
- return(-1);
-
- return(portal->rule_p);
+ if (!valid_pointer("PQrulep: invalid portal pointer", portal))
+ return (-1);
+
+ return (portal->rule_p);
}
/* --------------------------------
- * PQntuples - Return the number of tuples in a portal buffer
+ * PQntuples - Return the number of tuples in a portal buffer
* --------------------------------
*/
int
-PQntuples(PortalBuffer *portal)
+PQntuples(PortalBuffer * portal)
{
- if (!valid_pointer("PQntuples: invalid portal pointer", portal))
- return(-1);
-
- return(portal->no_tuples);
+ if (!valid_pointer("PQntuples: invalid portal pointer", portal))
+ return (-1);
+
+ return (portal->no_tuples);
}
int
-PQninstances(PortalBuffer *portal)
+PQninstances(PortalBuffer * portal)
{
- return(PQntuples(portal));
+ return (PQntuples(portal));
}
/* --------------------------------
- * PQngroups - Return the number of tuple groups in a portal buffer
+ * PQngroups - Return the number of tuple groups in a portal buffer
* --------------------------------
*/
int
-PQngroups(PortalBuffer *portal)
+PQngroups(PortalBuffer * portal)
{
- if (!valid_pointer("PQngroups: invalid portal pointer", portal))
- return(-1);
-
- return(portal->no_groups);
+ if (!valid_pointer("PQngroups: invalid portal pointer", portal))
+ return (-1);
+
+ return (portal->no_groups);
}
/* --------------------------------
- * PQntuplesGroup - Return the number of tuples in a tuple group
+ * PQntuplesGroup - Return the number of tuples in a tuple group
* --------------------------------
*/
int
-PQntuplesGroup(PortalBuffer *portal, int group_index)
+PQntuplesGroup(PortalBuffer * portal, int group_index)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQntuplesGroup: invalid portal pointer", portal) ||
- !in_range("PQntuplesGroup: group index",
- group_index, 0, portal->no_groups))
- return(-1);
+ GroupBuffer *gbp;
- gbp = pbuf_findGroup(portal, group_index);
- if (gbp)
- return(gbp->no_tuples);
- return(-1);
+ if (!valid_pointer("PQntuplesGroup: invalid portal pointer", portal) ||
+ !in_range("PQntuplesGroup: group index",
+ group_index, 0, portal->no_groups))
+ return (-1);
+
+ gbp = pbuf_findGroup(portal, group_index);
+ if (gbp)
+ return (gbp->no_tuples);
+ return (-1);
}
int
-PQninstancesGroup(PortalBuffer *portal, int group_index)
+PQninstancesGroup(PortalBuffer * portal, int group_index)
{
- return(PQntuplesGroup(portal, group_index));
+ return (PQntuplesGroup(portal, group_index));
}
/* --------------------------------
- * PQnfieldsGroup - Return the number of fields in a tuple group
+ * PQnfieldsGroup - Return the number of fields in a tuple group
* --------------------------------
*/
int
-PQnfieldsGroup(PortalBuffer *portal, int group_index)
+PQnfieldsGroup(PortalBuffer * portal, int group_index)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQnfieldsGroup: invalid portal pointer", portal) ||
- !in_range("PQnfieldsGroup: group index",
- group_index, 0, portal->no_groups))
- return(-1);
- gbp = pbuf_findGroup(portal, group_index);
- if (gbp)
- return(gbp->no_fields);
- return(-1);
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQnfieldsGroup: invalid portal pointer", portal) ||
+ !in_range("PQnfieldsGroup: group index",
+ group_index, 0, portal->no_groups))
+ return (-1);
+ gbp = pbuf_findGroup(portal, group_index);
+ if (gbp)
+ return (gbp->no_fields);
+ return (-1);
}
/* --------------------------------
- * PQfnumberGroup - Return the field number (index) given
- * the group index and the field name
+ * PQfnumberGroup - Return the field number (index) given
+ * the group index and the field name
* --------------------------------
*/
int
-PQfnumberGroup(PortalBuffer *portal, int group_index, char *field_name)
-{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQfnumberGroup: invalid portal pointer", portal) ||
- !valid_pointer("PQfnumberGroup: invalid field name pointer",
- field_name) ||
- !in_range("PQfnumberGroup: group index",
- group_index, 0, portal->no_groups))
- return(-1);
- gbp = pbuf_findGroup(portal, group_index);
- if (gbp)
- return(pbuf_findFnumber(gbp, field_name));
- return(-1);
+PQfnumberGroup(PortalBuffer * portal, int group_index, char *field_name)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfnumberGroup: invalid portal pointer", portal) ||
+ !valid_pointer("PQfnumberGroup: invalid field name pointer",
+ field_name) ||
+ !in_range("PQfnumberGroup: group index",
+ group_index, 0, portal->no_groups))
+ return (-1);
+ gbp = pbuf_findGroup(portal, group_index);
+ if (gbp)
+ return (pbuf_findFnumber(gbp, field_name));
+ return (-1);
}
/* --------------------------------
- * PQfnameGroup - Return the field (attribute) name given
- * the group index and field index.
+ * PQfnameGroup - Return the field (attribute) name given
+ * the group index and field index.
* --------------------------------
*/
-char *
-PQfnameGroup(PortalBuffer *portal, int group_index, int field_number)
-{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQfnameGroup: invalid portal pointer", portal) ||
- !in_range("PQfnameGroup: group index",
- group_index, 0, portal->no_groups))
- return((char *) NULL);
-
- if ((gbp = pbuf_findGroup(portal, group_index)) &&
- in_range("PQfnameGroup: field number",
- field_number, 0, gbp->no_fields))
- return(pbuf_findFname(gbp, field_number));
- return((char *) NULL);
+char *
+PQfnameGroup(PortalBuffer * portal, int group_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfnameGroup: invalid portal pointer", portal) ||
+ !in_range("PQfnameGroup: group index",
+ group_index, 0, portal->no_groups))
+ return ((char *) NULL);
+
+ if ((gbp = pbuf_findGroup(portal, group_index)) &&
+ in_range("PQfnameGroup: field number",
+ field_number, 0, gbp->no_fields))
+ return (pbuf_findFname(gbp, field_number));
+ return ((char *) NULL);
}
/* --------------------------------
- * PQftypeGroup - Return the type of a field given
- * the group index and field index
+ * PQftypeGroup - Return the type of a field given
+ * the group index and field index
* --------------------------------
*/
int
-PQftypeGroup(PortalBuffer *portal, int group_index, int field_number)
+PQftypeGroup(PortalBuffer * portal, int group_index, int field_number)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQftypeGroup: invalid portal pointer", portal) ||
- !in_range("PQftypeGroup: group index",
- group_index, 0, portal->no_groups))
- return(-1);
-
- if ((gbp = pbuf_findGroup(portal, group_index)) &&
- in_range("PQftypeGroup: field number", field_number, 0, gbp->no_fields))
- return(gbp->types[field_number].adtid);
- return(-1);
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQftypeGroup: invalid portal pointer", portal) ||
+ !in_range("PQftypeGroup: group index",
+ group_index, 0, portal->no_groups))
+ return (-1);
+
+ if ((gbp = pbuf_findGroup(portal, group_index)) &&
+ in_range("PQftypeGroup: field number", field_number, 0, gbp->no_fields))
+ return (gbp->types[field_number].adtid);
+ return (-1);
}
/* --------------------------------
- * PQfsizeGroup - Return the size of a field given
- * the group index and field index
+ * PQfsizeGroup - Return the size of a field given
+ * the group index and field index
* --------------------------------
*/
int
-PQfsizeGroup(PortalBuffer *portal, int group_index, int field_number)
+PQfsizeGroup(PortalBuffer * portal, int group_index, int field_number)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQfsizeGroup: invalid portal pointer", portal) ||
- !in_range("PQfsizeGroup: tuple index",
- group_index, 0, portal->no_groups))
- return(-1);
-
- if ((gbp = pbuf_findGroup(portal, group_index)) &&
- in_range("PQfsizeGroup: field number", field_number, 0, gbp->no_fields))
- return(gbp->types[field_number].adtsize);
- return(-1);
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfsizeGroup: invalid portal pointer", portal) ||
+ !in_range("PQfsizeGroup: tuple index",
+ group_index, 0, portal->no_groups))
+ return (-1);
+
+ if ((gbp = pbuf_findGroup(portal, group_index)) &&
+ in_range("PQfsizeGroup: field number", field_number, 0, gbp->no_fields))
+ return (gbp->types[field_number].adtsize);
+ return (-1);
}
/* --------------------------------
- * PQgroup - Return the tuple group that a particular tuple is in
+ * PQgroup - Return the tuple group that a particular tuple is in
* --------------------------------
*/
-GroupBuffer *
-PQgroup(PortalBuffer *portal, int tuple_index)
-{
- GroupBuffer *gbp;
- int tuple_count = 0;
-
- if (!valid_pointer("PQgroup: invalid portal pointer", portal) ||
- !in_range("PQgroup: tuple index",
- tuple_index, 0, portal->no_tuples))
- return((GroupBuffer *) NULL);
-
- for (gbp = portal->groups;
- gbp && tuple_index >= (tuple_count += gbp->no_tuples);
- gbp = gbp->next)
- ;
- if (!in_range("PQgroup: tuple not found: tuple index",
- tuple_index, 0, tuple_count))
- return((GroupBuffer *) NULL);
- return(gbp);
+GroupBuffer *
+PQgroup(PortalBuffer * portal, int tuple_index)
+{
+ GroupBuffer *gbp;
+ int tuple_count = 0;
+
+ if (!valid_pointer("PQgroup: invalid portal pointer", portal) ||
+ !in_range("PQgroup: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return ((GroupBuffer *) NULL);
+
+ for (gbp = portal->groups;
+ gbp && tuple_index >= (tuple_count += gbp->no_tuples);
+ gbp = gbp->next)
+ ;
+ if (!in_range("PQgroup: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return ((GroupBuffer *) NULL);
+ return (gbp);
}
/* --------------------------------
- * PQgetgroup - Return the index of the group that a
- * particular tuple is in
+ * PQgetgroup - Return the index of the group that a
+ * particular tuple is in
* --------------------------------
*/
int
-PQgetgroup(PortalBuffer *portal, int tuple_index)
-{
- GroupBuffer *gbp;
- int tuple_count = 0, group_count = 0;
-
- if (!valid_pointer("PQgetgroup: invalid portal pointer", portal) ||
- !in_range("PQgetgroup: tuple index",
- tuple_index, 0, portal->no_tuples))
- return(-1);
-
- for (gbp = portal->groups;
- gbp && tuple_index >= (tuple_count += gbp->no_tuples);
- gbp = gbp->next)
- ++group_count;
- if (!gbp || !in_range("PQgetgroup: tuple not found: tuple index",
- tuple_index, 0, tuple_count))
- return(-1);
- return(group_count);
+PQgetgroup(PortalBuffer * portal, int tuple_index)
+{
+ GroupBuffer *gbp;
+ int tuple_count = 0,
+ group_count = 0;
+
+ if (!valid_pointer("PQgetgroup: invalid portal pointer", portal) ||
+ !in_range("PQgetgroup: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return (-1);
+
+ for (gbp = portal->groups;
+ gbp && tuple_index >= (tuple_count += gbp->no_tuples);
+ gbp = gbp->next)
+ ++group_count;
+ if (!gbp || !in_range("PQgetgroup: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return (-1);
+ return (group_count);
}
/* --------------------------------
- * PQnfields - Return the number of fields in a tuple
+ * PQnfields - Return the number of fields in a tuple
* --------------------------------
*/
int
-PQnfields(PortalBuffer *portal, int tuple_index)
+PQnfields(PortalBuffer * portal, int tuple_index)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQnfields: invalid portal pointer", portal) ||
- !in_range("PQnfields: tuple index",
- tuple_index, 0, portal->no_tuples))
- return(-1);
- gbp = PQgroup(portal, tuple_index);
- if (gbp)
- return(gbp->no_fields);
- return(-1);
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQnfields: invalid portal pointer", portal) ||
+ !in_range("PQnfields: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return (-1);
+ gbp = PQgroup(portal, tuple_index);
+ if (gbp)
+ return (gbp->no_fields);
+ return (-1);
}
/* --------------------------------
- * PQfnumber - Return the field index of a given
- * field name within a tuple.
+ * PQfnumber - Return the field index of a given
+ * field name within a tuple.
* --------------------------------
*/
int
-PQfnumber(PortalBuffer *portal, int tuple_index, char *field_name)
+PQfnumber(PortalBuffer * portal, int tuple_index, char *field_name)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQfnumber: invalid portal pointer", portal) ||
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfnumber: invalid portal pointer", portal) ||
!valid_pointer("PQfnumber: invalid field name pointer", field_name) ||
- !in_range("PQfnumber: tuple index",
- tuple_index, 0, portal->no_tuples))
- return(-1);
- gbp = PQgroup(portal, tuple_index);
- if (gbp)
- return(pbuf_findFnumber(gbp, field_name));
- return(-1);
+ !in_range("PQfnumber: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return (-1);
+ gbp = PQgroup(portal, tuple_index);
+ if (gbp)
+ return (pbuf_findFnumber(gbp, field_name));
+ return (-1);
}
/* --------------------------------
- * PQfname - Return the name of a field
+ * PQfname - Return the name of a field
* --------------------------------
*/
-char *
-PQfname(PortalBuffer *portal, int tuple_index, int field_number)
-{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQfname: invalid portal pointer", portal) ||
- !in_range("PQfname: tuple index",
- tuple_index, 0, portal->no_tuples))
- return((char *) NULL);
-
- if ((gbp = PQgroup(portal, tuple_index)) &&
- in_range("PQfname: field number",
- field_number, 0, gbp->no_fields))
- return(pbuf_findFname(gbp, field_number));
- return((char *) NULL);
+char *
+PQfname(PortalBuffer * portal, int tuple_index, int field_number)
+{
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfname: invalid portal pointer", portal) ||
+ !in_range("PQfname: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return ((char *) NULL);
+
+ if ((gbp = PQgroup(portal, tuple_index)) &&
+ in_range("PQfname: field number",
+ field_number, 0, gbp->no_fields))
+ return (pbuf_findFname(gbp, field_number));
+ return ((char *) NULL);
}
/* --------------------------------
- * PQftype - Return the type of a field
+ * PQftype - Return the type of a field
* --------------------------------
*/
int
-PQftype(PortalBuffer *portal, int tuple_index, int field_number)
+PQftype(PortalBuffer * portal, int tuple_index, int field_number)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQftype: invalid portal pointer", portal) ||
- !in_range("PQfname: tuple index",
- tuple_index, 0, portal->no_tuples))
- return(-1);
-
- if ((gbp = PQgroup(portal, tuple_index)) &&
- in_range("PQftype: field number", field_number, 0, gbp->no_fields))
- return(gbp->types[field_number].adtid);
- return(-1);
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQftype: invalid portal pointer", portal) ||
+ !in_range("PQfname: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return (-1);
+
+ if ((gbp = PQgroup(portal, tuple_index)) &&
+ in_range("PQftype: field number", field_number, 0, gbp->no_fields))
+ return (gbp->types[field_number].adtid);
+ return (-1);
}
/* --------------------------------
- * PQfsize - Return the size of a field
+ * PQfsize - Return the size of a field
* --------------------------------
*/
int
-PQfsize(PortalBuffer *portal, int tuple_index, int field_number)
+PQfsize(PortalBuffer * portal, int tuple_index, int field_number)
{
- GroupBuffer *gbp;
-
- if (!valid_pointer("PQfsize: invalid portal pointer", portal) ||
- !in_range("PQfsize: tuple index",
- tuple_index, 0, portal->no_tuples))
- return(-1);
-
- if ((gbp = PQgroup(portal, tuple_index)) &&
- in_range("PQfsize: field number", field_number, 0, gbp->no_fields))
- return(gbp->types[field_number].adtsize);
- return(-1);
+ GroupBuffer *gbp;
+
+ if (!valid_pointer("PQfsize: invalid portal pointer", portal) ||
+ !in_range("PQfsize: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return (-1);
+
+ if ((gbp = PQgroup(portal, tuple_index)) &&
+ in_range("PQfsize: field number", field_number, 0, gbp->no_fields))
+ return (gbp->types[field_number].adtsize);
+ return (-1);
}
-
+
/* --------------------------------
- * PQsametype - Return 1 if the two tuples have the same type
- * (in the same group)
+ * PQsametype - Return 1 if the two tuples have the same type
+ * (in the same group)
* --------------------------------
*/
int
-PQsametype(PortalBuffer *portal, int tuple_index1, int tuple_index2)
-{
- GroupBuffer *gbp1, *gbp2;
-
- if (!valid_pointer("PQsametype: invalid portal pointer", portal) ||
- !in_range("PQsametype: tuple index 1",
- tuple_index1, 0, portal->no_tuples) ||
- !in_range("PQsametype: tuple index 2",
- tuple_index2, 0, portal->no_tuples))
- return(-1);
-
- gbp1 = PQgroup(portal, tuple_index1);
- gbp2 = PQgroup(portal, tuple_index2);
- if (gbp1 && gbp2)
- return(gbp1 == gbp2);
- return(-1);
+PQsametype(PortalBuffer * portal, int tuple_index1, int tuple_index2)
+{
+ GroupBuffer *gbp1,
+ *gbp2;
+
+ if (!valid_pointer("PQsametype: invalid portal pointer", portal) ||
+ !in_range("PQsametype: tuple index 1",
+ tuple_index1, 0, portal->no_tuples) ||
+ !in_range("PQsametype: tuple index 2",
+ tuple_index2, 0, portal->no_tuples))
+ return (-1);
+
+ gbp1 = PQgroup(portal, tuple_index1);
+ gbp2 = PQgroup(portal, tuple_index2);
+ if (gbp1 && gbp2)
+ return (gbp1 == gbp2);
+ return (-1);
}
static TupleBlock *
-PQGetTupleBlock(PortalBuffer *portal,
- int tuple_index,
- int *tuple_offset)
-{
- GroupBuffer *gbp;
- TupleBlock *tbp;
- int tuple_count = 0;
-
- if (!valid_pointer("PQGetTupleBlock: invalid portal pointer", portal) ||
- !valid_pointer("PQGetTupleBlock: invalid offset pointer",
- tuple_offset) ||
- !in_range("PQGetTupleBlock: tuple index",
- tuple_index, 0, portal->no_tuples))
- return((TupleBlock *) NULL);
-
- for (gbp = portal->groups;
- gbp && tuple_index >= (tuple_count += gbp->no_tuples);
- gbp = gbp->next)
- ;
- if (!gbp ||
- !in_range("PQGetTupleBlock: tuple not found: tuple index",
- tuple_index, 0, tuple_count))
- return((TupleBlock *) NULL);
- tuple_count -= gbp->no_tuples;
- for (tbp = gbp->tuples;
- tbp && tuple_index >= (tuple_count += TupleBlockSize);
- tbp = tbp->next)
- ;
- if (!tbp ||
- !in_range("PQGetTupleBlock: tuple not found: tuple index",
- tuple_index, 0, tuple_count))
- return((TupleBlock *) NULL);
- tuple_count -= TupleBlockSize;
-
- *tuple_offset = tuple_index - tuple_count;
- return(tbp);
+PQGetTupleBlock(PortalBuffer * portal,
+ int tuple_index,
+ int *tuple_offset)
+{
+ GroupBuffer *gbp;
+ TupleBlock *tbp;
+ int tuple_count = 0;
+
+ if (!valid_pointer("PQGetTupleBlock: invalid portal pointer", portal) ||
+ !valid_pointer("PQGetTupleBlock: invalid offset pointer",
+ tuple_offset) ||
+ !in_range("PQGetTupleBlock: tuple index",
+ tuple_index, 0, portal->no_tuples))
+ return ((TupleBlock *) NULL);
+
+ for (gbp = portal->groups;
+ gbp && tuple_index >= (tuple_count += gbp->no_tuples);
+ gbp = gbp->next)
+ ;
+ if (!gbp ||
+ !in_range("PQGetTupleBlock: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return ((TupleBlock *) NULL);
+ tuple_count -= gbp->no_tuples;
+ for (tbp = gbp->tuples;
+ tbp && tuple_index >= (tuple_count += TupleBlockSize);
+ tbp = tbp->next)
+ ;
+ if (!tbp ||
+ !in_range("PQGetTupleBlock: tuple not found: tuple index",
+ tuple_index, 0, tuple_count))
+ return ((TupleBlock *) NULL);
+ tuple_count -= TupleBlockSize;
+
+ *tuple_offset = tuple_index - tuple_count;
+ return (tbp);
}
/* --------------------------------
- * PQgetvalue - Return an attribute (field) value
+ * PQgetvalue - Return an attribute (field) value
* --------------------------------
*/
-char *
-PQgetvalue(PortalBuffer *portal,
- int tuple_index,
- int field_number)
+char *
+PQgetvalue(PortalBuffer * portal,
+ int tuple_index,
+ int field_number)
{
- TupleBlock *tbp;
- int tuple_offset;
+ TupleBlock *tbp;
+ int tuple_offset;
- tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
- if (tbp)
- return(tbp->values[tuple_offset][field_number]);
- return((char *) NULL);
+ tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
+ if (tbp)
+ return (tbp->values[tuple_offset][field_number]);
+ return ((char *) NULL);
}
/* --------------------------------
- * PQgetAttr - Return an attribute (field) value
- * this differs from PQgetvalue in that the value returned is
- * a copy. The CALLER is responsible for free'ing the data returned.
+ * PQgetAttr - Return an attribute (field) value
+ * this differs from PQgetvalue in that the value returned is
+ * a copy. The CALLER is responsible for free'ing the data returned.
* --------------------------------
*/
-char *
-PQgetAttr(PortalBuffer *portal,
- int tuple_index,
- int field_number)
-{
- TupleBlock *tbp;
- int tuple_offset;
- int len;
- char* result = NULL;
-
- tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
- if (tbp) {
- len = tbp->lengths[tuple_offset][field_number];
- result = malloc(len + 1);
- memcpy(result,
- tbp->values[tuple_offset][field_number],
- len);
- result[len] = '\0';
- }
- return result;
+char *
+PQgetAttr(PortalBuffer * portal,
+ int tuple_index,
+ int field_number)
+{
+ TupleBlock *tbp;
+ int tuple_offset;
+ int len;
+ char *result = NULL;
+
+ tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
+ if (tbp)
+ {
+ len = tbp->lengths[tuple_offset][field_number];
+ result = malloc(len + 1);
+ memcpy(result,
+ tbp->values[tuple_offset][field_number],
+ len);
+ result[len] = '\0';
+ }
+ return result;
}
/* --------------------------------
- * PQgetlength - Return an attribute (field) length
+ * PQgetlength - Return an attribute (field) length
* --------------------------------
*/
int
-PQgetlength(PortalBuffer *portal,
- int tuple_index,
- int field_number)
+PQgetlength(PortalBuffer * portal,
+ int tuple_index,
+ int field_number)
{
- TupleBlock *tbp;
- int tuple_offset;
+ TupleBlock *tbp;
+ int tuple_offset;
- tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
- if (tbp)
- return(tbp->lengths[tuple_offset][field_number]);
- return(-1);
+ tbp = PQGetTupleBlock(portal, tuple_index, &tuple_offset);
+ if (tbp)
+ return (tbp->lengths[tuple_offset][field_number]);
+ return (-1);
}
/* ----------------
- * PQclear - free storage claimed by named portal
+ * PQclear - free storage claimed by named portal
* ----------------
*/
void
PQclear(char *pname)
-{
- if (!valid_pointer("PQclear: invalid portal name pointer", pname))
- return;
- pbuf_close(pname);
+{
+ if (!valid_pointer("PQclear: invalid portal name pointer", pname))
+ return;
+ pbuf_close(pname);
}
/*
@@ -644,74 +657,81 @@ PQclear(char *pname)
* This is going away with pending rewrite of comm. code...
*/
/* static SLList pqNotifyList;*/
-static Dllist *pqNotifyList = NULL;
+static Dllist *pqNotifyList = NULL;
/* remove invalid notifies before returning */
void
PQcleanNotify()
{
- Dlelem *e, *next;
- PQNotifyList *p;
-
- e = DLGetHead(pqNotifyList);
-
- while (e) {
- next = DLGetSucc(e);
- p = (PQNotifyList*)DLE_VAL(e);
- if (p->valid == 0) {
- DLRemove(e);
- DLFreeElem(e);
- pfree(p);
- }
- e = next;
- }
+ Dlelem *e,
+ *next;
+ PQNotifyList *p;
+
+ e = DLGetHead(pqNotifyList);
+
+ while (e)
+ {
+ next = DLGetSucc(e);
+ p = (PQNotifyList *) DLE_VAL(e);
+ if (p->valid == 0)
+ {
+ DLRemove(e);
+ DLFreeElem(e);
+ pfree(p);
+ }
+ e = next;
+ }
}
void
PQnotifies_init()
{
- Dlelem *e;
- PQNotifyList *p;
-
- if (pqNotifyList == NULL) {
- pqNotifyList = DLNewList();
- }
- else {
- /* clean all notifies */
- for (e = DLGetHead(pqNotifyList); e != NULL; e = DLGetSucc(e)) {
- p = (PQNotifyList*)DLE_VAL(e);
- p->valid = 0;
+ Dlelem *e;
+ PQNotifyList *p;
+
+ if (pqNotifyList == NULL)
+ {
+ pqNotifyList = DLNewList();
+ }
+ else
+ {
+ /* clean all notifies */
+ for (e = DLGetHead(pqNotifyList); e != NULL; e = DLGetSucc(e))
+ {
+ p = (PQNotifyList *) DLE_VAL(e);
+ p->valid = 0;
+ }
+ PQcleanNotify();
}
- PQcleanNotify();
- }
}
-PQNotifyList *
+PQNotifyList *
PQnotifies()
{
- Dlelem *e;
- PQcleanNotify();
- e = DLGetHead(pqNotifyList);
- return (e ? (PQNotifyList*)DLE_VAL(e) : NULL);
+ Dlelem *e;
+
+ PQcleanNotify();
+ e = DLGetHead(pqNotifyList);
+ return (e ? (PQNotifyList *) DLE_VAL(e) : NULL);
}
void
-PQremoveNotify(PQNotifyList *nPtr)
+PQremoveNotify(PQNotifyList * nPtr)
{
- nPtr->valid = 0; /* remove later */
+ nPtr->valid = 0; /* remove later */
}
void
PQappendNotify(char *relname, int pid)
{
- PQNotifyList *p;
-
- if (pqNotifyList == NULL)
- pqNotifyList = DLNewList();
-
- p = (PQNotifyList*)pbuf_alloc(sizeof(PQNotifyList));
- strNcpy(p->relname, relname, NAMEDATALEN-1);
- p->be_pid = pid;
- p->valid = 1;
- DLAddTail(pqNotifyList, DLNewElem(p));
+ PQNotifyList *p;
+
+ if (pqNotifyList == NULL)
+ pqNotifyList = DLNewList();
+
+ p = (PQNotifyList *) pbuf_alloc(sizeof(PQNotifyList));
+ strNcpy(p->relname, relname, NAMEDATALEN - 1);
+ p->be_pid = pid;
+ p->valid = 1;
+ DLAddTail(pqNotifyList, DLNewElem(p));
}
diff --git a/src/backend/libpq/portalbuf.c b/src/backend/libpq/portalbuf.c
index b7a527dcfaf..ed2d5bbe615 100644
--- a/src/backend/libpq/portalbuf.c
+++ b/src/backend/libpq/portalbuf.c
@@ -1,50 +1,50 @@
/*-------------------------------------------------------------------------
*
* portalbuf.c--
- * portal buffer support routines for src/libpq/portal.c
+ * portal buffer support routines for src/libpq/portal.c
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portalbuf.c,v 1.4 1997/08/12 20:15:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/portalbuf.c,v 1.5 1997/09/07 04:42:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * pbuf_alloc - allocate memory for libpq routines
- * pbuf_free - free memory for libpq routines
- * pbuf_addPortal - Allocate a new portal buffer
- * pbuf_addGroup - Add a new tuple group to the portal
- * pbuf_addTypes - Allocate n type blocks
- * pbuf_addTuples - Allocate a tuple block
- * pbuf_addTuple - Allocate a tuple of n fields (attributes)
- * pbuf_addValues - Allocate n bytes for a value
- * pbuf_addEntry - Allocate a portal entry
- * pbuf_freeEntry - Free a portal entry in the portal table
- * pbuf_freeTypes - Free up the space used by a portal
- * pbuf_freeTuples - free space used by tuple block
- * pbuf_freeGroup - free space used by group, types and tuples
- * pbuf_freePortal - free space used by portal and portal's group
- * pbuf_getIndex - Return the index of the portal entry
- * pbuf_setup - Set up a portal for dumping data
- * pbuf_close - Close a portal, remove it from the portal table
- * pbuf_findGroup - Return group given the group_index
- * pbuf_findFnumber - Return field index of a given field within a group
- * pbuf_findFname - Find the field name given the field index
- * pbuf_checkFnumber - signal an error if field number is out of bounds
+ * pbuf_alloc - allocate memory for libpq routines
+ * pbuf_free - free memory for libpq routines
+ * pbuf_addPortal - Allocate a new portal buffer
+ * pbuf_addGroup - Add a new tuple group to the portal
+ * pbuf_addTypes - Allocate n type blocks
+ * pbuf_addTuples - Allocate a tuple block
+ * pbuf_addTuple - Allocate a tuple of n fields (attributes)
+ * pbuf_addValues - Allocate n bytes for a value
+ * pbuf_addEntry - Allocate a portal entry
+ * pbuf_freeEntry - Free a portal entry in the portal table
+ * pbuf_freeTypes - Free up the space used by a portal
+ * pbuf_freeTuples - free space used by tuple block
+ * pbuf_freeGroup - free space used by group, types and tuples
+ * pbuf_freePortal - free space used by portal and portal's group
+ * pbuf_getIndex - Return the index of the portal entry
+ * pbuf_setup - Set up a portal for dumping data
+ * pbuf_close - Close a portal, remove it from the portal table
+ * pbuf_findGroup - Return group given the group_index
+ * pbuf_findFnumber - Return field index of a given field within a group
+ * pbuf_findFname - Find the field name given the field index
+ * pbuf_checkFnumber - signal an error if field number is out of bounds
*
* NOTES
- * These functions may be used by both frontend routines which
- * communicate with a backend or by user-defined functions which
- * are compiled or dynamically loaded into a backend.
+ * These functions may be used by both frontend routines which
+ * communicate with a backend or by user-defined functions which
+ * are compiled or dynamically loaded into a backend.
*
- * the portals[] array should be organized as a hash table for
- * quick portal-by-name lookup.
+ * the portals[] array should be organized as a hash table for
+ * quick portal-by-name lookup.
*
- * Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
- * see utils/mmgr/portalmem.c for why. -cim 2/22/91
+ * Do not confuse "PortalEntry" (or "PortalBuffer") with "Portal"
+ * see utils/mmgr/portalmem.c for why. -cim 2/22/91
*
*/
#include <string.h>
@@ -55,407 +55,417 @@
#include <libpq/libpq.h> /* where the declarations go */
#include <utils/exc.h>
-PortalEntry** portals = (PortalEntry**) NULL;
-size_t portals_array_size = 0;
+PortalEntry **portals = (PortalEntry **) NULL;
+size_t portals_array_size = 0;
/* portals array memory is malloc'd instead of using MemoryContexts */
/* since it will be used by both front and backend programs*/
-/* GlobalMemory portals_mmcxt = (GlobalMemory) NULL; */
+/* GlobalMemory portals_mmcxt = (GlobalMemory) NULL; */
-/* -------------------------------
+/* -------------------------------
* portals_realloc --
- * grow the size of the portals array by size
+ * grow the size of the portals array by size
*
- * also ensures that elements are initially NULL
+ * also ensures that elements are initially NULL
*/
static void
portals_realloc(size_t size)
{
- size_t oldsize;
- int i;
- PortalEntry** newp;
-
- oldsize = portals_array_size;
-
- portals_array_size += size;
- if (portals)
- newp= (PortalEntry**)realloc(portals,
- portals_array_size*sizeof(PortalEntry*));
- else
- newp= (PortalEntry**)malloc(portals_array_size*sizeof(PortalEntry*));
-
- if (newp)
- portals = newp;
- else
- libpq_raise(&PortalError,
- form("Cannot alloc more memory in portals_realloc"));
-
- for (i=oldsize;i<portals_array_size;i++)
- portals[i]=(PortalEntry*)NULL;
-
+ size_t oldsize;
+ int i;
+ PortalEntry **newp;
+
+ oldsize = portals_array_size;
+
+ portals_array_size += size;
+ if (portals)
+ newp = (PortalEntry **) realloc(portals,
+ portals_array_size * sizeof(PortalEntry *));
+ else
+ newp = (PortalEntry **) malloc(portals_array_size * sizeof(PortalEntry *));
+
+ if (newp)
+ portals = newp;
+ else
+ libpq_raise(&PortalError,
+ form("Cannot alloc more memory in portals_realloc"));
+
+ for (i = oldsize; i < portals_array_size; i++)
+ portals[i] = (PortalEntry *) NULL;
+
}
/* --------------------------------
- * pbuf_alloc - allocate memory for portal buffers
+ * pbuf_alloc - allocate memory for portal buffers
*
- * remember: palloc() in the backend uses the postgres MemoryContext
- * library and palloc() in the frontend (fe-pqstubs.c) calls malloc().
+ * remember: palloc() in the backend uses the postgres MemoryContext
+ * library and palloc() in the frontend (fe-pqstubs.c) calls malloc().
* --------------------------------
*/
caddr_t
pbuf_alloc(size_t size)
{
- caddr_t addr;
-
- if (size <= 0)
- libpq_raise(&MemoryError, form("Invalid argument to pbuf_alloc()."));
-
- addr = (caddr_t) palloc(size);
- if (addr == (caddr_t) NULL)
- libpq_raise(&MemoryError, form("Cannot Allocate space."));
-
- return (addr);
+ caddr_t addr;
+
+ if (size <= 0)
+ libpq_raise(&MemoryError, form("Invalid argument to pbuf_alloc()."));
+
+ addr = (caddr_t) palloc(size);
+ if (addr == (caddr_t) NULL)
+ libpq_raise(&MemoryError, form("Cannot Allocate space."));
+
+ return (addr);
}
/* --------------------------------
- * pbuf_free - free memory for portal buffers
+ * pbuf_free - free memory for portal buffers
*
- * remember: pfree() in the backend uses the postgres MemoryContext
- * library and pfree() in the frontend (fe-pqstubs.c) calls free().
+ * remember: pfree() in the backend uses the postgres MemoryContext
+ * library and pfree() in the frontend (fe-pqstubs.c) calls free().
* --------------------------------
*/
void
pbuf_free(caddr_t pointer)
{
- if (pointer)
- pfree(pointer);
- else
- libpq_raise(&MemoryError, form("Tried to free NULL memory pointer"));
-
+ if (pointer)
+ pfree(pointer);
+ else
+ libpq_raise(&MemoryError, form("Tried to free NULL memory pointer"));
+
}
/* --------------------------------
- * pbuf_addPortal - Allocate a new portal buffer
+ * pbuf_addPortal - Allocate a new portal buffer
* --------------------------------
*/
-PortalBuffer *
+PortalBuffer *
pbuf_addPortal()
{
- PortalBuffer *portal;
-
- portal = (PortalBuffer *)
- pbuf_alloc(sizeof (PortalBuffer));
-
- portal->rule_p = 0;
- portal->no_tuples = 0;
- portal->no_groups = 0;
- portal->groups = NULL;
-
- return (portal);
+ PortalBuffer *portal;
+
+ portal = (PortalBuffer *)
+ pbuf_alloc(sizeof(PortalBuffer));
+
+ portal->rule_p = 0;
+ portal->no_tuples = 0;
+ portal->no_groups = 0;
+ portal->groups = NULL;
+
+ return (portal);
}
/* --------------------------------
- * pbuf_addGroup - Add a new tuple group to the portal
+ * pbuf_addGroup - Add a new tuple group to the portal
* --------------------------------
*/
-GroupBuffer *
-pbuf_addGroup(PortalBuffer *portal)
+GroupBuffer *
+pbuf_addGroup(PortalBuffer * portal)
{
- GroupBuffer *group, *group1;
-
- group = (GroupBuffer *)
- pbuf_alloc(sizeof (GroupBuffer));
-
- /* Initialize the new group buffer. */
- group->no_tuples = 0;
- group->no_fields = 0;
- group->types = NULL;
- group->tuples = NULL;
- group->next = NULL;
-
- if ((group1 = portal->groups) == NULL)
- portal->groups = group;
- else {
- while (group1->next != NULL)
- group1 = group1->next;
- group1->next = group;
- }
-
- return (group);
+ GroupBuffer *group,
+ *group1;
+
+ group = (GroupBuffer *)
+ pbuf_alloc(sizeof(GroupBuffer));
+
+ /* Initialize the new group buffer. */
+ group->no_tuples = 0;
+ group->no_fields = 0;
+ group->types = NULL;
+ group->tuples = NULL;
+ group->next = NULL;
+
+ if ((group1 = portal->groups) == NULL)
+ portal->groups = group;
+ else
+ {
+ while (group1->next != NULL)
+ group1 = group1->next;
+ group1->next = group;
+ }
+
+ return (group);
}
/* --------------------------------
- * pbuf_addTypes - Allocate n type blocks
+ * pbuf_addTypes - Allocate n type blocks
* --------------------------------
*/
-TypeBlock *
+TypeBlock *
pbuf_addTypes(int n)
{
- TypeBlock *types;
-
- types = (TypeBlock *)
- pbuf_alloc(n * sizeof (TypeBlock));
-
- return (types);
+ TypeBlock *types;
+
+ types = (TypeBlock *)
+ pbuf_alloc(n * sizeof(TypeBlock));
+
+ return (types);
}
/* --------------------------------
- * pbuf_addTuples - Allocate a tuple block
+ * pbuf_addTuples - Allocate a tuple block
* --------------------------------
*/
-TupleBlock *
+TupleBlock *
pbuf_addTuples()
{
- TupleBlock *tuples;
-
- tuples = (TupleBlock *)
- pbuf_alloc(sizeof (TupleBlock));
-
- tuples->next = NULL;
- tuples->tuple_index = 0;
-
- return (tuples);
+ TupleBlock *tuples;
+
+ tuples = (TupleBlock *)
+ pbuf_alloc(sizeof(TupleBlock));
+
+ tuples->next = NULL;
+ tuples->tuple_index = 0;
+
+ return (tuples);
}
/* --------------------------------
- * pbuf_addTuple - Allocate a tuple of n fields (attributes)
+ * pbuf_addTuple - Allocate a tuple of n fields (attributes)
* --------------------------------
*/
-char **
+char **
pbuf_addTuple(int n)
{
- return (char **)
- pbuf_alloc(n * sizeof (char *));
+ return (char **)
+ pbuf_alloc(n * sizeof(char *));
}
/* --------------------------------
- * pbuf_addTupleValueLengths - Allocate a tuple of n lengths (attributes)
+ * pbuf_addTupleValueLengths - Allocate a tuple of n lengths (attributes)
* --------------------------------
*/
-int *
+int *
pbuf_addTupleValueLengths(int n)
{
- return (int *)
+ return (int *)
pbuf_alloc(n * sizeof(int));
}
/* --------------------------------
- * pbuf_addValues - Allocate n bytes for a value
+ * pbuf_addValues - Allocate n bytes for a value
* --------------------------------
*/
-char *
+char *
pbuf_addValues(int n)
{
- return
+ return
pbuf_alloc(n);
}
/* --------------------------------
- * pbuf_addEntry - Allocate a portal entry
+ * pbuf_addEntry - Allocate a portal entry
* --------------------------------
*/
-PortalEntry *pbuf_addEntry()
+PortalEntry *
+pbuf_addEntry()
{
- return (PortalEntry *)
- pbuf_alloc (sizeof (PortalEntry));
+ return (PortalEntry *)
+ pbuf_alloc(sizeof(PortalEntry));
}
/* --------------------------------
- * pbuf_freeEntry - Free a portal entry in the portal table
- * the portal is freed separately.
+ * pbuf_freeEntry - Free a portal entry in the portal table
+ * the portal is freed separately.
* --------------------------------
*/
void
pbuf_freeEntry(int i)
{
- if (portals)
+ if (portals)
{
- pbuf_free ((caddr_t)portals[i]);
- portals[i] = NULL;
+ pbuf_free((caddr_t) portals[i]);
+ portals[i] = NULL;
}
}
/* --------------------------------
- * pbuf_freeTypes - Free up the space used by a portal
+ * pbuf_freeTypes - Free up the space used by a portal
* --------------------------------
*/
void
-pbuf_freeTypes(TypeBlock *types)
+pbuf_freeTypes(TypeBlock * types)
{
- pbuf_free((caddr_t)types);
+ pbuf_free((caddr_t) types);
}
/* --------------------------------
- * pbuf_freeTuples - free space used by tuple block
+ * pbuf_freeTuples - free space used by tuple block
* --------------------------------
*/
void
-pbuf_freeTuples(TupleBlock *tuples,
- int no_tuples,
- int no_fields)
+pbuf_freeTuples(TupleBlock * tuples,
+ int no_tuples,
+ int no_fields)
{
- int i, j;
-
- if (no_tuples > TupleBlockSize) {
- pbuf_freeTuples (tuples->next, no_tuples - TupleBlockSize, no_fields);
- no_tuples = TupleBlockSize;
- }
-
- /* For each tuple, free all its attribute values. */
- for (i = 0; i < no_tuples; i++) {
- for (j = 0; j < no_fields; j++)
- if (tuples->values[i][j] != NULL)
- pbuf_free((caddr_t)tuples->values[i][j]);
- if (tuples->lengths[i])
- pbuf_free((caddr_t)tuples->lengths[i]);
- if (tuples->values[i])
- pbuf_free((caddr_t)tuples->values[i]);
- }
-
- pbuf_free((caddr_t)tuples);
+ int i,
+ j;
+
+ if (no_tuples > TupleBlockSize)
+ {
+ pbuf_freeTuples(tuples->next, no_tuples - TupleBlockSize, no_fields);
+ no_tuples = TupleBlockSize;
+ }
+
+ /* For each tuple, free all its attribute values. */
+ for (i = 0; i < no_tuples; i++)
+ {
+ for (j = 0; j < no_fields; j++)
+ if (tuples->values[i][j] != NULL)
+ pbuf_free((caddr_t) tuples->values[i][j]);
+ if (tuples->lengths[i])
+ pbuf_free((caddr_t) tuples->lengths[i]);
+ if (tuples->values[i])
+ pbuf_free((caddr_t) tuples->values[i]);
+ }
+
+ pbuf_free((caddr_t) tuples);
}
/* --------------------------------
- * pbuf_freeGroup - free space used by group, types and tuples
+ * pbuf_freeGroup - free space used by group, types and tuples
* --------------------------------
*/
void
-pbuf_freeGroup(GroupBuffer *group)
+pbuf_freeGroup(GroupBuffer * group)
{
- if (group->next != NULL)
- pbuf_freeGroup(group->next);
-
- if (group->types != NULL)
- pbuf_freeTypes(group->types);
-
- if (group->tuples != NULL)
- pbuf_freeTuples(group->tuples, group->no_tuples,group->no_fields);
-
- pbuf_free((caddr_t)group);
+ if (group->next != NULL)
+ pbuf_freeGroup(group->next);
+
+ if (group->types != NULL)
+ pbuf_freeTypes(group->types);
+
+ if (group->tuples != NULL)
+ pbuf_freeTuples(group->tuples, group->no_tuples, group->no_fields);
+
+ pbuf_free((caddr_t) group);
}
/* --------------------------------
- * pbuf_freePortal - free space used by portal and portal's group
+ * pbuf_freePortal - free space used by portal and portal's group
* --------------------------------
*/
void
-pbuf_freePortal(PortalBuffer *portal)
+pbuf_freePortal(PortalBuffer * portal)
{
- if (portal->groups != NULL)
- pbuf_freeGroup(portal->groups);
-
- pbuf_free((caddr_t)portal);
+ if (portal->groups != NULL)
+ pbuf_freeGroup(portal->groups);
+
+ pbuf_free((caddr_t) portal);
}
/* --------------------------------
- * pbuf_getIndex - Return the index of the portal entry
- * note: portals[] maps portal names to portal buffers.
+ * pbuf_getIndex - Return the index of the portal entry
+ * note: portals[] maps portal names to portal buffers.
* --------------------------------
*/
int
pbuf_getIndex(char *pname)
{
- int i;
-
- if (portals) {
- for (i = 0; i < portals_array_size; i++)
- if (portals[i] != NULL &&
- strncmp(portals[i]->name, pname, PortalNameLength) == 0)
- return i;
- }
-
- return (-1);
+ int i;
+
+ if (portals)
+ {
+ for (i = 0; i < portals_array_size; i++)
+ if (portals[i] != NULL &&
+ strncmp(portals[i]->name, pname, PortalNameLength) == 0)
+ return i;
+ }
+
+ return (-1);
}
/* --------------------------------
- * pbuf_setportalname - assign a user given name to a portal
+ * pbuf_setportalname - assign a user given name to a portal
* --------------------------------
*/
void
-pbuf_setportalinfo(PortalEntry *entry, char *pname)
+pbuf_setportalinfo(PortalEntry * entry, char *pname)
{
- if (entry)
- strNcpy(entry->name, pname, PortalNameLength-1);
+ if (entry)
+ strNcpy(entry->name, pname, PortalNameLength - 1);
}
/* --------------------------------
- * pbuf_setup - Set up a portal for dumping data
+ * pbuf_setup - Set up a portal for dumping data
* --------------------------------
*/
-PortalEntry *
+PortalEntry *
pbuf_setup(char *pname)
{
- int i;
-
- if (!portals) /* the portals array has not been allocated yet */
+ int i;
+
+ if (!portals) /* the portals array has not been
+ * allocated yet */
{
- /* allocate portals[] array here */
- portals_realloc(PORTALS_INITIAL_SIZE);
+ /* allocate portals[] array here */
+ portals_realloc(PORTALS_INITIAL_SIZE);
}
-
- /* If a portal with the same name already exists, close it. */
- /* else look for an empty entry in the portal table. */
- if ((i = pbuf_getIndex(pname)) != -1)
- pbuf_freePortal(portals[i]->portal);
- else {
- for (i = 0; i < portals_array_size; i++)
- if (portals[i] == NULL)
- break;
-
- /* If the portal table is full, enlarge it */
- if (i >= portals_array_size)
- portals_realloc(PORTALS_GROW_BY);
-
- portals[i] = pbuf_addEntry();
- strncpy(portals[i]->name, pname, PortalNameLength);
- }
- portals[i]->portal = pbuf_addPortal();
- portals[i]->portalcxt = NULL;
- portals[i]->result = NULL;
-
- return portals[i];
+
+ /* If a portal with the same name already exists, close it. */
+ /* else look for an empty entry in the portal table. */
+ if ((i = pbuf_getIndex(pname)) != -1)
+ pbuf_freePortal(portals[i]->portal);
+ else
+ {
+ for (i = 0; i < portals_array_size; i++)
+ if (portals[i] == NULL)
+ break;
+
+ /* If the portal table is full, enlarge it */
+ if (i >= portals_array_size)
+ portals_realloc(PORTALS_GROW_BY);
+
+ portals[i] = pbuf_addEntry();
+ strncpy(portals[i]->name, pname, PortalNameLength);
+ }
+ portals[i]->portal = pbuf_addPortal();
+ portals[i]->portalcxt = NULL;
+ portals[i]->result = NULL;
+
+ return portals[i];
}
/* --------------------------------
- * pbuf_close - Close a portal, remove it from the portal table
- * and free up the space
+ * pbuf_close - Close a portal, remove it from the portal table
+ * and free up the space
* --------------------------------
*/
void
pbuf_close(char *pname)
{
- int i;
-
- if ((i = pbuf_getIndex(pname)) == -1)
- libpq_raise(&PortalError, form("Portal %s does not exist.", pname));
-
- pbuf_freePortal(portals[i]->portal);
- pbuf_freeEntry(i);
+ int i;
+
+ if ((i = pbuf_getIndex(pname)) == -1)
+ libpq_raise(&PortalError, form("Portal %s does not exist.", pname));
+
+ pbuf_freePortal(portals[i]->portal);
+ pbuf_freeEntry(i);
}
/* --------------------------------
- * pbuf_findGroup - Return the group given the group_index
+ * pbuf_findGroup - Return the group given the group_index
* --------------------------------
*/
-GroupBuffer *
-pbuf_findGroup(PortalBuffer *portal,
- int group_index)
+GroupBuffer *
+pbuf_findGroup(PortalBuffer * portal,
+ int group_index)
{
- GroupBuffer *group;
-
- group = portal->groups;
- while (group_index > 0 && group != NULL) {
- group = group->next;
- group_index--;
- }
-
- if (group == NULL)
- libpq_raise(&PortalError,
- form("Group index %d out of bound.", group_index));
-
- return (group);
+ GroupBuffer *group;
+
+ group = portal->groups;
+ while (group_index > 0 && group != NULL)
+ {
+ group = group->next;
+ group_index--;
+ }
+
+ if (group == NULL)
+ libpq_raise(&PortalError,
+ form("Group index %d out of bound.", group_index));
+
+ return (group);
}
/* --------------------------------
@@ -463,49 +473,48 @@ pbuf_findGroup(PortalBuffer *portal,
* --------------------------------
*/
int
-pbuf_findFnumber(GroupBuffer *group,
- char *field_name)
-{
- TypeBlock *types;
- int i;
-
- types = group->types;
-
- for (i = 0; i < group->no_fields; i++)
- if (strncmp(types[i].name, field_name, NAMEDATALEN) == 0)
- return (i);
-
- libpq_raise(&PortalError,
- form("Field-name %s does not exist.", field_name));
-
- /* not reached, here to make compiler happy */
- return 0;
+pbuf_findFnumber(GroupBuffer * group,
+ char *field_name)
+{
+ TypeBlock *types;
+ int i;
+
+ types = group->types;
+
+ for (i = 0; i < group->no_fields; i++)
+ if (strncmp(types[i].name, field_name, NAMEDATALEN) == 0)
+ return (i);
+
+ libpq_raise(&PortalError,
+ form("Field-name %s does not exist.", field_name));
+
+ /* not reached, here to make compiler happy */
+ return 0;
}
/* --------------------------------
- * pbuf_checkFnumber - signal an error if field number is out of bounds
+ * pbuf_checkFnumber - signal an error if field number is out of bounds
* --------------------------------
*/
void
-pbuf_checkFnumber(GroupBuffer *group,
- int field_number)
+pbuf_checkFnumber(GroupBuffer * group,
+ int field_number)
{
- if (field_number < 0 || field_number >= group->no_fields)
- libpq_raise(&PortalError,
- form("Field number %d out of bound.", field_number));
+ if (field_number < 0 || field_number >= group->no_fields)
+ libpq_raise(&PortalError,
+ form("Field number %d out of bound.", field_number));
}
/* --------------------------------
- * pbuf_findFname - Find the field name given the field index
+ * pbuf_findFname - Find the field name given the field index
* --------------------------------
*/
-char *
-pbuf_findFname(GroupBuffer *group,
- int field_number)
+char *
+pbuf_findFname(GroupBuffer * group,
+ int field_number)
{
- pbuf_checkFnumber(group, field_number);
- return
- (group->types[field_number]).name;
+ pbuf_checkFnumber(group, field_number);
+ return
+ (group->types[field_number]).name;
}
-
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index cfa0aebc521..6a7df5771ac 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -1,37 +1,37 @@
/*-------------------------------------------------------------------------
*
* pqcomm.c--
- * Communication functions between the Frontend and the Backend
+ * Communication functions between the Frontend and the Backend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.19 1997/08/12 22:52:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.20 1997/09/07 04:42:25 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * pq_gettty - return the name of the tty in the given buffer
- * pq_getport - return the PGPORT setting
- * pq_close - close input / output connections
- * pq_flush - flush pending output
- * pq_getstr - get a null terminated string from connection
- * pq_getnchar - get n characters from connection
- * pq_getint - get an integer from connection
- * pq_putstr - send a null terminated string to connection
- * pq_putnchar - send n characters to connection
- * pq_putint - send an integer to connection
- * pq_getinaddr - initialize address from host and port number
- * pq_getinserv - initialize address from host and service name
- * pq_connect - create remote input / output connection
- * pq_accept - accept remote input / output connection
- * pq_async_notify - receive notification from backend.
+ * pq_gettty - return the name of the tty in the given buffer
+ * pq_getport - return the PGPORT setting
+ * pq_close - close input / output connections
+ * pq_flush - flush pending output
+ * pq_getstr - get a null terminated string from connection
+ * pq_getnchar - get n characters from connection
+ * pq_getint - get an integer from connection
+ * pq_putstr - send a null terminated string to connection
+ * pq_putnchar - send n characters to connection
+ * pq_putint - send an integer to connection
+ * pq_getinaddr - initialize address from host and port number
+ * pq_getinserv - initialize address from host and service name
+ * pq_connect - create remote input / output connection
+ * pq_accept - accept remote input / output connection
+ * pq_async_notify - receive notification from backend.
*
* NOTES
- * These functions are used by both frontend applications and
- * the postgres backend.
+ * These functions are used by both frontend applications and
+ * the postgres backend.
*
*/
#include <stdio.h>
@@ -39,7 +39,7 @@
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h> /* for ttyname() */
+#include <unistd.h> /* for ttyname() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
@@ -49,208 +49,217 @@
#if defined(linux)
#ifndef SOMAXCONN
-#define SOMAXCONN 5 /* from Linux listen(2) man page */
-#endif /* SOMAXCONN */
-#endif /* linux */
+#define SOMAXCONN 5 /* from Linux listen(2) man page */
+#endif /* SOMAXCONN */
+#endif /* linux */
#include <postgres.h>
#include <libpq/pqsignal.h>
#include <libpq/auth.h>
-#include <libpq/libpq.h> /* where the declarations go */
+#include <libpq/libpq.h> /* where the declarations go */
/* ----------------
- * declarations
+ * declarations
* ----------------
*/
-FILE *Pfout, *Pfin;
-FILE *Pfdebug; /* debugging libpq */
-int PQAsyncNotifyWaiting; /* for async. notification */
+FILE *Pfout,
+ *Pfin;
+FILE *Pfdebug; /* debugging libpq */
+int PQAsyncNotifyWaiting; /* for async. notification */
/* --------------------------------
- * pq_init - open portal file descriptors
+ * pq_init - open portal file descriptors
* --------------------------------
*/
void
pq_init(int fd)
{
- Pfin = fdopen(fd, "r");
- Pfout = fdopen(dup(fd), "w");
- if (!Pfin || !Pfout)
- elog(FATAL, "pq_init: Couldn't initialize socket connection");
- PQnotifies_init();
- if (getenv("LIBPQ_DEBUG")) {
- Pfdebug = stderr;
- }else {
- Pfdebug = NULL;
- }
+ Pfin = fdopen(fd, "r");
+ Pfout = fdopen(dup(fd), "w");
+ if (!Pfin || !Pfout)
+ elog(FATAL, "pq_init: Couldn't initialize socket connection");
+ PQnotifies_init();
+ if (getenv("LIBPQ_DEBUG"))
+ {
+ Pfdebug = stderr;
+ }
+ else
+ {
+ Pfdebug = NULL;
+ }
}
/* -------------------------
- * pq_getc(File* fin)
- *
- * get a character from the input file,
+ * pq_getc(File* fin)
+ *
+ * get a character from the input file,
*
- * if Pfdebug is set, also echo the character fetched into Pfdebug
+ * if Pfdebug is set, also echo the character fetched into Pfdebug
*
- * used for debugging libpq
+ * used for debugging libpq
*/
static int
-pq_getc(FILE* fin)
+pq_getc(FILE * fin)
{
- int c;
+ int c;
- c = getc(fin);
- if (Pfdebug && c != EOF)
- putc(c,Pfdebug);
- return c;
+ c = getc(fin);
+ if (Pfdebug && c != EOF)
+ putc(c, Pfdebug);
+ return c;
}
/* --------------------------------
- * pq_gettty - return the name of the tty in the given buffer
+ * pq_gettty - return the name of the tty in the given buffer
* --------------------------------
*/
void
pq_gettty(char *tp)
-{
- strncpy(tp, ttyname(0), 19);
+{
+ strncpy(tp, ttyname(0), 19);
}
/* --------------------------------
- * pq_getport - return the PGPORT setting
+ * pq_getport - return the PGPORT setting
* --------------------------------
*/
int
pq_getport()
{
- char *envport = getenv("PGPORT");
-
- if (envport)
- return(atoi(envport));
- return(atoi(DEF_PGPORT));
+ char *envport = getenv("PGPORT");
+
+ if (envport)
+ return (atoi(envport));
+ return (atoi(DEF_PGPORT));
}
/* --------------------------------
- * pq_close - close input / output connections
+ * pq_close - close input / output connections
* --------------------------------
*/
void
pq_close()
{
- if (Pfin) {
- fclose(Pfin);
- Pfin = NULL;
- }
- if (Pfout) {
- fclose(Pfout);
- Pfout = NULL;
- }
- PQAsyncNotifyWaiting = 0;
- PQnotifies_init();
- pq_unregoob();
+ if (Pfin)
+ {
+ fclose(Pfin);
+ Pfin = NULL;
+ }
+ if (Pfout)
+ {
+ fclose(Pfout);
+ Pfout = NULL;
+ }
+ PQAsyncNotifyWaiting = 0;
+ PQnotifies_init();
+ pq_unregoob();
}
/* --------------------------------
- * pq_flush - flush pending output
+ * pq_flush - flush pending output
* --------------------------------
*/
void
pq_flush()
{
- if (Pfout)
- fflush(Pfout);
+ if (Pfout)
+ fflush(Pfout);
}
/* --------------------------------
- * pq_getstr - get a null terminated string from connection
+ * pq_getstr - get a null terminated string from connection
* --------------------------------
*/
int
pq_getstr(char *s, int maxlen)
{
- int c = '\0';
-
- if (Pfin == (FILE *) NULL) {
-/* elog(DEBUG, "Input descriptor is null"); */
- return(EOF);
- }
-
- while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
- *s++ = c;
- *s = '\0';
-
- /* -----------------
- * If EOF reached let caller know.
- * (This will only happen if we hit EOF before the string
- * delimiter is reached.)
- * -----------------
- */
- if (c == EOF)
- return(EOF);
- return(!EOF);
+ int c = '\0';
+
+ if (Pfin == (FILE *) NULL)
+ {
+/* elog(DEBUG, "Input descriptor is null"); */
+ return (EOF);
+ }
+
+ while (maxlen-- && (c = pq_getc(Pfin)) != EOF && c)
+ *s++ = c;
+ *s = '\0';
+
+ /* -----------------
+ * If EOF reached let caller know.
+ * (This will only happen if we hit EOF before the string
+ * delimiter is reached.)
+ * -----------------
+ */
+ if (c == EOF)
+ return (EOF);
+ return (!EOF);
}
/*
* USER FUNCTION - gets a newline-terminated string from the backend.
- *
+ *
* Chiefly here so that applications can use "COPY <rel> to stdout"
- * and read the output string. Returns a null-terminated string in s.
+ * and read the output string. Returns a null-terminated string in s.
*
* PQgetline reads up to maxlen-1 characters (like fgets(3)) but strips
* the terminating \n (like gets(3)).
*
* RETURNS:
- * EOF if it is detected or invalid arguments are given
- * 0 if EOL is reached (i.e., \n has been read)
- * (this is required for backward-compatibility -- this
- * routine used to always return EOF or 0, assuming that
- * the line ended within maxlen bytes.)
- * 1 in other cases
+ * EOF if it is detected or invalid arguments are given
+ * 0 if EOL is reached (i.e., \n has been read)
+ * (this is required for backward-compatibility -- this
+ * routine used to always return EOF or 0, assuming that
+ * the line ended within maxlen bytes.)
+ * 1 in other cases
*/
-int PQgetline(char *s, int maxlen)
+int
+PQgetline(char *s, int maxlen)
+{
+ if (!Pfin || !s || maxlen <= 1)
+ return (EOF);
+
+ if (fgets(s, maxlen - 1, Pfin) == NULL)
{
- if (!Pfin || !s || maxlen <= 1)
- return(EOF);
-
- if(fgets(s, maxlen - 1, Pfin) == NULL)
- {
- return feof(Pfin) ? EOF : 1;
- }
- else
- {
- for( ; *s; s++)
- {
- if(*s == '\n')
- {
- *s = '\0';
- break;
- }
- }
- }
-
- return 0;
- }
+ return feof(Pfin) ? EOF : 1;
+ }
+ else
+ {
+ for (; *s; s++)
+ {
+ if (*s == '\n')
+ {
+ *s = '\0';
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
/*
* USER FUNCTION - sends a string to the backend.
- *
+ *
* Chiefly here so that applications can use "COPY <rel> from stdin".
*
* RETURNS:
- * 0 in all cases.
+ * 0 in all cases.
*/
int
PQputline(char *s)
{
- if (Pfout) {
- fputs(s, Pfout);
- fflush(Pfout);
- }
- return(0);
+ if (Pfout)
+ {
+ fputs(s, Pfout);
+ fflush(Pfout);
+ }
+ return (0);
}
/* --------------------------------
- * pq_getnchar - get n characters from connection
+ * pq_getnchar - get n characters from connection
* --------------------------------
*/
int
@@ -259,228 +268,239 @@ pq_getnchar(char *s, int off, int maxlen)
return pqGetNBytes(s + off, maxlen, Pfin);
#if 0
- int c = '\0';
-
- if (Pfin == (FILE *) NULL) {
-/* elog(DEBUG, "Input descriptor is null"); */
- return(EOF);
- }
-
- s += off;
- while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
- *s++ = c;
-
- /* -----------------
- * If EOF reached let caller know
- * -----------------
- */
- if (c == EOF)
- return(EOF);
- return(!EOF);
+ int c = '\0';
+
+ if (Pfin == (FILE *) NULL)
+ {
+/* elog(DEBUG, "Input descriptor is null"); */
+ return (EOF);
+ }
+
+ s += off;
+ while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
+ *s++ = c;
+
+ /* -----------------
+ * If EOF reached let caller know
+ * -----------------
+ */
+ if (c == EOF)
+ return (EOF);
+ return (!EOF);
#endif
}
/* --------------------------------
- * pq_getint - get an integer from connection
- * we receive an integer a byte at a type and reconstruct it so that
- * machines with different ENDIAN representations can talk to each
- * other
+ * pq_getint - get an integer from connection
+ * we receive an integer a byte at a type and reconstruct it so that
+ * machines with different ENDIAN representations can talk to each
+ * other
* --------------------------------
*/
int
pq_getint(int b)
{
- int n, status = 1;
-
- if(!Pfin)
- return EOF;
- /* mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
- EOF is a valid return value for an int! XXX */
-
- switch(b)
- {
- case 1:
- status = ((n = fgetc(Pfin)) == EOF);
- break;
- case 2:
- status = pqGetShort(&n, Pfin);
- break;
- case 4:
- status = pqGetLong(&n, Pfin);
- break;
- default:
- fprintf(stderr, "** Unsupported size %d\n", b);
- }
-
- if(status)
- {
- sprintf(PQerrormsg,
- "FATAL: pq_getint failed: errno=%d\n", errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- n = 0;
- }
-
- return n;
+ int n,
+ status = 1;
+
+ if (!Pfin)
+ return EOF;
+
+ /*
+ * mjl: Seems inconsisten w/ return value of pq_putint (void). Also,
+ * EOF is a valid return value for an int! XXX
+ */
+
+ switch (b)
+ {
+ case 1:
+ status = ((n = fgetc(Pfin)) == EOF);
+ break;
+ case 2:
+ status = pqGetShort(&n, Pfin);
+ break;
+ case 4:
+ status = pqGetLong(&n, Pfin);
+ break;
+ default:
+ fprintf(stderr, "** Unsupported size %d\n", b);
+ }
+
+ if (status)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: pq_getint failed: errno=%d\n", errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ n = 0;
+ }
+
+ return n;
}
/* --------------------------------
- * pq_putstr - send a null terminated string to connection
+ * pq_putstr - send a null terminated string to connection
* --------------------------------
*/
void
pq_putstr(char *s)
{
- if(pqPutString(s, Pfout))
- {
- sprintf(PQerrormsg,
- "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
+ if (pqPutString(s, Pfout))
+ {
+ sprintf(PQerrormsg,
+ "FATAL: pq_putstr: fputs() failed: errno=%d\n", errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
}
}
/* --------------------------------
- * pq_putnchar - send n characters to connection
+ * pq_putnchar - send n characters to connection
* --------------------------------
*/
void
pq_putnchar(char *s, int n)
+{
+ if (pqPutNBytes(s, n, Pfout))
{
- if(pqPutNBytes(s, n, Pfout))
- {
sprintf(PQerrormsg,
- "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
- errno);
+ "FATAL: pq_putnchar: fputc() failed: errno=%d\n",
+ errno);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
- }
}
+}
/* --------------------------------
- * pq_putint - send an integer to connection
- * we chop an integer into bytes and send individual bytes
- * machines with different ENDIAN representations can still talk to each
- * other
+ * pq_putint - send an integer to connection
+ * we chop an integer into bytes and send individual bytes
+ * machines with different ENDIAN representations can still talk to each
+ * other
* --------------------------------
*/
void
pq_putint(int i, int b)
{
- int status;
-
- if(!Pfout) return;
-
- status = 1;
- switch(b)
- {
- case 1:
- status = (fputc(i, Pfout) == EOF);
- break;
- case 2:
- status = pqPutShort(i, Pfout);
- break;
- case 4:
- status = pqPutLong(i, Pfout);
- break;
- default:
- fprintf(stderr, "** Unsupported size %d\n", b);
- }
-
- if(status)
- {
+ int status;
+
+ if (!Pfout)
+ return;
+
+ status = 1;
+ switch (b)
+ {
+ case 1:
+ status = (fputc(i, Pfout) == EOF);
+ break;
+ case 2:
+ status = pqPutShort(i, Pfout);
+ break;
+ case 4:
+ status = pqPutLong(i, Pfout);
+ break;
+ default:
+ fprintf(stderr, "** Unsupported size %d\n", b);
+ }
+
+ if (status)
+ {
sprintf(PQerrormsg,
- "FATAL: pq_putint failed: errno=%d\n", errno);
+ "FATAL: pq_putint failed: errno=%d\n", errno);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
- }
+ }
}
/* ---
- * pq_sendoob - send a string over the out-of-band channel
- * pq_recvoob - receive a string over the oob channel
- * NB: Fortunately, the out-of-band channel doesn't conflict with
- * buffered I/O because it is separate from regular com. channel.
+ * pq_sendoob - send a string over the out-of-band channel
+ * pq_recvoob - receive a string over the oob channel
+ * NB: Fortunately, the out-of-band channel doesn't conflict with
+ * buffered I/O because it is separate from regular com. channel.
* ---
*/
int
pq_sendoob(char *msg, int len)
{
- int fd = fileno(Pfout);
-
- return(send(fd,msg,len,MSG_OOB));
+ int fd = fileno(Pfout);
+
+ return (send(fd, msg, len, MSG_OOB));
}
int
pq_recvoob(char *msgPtr, int *lenPtr)
{
- int fd = fileno(Pfout);
- int len = 0;
-
- len = recv(fd,msgPtr+len,*lenPtr,MSG_OOB);
- *lenPtr = len;
- return(len);
+ int fd = fileno(Pfout);
+ int len = 0;
+
+ len = recv(fd, msgPtr + len, *lenPtr, MSG_OOB);
+ *lenPtr = len;
+ return (len);
}
/* --------------------------------
- * pq_getinaddr - initialize address from host and port number
+ * pq_getinaddr - initialize address from host and port number
* --------------------------------
*/
int
-pq_getinaddr(struct sockaddr_in *sin,
- char *host,
- int port)
+pq_getinaddr(struct sockaddr_in * sin,
+ char *host,
+ int port)
{
- struct hostent *hs;
-
- memset((char *) sin, 0, sizeof(*sin));
-
- if (host) {
- if (*host >= '0' && *host <= '9')
- sin->sin_addr.s_addr = inet_addr(host);
- else {
- if (!(hs = gethostbyname(host))) {
- perror(host);
- return(1);
- }
- if (hs->h_addrtype != AF_INET) {
- sprintf(PQerrormsg,
- "FATAL: pq_getinaddr: %s not on Internet\n",
- host);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(1);
- }
- memmove((char *) &sin->sin_addr,
- hs->h_addr,
- hs->h_length);
+ struct hostent *hs;
+
+ memset((char *) sin, 0, sizeof(*sin));
+
+ if (host)
+ {
+ if (*host >= '0' && *host <= '9')
+ sin->sin_addr.s_addr = inet_addr(host);
+ else
+ {
+ if (!(hs = gethostbyname(host)))
+ {
+ perror(host);
+ return (1);
+ }
+ if (hs->h_addrtype != AF_INET)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: pq_getinaddr: %s not on Internet\n",
+ host);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (1);
+ }
+ memmove((char *) &sin->sin_addr,
+ hs->h_addr,
+ hs->h_length);
+ }
}
- }
- sin->sin_family = AF_INET;
- sin->sin_port = htons(port);
- return(0);
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ return (0);
}
/* --------------------------------
- * pq_getinserv - initialize address from host and servive name
+ * pq_getinserv - initialize address from host and servive name
* --------------------------------
*/
int
-pq_getinserv(struct sockaddr_in *sin, char *host, char *serv)
+pq_getinserv(struct sockaddr_in * sin, char *host, char *serv)
{
- struct servent *ss;
-
- if (*serv >= '0' && *serv <= '9')
- return(pq_getinaddr(sin, host, atoi(serv)));
- if (!(ss = getservbyname(serv, NULL))) {
- sprintf(PQerrormsg,
- "FATAL: pq_getinserv: unknown service: %s\n",
- serv);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(1);
- }
- return(pq_getinaddr(sin, host, ntohs(ss->s_port)));
+ struct servent *ss;
+
+ if (*serv >= '0' && *serv <= '9')
+ return (pq_getinaddr(sin, host, atoi(serv)));
+ if (!(ss = getservbyname(serv, NULL)))
+ {
+ sprintf(PQerrormsg,
+ "FATAL: pq_getinserv: unknown service: %s\n",
+ serv);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (1);
+ }
+ return (pq_getinaddr(sin, host, ntohs(ss->s_port)));
}
/*
@@ -488,279 +508,297 @@ pq_getinserv(struct sockaddr_in *sin, char *host, char *serv)
* This is used for receiving async. notification from the backend.
*/
void
-pq_regoob(void (*fptr)())
+pq_regoob(void (*fptr) ())
{
- int fd = fileno(Pfout);
+ int fd = fileno(Pfout);
+
#if defined(hpux)
- ioctl(fd, FIOSSAIOOWN, getpid());
+ ioctl(fd, FIOSSAIOOWN, getpid());
#elif defined(sco)
- ioctl(fd, SIOCSPGRP, getpid());
+ ioctl(fd, SIOCSPGRP, getpid());
#else
- fcntl(fd, F_SETOWN, getpid());
-#endif /* hpux */
- pqsignal(SIGURG,fptr);
+ fcntl(fd, F_SETOWN, getpid());
+#endif /* hpux */
+ pqsignal(SIGURG, fptr);
}
void
pq_unregoob()
{
- pqsignal(SIGURG,SIG_DFL);
+ pqsignal(SIGURG, SIG_DFL);
}
void
pq_async_notify()
{
- char msg[20];
- /* int len = sizeof(msg);*/
- int len = 20;
-
- if (pq_recvoob(msg,&len) >= 0) {
- /* debugging */
- printf("received notification: %s\n",msg);
- PQAsyncNotifyWaiting = 1;
- /* PQappendNotify(msg+1);*/
- } else {
- extern int errno;
- printf("SIGURG but no data: len = %d, err=%d\n",len,errno);
- }
+ char msg[20];
+
+ /* int len = sizeof(msg); */
+ int len = 20;
+
+ if (pq_recvoob(msg, &len) >= 0)
+ {
+ /* debugging */
+ printf("received notification: %s\n", msg);
+ PQAsyncNotifyWaiting = 1;
+ /* PQappendNotify(msg+1); */
+ }
+ else
+ {
+ extern int errno;
+
+ printf("SIGURG but no data: len = %d, err=%d\n", len, errno);
+ }
}
/*
* Streams -- wrapper around Unix socket system calls
*
*
- * Stream functions are used for vanilla TCP connection protocol.
+ * Stream functions are used for vanilla TCP connection protocol.
*/
/*
* StreamServerPort -- open a sock stream "listening" port.
*
* This initializes the Postmaster's connection
- * accepting port.
+ * accepting port.
*
* ASSUME: that this doesn't need to be non-blocking because
- * the Postmaster uses select() to tell when the socket
- * is ready.
+ * the Postmaster uses select() to tell when the socket
+ * is ready.
*
* RETURNS: STATUS_OK or STATUS_ERROR
*/
int
StreamServerPort(char *hostName, short portName, int *fdP)
{
- struct sockaddr_in sin;
- int fd;
- int one = 1;
-
-
- if (! hostName)
- hostName = "localhost";
-
- memset((char *)&sin, 0, sizeof sin);
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- sprintf(PQerrormsg,
- "FATAL: StreamServerPort: socket() failed: errno=%d\n",
- errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
-
- if((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
- sizeof(one))) == -1) {
- sprintf(PQerrormsg,
- "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
- errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
-
- sin.sin_family = AF_INET;
- sin.sin_port = htons(portName);
-
- if (bind(fd, (struct sockaddr *)&sin, sizeof sin) < 0) {
- sprintf(PQerrormsg,
- "FATAL: StreamServerPort: bind() failed: errno=%d\n",
- errno);
- pqdebug("%s", PQerrormsg);
- strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
- strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
- fputs(PQerrormsg, stderr);
- return(STATUS_ERROR);
- }
-
- listen(fd, SOMAXCONN);
-
- /* MS: I took this code from Dillon's version. It makes the
- * listening port non-blocking. That is not necessary (and
- * may tickle kernel bugs).
-
- fcntl(fd, F_SETFD, 1);
- fcntl(fd, F_SETFL, FNDELAY);
- */
-
- *fdP = fd;
- return(STATUS_OK);
+ struct sockaddr_in sin;
+ int fd;
+ int one = 1;
+
+
+ if (!hostName)
+ hostName = "localhost";
+
+ memset((char *) &sin, 0, sizeof sin);
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: StreamServerPort: socket() failed: errno=%d\n",
+ errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+
+ if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
+ sizeof(one))) == -1)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: StreamServerPort: setsockopt (SO_REUSEADDR) failed: errno=%d\n",
+ errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(portName);
+
+ if (bind(fd, (struct sockaddr *) & sin, sizeof sin) < 0)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: StreamServerPort: bind() failed: errno=%d\n",
+ errno);
+ pqdebug("%s", PQerrormsg);
+ strcat(PQerrormsg, "\tIs another postmaster already running on that port?\n");
+ strcat(PQerrormsg, "\tIf not, wait a few seconds and retry.\n");
+ fputs(PQerrormsg, stderr);
+ return (STATUS_ERROR);
+ }
+
+ listen(fd, SOMAXCONN);
+
+ /*
+ * MS: I took this code from Dillon's version. It makes the listening
+ * port non-blocking. That is not necessary (and may tickle kernel
+ * bugs).
+ *
+ * fcntl(fd, F_SETFD, 1); fcntl(fd, F_SETFL, FNDELAY);
+ */
+
+ *fdP = fd;
+ return (STATUS_OK);
}
/*
* StreamConnection -- create a new connection with client using
- * server port.
+ * server port.
*
* This one should be non-blocking.
- *
+ *
* RETURNS: STATUS_OK or STATUS_ERROR
*/
int
-StreamConnection(int server_fd, Port *port)
+StreamConnection(int server_fd, Port * port)
{
- int addrlen;
-
- /* accept connection (and fill in the client (remote) address) */
- addrlen = sizeof(struct sockaddr_in);
- if ((port->sock = accept(server_fd,
- (struct sockaddr *) &port->raddr,
- &addrlen)) < 0) {
- elog(WARN, "postmaster: StreamConnection: accept: %m");
- return(STATUS_ERROR);
- }
-
- /* fill in the server (local) address */
- addrlen = sizeof(struct sockaddr_in);
- if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
- &addrlen) < 0) {
- elog(WARN, "postmaster: StreamConnection: getsockname: %m");
- return(STATUS_ERROR);
- }
- {
- struct protoent *pe;
- int on=1;
-
- pe = getprotobyname ("TCP");
- if ( pe == NULL )
- {
- elog(WARN, "postmaster: getprotobyname failed");
- return(STATUS_ERROR);
+ int addrlen;
+
+ /* accept connection (and fill in the client (remote) address) */
+ addrlen = sizeof(struct sockaddr_in);
+ if ((port->sock = accept(server_fd,
+ (struct sockaddr *) & port->raddr,
+ &addrlen)) < 0)
+ {
+ elog(WARN, "postmaster: StreamConnection: accept: %m");
+ return (STATUS_ERROR);
+ }
+
+ /* fill in the server (local) address */
+ addrlen = sizeof(struct sockaddr_in);
+ if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
+ &addrlen) < 0)
+ {
+ elog(WARN, "postmaster: StreamConnection: getsockname: %m");
+ return (STATUS_ERROR);
}
- if ( setsockopt (port->sock, pe->p_proto, TCP_NODELAY,
- &on, sizeof (on)) < 0 )
- {
- elog(WARN, "postmaster: setsockopt failed");
- return(STATUS_ERROR);
+ {
+ struct protoent *pe;
+ int on = 1;
+
+ pe = getprotobyname("TCP");
+ if (pe == NULL)
+ {
+ elog(WARN, "postmaster: getprotobyname failed");
+ return (STATUS_ERROR);
+ }
+ if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
+ &on, sizeof(on)) < 0)
+ {
+ elog(WARN, "postmaster: setsockopt failed");
+ return (STATUS_ERROR);
+ }
}
- }
-
- port->mask = 1 << port->sock;
-
- /* reset to non-blocking */
- fcntl(port->sock, F_SETFL, 1);
-
- return(STATUS_OK);
+
+ port->mask = 1 << port->sock;
+
+ /* reset to non-blocking */
+ fcntl(port->sock, F_SETFL, 1);
+
+ return (STATUS_OK);
}
-/*
+/*
* StreamClose -- close a client/backend connection
*/
void
StreamClose(int sock)
{
- close(sock);
+ close(sock);
}
/* ---------------------------
- * StreamOpen -- From client, initiate a connection with the
- * server (Postmaster).
+ * StreamOpen -- From client, initiate a connection with the
+ * server (Postmaster).
*
* RETURNS: STATUS_OK or STATUS_ERROR
*
* NOTE: connection is NOT established just because this
- * routine exits. Local state is ok, but we haven't
- * spoken to the postmaster yet.
+ * routine exits. Local state is ok, but we haven't
+ * spoken to the postmaster yet.
* ---------------------------
*/
int
-StreamOpen(char *hostName, short portName, Port *port)
+StreamOpen(char *hostName, short portName, Port * port)
{
- struct hostent *hp;
- int laddrlen = sizeof(struct sockaddr_in);
- extern int errno;
-
- if (!hostName)
- hostName = "localhost";
-
- /* set up the server (remote) address */
- if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET) {
- sprintf(PQerrormsg,
- "FATAL: StreamOpen: unknown hostname: %s\n",
- hostName);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- memset((char *) &port->raddr, 0, sizeof(port->raddr));
- memmove((char *) &(port->raddr.sin_addr),
- (char *) hp->h_addr,
- hp->h_length);
- port->raddr.sin_family = AF_INET;
- port->raddr.sin_port = htons(portName);
-
- /* connect to the server */
- if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- sprintf(PQerrormsg,
- "FATAL: StreamOpen: socket() failed: errno=%d\n",
- errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
- if (connect(port->sock, (struct sockaddr *)&port->raddr,
- sizeof(port->raddr)) < 0) {
- sprintf(PQerrormsg,
- "FATAL: StreamOpen: connect() failed: errno=%d\n",
- errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
-
- /* fill in the client address */
- if (getsockname(port->sock, (struct sockaddr *) &port->laddr,
- &laddrlen) < 0) {
- sprintf(PQerrormsg,
- "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
- errno);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return(STATUS_ERROR);
- }
-
- return(STATUS_OK);
+ struct hostent *hp;
+ int laddrlen = sizeof(struct sockaddr_in);
+ extern int errno;
+
+ if (!hostName)
+ hostName = "localhost";
+
+ /* set up the server (remote) address */
+ if (!(hp = gethostbyname(hostName)) || hp->h_addrtype != AF_INET)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: StreamOpen: unknown hostname: %s\n",
+ hostName);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ memset((char *) &port->raddr, 0, sizeof(port->raddr));
+ memmove((char *) &(port->raddr.sin_addr),
+ (char *) hp->h_addr,
+ hp->h_length);
+ port->raddr.sin_family = AF_INET;
+ port->raddr.sin_port = htons(portName);
+
+ /* connect to the server */
+ if ((port->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: StreamOpen: socket() failed: errno=%d\n",
+ errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+ if (connect(port->sock, (struct sockaddr *) & port->raddr,
+ sizeof(port->raddr)) < 0)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: StreamOpen: connect() failed: errno=%d\n",
+ errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+
+ /* fill in the client address */
+ if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
+ &laddrlen) < 0)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: StreamOpen: getsockname() failed: errno=%d\n",
+ errno);
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+ return (STATUS_ERROR);
+ }
+
+ return (STATUS_OK);
}
-static char *authentication_type_name[] = {
- 0, 0, 0, 0, 0, 0, 0,
- "the default authentication type",
- 0, 0,
- "Kerberos v4",
- "Kerberos v5",
- "host-based authentication",
- "unauthenication",
- "plaintext password authentication"
+static char *authentication_type_name[] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ "the default authentication type",
+ 0, 0,
+ "Kerberos v4",
+ "Kerberos v5",
+ "host-based authentication",
+ "unauthenication",
+ "plaintext password authentication"
};
-char *name_of_authentication_type(int type)
+char *
+name_of_authentication_type(int type)
{
- char *result = 0;
+ char *result = 0;
- if(type >= 1 && type <= LAST_AUTHENTICATION_TYPE) {
- result = authentication_type_name[type];
- }
+ if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
+ {
+ result = authentication_type_name[type];
+ }
- if(result == 0) {
- result = "<unknown authentication type>";
- }
+ if (result == 0)
+ {
+ result = "<unknown authentication type>";
+ }
- return result;
+ return result;
}
diff --git a/src/backend/libpq/pqcomprim.c b/src/backend/libpq/pqcomprim.c
index 3501b63c7b6..8675205d784 100644
--- a/src/backend/libpq/pqcomprim.c
+++ b/src/backend/libpq/pqcomprim.c
@@ -4,171 +4,185 @@
#include "postgres.h"
#include "libpq/pqcomm.h"
-#ifdef HAVE_ENDIAN_H
-# include <endian.h>
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
#endif
/* --------------------------------------------------------------------- */
/* These definitions for ntoh/hton are the other way around from the
- * default system definitions, so we roll our own here.
+ * default system definitions, so we roll our own here.
*/
-#ifndef BYTE_ORDER
+#ifndef BYTE_ORDER
#error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
-# define ntoh_s(n) n
-# define ntoh_l(n) n
-# define hton_s(n) n
-# define hton_l(n) n
-#else /* BYTE_ORDER != LITTLE_ENDIAN */
-# if BYTE_ORDER == BIG_ENDIAN
-# define ntoh_s(n) (u_short)(((u_char *)&n)[1] << 8 \
- | ((u_char *)&n)[0])
-# define ntoh_l(n) (u_long) (((u_char *)&n)[3] << 24 \
- | ((u_char *)&n)[2] << 16 \
- | ((u_char *)&n)[1] << 8 \
- | ((u_char *)&n)[0])
-# define hton_s(n) (ntoh_s(n))
-# define hton_l(n) (ntoh_l(n))
-# else /* BYTE_ORDER != BIG_ENDIAN */
-# if BYTE_ORDER == PDP_ENDIAN
-# error PDP_ENDIAN macros not written yet
-# else /* BYTE_ORDER != anything known */
-# error BYTE_ORDER not defined as anything understood
-# endif /* BYTE_ORDER == PDP_ENDIAN */
-# endif /* BYTE_ORDER == BIG_ENDIAN */
-#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+#define ntoh_s(n) n
+#define ntoh_l(n) n
+#define hton_s(n) n
+#define hton_l(n) n
+#else /* BYTE_ORDER != LITTLE_ENDIAN */
+#if BYTE_ORDER == BIG_ENDIAN
+#define ntoh_s(n) (u_short)(((u_char *)&n)[1] << 8 \
+ | ((u_char *)&n)[0])
+#define ntoh_l(n) (u_long) (((u_char *)&n)[3] << 24 \
+ | ((u_char *)&n)[2] << 16 \
+ | ((u_char *)&n)[1] << 8 \
+ | ((u_char *)&n)[0])
+#define hton_s(n) (ntoh_s(n))
+#define hton_l(n) (ntoh_l(n))
+#else
+/* BYTE_ORDER != BIG_ENDIAN */
+#if BYTE_ORDER == PDP_ENDIAN
+#error PDP_ENDIAN macros not written yet
+#else
+/* BYTE_ORDER != anything known */
+#error BYTE_ORDER not defined as anything understood
+#endif /* BYTE_ORDER == PDP_ENDIAN */
+#endif /* BYTE_ORDER == BIG_ENDIAN */
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */
/* --------------------------------------------------------------------- */
-int pqPutShort(int integer, FILE *f)
- {
- int retval = 0;
- u_short n,s;
-
- s = integer;
- n = hton_s(s);
- if(fwrite(&n, sizeof(u_short), 1, f) != 1)
- retval = EOF;
-
- return retval;
- }
+int
+pqPutShort(int integer, FILE * f)
+{
+ int retval = 0;
+ u_short n,
+ s;
+
+ s = integer;
+ n = hton_s(s);
+ if (fwrite(&n, sizeof(u_short), 1, f) != 1)
+ retval = EOF;
+
+ return retval;
+}
/* --------------------------------------------------------------------- */
-int pqPutLong(int integer, FILE *f)
- {
- int retval = 0;
- u_long n;
-
- n = hton_l(integer);
- if(fwrite(&n, sizeof(u_long), 1, f) != 1)
- retval = EOF;
-
- return retval;
- }
-
+int
+pqPutLong(int integer, FILE * f)
+{
+ int retval = 0;
+ u_long n;
+
+ n = hton_l(integer);
+ if (fwrite(&n, sizeof(u_long), 1, f) != 1)
+ retval = EOF;
+
+ return retval;
+}
+
/* --------------------------------------------------------------------- */
-int pqGetShort(int *result, FILE *f)
- {
- int retval = 0;
- u_short n;
-
- if(fread(&n, sizeof(u_short), 1, f) != 1)
- retval = EOF;
-
- *result = ntoh_s(n);
- return retval;
- }
+int
+pqGetShort(int *result, FILE * f)
+{
+ int retval = 0;
+ u_short n;
+
+ if (fread(&n, sizeof(u_short), 1, f) != 1)
+ retval = EOF;
+
+ *result = ntoh_s(n);
+ return retval;
+}
/* --------------------------------------------------------------------- */
-int pqGetLong(int *result, FILE *f)
- {
- int retval = 0;
- u_long n;
-
- if(fread(&n, sizeof(u_long), 1, f) != 1)
- retval = EOF;
-
- *result = ntoh_l(n);
- return retval;
- }
+int
+pqGetLong(int *result, FILE * f)
+{
+ int retval = 0;
+ u_long n;
+
+ if (fread(&n, sizeof(u_long), 1, f) != 1)
+ retval = EOF;
+
+ *result = ntoh_l(n);
+ return retval;
+}
/* --------------------------------------------------------------------- */
/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s.
- Return 0 if ok.
+ Return 0 if ok.
*/
-int pqGetNBytes(char *s, size_t len, FILE *f)
- {
- int cnt;
+int
+pqGetNBytes(char *s, size_t len, FILE * f)
+{
+ int cnt;
if (f == NULL)
return EOF;
-
+
cnt = fread(s, 1, len, f);
s[cnt] = '\0';
- /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
+ /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
return (cnt == len) ? 0 : EOF;
- }
+}
/* --------------------------------------------------------------------- */
-int pqPutNBytes(const char *s, size_t len, FILE *f)
- {
+int
+pqPutNBytes(const char *s, size_t len, FILE * f)
+{
if (f == NULL)
return 0;
- if(fwrite(s, 1, len, f) != len)
- return EOF;
+ if (fwrite(s, 1, len, f) != len)
+ return EOF;
return 0;
- }
-
+}
+
/* --------------------------------------------------------------------- */
-int pqGetString(char *s, size_t len, FILE *f)
- {
- int c;
+int
+pqGetString(char *s, size_t len, FILE * f)
+{
+ int c;
if (f == NULL)
- return EOF;
-
+ return EOF;
+
while (len-- && (c = getc(f)) != EOF && c)
*s++ = c;
*s = '\0';
- /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
+ /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
return 0;
- }
+}
/* --------------------------------------------------------------------- */
-int pqPutString(const char *s, FILE *f)
- {
+int
+pqPutString(const char *s, FILE * f)
+{
if (f == NULL)
return 0;
-
+
if (fputs(s, f) == EOF)
return EOF;
- fputc('\0', f); /* important to send an ending \0 since backend expects it */
+ fputc('\0', f); /* important to send an ending \0 since
+ * backend expects it */
fflush(f);
return 0;
- }
+}
/* --------------------------------------------------------------------- */
-int pqGetByte(FILE *f)
- {
+int
+pqGetByte(FILE * f)
+{
return getc(f);
- }
-
+}
+
/* --------------------------------------------------------------------- */
-int pqPutByte(int c, FILE *f)
- {
- if(!f) return 0;
-
+int
+pqPutByte(int c, FILE * f)
+{
+ if (!f)
+ return 0;
+
return (putc(c, f) == c) ? 0 : EOF;
- }
-
-/* --------------------------------------------------------------------- */
+}
+/* --------------------------------------------------------------------- */
diff --git a/src/backend/libpq/pqpacket.c b/src/backend/libpq/pqpacket.c
index 6f67ddc5f5b..9f56556537f 100644
--- a/src/backend/libpq/pqpacket.c
+++ b/src/backend/libpq/pqpacket.c
@@ -1,39 +1,39 @@
/*-------------------------------------------------------------------------
*
* pqpacket.c--
- * routines for reading and writing data packets sent/received by
- * POSTGRES clients and servers
+ * routines for reading and writing data packets sent/received by
+ * POSTGRES clients and servers
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.5 1997/08/12 22:53:00 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.6 1997/09/07 04:42:28 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* NOTES
- * This is the module that understands the lowest-level part
- * of the communication protocol. All of the trickiness in
- * this module is for making sure that non-blocking I/O in
- * the Postmaster works correctly. Check the notes in PacketRecv
- * on non-blocking I/O.
+ * This is the module that understands the lowest-level part
+ * of the communication protocol. All of the trickiness in
+ * this module is for making sure that non-blocking I/O in
+ * the Postmaster works correctly. Check the notes in PacketRecv
+ * on non-blocking I/O.
*
* Data Structures:
- * Port has two important functions. (1) It records the
- * sock/addr used in communication. (2) It holds partially
- * read in messages. This is especially important when
- * we haven't seen enough to construct a complete packet
- * header.
+ * Port has two important functions. (1) It records the
+ * sock/addr used in communication. (2) It holds partially
+ * read in messages. This is especially important when
+ * we haven't seen enough to construct a complete packet
+ * header.
*
* PacketBuf -- None of the clients of this module should know
- * what goes into a packet hdr (although they know how big
- * it is). This routine is in charge of host to net order
- * conversion for headers. Data conversion is someone elses
- * responsibility.
+ * what goes into a packet hdr (although they know how big
+ * it is). This routine is in charge of host to net order
+ * conversion for headers. Data conversion is someone elses
+ * responsibility.
*
* IMPORTANT: these routines are called by backends, clients, and
- * the Postmaster.
+ * the Postmaster.
*
*/
#include <stdio.h>
@@ -57,134 +57,156 @@
*
*/
int
-PacketReceive(Port *port, /* receive port */
- PacketBuf *buf, /* MAX_PACKET_SIZE-worth of buffer space */
- bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
+PacketReceive(Port * port, /* receive port */
+ PacketBuf * buf, /* MAX_PACKET_SIZE-worth of buffer space */
+ bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
{
- PacketLen max_size = sizeof(PacketBuf);
- PacketLen cc; /* character count -- bytes recvd */
- PacketLen packetLen; /* remaining packet chars to read */
- Addr tmp; /* curr recv buf pointer */
- int addrLen = sizeof(struct sockaddr_in);
- int hdrLen;
- int flag;
- int decr;
-
- hdrLen = sizeof(buf->len);
-
- if (nonBlocking == NON_BLOCKING) {
- flag = MSG_PEEK;
- decr = 0;
- } else {
- flag = 0;
- decr = hdrLen;
- }
- /*
- * Assume port->nBytes is zero unless we were interrupted during
- * non-blocking I/O. This first recvfrom() is to get the hdr
- * information so we know how many bytes to read. Life would
- * be very complicated if we read too much data (buffering).
- */
- tmp = ((Addr)buf) + port->nBytes;
-
- if (port->nBytes >= hdrLen) {
- packetLen = ntohl(buf->len) - port->nBytes;
- }
- else {
- /* peeking into the incoming message */
- cc = recvfrom(port->sock, (char *)&(buf->len), hdrLen, flag,
- (struct sockaddr*) &(port->raddr), &addrLen);
- if (cc < hdrLen) {
- /* if cc is negative, the system call failed */
- if (cc < 0) {
- return(STATUS_ERROR);
- }
- /*
- * cc == 0 means the connection was broken at the
- * other end.
- */
- else if (! cc) {
- return(STATUS_INVALID);
-
- } else {
- /*
- * Worst case. We didn't even read in enough data to
- * get the header length.
- * since we are using a data stream,
- * this happens only if the client is mallicious.
- *
- * Don't save the number of bytes we've read so far.
- * Since we only peeked at the incoming message, the
- * kernel is going to keep it for us.
- */
- return(STATUS_NOT_DONE);
- }
- } else {
- /*
- * This is an attempt to shield the Postmaster
- * from mallicious attacks by placing tighter
- * restrictions on the reported packet length.
- *
- * Check for negative packet length
- */
- if ((buf->len) <= 0) {
- return(STATUS_INVALID);
- }
- /*
- * Check for oversize packet
- */
- if ((ntohl(buf->len)) > max_size) {
- return(STATUS_INVALID);
- }
- /*
- * great. got the header. now get the true length (including
- * header size).
- */
- packetLen = ntohl(buf->len);
- /*
- * if someone is sending us junk, close the connection
- */
- if (packetLen > max_size) {
- port->nBytes = packetLen;
- return(STATUS_BAD_PACKET);
- }
- packetLen -= decr;
- tmp += decr - port->nBytes;
+ PacketLen max_size = sizeof(PacketBuf);
+ PacketLen cc; /* character count -- bytes recvd */
+ PacketLen packetLen; /* remaining packet chars to read */
+ Addr tmp; /* curr recv buf pointer */
+ int addrLen = sizeof(struct sockaddr_in);
+ int hdrLen;
+ int flag;
+ int decr;
+
+ hdrLen = sizeof(buf->len);
+
+ if (nonBlocking == NON_BLOCKING)
+ {
+ flag = MSG_PEEK;
+ decr = 0;
+ }
+ else
+ {
+ flag = 0;
+ decr = hdrLen;
+ }
+
+ /*
+ * Assume port->nBytes is zero unless we were interrupted during
+ * non-blocking I/O. This first recvfrom() is to get the hdr
+ * information so we know how many bytes to read. Life would be very
+ * complicated if we read too much data (buffering).
+ */
+ tmp = ((Addr) buf) + port->nBytes;
+
+ if (port->nBytes >= hdrLen)
+ {
+ packetLen = ntohl(buf->len) - port->nBytes;
+ }
+ else
+ {
+ /* peeking into the incoming message */
+ cc = recvfrom(port->sock, (char *) &(buf->len), hdrLen, flag,
+ (struct sockaddr *) & (port->raddr), &addrLen);
+ if (cc < hdrLen)
+ {
+ /* if cc is negative, the system call failed */
+ if (cc < 0)
+ {
+ return (STATUS_ERROR);
+ }
+
+ /*
+ * cc == 0 means the connection was broken at the other end.
+ */
+ else if (!cc)
+ {
+ return (STATUS_INVALID);
+
+ }
+ else
+ {
+
+ /*
+ * Worst case. We didn't even read in enough data to get
+ * the header length. since we are using a data stream,
+ * this happens only if the client is mallicious.
+ *
+ * Don't save the number of bytes we've read so far. Since we
+ * only peeked at the incoming message, the kernel is
+ * going to keep it for us.
+ */
+ return (STATUS_NOT_DONE);
+ }
+ }
+ else
+ {
+
+ /*
+ * This is an attempt to shield the Postmaster from mallicious
+ * attacks by placing tighter restrictions on the reported
+ * packet length.
+ *
+ * Check for negative packet length
+ */
+ if ((buf->len) <= 0)
+ {
+ return (STATUS_INVALID);
+ }
+
+ /*
+ * Check for oversize packet
+ */
+ if ((ntohl(buf->len)) > max_size)
+ {
+ return (STATUS_INVALID);
+ }
+
+ /*
+ * great. got the header. now get the true length (including
+ * header size).
+ */
+ packetLen = ntohl(buf->len);
+
+ /*
+ * if someone is sending us junk, close the connection
+ */
+ if (packetLen > max_size)
+ {
+ port->nBytes = packetLen;
+ return (STATUS_BAD_PACKET);
+ }
+ packetLen -= decr;
+ tmp += decr - port->nBytes;
+ }
}
- }
-
- /*
- * Now that we know how big it is, read the packet. We read
- * the entire packet, since the last call was just a peek.
- */
- while (packetLen) {
- cc = recvfrom(port->sock, tmp, packetLen, 0,
- (struct sockaddr*) &(port->raddr), &addrLen);
- if (cc < 0)
- return(STATUS_ERROR);
- /*
- * cc == 0 means the connection was broken at the
- * other end.
+
+ /*
+ * Now that we know how big it is, read the packet. We read the
+ * entire packet, since the last call was just a peek.
*/
- else if (! cc)
- return(STATUS_INVALID);
-
+ while (packetLen)
+ {
+ cc = recvfrom(port->sock, tmp, packetLen, 0,
+ (struct sockaddr *) & (port->raddr), &addrLen);
+ if (cc < 0)
+ return (STATUS_ERROR);
+
+ /*
+ * cc == 0 means the connection was broken at the other end.
+ */
+ else if (!cc)
+ return (STATUS_INVALID);
+
/*
fprintf(stderr,"expected packet of %d bytes, got %d bytes\n",
- packetLen, cc);
+ packetLen, cc);
*/
- tmp += cc;
- packetLen -= cc;
-
- /* if non-blocking, we're done. */
- if (nonBlocking && packetLen) {
- port->nBytes += cc;
- return(STATUS_NOT_DONE);
+ tmp += cc;
+ packetLen -= cc;
+
+ /* if non-blocking, we're done. */
+ if (nonBlocking && packetLen)
+ {
+ port->nBytes += cc;
+ return (STATUS_NOT_DONE);
+ }
}
- }
-
- port->nBytes = 0;
- return(STATUS_OK);
+
+ port->nBytes = 0;
+ return (STATUS_OK);
}
/*
@@ -192,46 +214,47 @@ PacketReceive(Port *port, /* receive port */
*
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
* SIDE_EFFECTS: may block.
- * NOTES: Non-blocking writes would significantly complicate
- * buffer management. For now, we're not going to do it.
+ * NOTES: Non-blocking writes would significantly complicate
+ * buffer management. For now, we're not going to do it.
*
*/
int
-PacketSend(Port *port,
- PacketBuf *buf,
- PacketLen len,
- bool nonBlocking)
+PacketSend(Port * port,
+ PacketBuf * buf,
+ PacketLen len,
+ bool nonBlocking)
{
- PacketLen totalLen;
- int addrLen = sizeof(struct sockaddr_in);
-
- Assert(!nonBlocking);
- Assert(buf);
-
- totalLen = len;
-
- len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
- (struct sockaddr *)&(port->raddr), addrLen);
-
- if (len < totalLen) {
- sprintf(PQerrormsg,
- "FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
- errno);
- fputs(PQerrormsg, stderr);
- return(STATUS_ERROR);
- }
-
- return(STATUS_OK);
+ PacketLen totalLen;
+ int addrLen = sizeof(struct sockaddr_in);
+
+ Assert(!nonBlocking);
+ Assert(buf);
+
+ totalLen = len;
+
+ len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
+ (struct sockaddr *) & (port->raddr), addrLen);
+
+ if (len < totalLen)
+ {
+ sprintf(PQerrormsg,
+ "FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
+ errno);
+ fputs(PQerrormsg, stderr);
+ return (STATUS_ERROR);
+ }
+
+ return (STATUS_OK);
}
/*
* StartupInfo2PacketBuf -
- * convert the fields of the StartupInfo to a PacketBuf
+ * convert the fields of the StartupInfo to a PacketBuf
*
*/
/* moved to src/libpq/fe-connect.c */
/*
-PacketBuf*
+PacketBuf*
StartupInfo2PacketBuf(StartupInfo* s)
{
PacketBuf* res;
@@ -259,10 +282,10 @@ StartupInfo2PacketBuf(StartupInfo* s)
/*
* PacketBuf2StartupInfo -
- * convert the fields of the StartupInfo to a PacketBuf
+ * convert the fields of the StartupInfo to a PacketBuf
*
*/
-/* moved to postmaster.c
+/* moved to postmaster.c
StartupInfo*
PacketBuf2StartupInfo(PacketBuf* p)
{
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c
index 0c91f50df03..727a2a7207d 100644
--- a/src/backend/libpq/pqsignal.c
+++ b/src/backend/libpq/pqsignal.c
@@ -1,41 +1,41 @@
/*-------------------------------------------------------------------------
*
* pqsignal.c--
- * reliable BSD-style signal(2) routine stolen from RWW who stole it
- * from Stevens...
+ * reliable BSD-style signal(2) routine stolen from RWW who stole it
+ * from Stevens...
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.5 1996/12/26 22:07:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.6 1997/09/07 04:42:29 momjian Exp $
*
* NOTES
- * This shouldn't be in libpq, but the monitor and some other
- * things need it...
+ * This shouldn't be in libpq, but the monitor and some other
+ * things need it...
*
- * A NOTE ABOUT SIGNAL HANDLING ACROSS THE VARIOUS PLATFORMS.
+ * A NOTE ABOUT SIGNAL HANDLING ACROSS THE VARIOUS PLATFORMS.
*
- * config.h defines the macro USE_POSIX_SIGNALS for some platforms and
- * not for others. This file and pqsignal.h use that macro to decide
- * how to handle signalling.
+ * config.h defines the macro USE_POSIX_SIGNALS for some platforms and
+ * not for others. This file and pqsignal.h use that macro to decide
+ * how to handle signalling.
*
- * signal(2) handling - this is here because it affects some of
- * the frontend commands as well as the backend server.
- *
- * Ultrix and SunOS provide BSD signal(2) semantics by default.
- *
- * SVID2 and POSIX signal(2) semantics differ from BSD signal(2)
- * semantics. We can use the POSIX sigaction(2) on systems that
- * allow us to request restartable signals (SA_RESTART).
- *
- * Some systems don't allow restartable signals at all unless we
- * link to a special BSD library.
- *
- * We devoutly hope that there aren't any systems that provide
- * neither POSIX signals nor BSD signals. The alternative
- * is to do signal-handler reinstallation, which doesn't work well
- * at all.
+ * signal(2) handling - this is here because it affects some of
+ * the frontend commands as well as the backend server.
+ *
+ * Ultrix and SunOS provide BSD signal(2) semantics by default.
+ *
+ * SVID2 and POSIX signal(2) semantics differ from BSD signal(2)
+ * semantics. We can use the POSIX sigaction(2) on systems that
+ * allow us to request restartable signals (SA_RESTART).
+ *
+ * Some systems don't allow restartable signals at all unless we
+ * link to a special BSD library.
+ *
+ * We devoutly hope that there aren't any systems that provide
+ * neither POSIX signals nor BSD signals. The alternative
+ * is to do signal-handler reinstallation, which doesn't work well
+ * at all.
* ------------------------------------------------------------------------*/
#include <postgres.h>
@@ -47,18 +47,20 @@ pqsigfunc
pqsignal(int signo, pqsigfunc func)
{
#if !defined(USE_POSIX_SIGNALS)
- return signal(signo, func);
+ return signal(signo, func);
#else
- struct sigaction act, oact;
-
- act.sa_handler = func;
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- if (signo != SIGALRM) {
- act.sa_flags |= SA_RESTART;
- }
- if (sigaction(signo, &act, &oact) < 0)
- return(SIG_ERR);
- return(oact.sa_handler);
-#endif /* !USE_POSIX_SIGNALS */
+ struct sigaction act,
+ oact;
+
+ act.sa_handler = func;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+ if (signo != SIGALRM)
+ {
+ act.sa_flags |= SA_RESTART;
+ }
+ if (sigaction(signo, &act, &oact) < 0)
+ return (SIG_ERR);
+ return (oact.sa_handler);
+#endif /* !USE_POSIX_SIGNALS */
}
diff --git a/src/backend/libpq/util.c b/src/backend/libpq/util.c
index e8ca2e4ccc5..f4efec13f3a 100644
--- a/src/backend/libpq/util.c
+++ b/src/backend/libpq/util.c
@@ -1,100 +1,100 @@
/*-------------------------------------------------------------------------
*
* util.c--
- * general routines for libpq backend
+ * general routines for libpq backend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/util.c,v 1.3 1996/11/06 08:48:33 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/util.c,v 1.4 1997/09/07 04:42:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * UTILITY ROUTINES
- * pqdebug - send a string to the debugging output port
- * pqdebug2 - send two strings to stdout
- * PQtrace - turn on pqdebug() tracing
- * PQuntrace - turn off pqdebug() tracing
+ * UTILITY ROUTINES
+ * pqdebug - send a string to the debugging output port
+ * pqdebug2 - send two strings to stdout
+ * PQtrace - turn on pqdebug() tracing
+ * PQuntrace - turn off pqdebug() tracing
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <postgres.h>
#include <lib/dllist.h>
-#include <libpq/libpq.h> /* where the declarations go */
+#include <libpq/libpq.h> /* where the declarations go */
#include <utils/exc.h>
/* ----------------
- * exceptions
+ * exceptions
* ----------------
*/
-Exception MemoryError = {"Memory Allocation Error"};
-Exception PortalError = {"Invalid arguments to portal functions"};
-Exception PostquelError = {"Sql Error"};
-Exception ProtocolError = {"Protocol Error"};
-char PQerrormsg[ERROR_MSG_LENGTH];
+Exception MemoryError = {"Memory Allocation Error"};
+Exception PortalError = {"Invalid arguments to portal functions"};
+Exception PostquelError = {"Sql Error"};
+Exception ProtocolError = {"Protocol Error"};
+char PQerrormsg[ERROR_MSG_LENGTH];
-int PQtracep = 0; /* 1 to print out debugging messages */
-FILE *debug_port = (FILE *) NULL;
+int PQtracep = 0; /* 1 to print out debugging messages */
+FILE *debug_port = (FILE *) NULL;
/* ----------------------------------------------------------------
- * PQ utility routines
+ * PQ utility routines
* ----------------------------------------------------------------
*/
void
pqdebug(char *target, char *msg)
{
- if (!target)
- return;
-
- if (PQtracep) {
- /*
- * if nothing else was suggested default to stdout
- */
- if (!debug_port)
- debug_port = stdout;
- fprintf(debug_port, target, msg);
- fprintf(debug_port, "\n");
- }
+ if (!target)
+ return;
+
+ if (PQtracep)
+ {
+
+ /*
+ * if nothing else was suggested default to stdout
+ */
+ if (!debug_port)
+ debug_port = stdout;
+ fprintf(debug_port, target, msg);
+ fprintf(debug_port, "\n");
+ }
}
void
pqdebug2(char *target, char *msg1, char *msg2)
{
- if (!target)
- return;
-
- if (PQtracep) {
- /*
- * if nothing else was suggested default to stdout
- */
- if (!debug_port)
- debug_port = stdout;
- fprintf(debug_port, target, msg1, msg2);
- fprintf(debug_port, "\n");
- }
+ if (!target)
+ return;
+
+ if (PQtracep)
+ {
+
+ /*
+ * if nothing else was suggested default to stdout
+ */
+ if (!debug_port)
+ debug_port = stdout;
+ fprintf(debug_port, target, msg1, msg2);
+ fprintf(debug_port, "\n");
+ }
}
/* --------------------------------
- * PQtrace() / PQuntrace()
+ * PQtrace() / PQuntrace()
* --------------------------------
*/
void
PQtrace()
{
- PQtracep = 1;
+ PQtracep = 1;
}
void
PQuntrace()
{
- PQtracep = 0;
+ PQtracep = 0;
}
-
-
-
-
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index c3bb0793394..b70be2a08c4 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* main.c--
- * Stub main() routine for the postgres backend.
+ * Stub main() routine for the postgres backend.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.7 1997/04/24 20:30:09 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.8 1997/09/07 04:42:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,11 +16,11 @@
#include <unistd.h>
#include "postgres.h"
-#ifdef USE_LOCALE
-# include <locale.h>
+#ifdef USE_LOCALE
+#include <locale.h>
#endif
#include "miscadmin.h"
-#include "bootstrap/bootstrap.h" /* for BootstrapMain() */
+#include "bootstrap/bootstrap.h"/* for BootstrapMain() */
#include "tcop/tcopprot.h" /* for PostgresMain() */
#include "port-protos.h" /* for init_address_fixup() */
@@ -34,36 +34,45 @@ echo \"postmaster -B 256 >/var/log/pglog 2>&1 &\" | su - postgres\n\n"
int
main(int argc, char *argv[])
{
- int len;
+ int len;
+
#ifdef USE_LOCALE
- setlocale(LC_CTYPE,""); /* take locale information from an environment */
- setlocale(LC_COLLATE,"");
- setlocale(LC_MONETARY,"");
+ setlocale(LC_CTYPE, ""); /* take locale information from an
+ * environment */
+ setlocale(LC_COLLATE, "");
+ setlocale(LC_MONETARY, "");
#endif
#if defined(NOFIXADE) || defined(NOPRINTADE)
- /*
- * Must be first so that the bootstrap code calls it, too.
- * (Only needed on some RISC architectures.)
- */
- init_address_fixup();
-#endif /* NOFIXADE || NOPRINTADE */
-
- /* use one executable for both postgres and postmaster,
- invoke one or the other depending on the name of the executable */
- len = strlen(argv[0]);
- if (!geteuid()) {
- fprintf(stderr, "%s", NOROOTEXEC);
- exit(1);
- }
+ /*
+ * Must be first so that the bootstrap code calls it, too. (Only
+ * needed on some RISC architectures.)
+ */
+ init_address_fixup();
+#endif /* NOFIXADE || NOPRINTADE */
+
+ /*
+ * use one executable for both postgres and postmaster, invoke one or
+ * the other depending on the name of the executable
+ */
+ len = strlen(argv[0]);
+
+ if (!geteuid())
+ {
+ fprintf(stderr, "%s", NOROOTEXEC);
+ exit(1);
+ }
- if(len >= 10 && ! strcmp(argv[0] + len - 10, "postmaster"))
- exit(PostmasterMain(argc, argv));
+ if (len >= 10 && !strcmp(argv[0] + len - 10, "postmaster"))
+ exit(PostmasterMain(argc, argv));
- /* if the first argument is "-boot", then invoke the backend in
- bootstrap mode */
- if (argc > 1 && strcmp(argv[1], "-boot") == 0)
- exit(BootstrapMain(argc-1, argv+1)); /* remove the -boot arg from the command line */
- else
- exit(PostgresMain(argc, argv));
+ /*
+ * if the first argument is "-boot", then invoke the backend in
+ * bootstrap mode
+ */
+ if (argc > 1 && strcmp(argv[1], "-boot") == 0)
+ exit(BootstrapMain(argc - 1, argv + 1)); /* remove the -boot arg
+ * from the command line */
+ else
+ exit(PostgresMain(argc, argv));
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e763b9cd7ce..caf9e176ef3 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* copyfuncs.c--
- * Copy functions for Postgres tree nodes.
+ * Copy functions for Postgres tree nodes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.6 1997/09/04 13:24:01 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.7 1997/09/07 04:42:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,7 +25,7 @@
#include "parser/parse_query.h"
#include "utils/syscache.h"
-#include "utils/builtins.h" /* for namecpy */
+#include "utils/builtins.h" /* for namecpy */
#include "utils/elog.h"
#include "utils/palloc.h"
#include "catalog/pg_type.h"
@@ -33,1716 +33,1774 @@
/*
* listCopy--
- * this copy function only copies the "lcons-cells" of the list but not
- * its contents. (good for list of pointers as well as list of integers).
+ * this copy function only copies the "lcons-cells" of the list but not
+ * its contents. (good for list of pointers as well as list of integers).
*/
-List *
-listCopy(List *list)
+List *
+listCopy(List * list)
{
- List *newlist=NIL;
- List *l, *nl=NIL;
-
- foreach(l, list) {
- if (newlist==NIL) {
- newlist = nl = lcons(lfirst(l),NIL);
- }else {
- lnext(nl) = lcons(lfirst(l),NIL);
- nl = lnext(nl);
+ List *newlist = NIL;
+ List *l,
+ *nl = NIL;
+
+ foreach(l, list)
+ {
+ if (newlist == NIL)
+ {
+ newlist = nl = lcons(lfirst(l), NIL);
+ }
+ else
+ {
+ lnext(nl) = lcons(lfirst(l), NIL);
+ nl = lnext(nl);
+ }
}
- }
- return newlist;
+ return newlist;
}
-
+
/*
* Node_Copy--
- * a macro to simplify calling of copyObject on the specified field
+ * a macro to simplify calling of copyObject on the specified field
*/
#define Node_Copy(from, newnode, field) \
- newnode->field = copyObject(from->field)
+ newnode->field = copyObject(from->field)
/* ****************************************************************
- * plannodes.h copy functions
+ * plannodes.h copy functions
* ****************************************************************
*/
/* ----------------
- * CopyPlanFields
+ * CopyPlanFields
*
- * This function copies the fields of the Plan node. It is used by
- * all the copy functions for classes which inherit from Plan.
+ * This function copies the fields of the Plan node. It is used by
+ * all the copy functions for classes which inherit from Plan.
* ----------------
*/
static void
-CopyPlanFields(Plan *from, Plan *newnode)
+CopyPlanFields(Plan * from, Plan * newnode)
{
- newnode->cost = from->cost;
- newnode->plan_size = from->plan_size;
- newnode->plan_width = from->plan_width;
- newnode->state = from->state;
- newnode->targetlist = copyObject(from->targetlist);
- newnode->qual = copyObject(from->qual);
- newnode->lefttree = copyObject(from->lefttree);
- newnode->righttree = copyObject(from->righttree);
+ newnode->cost = from->cost;
+ newnode->plan_size = from->plan_size;
+ newnode->plan_width = from->plan_width;
+ newnode->state = from->state;
+ newnode->targetlist = copyObject(from->targetlist);
+ newnode->qual = copyObject(from->qual);
+ newnode->lefttree = copyObject(from->lefttree);
+ newnode->righttree = copyObject(from->righttree);
}
/* ----------------
- * _copyPlan
+ * _copyPlan
* ----------------
*/
-static Plan *
-_copyPlan(Plan *from)
+static Plan *
+_copyPlan(Plan * from)
{
- Plan *newnode = makeNode(Plan);
-
- /* ----------------
- * copy the node superclass fields
- * ----------------
- */
- CopyPlanFields(from, newnode);
-
- return newnode;
+ Plan *newnode = makeNode(Plan);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPlanFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copyExistential
+ * _copyExistential
* ----------------
*/
static Existential *
-_copyExistential(Existential *from)
+_copyExistential(Existential * from)
{
- Existential *newnode = makeNode(Existential);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields(from, newnode);
-
- return newnode;
+ Existential *newnode = makeNode(Existential);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copyResult
+ * _copyResult
* ----------------
*/
-static Result *
-_copyResult(Result *from)
+static Result *
+_copyResult(Result * from)
{
- Result *newnode = makeNode(Result);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, resconstantqual);
- Node_Copy(from, newnode, resstate);
-
- return newnode;
+ Result *newnode = makeNode(Result);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, resconstantqual);
+ Node_Copy(from, newnode, resstate);
+
+ return newnode;
}
/* ----------------
- * _copyAppend
+ * _copyAppend
* ----------------
*/
-static Append *
-_copyAppend(Append *from)
+static Append *
+_copyAppend(Append * from)
{
- Append *newnode = makeNode(Append);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, unionplans);
- newnode->unionrelid = from->unionrelid;
- Node_Copy(from, newnode, unionrtentries);
- Node_Copy(from, newnode, unionstate);
-
- return newnode;
+ Append *newnode = makeNode(Append);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, unionplans);
+ newnode->unionrelid = from->unionrelid;
+ Node_Copy(from, newnode, unionrtentries);
+ Node_Copy(from, newnode, unionstate);
+
+ return newnode;
}
/* ----------------
- * CopyScanFields
+ * CopyScanFields
*
- * This function copies the fields of the Scan node. It is used by
- * all the copy functions for classes which inherit from Scan.
+ * This function copies the fields of the Scan node. It is used by
+ * all the copy functions for classes which inherit from Scan.
* ----------------
*/
static void
-CopyScanFields(Scan *from, Scan *newnode)
+CopyScanFields(Scan * from, Scan * newnode)
{
- newnode->scanrelid = from->scanrelid;
- Node_Copy(from, newnode, scanstate);
- return;
+ newnode->scanrelid = from->scanrelid;
+ Node_Copy(from, newnode, scanstate);
+ return;
}
/* ----------------
- * _copyScan
+ * _copyScan
* ----------------
*/
-static Scan *
-_copyScan(Scan *from)
+static Scan *
+_copyScan(Scan * from)
{
- Scan *newnode = makeNode(Scan);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyScanFields(from, newnode);
-
- return newnode;
+ Scan *newnode = makeNode(Scan);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyScanFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copySeqScan
+ * _copySeqScan
* ----------------
*/
static SeqScan *
-_copySeqScan(SeqScan *from)
+_copySeqScan(SeqScan * from)
{
- SeqScan *newnode = makeNode(SeqScan);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyScanFields((Scan*)from, (Scan*)newnode);
-
- return newnode;
+ SeqScan *newnode = makeNode(SeqScan);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyScanFields((Scan *) from, (Scan *) newnode);
+
+ return newnode;
}
/* ----------------
- * _copyIndexScan
+ * _copyIndexScan
* ----------------
*/
static IndexScan *
-_copyIndexScan(IndexScan *from)
+_copyIndexScan(IndexScan * from)
{
- IndexScan *newnode = makeNode(IndexScan);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyScanFields((Scan*)from, (Scan*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->indxid = listCopy(from->indxid);
- Node_Copy(from, newnode, indxqual);
- Node_Copy(from, newnode, indxstate);
-
- return newnode;
+ IndexScan *newnode = makeNode(IndexScan);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyScanFields((Scan *) from, (Scan *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->indxid = listCopy(from->indxid);
+ Node_Copy(from, newnode, indxqual);
+ Node_Copy(from, newnode, indxstate);
+
+ return newnode;
}
/* ----------------
- * CopyJoinFields
+ * CopyJoinFields
*
- * This function copies the fields of the Join node. It is used by
- * all the copy functions for classes which inherit from Join.
+ * This function copies the fields of the Join node. It is used by
+ * all the copy functions for classes which inherit from Join.
* ----------------
*/
static void
-CopyJoinFields(Join *from, Join *newnode)
+CopyJoinFields(Join * from, Join * newnode)
{
- /* nothing extra */
- return;
+ /* nothing extra */
+ return;
}
/* ----------------
- * _copyJoin
+ * _copyJoin
* ----------------
*/
-static Join *
-_copyJoin(Join *from)
+static Join *
+_copyJoin(Join * from)
{
- Join *newnode = makeNode(Join);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyJoinFields(from, newnode);
-
- return newnode;
+ Join *newnode = makeNode(Join);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyJoinFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copyNestLoop
+ * _copyNestLoop
* ----------------
*/
static NestLoop *
-_copyNestLoop(NestLoop *from)
+_copyNestLoop(NestLoop * from)
{
- NestLoop *newnode = makeNode(NestLoop);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyJoinFields((Join*)from, (Join*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, nlstate);
-
- return newnode;
+ NestLoop *newnode = makeNode(NestLoop);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyJoinFields((Join *) from, (Join *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, nlstate);
+
+ return newnode;
}
/* ----------------
- * _copyMergeJoin
+ * _copyMergeJoin
* ----------------
*/
static MergeJoin *
-_copyMergeJoin(MergeJoin *from)
+_copyMergeJoin(MergeJoin * from)
{
- MergeJoin *newnode = makeNode(MergeJoin);
- List *newlist;
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyJoinFields((Join*)from, (Join*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, mergeclauses);
-
- newnode->mergesortop = from->mergesortop;
- newlist = NIL;
-
- newnode->mergerightorder = (Oid *)palloc(sizeof(Oid)*2);
- newnode->mergerightorder[0] = from->mergerightorder[0];
- newnode->mergerightorder[1] = 0;
-
- newnode->mergeleftorder = (Oid *)palloc(sizeof(Oid)*2);
- newnode->mergeleftorder[0] = from->mergeleftorder[0];
- newnode->mergeleftorder[1] = 0;
-
- Node_Copy(from, newnode, mergestate);
-
- return newnode;
+ MergeJoin *newnode = makeNode(MergeJoin);
+ List *newlist;
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyJoinFields((Join *) from, (Join *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, mergeclauses);
+
+ newnode->mergesortop = from->mergesortop;
+ newlist = NIL;
+
+ newnode->mergerightorder = (Oid *) palloc(sizeof(Oid) * 2);
+ newnode->mergerightorder[0] = from->mergerightorder[0];
+ newnode->mergerightorder[1] = 0;
+
+ newnode->mergeleftorder = (Oid *) palloc(sizeof(Oid) * 2);
+ newnode->mergeleftorder[0] = from->mergeleftorder[0];
+ newnode->mergeleftorder[1] = 0;
+
+ Node_Copy(from, newnode, mergestate);
+
+ return newnode;
}
/* ----------------
- * _copyHashJoin
+ * _copyHashJoin
* ----------------
*/
static HashJoin *
-_copyHashJoin(HashJoin *from)
+_copyHashJoin(HashJoin * from)
{
- HashJoin *newnode = makeNode(HashJoin);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyJoinFields((Join*)from, (Join*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, hashclauses);
-
- newnode->hashjoinop = from->hashjoinop;
-
- Node_Copy(from, newnode, hashjoinstate);
-
- newnode->hashjointable = from->hashjointable;
- newnode->hashjointablekey = from->hashjointablekey;
- newnode->hashjointablesize = from->hashjointablesize;
- newnode->hashdone = from->hashdone;
-
- return newnode;
+ HashJoin *newnode = makeNode(HashJoin);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyJoinFields((Join *) from, (Join *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, hashclauses);
+
+ newnode->hashjoinop = from->hashjoinop;
+
+ Node_Copy(from, newnode, hashjoinstate);
+
+ newnode->hashjointable = from->hashjointable;
+ newnode->hashjointablekey = from->hashjointablekey;
+ newnode->hashjointablesize = from->hashjointablesize;
+ newnode->hashdone = from->hashdone;
+
+ return newnode;
}
/* ----------------
- * CopyTempFields
+ * CopyTempFields
*
- * This function copies the fields of the Temp node. It is used by
- * all the copy functions for classes which inherit from Temp.
+ * This function copies the fields of the Temp node. It is used by
+ * all the copy functions for classes which inherit from Temp.
* ----------------
*/
static void
-CopyTempFields(Temp *from, Temp *newnode)
+CopyTempFields(Temp * from, Temp * newnode)
{
- newnode->tempid = from->tempid;
- newnode->keycount = from->keycount;
- return;
+ newnode->tempid = from->tempid;
+ newnode->keycount = from->keycount;
+ return;
}
/* ----------------
- * _copyTemp
+ * _copyTemp
* ----------------
*/
-static Temp *
-_copyTemp(Temp *from)
+static Temp *
+_copyTemp(Temp * from)
{
- Temp *newnode = makeNode(Temp);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyTempFields(from, newnode);
-
- return newnode;
+ Temp *newnode = makeNode(Temp);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyTempFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copyMaterial
+ * _copyMaterial
* ----------------
*/
static Material *
-_copyMaterial(Material *from)
+_copyMaterial(Material * from)
{
- Material *newnode = makeNode(Material);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyTempFields((Temp*)from, (Temp*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, matstate);
-
- return newnode;
+ Material *newnode = makeNode(Material);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyTempFields((Temp *) from, (Temp *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, matstate);
+
+ return newnode;
}
/* ----------------
- * _copySort
+ * _copySort
* ----------------
*/
-static Sort *
-_copySort(Sort *from)
+static Sort *
+_copySort(Sort * from)
{
- Sort *newnode = makeNode(Sort);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyTempFields((Temp*)from, (Temp*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, sortstate);
-
- return newnode;
+ Sort *newnode = makeNode(Sort);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyTempFields((Temp *) from, (Temp *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, sortstate);
+
+ return newnode;
}
/* ---------------
- * _copyAgg
+ * _copyAgg
* --------------
*/
-static Agg *
-_copyAgg(Agg *from)
+static Agg *
+_copyAgg(Agg * from)
{
- Agg *newnode = makeNode(Agg);
- int i;
-
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyTempFields((Temp*)from, (Temp*)newnode);
-
- newnode->numAgg = from->numAgg;
- newnode->aggs = malloc(sizeof(Aggreg *));
- for(i=0; i < from->numAgg; i++) {
- newnode->aggs[i] = copyObject(from->aggs[i]);
- }
-
- Node_Copy(from, newnode, aggstate);
-
- return newnode;
+ Agg *newnode = makeNode(Agg);
+ int i;
+
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyTempFields((Temp *) from, (Temp *) newnode);
+
+ newnode->numAgg = from->numAgg;
+ newnode->aggs = malloc(sizeof(Aggreg *));
+ for (i = 0; i < from->numAgg; i++)
+ {
+ newnode->aggs[i] = copyObject(from->aggs[i]);
+ }
+
+ Node_Copy(from, newnode, aggstate);
+
+ return newnode;
}
/* ----------------
- * _copyUnique
+ * _copyUnique
* ----------------
*/
-static Unique *
-_copyUnique(Unique *from)
+static Unique *
+_copyUnique(Unique * from)
{
- Unique *newnode = makeNode(Unique);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
- CopyTempFields((Temp*)from, (Temp*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, uniquestate);
-
- return newnode;
+ Unique *newnode = makeNode(Unique);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+ CopyTempFields((Temp *) from, (Temp *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, uniquestate);
+
+ return newnode;
}
/* ----------------
- * _copyHash
+ * _copyHash
* ----------------
*/
-static Hash *
-_copyHash(Hash *from)
+static Hash *
+_copyHash(Hash * from)
{
- Hash *newnode = makeNode(Hash);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyPlanFields((Plan*)from, (Plan*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, hashkey);
- Node_Copy(from, newnode, hashstate);
-
- newnode->hashtable = from->hashtable;
- newnode->hashtablekey = from->hashtablekey;
- newnode->hashtablesize = from->hashtablesize;
-
- return newnode;
+ Hash *newnode = makeNode(Hash);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyPlanFields((Plan *) from, (Plan *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, hashkey);
+ Node_Copy(from, newnode, hashstate);
+
+ newnode->hashtable = from->hashtable;
+ newnode->hashtablekey = from->hashtablekey;
+ newnode->hashtablesize = from->hashtablesize;
+
+ return newnode;
}
/* ****************************************************************
- * primnodes.h copy functions
+ * primnodes.h copy functions
* ****************************************************************
*/
/* ----------------
- * _copyResdom
+ * _copyResdom
* ----------------
*/
-static Resdom *
-_copyResdom(Resdom *from)
+static Resdom *
+_copyResdom(Resdom * from)
{
- Resdom *newnode = makeNode(Resdom);
-
- newnode->resno = from->resno;
- newnode->restype = from->restype;
- newnode->reslen = from->reslen;
-
- if (from->resname != NULL) {
- newnode->resname = palloc(strlen(from->resname)+1);
- strcpy(newnode->resname, from->resname);
- } else
- newnode->resname = (char*) NULL;
-
- newnode->reskey = from->reskey;
- newnode->reskeyop = from->reskeyop;
- newnode->resjunk = from->resjunk;
-
- return newnode;
+ Resdom *newnode = makeNode(Resdom);
+
+ newnode->resno = from->resno;
+ newnode->restype = from->restype;
+ newnode->reslen = from->reslen;
+
+ if (from->resname != NULL)
+ {
+ newnode->resname = palloc(strlen(from->resname) + 1);
+ strcpy(newnode->resname, from->resname);
+ }
+ else
+ newnode->resname = (char *) NULL;
+
+ newnode->reskey = from->reskey;
+ newnode->reskeyop = from->reskeyop;
+ newnode->resjunk = from->resjunk;
+
+ return newnode;
}
-static Fjoin *
-_copyFjoin(Fjoin *from)
+static Fjoin *
+_copyFjoin(Fjoin * from)
{
- Fjoin *newnode = makeNode(Fjoin);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
-
- newnode->fj_initialized = from->fj_initialized;
- newnode->fj_nNodes = from->fj_nNodes;
-
- Node_Copy(from, newnode, fj_innerNode);
-
- newnode->fj_results = (DatumPtr)
- palloc((from->fj_nNodes)*sizeof(Datum));
-
- newnode->fj_alwaysDone = (BoolPtr)
- palloc((from->fj_nNodes)*sizeof(bool));
-
- memmove(from->fj_results,
- newnode->fj_results,
- (from->fj_nNodes)*sizeof(Datum));
-
- memmove(from->fj_alwaysDone,
- newnode->fj_alwaysDone,
- (from->fj_nNodes)*sizeof(bool));
-
-
- return newnode;
+ Fjoin *newnode = makeNode(Fjoin);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+
+ newnode->fj_initialized = from->fj_initialized;
+ newnode->fj_nNodes = from->fj_nNodes;
+
+ Node_Copy(from, newnode, fj_innerNode);
+
+ newnode->fj_results = (DatumPtr)
+ palloc((from->fj_nNodes) * sizeof(Datum));
+
+ newnode->fj_alwaysDone = (BoolPtr)
+ palloc((from->fj_nNodes) * sizeof(bool));
+
+ memmove(from->fj_results,
+ newnode->fj_results,
+ (from->fj_nNodes) * sizeof(Datum));
+
+ memmove(from->fj_alwaysDone,
+ newnode->fj_alwaysDone,
+ (from->fj_nNodes) * sizeof(bool));
+
+
+ return newnode;
}
/* ----------------
- * _copyExpr
+ * _copyExpr
* ----------------
*/
-static Expr *
-_copyExpr(Expr *from)
+static Expr *
+_copyExpr(Expr * from)
{
- Expr *newnode = makeNode(Expr);
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- newnode->typeOid = from->typeOid;
- newnode->opType = from->opType;
-
- Node_Copy(from, newnode, oper);
- Node_Copy(from, newnode, args);
-
- return newnode;
+ Expr *newnode = makeNode(Expr);
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ newnode->typeOid = from->typeOid;
+ newnode->opType = from->opType;
+
+ Node_Copy(from, newnode, oper);
+ Node_Copy(from, newnode, args);
+
+ return newnode;
}
/* ----------------
- * _copyVar
+ * _copyVar
* ----------------
*/
-static Var *
-_copyVar(Var *from)
+static Var *
+_copyVar(Var * from)
{
- Var *newnode = makeNode(Var);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->varno = from->varno;
- newnode->varattno = from->varattno;
- newnode->vartype = from->vartype;
-
- newnode->varnoold = from->varnoold;
- newnode->varoattno = from->varoattno;
-
- return newnode;
+ Var *newnode = makeNode(Var);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->varno = from->varno;
+ newnode->varattno = from->varattno;
+ newnode->vartype = from->vartype;
+
+ newnode->varnoold = from->varnoold;
+ newnode->varoattno = from->varoattno;
+
+ return newnode;
}
/* ----------------
- * _copyOper
+ * _copyOper
* ----------------
*/
-static Oper *
-_copyOper(Oper *from)
+static Oper *
+_copyOper(Oper * from)
{
- Oper *newnode = makeNode(Oper);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->opno = from->opno;
- newnode->opid = from->opid;
- newnode->opresulttype = from->opresulttype;
- newnode->opsize = from->opsize;
-
- /*
- * NOTE: shall we copy the cache structure or just the pointer ?
- * Alternatively we can set 'op_fcache' to NULL, in which
- * case the executor will initialize it when it needs it...
- */
- newnode->op_fcache = from->op_fcache;
-
- return newnode;
+ Oper *newnode = makeNode(Oper);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->opno = from->opno;
+ newnode->opid = from->opid;
+ newnode->opresulttype = from->opresulttype;
+ newnode->opsize = from->opsize;
+
+ /*
+ * NOTE: shall we copy the cache structure or just the pointer ?
+ * Alternatively we can set 'op_fcache' to NULL, in which case the
+ * executor will initialize it when it needs it...
+ */
+ newnode->op_fcache = from->op_fcache;
+
+ return newnode;
}
/* ----------------
- * _copyConst
+ * _copyConst
* ----------------
*/
-static Const *
-_copyConst(Const *from)
+static Const *
+_copyConst(Const * from)
{
- static Oid cached_type;
- static bool cached_typbyval;
-
- Const *newnode = makeNode(Const);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->consttype = from->consttype;
- newnode->constlen = from->constlen;
-
- /* ----------------
- * XXX super cheesy hack until parser/planner
- * puts in the right values here.
- * ----------------
- */
- if (cached_type != from->consttype) {
- HeapTuple typeTuple;
- TypeTupleForm typeStruct;
-
- /* ----------------
- * get the type tuple corresponding to the paramList->type,
- * If this fails, returnValue has been pre-initialized
- * to "null" so we just return it.
- * ----------------
- */
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(from->consttype),
- 0,0,0);
-
+ static Oid cached_type;
+ static bool cached_typbyval;
+
+ Const *newnode = makeNode(Const);
+
/* ----------------
- * get the type length and by-value from the type tuple and
- * save the information in our one element cache.
+ * copy remainder of node
* ----------------
*/
- Assert(PointerIsValid(typeTuple));
-
- typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
- cached_typbyval = (typeStruct)->typbyval ? true : false ;
- cached_type = from->consttype;
- }
-
- from->constbyval = cached_typbyval;
-
- if (!from->constisnull) {
+ newnode->consttype = from->consttype;
+ newnode->constlen = from->constlen;
+
/* ----------------
- * copying the Datum in a const node is a bit trickier
- * because it might be a pointer and it might also be of
- * variable length...
+ * XXX super cheesy hack until parser/planner
+ * puts in the right values here.
* ----------------
*/
- if (from->constbyval == true) {
- /* ----------------
- * passed by value so just copy the datum.
- * ----------------
- */
- newnode->constvalue = from->constvalue;
- } else {
- /* ----------------
- * not passed by value. datum contains a pointer.
- * ----------------
- */
- if (from->constlen != -1) {
+ if (cached_type != from->consttype)
+ {
+ HeapTuple typeTuple;
+ TypeTupleForm typeStruct;
+
+ /* ----------------
+ * get the type tuple corresponding to the paramList->type,
+ * If this fails, returnValue has been pre-initialized
+ * to "null" so we just return it.
+ * ----------------
+ */
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(from->consttype),
+ 0, 0, 0);
+
/* ----------------
- * fixed length structure
+ * get the type length and by-value from the type tuple and
+ * save the information in our one element cache.
* ----------------
*/
- newnode->constvalue = PointerGetDatum(palloc(from->constlen));
- memmove((char*)newnode->constvalue,
- (char*)from->constvalue, from->constlen);
- } else {
+ Assert(PointerIsValid(typeTuple));
+
+ typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
+ cached_typbyval = (typeStruct)->typbyval ? true : false;
+ cached_type = from->consttype;
+ }
+
+ from->constbyval = cached_typbyval;
+
+ if (!from->constisnull)
+ {
/* ----------------
- * variable length structure. here the length is stored
- * in the first int pointed to by the constval.
+ * copying the Datum in a const node is a bit trickier
+ * because it might be a pointer and it might also be of
+ * variable length...
* ----------------
*/
- int length;
- length = *((int *) from->constvalue);
- newnode->constvalue = PointerGetDatum(palloc(length));
- memmove((char*)newnode->constvalue,
- (char*)from->constvalue, length);
- }
+ if (from->constbyval == true)
+ {
+ /* ----------------
+ * passed by value so just copy the datum.
+ * ----------------
+ */
+ newnode->constvalue = from->constvalue;
+ }
+ else
+ {
+ /* ----------------
+ * not passed by value. datum contains a pointer.
+ * ----------------
+ */
+ if (from->constlen != -1)
+ {
+ /* ----------------
+ * fixed length structure
+ * ----------------
+ */
+ newnode->constvalue = PointerGetDatum(palloc(from->constlen));
+ memmove((char *) newnode->constvalue,
+ (char *) from->constvalue, from->constlen);
+ }
+ else
+ {
+ /* ----------------
+ * variable length structure. here the length is stored
+ * in the first int pointed to by the constval.
+ * ----------------
+ */
+ int length;
+
+ length = *((int *) from->constvalue);
+ newnode->constvalue = PointerGetDatum(palloc(length));
+ memmove((char *) newnode->constvalue,
+ (char *) from->constvalue, length);
+ }
+ }
+ }
+ else
+ {
+ newnode->constvalue = from->constvalue;
}
- }
- else {
- newnode->constvalue = from->constvalue;
- }
- newnode->constisnull = from->constisnull;
- newnode->constbyval = from->constbyval;
-
- return newnode;
+ newnode->constisnull = from->constisnull;
+ newnode->constbyval = from->constbyval;
+
+ return newnode;
}
/* ----------------
- * _copyParam
+ * _copyParam
* ----------------
*/
-static Param *
-_copyParam(Param *from)
+static Param *
+_copyParam(Param * from)
{
- Param *newnode = makeNode(Param);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->paramkind = from->paramkind;
- newnode->paramid = from->paramid;
-
- if (from->paramname != NULL) {
- newnode->paramname = pstrdup(from->paramname);
- } else
- newnode->paramname = (char*)NULL;
-
- newnode->paramtype = from->paramtype;
- Node_Copy(from, newnode, param_tlist);
-
- return newnode;
+ Param *newnode = makeNode(Param);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->paramkind = from->paramkind;
+ newnode->paramid = from->paramid;
+
+ if (from->paramname != NULL)
+ {
+ newnode->paramname = pstrdup(from->paramname);
+ }
+ else
+ newnode->paramname = (char *) NULL;
+
+ newnode->paramtype = from->paramtype;
+ Node_Copy(from, newnode, param_tlist);
+
+ return newnode;
}
/* ----------------
- * _copyFunc
+ * _copyFunc
* ----------------
*/
-static Func *
-_copyFunc(Func *from)
+static Func *
+_copyFunc(Func * from)
{
- Func *newnode = makeNode(Func);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->funcid = from->funcid;
- newnode->functype = from->functype;
- newnode->funcisindex = from->funcisindex;
- newnode->funcsize = from->funcsize;
- newnode->func_fcache = from->func_fcache;
- Node_Copy(from, newnode, func_tlist);
- Node_Copy(from, newnode, func_planlist);
-
- return newnode;
+ Func *newnode = makeNode(Func);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->funcid = from->funcid;
+ newnode->functype = from->functype;
+ newnode->funcisindex = from->funcisindex;
+ newnode->funcsize = from->funcsize;
+ newnode->func_fcache = from->func_fcache;
+ Node_Copy(from, newnode, func_tlist);
+ Node_Copy(from, newnode, func_planlist);
+
+ return newnode;
}
/* ----------------
- * _copyAggreg
+ * _copyAggreg
* ----------------
*/
-static Aggreg *
-_copyAggreg(Aggreg *from)
+static Aggreg *
+_copyAggreg(Aggreg * from)
{
- Aggreg *newnode = makeNode(Aggreg);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->aggname = pstrdup(from->aggname);
- newnode->basetype = from->basetype;
- newnode->aggtype = from->aggtype;
-
- Node_Copy(from, newnode, target);
-
- newnode->aggno = from->aggno;
-
- return newnode;
+ Aggreg *newnode = makeNode(Aggreg);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->aggname = pstrdup(from->aggname);
+ newnode->basetype = from->basetype;
+ newnode->aggtype = from->aggtype;
+
+ Node_Copy(from, newnode, target);
+
+ newnode->aggno = from->aggno;
+
+ return newnode;
}
-static Array *
-_copyArray(Array *from)
+static Array *
+_copyArray(Array * from)
{
- Array *newnode = makeNode(Array);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->arrayelemtype = from->arrayelemtype;
- newnode->arrayelemlength = from->arrayelemlength;
- newnode->arrayelembyval = from->arrayelembyval;
- newnode->arrayndim = from->arrayndim;
- newnode->arraylow = from->arraylow;
- newnode->arrayhigh = from->arrayhigh;
- newnode->arraylen = from->arraylen;
-
- return newnode;
+ Array *newnode = makeNode(Array);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->arrayelemtype = from->arrayelemtype;
+ newnode->arrayelemlength = from->arrayelemlength;
+ newnode->arrayelembyval = from->arrayelembyval;
+ newnode->arrayndim = from->arrayndim;
+ newnode->arraylow = from->arraylow;
+ newnode->arrayhigh = from->arrayhigh;
+ newnode->arraylen = from->arraylen;
+
+ return newnode;
}
static ArrayRef *
-_copyArrayRef(ArrayRef *from)
+_copyArrayRef(ArrayRef * from)
{
- ArrayRef *newnode = makeNode(ArrayRef);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->refelemtype = from->refelemtype;
- newnode->refattrlength = from->refattrlength;
- newnode->refelemlength = from->refelemlength;
- newnode->refelembyval = from->refelembyval;
-
- Node_Copy(from,newnode,refupperindexpr);
- Node_Copy(from,newnode,reflowerindexpr);
- Node_Copy(from,newnode,refexpr);
- Node_Copy(from,newnode,refassgnexpr);
-
- return newnode;
+ ArrayRef *newnode = makeNode(ArrayRef);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->refelemtype = from->refelemtype;
+ newnode->refattrlength = from->refattrlength;
+ newnode->refelemlength = from->refelemlength;
+ newnode->refelembyval = from->refelembyval;
+
+ Node_Copy(from, newnode, refupperindexpr);
+ Node_Copy(from, newnode, reflowerindexpr);
+ Node_Copy(from, newnode, refexpr);
+ Node_Copy(from, newnode, refassgnexpr);
+
+ return newnode;
}
/* ****************************************************************
- * relation.h copy functions
+ * relation.h copy functions
* ****************************************************************
*/
/* ----------------
- * _copyRel
+ * _copyRel
* ----------------
*/
/*
- ** when you change this, also make sure to fix up xfunc_copyRel in
+ ** when you change this, also make sure to fix up xfunc_copyRel in
** planner/path/xfunc.c accordingly!!!
- ** -- JMH, 8/2/93
+ ** -- JMH, 8/2/93
*/
-static Rel *
-_copyRel(Rel *from)
+static Rel *
+_copyRel(Rel * from)
{
- Rel *newnode = makeNode(Rel);
- int i, len;
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->relids = listCopy(from->relids);
-
- newnode->indexed = from->indexed;
- newnode->pages = from->pages;
- newnode->tuples = from->tuples;
- newnode->size = from->size;
- newnode->width = from->width;
- newnode->indproc = from->indproc;
-
- Node_Copy(from, newnode, targetlist);
- Node_Copy(from, newnode, pathlist);
- Node_Copy(from, newnode, unorderedpath);
- Node_Copy(from, newnode, cheapestpath);
- newnode->pruneable = from->pruneable;
- newnode->relam = from->relam;
-
- if (from->classlist) {
- for(len=0; from->classlist[len]!=0; len++)
- ;
- newnode->classlist = (Oid *)palloc(sizeof(Oid) * (len+1));
- for(i=0; i < len; i++) {
- newnode->classlist[i] = from->classlist[i];
+ Rel *newnode = makeNode(Rel);
+ int i,
+ len;
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->relids = listCopy(from->relids);
+
+ newnode->indexed = from->indexed;
+ newnode->pages = from->pages;
+ newnode->tuples = from->tuples;
+ newnode->size = from->size;
+ newnode->width = from->width;
+ newnode->indproc = from->indproc;
+
+ Node_Copy(from, newnode, targetlist);
+ Node_Copy(from, newnode, pathlist);
+ Node_Copy(from, newnode, unorderedpath);
+ Node_Copy(from, newnode, cheapestpath);
+ newnode->pruneable = from->pruneable;
+ newnode->relam = from->relam;
+
+ if (from->classlist)
+ {
+ for (len = 0; from->classlist[len] != 0; len++)
+ ;
+ newnode->classlist = (Oid *) palloc(sizeof(Oid) * (len + 1));
+ for (i = 0; i < len; i++)
+ {
+ newnode->classlist[i] = from->classlist[i];
+ }
+ newnode->classlist[len] = 0;
}
- newnode->classlist[len] = 0;
- }
-
- if (from->indexkeys) {
- for(len=0; from->indexkeys[len]!=0; len++)
- ;
- newnode->indexkeys = (int *)palloc(sizeof(int) * (len+1));
- for(i=0; i < len; i++) {
- newnode->indexkeys[i] = from->indexkeys[i];
+
+ if (from->indexkeys)
+ {
+ for (len = 0; from->indexkeys[len] != 0; len++)
+ ;
+ newnode->indexkeys = (int *) palloc(sizeof(int) * (len + 1));
+ for (i = 0; i < len; i++)
+ {
+ newnode->indexkeys[i] = from->indexkeys[i];
+ }
+ newnode->indexkeys[len] = 0;
}
- newnode->indexkeys[len] = 0;
- }
-
- if (from->ordering) {
- for(len=0; from->ordering[len]!=0; len++)
- ;
- newnode->ordering = (Oid *)palloc(sizeof(Oid) * (len+1));
- for(i=0; i < len; i++) {
- newnode->ordering[i] = from->ordering[i];
+
+ if (from->ordering)
+ {
+ for (len = 0; from->ordering[len] != 0; len++)
+ ;
+ newnode->ordering = (Oid *) palloc(sizeof(Oid) * (len + 1));
+ for (i = 0; i < len; i++)
+ {
+ newnode->ordering[i] = from->ordering[i];
+ }
+ newnode->ordering[len] = 0;
}
- newnode->ordering[len] = 0;
- }
-
- Node_Copy(from, newnode, clauseinfo);
- Node_Copy(from, newnode, joininfo);
- Node_Copy(from, newnode, innerjoin);
- Node_Copy(from, newnode, superrels);
-
- return newnode;
+
+ Node_Copy(from, newnode, clauseinfo);
+ Node_Copy(from, newnode, joininfo);
+ Node_Copy(from, newnode, innerjoin);
+ Node_Copy(from, newnode, superrels);
+
+ return newnode;
}
/* ----------------
- * CopyPathFields
+ * CopyPathFields
*
- * This function copies the fields of the Path node. It is used by
- * all the copy functions for classes which inherit from Path.
+ * This function copies the fields of the Path node. It is used by
+ * all the copy functions for classes which inherit from Path.
* ----------------
*/
static void
-CopyPathFields(Path *from, Path *newnode)
+CopyPathFields(Path * from, Path * newnode)
{
- newnode->pathtype = from->pathtype;
- /* Modify the next line, since it causes the copying to cycle
- (i.e. the parent points right back here!
- -- JMH, 7/7/92.
- Old version:
- Node_Copy(from, newnode, parent);
- */
- newnode->parent = from->parent;
-
- newnode->path_cost = from->path_cost;
-
- newnode->p_ordering.ordtype = from->p_ordering.ordtype;
- if (from->p_ordering.ordtype == SORTOP_ORDER) {
- int len, i;
- Oid *ordering = from->p_ordering.ord.sortop;
-
- if (ordering) {
- for(len=0; ordering[len]!=0; len++)
- ;
- newnode->p_ordering.ord.sortop =
- (Oid *)palloc(sizeof(Oid) * (len+1));
- for(i=0; i < len; i++) {
- newnode->p_ordering.ord.sortop[i] = ordering[i];
- }
- newnode->p_ordering.ord.sortop[len] = 0;
- } else {
- newnode->p_ordering.ord.sortop = NULL;
+ newnode->pathtype = from->pathtype;
+
+ /*
+ * Modify the next line, since it causes the copying to cycle (i.e.
+ * the parent points right back here! -- JMH, 7/7/92. Old version:
+ * Node_Copy(from, newnode, parent);
+ */
+ newnode->parent = from->parent;
+
+ newnode->path_cost = from->path_cost;
+
+ newnode->p_ordering.ordtype = from->p_ordering.ordtype;
+ if (from->p_ordering.ordtype == SORTOP_ORDER)
+ {
+ int len,
+ i;
+ Oid *ordering = from->p_ordering.ord.sortop;
+
+ if (ordering)
+ {
+ for (len = 0; ordering[len] != 0; len++)
+ ;
+ newnode->p_ordering.ord.sortop =
+ (Oid *) palloc(sizeof(Oid) * (len + 1));
+ for (i = 0; i < len; i++)
+ {
+ newnode->p_ordering.ord.sortop[i] = ordering[i];
+ }
+ newnode->p_ordering.ord.sortop[len] = 0;
+ }
+ else
+ {
+ newnode->p_ordering.ord.sortop = NULL;
+ }
+ }
+ else
+ {
+ Node_Copy(from, newnode, p_ordering.ord.merge);
}
- } else {
- Node_Copy(from, newnode, p_ordering.ord.merge);
- }
-
- Node_Copy(from, newnode, keys);
-
- newnode->outerjoincost = from->outerjoincost;
-
- newnode->joinid = listCopy(from->joinid);
- Node_Copy(from, newnode, locclauseinfo);
+
+ Node_Copy(from, newnode, keys);
+
+ newnode->outerjoincost = from->outerjoincost;
+
+ newnode->joinid = listCopy(from->joinid);
+ Node_Copy(from, newnode, locclauseinfo);
}
/* ----------------
- * _copyPath
+ * _copyPath
* ----------------
*/
-static Path *
-_copyPath(Path *from)
+static Path *
+_copyPath(Path * from)
{
- Path *newnode = makeNode(Path);
-
- CopyPathFields(from, newnode);
-
- return newnode;
+ Path *newnode = makeNode(Path);
+
+ CopyPathFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copyIndexPath
+ * _copyIndexPath
* ----------------
*/
static IndexPath *
-_copyIndexPath(IndexPath *from)
+_copyIndexPath(IndexPath * from)
{
- IndexPath *newnode = makeNode(IndexPath);
-
- /* ----------------
- * copy the node superclass fields
- * ----------------
- */
- CopyPathFields((Path*)from, (Path*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->indexid = listCopy(from->indexid);
- Node_Copy(from, newnode, indexqual);
-
- if (from->indexkeys)
- {
- int i, len;
-
- for(len=0; from->indexkeys[len]!=0; len++)
- ;
- newnode->indexkeys = (int *)palloc(sizeof(int) * (len+1));
- for(i=0; i < len; i++) {
- newnode->indexkeys[i] = from->indexkeys[i];
+ IndexPath *newnode = makeNode(IndexPath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path *) from, (Path *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->indexid = listCopy(from->indexid);
+ Node_Copy(from, newnode, indexqual);
+
+ if (from->indexkeys)
+ {
+ int i,
+ len;
+
+ for (len = 0; from->indexkeys[len] != 0; len++)
+ ;
+ newnode->indexkeys = (int *) palloc(sizeof(int) * (len + 1));
+ for (i = 0; i < len; i++)
+ {
+ newnode->indexkeys[i] = from->indexkeys[i];
+ }
+ newnode->indexkeys[len] = 0;
}
- newnode->indexkeys[len] = 0;
- }
-
- return newnode;
+
+ return newnode;
}
/* ----------------
- * CopyJoinPathFields
+ * CopyJoinPathFields
*
- * This function copies the fields of the JoinPath node. It is used by
- * all the copy functions for classes which inherit from JoinPath.
+ * This function copies the fields of the JoinPath node. It is used by
+ * all the copy functions for classes which inherit from JoinPath.
* ----------------
*/
static void
-CopyJoinPathFields(JoinPath *from, JoinPath *newnode)
+CopyJoinPathFields(JoinPath * from, JoinPath * newnode)
{
- Node_Copy(from, newnode, pathclauseinfo);
- Node_Copy(from, newnode, outerjoinpath);
- Node_Copy(from, newnode, innerjoinpath);
+ Node_Copy(from, newnode, pathclauseinfo);
+ Node_Copy(from, newnode, outerjoinpath);
+ Node_Copy(from, newnode, innerjoinpath);
}
/* ----------------
- * _copyJoinPath
+ * _copyJoinPath
* ----------------
*/
static JoinPath *
-_copyJoinPath(JoinPath *from)
+_copyJoinPath(JoinPath * from)
{
- JoinPath *newnode = makeNode(JoinPath);
-
- /* ----------------
- * copy the node superclass fields
- * ----------------
- */
- CopyPathFields((Path*)from, (Path*)newnode);
- CopyJoinPathFields(from, newnode);
-
- return newnode;
+ JoinPath *newnode = makeNode(JoinPath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path *) from, (Path *) newnode);
+ CopyJoinPathFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copyMergePath
+ * _copyMergePath
* ----------------
*/
static MergePath *
-_copyMergePath(MergePath *from)
+_copyMergePath(MergePath * from)
{
- MergePath *newnode = makeNode(MergePath);
-
- /* ----------------
- * copy the node superclass fields
- * ----------------
- */
- CopyPathFields((Path*)from, (Path*)newnode);
- CopyJoinPathFields((JoinPath*)from, (JoinPath*)newnode);
-
- /* ----------------
- * copy the remainder of the node
- * ----------------
- */
- Node_Copy(from, newnode, path_mergeclauses);
- Node_Copy(from, newnode, outersortkeys);
- Node_Copy(from, newnode, innersortkeys);
-
- return newnode;
+ MergePath *newnode = makeNode(MergePath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path *) from, (Path *) newnode);
+ CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
+
+ /* ----------------
+ * copy the remainder of the node
+ * ----------------
+ */
+ Node_Copy(from, newnode, path_mergeclauses);
+ Node_Copy(from, newnode, outersortkeys);
+ Node_Copy(from, newnode, innersortkeys);
+
+ return newnode;
}
/* ----------------
- * _copyHashPath
+ * _copyHashPath
* ----------------
*/
static HashPath *
-_copyHashPath(HashPath *from)
+_copyHashPath(HashPath * from)
{
- HashPath *newnode = makeNode(HashPath);
-
- /* ----------------
- * copy the node superclass fields
- * ----------------
- */
- CopyPathFields((Path*)from, (Path*)newnode);
- CopyJoinPathFields((JoinPath*)from, (JoinPath*)newnode);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, path_hashclauses);
- Node_Copy(from, newnode, outerhashkeys);
- Node_Copy(from, newnode, innerhashkeys);
-
- return newnode;
+ HashPath *newnode = makeNode(HashPath);
+
+ /* ----------------
+ * copy the node superclass fields
+ * ----------------
+ */
+ CopyPathFields((Path *) from, (Path *) newnode);
+ CopyJoinPathFields((JoinPath *) from, (JoinPath *) newnode);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, path_hashclauses);
+ Node_Copy(from, newnode, outerhashkeys);
+ Node_Copy(from, newnode, innerhashkeys);
+
+ return newnode;
}
/* ----------------
- * _copyOrderKey
+ * _copyOrderKey
* ----------------
*/
static OrderKey *
-_copyOrderKey(OrderKey *from)
+_copyOrderKey(OrderKey * from)
{
- OrderKey *newnode = makeNode(OrderKey);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->attribute_number = from->attribute_number;
- newnode->array_index = from->array_index;
-
- return newnode;
+ OrderKey *newnode = makeNode(OrderKey);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->attribute_number = from->attribute_number;
+ newnode->array_index = from->array_index;
+
+ return newnode;
}
/* ----------------
- * _copyJoinKey
+ * _copyJoinKey
* ----------------
*/
static JoinKey *
-_copyJoinKey(JoinKey *from)
+_copyJoinKey(JoinKey * from)
{
- JoinKey *newnode = makeNode(JoinKey);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, outer);
- Node_Copy(from, newnode, inner);
-
- return newnode;
+ JoinKey *newnode = makeNode(JoinKey);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, outer);
+ Node_Copy(from, newnode, inner);
+
+ return newnode;
}
/* ----------------
- * _copyMergeOrder
+ * _copyMergeOrder
* ----------------
*/
static MergeOrder *
-_copyMergeOrder(MergeOrder *from)
+_copyMergeOrder(MergeOrder * from)
{
- MergeOrder *newnode = makeNode(MergeOrder);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->join_operator = from->join_operator;
- newnode->left_operator = from->left_operator;
- newnode->right_operator = from->right_operator;
- newnode->left_type = from->left_type;
- newnode->right_type = from->right_type;
-
- return newnode;
+ MergeOrder *newnode = makeNode(MergeOrder);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->join_operator = from->join_operator;
+ newnode->left_operator = from->left_operator;
+ newnode->right_operator = from->right_operator;
+ newnode->left_type = from->left_type;
+ newnode->right_type = from->right_type;
+
+ return newnode;
}
/* ----------------
- * _copyCInfo
+ * _copyCInfo
* ----------------
*/
-static CInfo *
-_copyCInfo(CInfo *from)
+static CInfo *
+_copyCInfo(CInfo * from)
{
- CInfo *newnode = makeNode(CInfo);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, clause);
-
- newnode->selectivity = from->selectivity;
- newnode->notclause = from->notclause;
-
- Node_Copy(from, newnode, indexids);
- Node_Copy(from, newnode, mergesortorder);
- newnode->hashjoinoperator = from->hashjoinoperator;
- newnode->cinfojoinid = listCopy(from->cinfojoinid);
-
- return newnode;
+ CInfo *newnode = makeNode(CInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, clause);
+
+ newnode->selectivity = from->selectivity;
+ newnode->notclause = from->notclause;
+
+ Node_Copy(from, newnode, indexids);
+ Node_Copy(from, newnode, mergesortorder);
+ newnode->hashjoinoperator = from->hashjoinoperator;
+ newnode->cinfojoinid = listCopy(from->cinfojoinid);
+
+ return newnode;
}
/* ----------------
- * CopyJoinMethodFields
+ * CopyJoinMethodFields
*
- * This function copies the fields of the JoinMethod node. It is used by
- * all the copy functions for classes which inherit from JoinMethod.
+ * This function copies the fields of the JoinMethod node. It is used by
+ * all the copy functions for classes which inherit from JoinMethod.
* ----------------
*/
static void
-CopyJoinMethodFields(JoinMethod *from, JoinMethod *newnode)
+CopyJoinMethodFields(JoinMethod * from, JoinMethod * newnode)
{
- Node_Copy(from, newnode, jmkeys);
- Node_Copy(from, newnode, clauses);
- return;
+ Node_Copy(from, newnode, jmkeys);
+ Node_Copy(from, newnode, clauses);
+ return;
}
/* ----------------
- * _copyJoinMethod
+ * _copyJoinMethod
* ----------------
*/
static JoinMethod *
-_copyJoinMethod(JoinMethod *from)
+_copyJoinMethod(JoinMethod * from)
{
- JoinMethod *newnode = makeNode(JoinMethod);
-
- CopyJoinMethodFields(from, newnode);
-
- return newnode;
+ JoinMethod *newnode = makeNode(JoinMethod);
+
+ CopyJoinMethodFields(from, newnode);
+
+ return newnode;
}
/* ----------------
- * _copyHInfo
+ * _copyHInfo
* ----------------
*/
-static HInfo *
-_copyHInfo(HInfo *from)
+static HInfo *
+_copyHInfo(HInfo * from)
{
- HInfo *newnode = makeNode(HInfo);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->hashop = from->hashop;
-
- return newnode;
+ HInfo *newnode = makeNode(HInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->hashop = from->hashop;
+
+ return newnode;
}
/* ----------------
- * _copyMInfo
+ * _copyMInfo
* ----------------
*/
-static MInfo *
-_copyMInfo(MInfo *from)
+static MInfo *
+_copyMInfo(MInfo * from)
{
- MInfo *newnode = makeNode(MInfo);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, m_ordering);
-
- return newnode;
+ MInfo *newnode = makeNode(MInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, m_ordering);
+
+ return newnode;
}
/* ----------------
- * _copyJInfo
+ * _copyJInfo
* ----------------
*/
-static JInfo *
-_copyJInfo(JInfo *from)
+static JInfo *
+_copyJInfo(JInfo * from)
{
- JInfo *newnode = makeNode(JInfo);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- newnode->otherrels = listCopy(from->otherrels);
- Node_Copy(from, newnode, jinfoclauseinfo);
-
- newnode->mergesortable = from->mergesortable;
- newnode->hashjoinable = from->hashjoinable;
- newnode->inactive = from->inactive;
-
- return newnode;
+ JInfo *newnode = makeNode(JInfo);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ newnode->otherrels = listCopy(from->otherrels);
+ Node_Copy(from, newnode, jinfoclauseinfo);
+
+ newnode->mergesortable = from->mergesortable;
+ newnode->hashjoinable = from->hashjoinable;
+ newnode->inactive = from->inactive;
+
+ return newnode;
}
-static Iter *
-_copyIter(Iter *from)
+static Iter *
+_copyIter(Iter * from)
{
- Iter *newnode = makeNode(Iter);
+ Iter *newnode = makeNode(Iter);
+
+ Node_Copy(from, newnode, iterexpr);
+ newnode->itertype = from->itertype;
- Node_Copy(from, newnode, iterexpr);
- newnode->itertype = from->itertype;
-
- return newnode;
+ return newnode;
}
-static Stream *
-_copyStream(Stream *from)
+static Stream *
+_copyStream(Stream * from)
{
- Stream *newnode = makeNode(Stream);
-
- newnode->pathptr = from->pathptr;
- newnode->cinfo = from->cinfo;
- newnode->clausetype = from->clausetype;
- newnode->groupup = from->groupup;
- newnode->groupcost = from->groupcost;
- newnode->groupsel = from->groupsel;
- newnode->upstream = (StreamPtr)NULL; /* only copy nodes downwards! */
- Node_Copy(from, newnode, downstream);
- if (newnode->downstream)
- ((Stream*)newnode->downstream)->upstream = (Stream*)newnode;
-
- return newnode;
+ Stream *newnode = makeNode(Stream);
+
+ newnode->pathptr = from->pathptr;
+ newnode->cinfo = from->cinfo;
+ newnode->clausetype = from->clausetype;
+ newnode->groupup = from->groupup;
+ newnode->groupcost = from->groupcost;
+ newnode->groupsel = from->groupsel;
+ newnode->upstream = (StreamPtr) NULL; /* only copy nodes
+ * downwards! */
+ Node_Copy(from, newnode, downstream);
+ if (newnode->downstream)
+ ((Stream *) newnode->downstream)->upstream = (Stream *) newnode;
+
+ return newnode;
}
/* ****************
- * parsenodes.h routines have no copy functions
+ * parsenodes.h routines have no copy functions
* ****************
*/
static TargetEntry *
-_copyTargetEntry(TargetEntry *from)
+_copyTargetEntry(TargetEntry * from)
{
- TargetEntry *newnode = makeNode(TargetEntry);
+ TargetEntry *newnode = makeNode(TargetEntry);
- Node_Copy(from, newnode, resdom);
- Node_Copy(from, newnode, fjoin);
- Node_Copy(from, newnode, expr);
- return newnode;
+ Node_Copy(from, newnode, resdom);
+ Node_Copy(from, newnode, fjoin);
+ Node_Copy(from, newnode, expr);
+ return newnode;
}
static RangeTblEntry *
-_copyRangeTblEntry(RangeTblEntry *from)
+_copyRangeTblEntry(RangeTblEntry * from)
{
- RangeTblEntry *newnode = makeNode(RangeTblEntry);
-
- memcpy (newnode, from, sizeof (RangeTblEntry));
- if ( from->relname )
- newnode->relname = pstrdup (from->relname);
- if ( from->refname )
- newnode->refname = pstrdup (from->refname);
- if ( from->timeRange )
- {
- newnode->timeRange = makeNode (TimeRange);
- if ( from->timeRange->startDate )
- newnode->timeRange->startDate = pstrdup (from->timeRange->startDate);
- else
- newnode->timeRange->startDate = NULL;
- if ( from->timeRange->endDate )
- newnode->timeRange->endDate = pstrdup (from->timeRange->endDate);
- else
- newnode->timeRange->endDate = NULL;
- newnode->timeQual = makeTimeRange (newnode->timeRange->startDate,
- newnode->timeRange->endDate,
- ((newnode->timeRange->endDate == NULL) ? 0 : 1));
- }
-
- return newnode;
+ RangeTblEntry *newnode = makeNode(RangeTblEntry);
+
+ memcpy(newnode, from, sizeof(RangeTblEntry));
+ if (from->relname)
+ newnode->relname = pstrdup(from->relname);
+ if (from->refname)
+ newnode->refname = pstrdup(from->refname);
+ if (from->timeRange)
+ {
+ newnode->timeRange = makeNode(TimeRange);
+ if (from->timeRange->startDate)
+ newnode->timeRange->startDate = pstrdup(from->timeRange->startDate);
+ else
+ newnode->timeRange->startDate = NULL;
+ if (from->timeRange->endDate)
+ newnode->timeRange->endDate = pstrdup(from->timeRange->endDate);
+ else
+ newnode->timeRange->endDate = NULL;
+ newnode->timeQual = makeTimeRange(newnode->timeRange->startDate,
+ newnode->timeRange->endDate,
+ ((newnode->timeRange->endDate == NULL) ? 0 : 1));
+ }
+
+ return newnode;
}
static SortClause *
-_copySortClause(SortClause *from)
+_copySortClause(SortClause * from)
{
- SortClause *newnode = makeNode(SortClause);
+ SortClause *newnode = makeNode(SortClause);
+
+ Node_Copy(from, newnode, resdom);
+ newnode->opoid = from->opoid;
- Node_Copy(from, newnode, resdom);
- newnode->opoid = from->opoid;
-
- return newnode;
+ return newnode;
}
static A_Const *
-_copyAConst(A_Const *from)
+_copyAConst(A_Const * from)
{
- A_Const *newnode = makeNode(A_Const);
+ A_Const *newnode = makeNode(A_Const);
- newnode->val = *((Value *)(copyObject(&(from->val))));
- Node_Copy(from, newnode, typename);
+ newnode->val = *((Value *) (copyObject(&(from->val))));
+ Node_Copy(from, newnode, typename);
- return newnode;
+ return newnode;
}
static TypeName *
-_copyTypeName(TypeName *from)
+_copyTypeName(TypeName * from)
{
- TypeName *newnode = makeNode(TypeName);
-
- if(from->name) {
- newnode->name = pstrdup(from->name);
- } else {
- from->name = (char *)0;
- }
- newnode->setof = from->setof;
- Node_Copy(from, newnode, arrayBounds);
- newnode->typlen = from->typlen;
-
- return newnode;
+ TypeName *newnode = makeNode(TypeName);
+
+ if (from->name)
+ {
+ newnode->name = pstrdup(from->name);
+ }
+ else
+ {
+ from->name = (char *) 0;
+ }
+ newnode->setof = from->setof;
+ Node_Copy(from, newnode, arrayBounds);
+ newnode->typlen = from->typlen;
+
+ return newnode;
}
-static Query *
-_copyQuery(Query *from)
+static Query *
+_copyQuery(Query * from)
{
- Query *newnode = makeNode(Query);
-
- newnode->commandType = from->commandType;
- newnode->resultRelation = from->resultRelation;
- /* probably should dup this string instead of just pointing */
- /* to the old one --djm */
- if(from->into) {
- newnode->into = pstrdup(from->into);
- } else {
- newnode->into = (char *)0;
- }
- newnode->isPortal = from->isPortal;
- Node_Copy(from, newnode, rtable);
- if (from->utilityStmt && nodeTag(from->utilityStmt) == T_NotifyStmt) {
- NotifyStmt *from_notify = (NotifyStmt*)from->utilityStmt;
- NotifyStmt *n = makeNode(NotifyStmt);
- int length = strlen(from_notify->relname);
-
- n->relname = palloc(length + 1);
- strcpy(n->relname,from_notify->relname);
- newnode->utilityStmt = (Node*)n;
- }
- if (from->uniqueFlag) {
- newnode->uniqueFlag = (char*)palloc(strlen(from->uniqueFlag)+1);
- strcpy(newnode->uniqueFlag, from->uniqueFlag);
- }
- else
- newnode->uniqueFlag = NULL;
- Node_Copy(from, newnode, sortClause);
- Node_Copy(from, newnode, targetList);
- Node_Copy(from, newnode, qual);
-
- return newnode;
+ Query *newnode = makeNode(Query);
+
+ newnode->commandType = from->commandType;
+ newnode->resultRelation = from->resultRelation;
+ /* probably should dup this string instead of just pointing */
+ /* to the old one --djm */
+ if (from->into)
+ {
+ newnode->into = pstrdup(from->into);
+ }
+ else
+ {
+ newnode->into = (char *) 0;
+ }
+ newnode->isPortal = from->isPortal;
+ Node_Copy(from, newnode, rtable);
+ if (from->utilityStmt && nodeTag(from->utilityStmt) == T_NotifyStmt)
+ {
+ NotifyStmt *from_notify = (NotifyStmt *) from->utilityStmt;
+ NotifyStmt *n = makeNode(NotifyStmt);
+ int length = strlen(from_notify->relname);
+
+ n->relname = palloc(length + 1);
+ strcpy(n->relname, from_notify->relname);
+ newnode->utilityStmt = (Node *) n;
+ }
+ if (from->uniqueFlag)
+ {
+ newnode->uniqueFlag = (char *) palloc(strlen(from->uniqueFlag) + 1);
+ strcpy(newnode->uniqueFlag, from->uniqueFlag);
+ }
+ else
+ newnode->uniqueFlag = NULL;
+ Node_Copy(from, newnode, sortClause);
+ Node_Copy(from, newnode, targetList);
+ Node_Copy(from, newnode, qual);
+
+ return newnode;
}
/* ****************
- * mnodes.h routines have no copy functions
+ * mnodes.h routines have no copy functions
* ****************
*/
/* ****************************************************************
- * pg_list.h copy functions
+ * pg_list.h copy functions
* ****************************************************************
*/
-static Value *
-_copyValue(Value *from)
+static Value *
+_copyValue(Value * from)
{
- Value *newnode = makeNode(Value);
-
- newnode->type = from->type;
- switch(from->type) {
- case T_String:
- newnode->val.str = pstrdup(from->val.str);
- break;
- case T_Integer:
- newnode->val.ival = from->val.ival;
- break;
- case T_Float:
- newnode->val.dval = from->val.dval;
- break;
- default:
- break;
- }
- return newnode;
+ Value *newnode = makeNode(Value);
+
+ newnode->type = from->type;
+ switch (from->type)
+ {
+ case T_String:
+ newnode->val.str = pstrdup(from->val.str);
+ break;
+ case T_Integer:
+ newnode->val.ival = from->val.ival;
+ break;
+ case T_Float:
+ newnode->val.dval = from->val.dval;
+ break;
+ default:
+ break;
+ }
+ return newnode;
}
/* ----------------
- * copyObject returns a copy of the node or list. If it is a list, it
- * recursively copies its items.
+ * copyObject returns a copy of the node or list. If it is a list, it
+ * recursively copies its items.
* ----------------
*/
-void *
+void *
copyObject(void *from)
{
- void *retval;
-
- if (from==NULL)
- return NULL;
- switch(nodeTag(from)) {
- /*
- * PLAN NODES
- */
- case T_Plan:
- retval = _copyPlan(from);
- break;
- case T_Existential:
- retval = _copyExistential(from);
- break;
- case T_Result:
- retval = _copyResult(from);
- break;
- case T_Append:
- retval = _copyAppend(from);
- break;
- case T_Scan:
- retval = _copyScan(from);
- break;
- case T_SeqScan:
- retval = _copySeqScan(from);
- break;
- case T_IndexScan:
- retval = _copyIndexScan(from);
- break;
- case T_Join:
- retval = _copyJoin(from);
- break;
- case T_NestLoop:
- retval = _copyNestLoop(from);
- break;
- case T_MergeJoin:
- retval = _copyMergeJoin(from);
- break;
- case T_HashJoin:
- retval = _copyHashJoin(from);
- break;
- case T_Temp:
- retval = _copyTemp(from);
- break;
- case T_Material:
- retval = _copyMaterial(from);
- break;
- case T_Sort:
- retval = _copySort(from);
- break;
- case T_Agg:
- retval = _copyAgg(from);
- break;
- case T_Unique:
- retval = _copyUnique(from);
- break;
- case T_Hash:
- retval = _copyHash(from);
- break;
-
- /*
- * PRIMITIVE NODES
- */
- case T_Resdom:
- retval = _copyResdom(from);
- break;
- case T_Fjoin:
- retval = _copyFjoin(from);
- break;
- case T_Expr:
- retval = _copyExpr(from);
- break;
- case T_Var:
- retval = _copyVar(from);
- break;
- case T_Oper:
- retval = _copyOper(from);
- break;
- case T_Const:
- retval = _copyConst(from);
- break;
- case T_Param:
- retval = _copyParam(from);
- break;
- case T_Func:
- retval = _copyFunc(from);
- break;
- case T_Array:
- retval = _copyArray(from);
- break;
- case T_ArrayRef:
- retval = _copyArrayRef(from);
- break;
- case T_Aggreg:
- retval = _copyAggreg(from);
- break;
- /*
- * RELATION NODES
- */
- case T_Rel:
- retval = _copyRel(from);
- break;
- case T_Path:
- retval = _copyPath(from);
- break;
- case T_IndexPath:
- retval = _copyIndexPath(from);
- break;
- case T_JoinPath:
- retval = _copyJoinPath(from);
- break;
- case T_MergePath:
- retval = _copyMergePath(from);
- break;
- case T_HashPath:
- retval = _copyHashPath(from);
- break;
- case T_OrderKey:
- retval = _copyOrderKey(from);
- break;
- case T_JoinKey:
- retval = _copyJoinKey(from);
- break;
- case T_MergeOrder:
- retval = _copyMergeOrder(from);
- break;
- case T_CInfo:
- retval = _copyCInfo(from);
- break;
- case T_JoinMethod:
- retval = _copyJoinMethod(from);
- break;
- case T_HInfo:
- retval = _copyHInfo(from);
- break;
- case T_MInfo:
- retval = _copyMInfo(from);
- break;
- case T_JInfo:
- retval = _copyJInfo(from);
- break;
- case T_Iter:
- retval = _copyIter(from);
- break;
- case T_Stream:
- retval = _copyStream(from);
- break;
+ void *retval;
- /*
- * PARSE NODES
- */
- case T_Query:
- retval = _copyQuery(from);
- break;
- case T_TargetEntry:
- retval = _copyTargetEntry(from);
- break;
- case T_RangeTblEntry:
- retval = _copyRangeTblEntry(from);
- break;
- case T_SortClause:
- retval = _copySortClause(from);
- break;
- case T_A_Const:
- retval = _copyAConst(from);
- break;
- case T_TypeName:
- retval = _copyTypeName(from);
- break;
-
- /*
- * VALUE NODES
- */
- case T_Integer: case T_String: case T_Float:
- retval = _copyValue(from);
- break;
- case T_List:
+ if (from == NULL)
+ return NULL;
+ switch (nodeTag(from))
{
- List *list=from, *l;
- List *newlist = NIL, *nl=NIL;
- foreach(l, list) {
- if (newlist==NIL) {
- newlist = nl = lcons(copyObject(lfirst(l)),NIL);
- }else {
- lnext(nl) = lcons(copyObject(lfirst(l)),NIL);
- nl = lnext(nl);
+
+ /*
+ * PLAN NODES
+ */
+ case T_Plan:
+ retval = _copyPlan(from);
+ break;
+ case T_Existential:
+ retval = _copyExistential(from);
+ break;
+ case T_Result:
+ retval = _copyResult(from);
+ break;
+ case T_Append:
+ retval = _copyAppend(from);
+ break;
+ case T_Scan:
+ retval = _copyScan(from);
+ break;
+ case T_SeqScan:
+ retval = _copySeqScan(from);
+ break;
+ case T_IndexScan:
+ retval = _copyIndexScan(from);
+ break;
+ case T_Join:
+ retval = _copyJoin(from);
+ break;
+ case T_NestLoop:
+ retval = _copyNestLoop(from);
+ break;
+ case T_MergeJoin:
+ retval = _copyMergeJoin(from);
+ break;
+ case T_HashJoin:
+ retval = _copyHashJoin(from);
+ break;
+ case T_Temp:
+ retval = _copyTemp(from);
+ break;
+ case T_Material:
+ retval = _copyMaterial(from);
+ break;
+ case T_Sort:
+ retval = _copySort(from);
+ break;
+ case T_Agg:
+ retval = _copyAgg(from);
+ break;
+ case T_Unique:
+ retval = _copyUnique(from);
+ break;
+ case T_Hash:
+ retval = _copyHash(from);
+ break;
+
+ /*
+ * PRIMITIVE NODES
+ */
+ case T_Resdom:
+ retval = _copyResdom(from);
+ break;
+ case T_Fjoin:
+ retval = _copyFjoin(from);
+ break;
+ case T_Expr:
+ retval = _copyExpr(from);
+ break;
+ case T_Var:
+ retval = _copyVar(from);
+ break;
+ case T_Oper:
+ retval = _copyOper(from);
+ break;
+ case T_Const:
+ retval = _copyConst(from);
+ break;
+ case T_Param:
+ retval = _copyParam(from);
+ break;
+ case T_Func:
+ retval = _copyFunc(from);
+ break;
+ case T_Array:
+ retval = _copyArray(from);
+ break;
+ case T_ArrayRef:
+ retval = _copyArrayRef(from);
+ break;
+ case T_Aggreg:
+ retval = _copyAggreg(from);
+ break;
+
+ /*
+ * RELATION NODES
+ */
+ case T_Rel:
+ retval = _copyRel(from);
+ break;
+ case T_Path:
+ retval = _copyPath(from);
+ break;
+ case T_IndexPath:
+ retval = _copyIndexPath(from);
+ break;
+ case T_JoinPath:
+ retval = _copyJoinPath(from);
+ break;
+ case T_MergePath:
+ retval = _copyMergePath(from);
+ break;
+ case T_HashPath:
+ retval = _copyHashPath(from);
+ break;
+ case T_OrderKey:
+ retval = _copyOrderKey(from);
+ break;
+ case T_JoinKey:
+ retval = _copyJoinKey(from);
+ break;
+ case T_MergeOrder:
+ retval = _copyMergeOrder(from);
+ break;
+ case T_CInfo:
+ retval = _copyCInfo(from);
+ break;
+ case T_JoinMethod:
+ retval = _copyJoinMethod(from);
+ break;
+ case T_HInfo:
+ retval = _copyHInfo(from);
+ break;
+ case T_MInfo:
+ retval = _copyMInfo(from);
+ break;
+ case T_JInfo:
+ retval = _copyJInfo(from);
+ break;
+ case T_Iter:
+ retval = _copyIter(from);
+ break;
+ case T_Stream:
+ retval = _copyStream(from);
+ break;
+
+ /*
+ * PARSE NODES
+ */
+ case T_Query:
+ retval = _copyQuery(from);
+ break;
+ case T_TargetEntry:
+ retval = _copyTargetEntry(from);
+ break;
+ case T_RangeTblEntry:
+ retval = _copyRangeTblEntry(from);
+ break;
+ case T_SortClause:
+ retval = _copySortClause(from);
+ break;
+ case T_A_Const:
+ retval = _copyAConst(from);
+ break;
+ case T_TypeName:
+ retval = _copyTypeName(from);
+ break;
+
+ /*
+ * VALUE NODES
+ */
+ case T_Integer:
+ case T_String:
+ case T_Float:
+ retval = _copyValue(from);
+ break;
+ case T_List:
+ {
+ List *list = from,
+ *l;
+ List *newlist = NIL,
+ *nl = NIL;
+
+ foreach(l, list)
+ {
+ if (newlist == NIL)
+ {
+ newlist = nl = lcons(copyObject(lfirst(l)), NIL);
+ }
+ else
+ {
+ lnext(nl) = lcons(copyObject(lfirst(l)), NIL);
+ nl = lnext(nl);
+ }
+ }
+ retval = newlist;
}
- }
- retval = newlist;
+ break;
+ default:
+ elog(NOTICE, "copyObject: don't know how to copy %d", nodeTag(from));
+ retval = from;
+ break;
}
- break;
- default:
- elog(NOTICE, "copyObject: don't know how to copy %d", nodeTag(from));
- retval = from;
- break;
- }
- return retval;
+ return retval;
}
-
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 4a8a072d33f..792c8783f99 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* equalfuncs.c--
- * equal functions to compare the nodes
+ * equal functions to compare the nodes
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.6 1997/08/19 21:31:36 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.7 1997/09/07 04:42:44 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,700 +26,717 @@
#include "utils/elog.h"
#include "storage/itemptr.h"
-static bool equali(List *a, List *b);
+static bool equali(List * a, List * b);
/*
- * Stuff from primnodes.h
+ * Stuff from primnodes.h
*/
/*
- * Resdom is a subclass of Node.
+ * Resdom is a subclass of Node.
*/
-static bool
-_equalResdom(Resdom *a, Resdom *b)
+static bool
+_equalResdom(Resdom * a, Resdom * b)
{
- if (a->resno != b->resno)
- return (false);
- if (a->restype != b->restype)
- return (false);
- if (a->reslen != b->reslen)
- return (false);
- if (strcmp(a->resname, b->resname) != 0)
- return (false);
- if (a->reskey != b->reskey)
- return (false);
- if (a->reskeyop != b->reskeyop)
- return (false);
-
- return (true);
+ if (a->resno != b->resno)
+ return (false);
+ if (a->restype != b->restype)
+ return (false);
+ if (a->reslen != b->reslen)
+ return (false);
+ if (strcmp(a->resname, b->resname) != 0)
+ return (false);
+ if (a->reskey != b->reskey)
+ return (false);
+ if (a->reskeyop != b->reskeyop)
+ return (false);
+
+ return (true);
}
-static bool
-_equalFjoin(Fjoin *a, Fjoin *b)
+static bool
+_equalFjoin(Fjoin * a, Fjoin * b)
{
- int nNodes;
-
- if (a->fj_initialized != b->fj_initialized)
- return (false);
- if (a->fj_nNodes != b->fj_nNodes)
- return (false);
- if (!equal(a->fj_innerNode, b->fj_innerNode))
- return (false);
-
- nNodes = a->fj_nNodes;
- if (memcmp(a->fj_results, b->fj_results, nNodes*sizeof(Datum)) != 0)
- return (false);
- if (memcmp(a->fj_alwaysDone, b->fj_alwaysDone, nNodes*sizeof(bool)) != 0)
- return (false);
-
- return(true);
+ int nNodes;
+
+ if (a->fj_initialized != b->fj_initialized)
+ return (false);
+ if (a->fj_nNodes != b->fj_nNodes)
+ return (false);
+ if (!equal(a->fj_innerNode, b->fj_innerNode))
+ return (false);
+
+ nNodes = a->fj_nNodes;
+ if (memcmp(a->fj_results, b->fj_results, nNodes * sizeof(Datum)) != 0)
+ return (false);
+ if (memcmp(a->fj_alwaysDone, b->fj_alwaysDone, nNodes * sizeof(bool)) != 0)
+ return (false);
+
+ return (true);
}
/*
- * Expr is a subclass of Node.
+ * Expr is a subclass of Node.
*/
-static bool
-_equalExpr(Expr *a, Expr *b)
+static bool
+_equalExpr(Expr * a, Expr * b)
{
- if (a->opType != b->opType)
- return (false);
- if (!equal(a->oper, b->oper))
- return (false);
- if (!equal(a->args, b->args))
- return (false);
-
- return (true);
+ if (a->opType != b->opType)
+ return (false);
+ if (!equal(a->oper, b->oper))
+ return (false);
+ if (!equal(a->args, b->args))
+ return (false);
+
+ return (true);
}
-static bool
-_equalIter(Iter *a, Iter *b)
+static bool
+_equalIter(Iter * a, Iter * b)
{
- return (equal(a->iterexpr, b->iterexpr));
+ return (equal(a->iterexpr, b->iterexpr));
}
-static bool
-_equalStream(Stream *a, Stream *b)
+static bool
+_equalStream(Stream * a, Stream * b)
{
- if (a->clausetype != b->clausetype)
- return(false);
- if (a->groupup != b->groupup)
- return(false);
- if (a->groupcost != b->groupcost)
- return(false);
- if (a->groupsel != b->groupsel)
- return(false);
- if (!equal(a->pathptr, b->pathptr))
- return(false);
- if (!equal(a->cinfo, b->cinfo))
- return(false);
- if (!equal(a->upstream, b->upstream))
- return(false);
- return(equal(a->downstream, b->downstream));
+ if (a->clausetype != b->clausetype)
+ return (false);
+ if (a->groupup != b->groupup)
+ return (false);
+ if (a->groupcost != b->groupcost)
+ return (false);
+ if (a->groupsel != b->groupsel)
+ return (false);
+ if (!equal(a->pathptr, b->pathptr))
+ return (false);
+ if (!equal(a->cinfo, b->cinfo))
+ return (false);
+ if (!equal(a->upstream, b->upstream))
+ return (false);
+ return (equal(a->downstream, b->downstream));
}
/*
- * Var is a subclass of Expr.
+ * Var is a subclass of Expr.
*/
-static bool
-_equalVar(Var *a, Var *b)
+static bool
+_equalVar(Var * a, Var * b)
{
- if (a->varno != b->varno)
- return (false);
- if (a->varattno != b->varattno)
- return (false);
- if (a->vartype != b->vartype)
- return (false);
- if (a->varnoold != b->varnoold)
- return (false);
- if (a->varoattno != b->varoattno)
- return (false);
-
- return (true);
+ if (a->varno != b->varno)
+ return (false);
+ if (a->varattno != b->varattno)
+ return (false);
+ if (a->vartype != b->vartype)
+ return (false);
+ if (a->varnoold != b->varnoold)
+ return (false);
+ if (a->varoattno != b->varoattno)
+ return (false);
+
+ return (true);
}
-static bool
-_equalArray(Array *a, Array *b)
+static bool
+_equalArray(Array * a, Array * b)
{
- if (a->arrayelemtype != b->arrayelemtype)
- return (false);
- if (a->arrayndim != b->arrayndim)
- return (false);
- if (a->arraylow.indx[0] != b->arraylow.indx[0])
- return (false);
- if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
- return (false);
- if (a->arraylen != b->arraylen)
- return (false);
- return(TRUE);
+ if (a->arrayelemtype != b->arrayelemtype)
+ return (false);
+ if (a->arrayndim != b->arrayndim)
+ return (false);
+ if (a->arraylow.indx[0] != b->arraylow.indx[0])
+ return (false);
+ if (a->arrayhigh.indx[0] != b->arrayhigh.indx[0])
+ return (false);
+ if (a->arraylen != b->arraylen)
+ return (false);
+ return (TRUE);
}
-static bool
-_equalArrayRef(ArrayRef *a, ArrayRef *b)
+static bool
+_equalArrayRef(ArrayRef * a, ArrayRef * b)
{
- if (a->refelemtype != b->refelemtype)
- return (false);
- if (a->refattrlength != b->refattrlength)
- return (false);
- if (a->refelemlength != b->refelemlength)
- return (false);
- if (a->refelembyval != b->refelembyval)
- return (false);
- if (!equal(a->refupperindexpr, b->refupperindexpr))
- return (false);
- if (!equal(a->reflowerindexpr, b->reflowerindexpr))
- return (false);
- if (!equal(a->refexpr, b->refexpr))
- return (false);
- return (equal(a->refassgnexpr, b->refassgnexpr));
+ if (a->refelemtype != b->refelemtype)
+ return (false);
+ if (a->refattrlength != b->refattrlength)
+ return (false);
+ if (a->refelemlength != b->refelemlength)
+ return (false);
+ if (a->refelembyval != b->refelembyval)
+ return (false);
+ if (!equal(a->refupperindexpr, b->refupperindexpr))
+ return (false);
+ if (!equal(a->reflowerindexpr, b->reflowerindexpr))
+ return (false);
+ if (!equal(a->refexpr, b->refexpr))
+ return (false);
+ return (equal(a->refassgnexpr, b->refassgnexpr));
}
/*
- * Oper is a subclass of Expr.
+ * Oper is a subclass of Expr.
*/
-static bool
-_equalOper(Oper *a, Oper *b)
+static bool
+_equalOper(Oper * a, Oper * b)
{
- if (a->opno != b->opno)
- return (false);
- if (a->opresulttype != b->opresulttype)
- return (false);
-
- return (true);
+ if (a->opno != b->opno)
+ return (false);
+ if (a->opresulttype != b->opresulttype)
+ return (false);
+
+ return (true);
}
/*
- * Const is a subclass of Expr.
+ * Const is a subclass of Expr.
*/
-static bool
-_equalConst(Const *a, Const *b)
+static bool
+_equalConst(Const * a, Const * b)
{
- /*
- ** this function used to do a pointer compare on a and b. That's
- ** ridiculous. -- JMH, 7/11/92
- */
- if (a->consttype != b->consttype)
- return(false);
- if (a->constlen != b->constlen)
- return(false);
- if (a->constisnull != b->constisnull)
- return(false);
- if (a->constbyval != b->constbyval)
- return(false);
- return(datumIsEqual(a->constvalue, b->constvalue,
- a->consttype, a->constbyval, a->constlen));
+
+ /*
+ * * this function used to do a pointer compare on a and b. That's *
+ * ridiculous. -- JMH, 7/11/92
+ */
+ if (a->consttype != b->consttype)
+ return (false);
+ if (a->constlen != b->constlen)
+ return (false);
+ if (a->constisnull != b->constisnull)
+ return (false);
+ if (a->constbyval != b->constbyval)
+ return (false);
+ return (datumIsEqual(a->constvalue, b->constvalue,
+ a->consttype, a->constbyval, a->constlen));
}
/*
- * Param is a subclass of Expr.
+ * Param is a subclass of Expr.
*/
-static bool
-_equalParam(Param *a, Param *b)
+static bool
+_equalParam(Param * a, Param * b)
{
- if (a->paramkind != b->paramkind)
- return (false);
- if (a->paramtype != b->paramtype)
- return (false);
- if (!equal(a->param_tlist, b->param_tlist))
- return (false);
-
- switch (a->paramkind) {
- case PARAM_NAMED:
- case PARAM_NEW:
- case PARAM_OLD:
- if (strcmp(a->paramname, b->paramname) != 0)
- return (false);
- break;
- case PARAM_NUM:
- if (a->paramid != b->paramid)
- return (false);
- break;
- case PARAM_INVALID:
- /*
- * XXX: Hmmm... What are we supposed to return
- * in this case ??
- */
- return(true);
- break;
- default:
- elog(WARN, "_equalParam: Invalid paramkind value: %d",
- a->paramkind);
- }
-
- return (true);
+ if (a->paramkind != b->paramkind)
+ return (false);
+ if (a->paramtype != b->paramtype)
+ return (false);
+ if (!equal(a->param_tlist, b->param_tlist))
+ return (false);
+
+ switch (a->paramkind)
+ {
+ case PARAM_NAMED:
+ case PARAM_NEW:
+ case PARAM_OLD:
+ if (strcmp(a->paramname, b->paramname) != 0)
+ return (false);
+ break;
+ case PARAM_NUM:
+ if (a->paramid != b->paramid)
+ return (false);
+ break;
+ case PARAM_INVALID:
+
+ /*
+ * XXX: Hmmm... What are we supposed to return in this case ??
+ */
+ return (true);
+ break;
+ default:
+ elog(WARN, "_equalParam: Invalid paramkind value: %d",
+ a->paramkind);
+ }
+
+ return (true);
}
/*
- * Func is a subclass of Expr.
+ * Func is a subclass of Expr.
*/
-static bool
-_equalFunc(Func *a, Func *b)
+static bool
+_equalFunc(Func * a, Func * b)
{
- if (a->funcid != b->funcid)
- return (false);
- if (a->functype != b->functype)
- return (false);
- if (a->funcisindex != b->funcisindex)
- return (false);
- if (a->funcsize != b->funcsize)
- return (false);
- if (!equal(a->func_tlist, b->func_tlist))
- return (false);
- if (!equal(a->func_planlist, b->func_planlist))
- return (false);
-
- return (true);
+ if (a->funcid != b->funcid)
+ return (false);
+ if (a->functype != b->functype)
+ return (false);
+ if (a->funcisindex != b->funcisindex)
+ return (false);
+ if (a->funcsize != b->funcsize)
+ return (false);
+ if (!equal(a->func_tlist, b->func_tlist))
+ return (false);
+ if (!equal(a->func_planlist, b->func_planlist))
+ return (false);
+
+ return (true);
}
/*
* CInfo is a subclass of Node.
*/
-static bool
-_equalCInfo(CInfo *a, CInfo *b)
+static bool
+_equalCInfo(CInfo * a, CInfo * b)
{
- Assert(IsA(a,CInfo));
- Assert(IsA(b,CInfo));
-
- if (!equal(a->clause, b->clause))
- return(false);
- if (a->selectivity != b->selectivity)
- return(false);
- if (a->notclause != b->notclause)
- return(false);
+ Assert(IsA(a, CInfo));
+ Assert(IsA(b, CInfo));
+
+ if (!equal(a->clause, b->clause))
+ return (false);
+ if (a->selectivity != b->selectivity)
+ return (false);
+ if (a->notclause != b->notclause)
+ return (false);
#ifdef EqualMergeOrderExists
- if (!EqualMergeOrder(a->mergesortorder,b->mergesortorder))
- return(false);
+ if (!EqualMergeOrder(a->mergesortorder, b->mergesortorder))
+ return (false);
#endif
- if(a->hashjoinoperator != b->hashjoinoperator)
- return(false);
- return(equal((a->indexids),
- (b->indexids)));
+ if (a->hashjoinoperator != b->hashjoinoperator)
+ return (false);
+ return (equal((a->indexids),
+ (b->indexids)));
}
-static bool
-_equalJoinMethod(JoinMethod *a, JoinMethod *b)
+static bool
+_equalJoinMethod(JoinMethod * a, JoinMethod * b)
{
- Assert(IsA(a,JoinMethod));
- Assert(IsA(b,JoinMethod));
-
- if (!equal((a->jmkeys),
- (b->jmkeys)))
- return(false);
- if (!equal((a->clauses),
- (b->clauses)))
- return(false);
- return(true);
+ Assert(IsA(a, JoinMethod));
+ Assert(IsA(b, JoinMethod));
+
+ if (!equal((a->jmkeys),
+ (b->jmkeys)))
+ return (false);
+ if (!equal((a->clauses),
+ (b->clauses)))
+ return (false);
+ return (true);
}
-static bool
-_equalPath(Path *a, Path *b)
+static bool
+_equalPath(Path * a, Path * b)
{
- if (a->pathtype != b->pathtype)
- return(false);
- if (a->parent != b->parent)
- return(false);
- /*
- if (a->path_cost != b->path_cost)
- return(false);
- */
- if (a->p_ordering.ordtype == SORTOP_ORDER) {
- int i = 0;
- if (a->p_ordering.ord.sortop==NULL ||
- b->p_ordering.ord.sortop==NULL) {
-
- if (a->p_ordering.ord.sortop != b->p_ordering.ord.sortop)
- return false;
- } else {
- while(a->p_ordering.ord.sortop[i]!=0 &&
- b->p_ordering.ord.sortop[i]!=0) {
- if (a->p_ordering.ord.sortop[i] != b->p_ordering.ord.sortop[i])
- return false;
- i++;
- }
- if (a->p_ordering.ord.sortop[i]!=0 ||
- b->p_ordering.ord.sortop[i]!=0)
- return false;
+ if (a->pathtype != b->pathtype)
+ return (false);
+ if (a->parent != b->parent)
+ return (false);
+
+ /*
+ * if (a->path_cost != b->path_cost) return(false);
+ */
+ if (a->p_ordering.ordtype == SORTOP_ORDER)
+ {
+ int i = 0;
+
+ if (a->p_ordering.ord.sortop == NULL ||
+ b->p_ordering.ord.sortop == NULL)
+ {
+
+ if (a->p_ordering.ord.sortop != b->p_ordering.ord.sortop)
+ return false;
+ }
+ else
+ {
+ while (a->p_ordering.ord.sortop[i] != 0 &&
+ b->p_ordering.ord.sortop[i] != 0)
+ {
+ if (a->p_ordering.ord.sortop[i] != b->p_ordering.ord.sortop[i])
+ return false;
+ i++;
+ }
+ if (a->p_ordering.ord.sortop[i] != 0 ||
+ b->p_ordering.ord.sortop[i] != 0)
+ return false;
+ }
+ }
+ else
+ {
+ if (!equal((a->p_ordering.ord.merge),
+ (b->p_ordering.ord.merge)))
+ return (false);
}
- } else {
- if (!equal((a->p_ordering.ord.merge),
- (b->p_ordering.ord.merge)))
- return(false);
- }
- if (!equal((a->keys),
- (b->keys)))
- return(false);
- /*
- if (a->outerjoincost != b->outerjoincost)
- return(false);
- */
- if (!equali((a->joinid),
- (b->joinid)))
- return(false);
- return(true);
+ if (!equal((a->keys),
+ (b->keys)))
+ return (false);
+
+ /*
+ * if (a->outerjoincost != b->outerjoincost) return(false);
+ */
+ if (!equali((a->joinid),
+ (b->joinid)))
+ return (false);
+ return (true);
}
-static bool
-_equalIndexPath(IndexPath *a, IndexPath *b)
+static bool
+_equalIndexPath(IndexPath * a, IndexPath * b)
{
- if (!_equalPath((Path*)a,(Path*)b))
- return(false);
- if (!equali((a->indexid), (b->indexid)))
- return(false);
- if (!equal((a->indexqual), (b->indexqual)))
- return(false);
- return(true);
+ if (!_equalPath((Path *) a, (Path *) b))
+ return (false);
+ if (!equali((a->indexid), (b->indexid)))
+ return (false);
+ if (!equal((a->indexqual), (b->indexqual)))
+ return (false);
+ return (true);
}
-static bool
-_equalJoinPath(JoinPath *a,JoinPath *b)
+static bool
+_equalJoinPath(JoinPath * a, JoinPath * b)
{
- Assert(IsA_JoinPath(a));
- Assert(IsA_JoinPath(b));
-
- if (!_equalPath((Path*)a,(Path*)b))
- return(false);
- if (!equal((a->pathclauseinfo), (b->pathclauseinfo)))
- return(false);
- if (!equal((a->outerjoinpath), (b->outerjoinpath)))
- return(false);
- if (!equal((a->innerjoinpath), (b->innerjoinpath)))
- return(false);
- return(true);
+ Assert(IsA_JoinPath(a));
+ Assert(IsA_JoinPath(b));
+
+ if (!_equalPath((Path *) a, (Path *) b))
+ return (false);
+ if (!equal((a->pathclauseinfo), (b->pathclauseinfo)))
+ return (false);
+ if (!equal((a->outerjoinpath), (b->outerjoinpath)))
+ return (false);
+ if (!equal((a->innerjoinpath), (b->innerjoinpath)))
+ return (false);
+ return (true);
}
-static bool
-_equalMergePath(MergePath *a, MergePath *b)
+static bool
+_equalMergePath(MergePath * a, MergePath * b)
{
- Assert(IsA(a,MergePath));
- Assert(IsA(b,MergePath));
-
- if (!_equalJoinPath((JoinPath*)a,(JoinPath*)b))
- return(false);
- if (!equal((a->path_mergeclauses), (b->path_mergeclauses)))
- return(false);
- if (!equal((a->outersortkeys), (b->outersortkeys)))
- return(false);
- if (!equal((a->innersortkeys), (b->innersortkeys)))
- return(false);
- return(true);
+ Assert(IsA(a, MergePath));
+ Assert(IsA(b, MergePath));
+
+ if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
+ return (false);
+ if (!equal((a->path_mergeclauses), (b->path_mergeclauses)))
+ return (false);
+ if (!equal((a->outersortkeys), (b->outersortkeys)))
+ return (false);
+ if (!equal((a->innersortkeys), (b->innersortkeys)))
+ return (false);
+ return (true);
}
-static bool
-_equalHashPath(HashPath *a, HashPath *b)
+static bool
+_equalHashPath(HashPath * a, HashPath * b)
{
- Assert(IsA(a,HashPath));
- Assert(IsA(b,HashPath));
-
- if (!_equalJoinPath((JoinPath*)a,(JoinPath*)b))
- return(false);
- if (!equal((a->path_hashclauses), (b->path_hashclauses)))
- return(false);
- if (!equal((a->outerhashkeys), (b->outerhashkeys)))
- return(false);
- if (!equal((a->innerhashkeys), (b->innerhashkeys)))
- return(false);
- return(true);
+ Assert(IsA(a, HashPath));
+ Assert(IsA(b, HashPath));
+
+ if (!_equalJoinPath((JoinPath *) a, (JoinPath *) b))
+ return (false);
+ if (!equal((a->path_hashclauses), (b->path_hashclauses)))
+ return (false);
+ if (!equal((a->outerhashkeys), (b->outerhashkeys)))
+ return (false);
+ if (!equal((a->innerhashkeys), (b->innerhashkeys)))
+ return (false);
+ return (true);
}
-static bool
-_equalJoinKey(JoinKey *a, JoinKey *b)
+static bool
+_equalJoinKey(JoinKey * a, JoinKey * b)
{
- Assert(IsA(a,JoinKey));
- Assert(IsA(b,JoinKey));
-
- if (!equal((a->outer),(b->outer)))
- return(false);
- if (!equal((a->inner),(b->inner)))
- return(false);
- return(true);
+ Assert(IsA(a, JoinKey));
+ Assert(IsA(b, JoinKey));
+
+ if (!equal((a->outer), (b->outer)))
+ return (false);
+ if (!equal((a->inner), (b->inner)))
+ return (false);
+ return (true);
}
-static bool
-_equalMergeOrder(MergeOrder *a, MergeOrder *b)
+static bool
+_equalMergeOrder(MergeOrder * a, MergeOrder * b)
{
- if (a == (MergeOrder*)NULL && b == (MergeOrder*)NULL)
- return(true);
- Assert(IsA(a,MergeOrder));
- Assert(IsA(b,MergeOrder));
-
- if (a->join_operator != b->join_operator)
- return(false);
- if (a->left_operator != b->left_operator)
- return(false);
- if (a->right_operator != b->right_operator)
- return(false);
- if (a->left_type != b->left_type)
- return(false);
- if (a->right_type != b->right_type)
- return(false);
- return(true);
+ if (a == (MergeOrder *) NULL && b == (MergeOrder *) NULL)
+ return (true);
+ Assert(IsA(a, MergeOrder));
+ Assert(IsA(b, MergeOrder));
+
+ if (a->join_operator != b->join_operator)
+ return (false);
+ if (a->left_operator != b->left_operator)
+ return (false);
+ if (a->right_operator != b->right_operator)
+ return (false);
+ if (a->left_type != b->left_type)
+ return (false);
+ if (a->right_type != b->right_type)
+ return (false);
+ return (true);
}
-static bool
-_equalHInfo(HInfo *a, HInfo *b)
+static bool
+_equalHInfo(HInfo * a, HInfo * b)
{
- Assert(IsA(a,HInfo));
- Assert(IsA(b,HInfo));
-
- if (a->hashop != b->hashop)
- return(false);
- return(true);
+ Assert(IsA(a, HInfo));
+ Assert(IsA(b, HInfo));
+
+ if (a->hashop != b->hashop)
+ return (false);
+ return (true);
}
-/* XXX This equality function is a quick hack, should be
- * fixed to compare all fields.
+/* XXX This equality function is a quick hack, should be
+ * fixed to compare all fields.
*/
-static bool
-_equalIndexScan(IndexScan *a, IndexScan *b)
+static bool
+_equalIndexScan(IndexScan * a, IndexScan * b)
{
- Assert(IsA(a,IndexScan));
- Assert(IsA(b,IndexScan));
-
- /*
- if(a->scan.plan.cost != b->scan.plan.cost)
- return(false);
- */
-
- if (!equal((a->indxqual),(b->indxqual)))
- return(false);
-
- if (a->scan.scanrelid != b->scan.scanrelid)
- return(false);
-
- if (!equali((a->indxid),(b->indxid)))
- return(false);
- return(true);
+ Assert(IsA(a, IndexScan));
+ Assert(IsA(b, IndexScan));
+
+ /*
+ * if(a->scan.plan.cost != b->scan.plan.cost) return(false);
+ */
+
+ if (!equal((a->indxqual), (b->indxqual)))
+ return (false);
+
+ if (a->scan.scanrelid != b->scan.scanrelid)
+ return (false);
+
+ if (!equali((a->indxid), (b->indxid)))
+ return (false);
+ return (true);
}
-static bool
-_equalJInfo(JInfo *a, JInfo *b)
+static bool
+_equalJInfo(JInfo * a, JInfo * b)
{
- Assert(IsA(a,JInfo));
- Assert(IsA(b,JInfo));
- if (!equal((a->otherrels),(b->otherrels)))
- return(false);
- if (!equal((a->jinfoclauseinfo),(b->jinfoclauseinfo)))
- return(false);
- if (a->mergesortable != b->mergesortable)
- return(false);
- if (a->hashjoinable != b->hashjoinable)
- return(false);
- return(true);
+ Assert(IsA(a, JInfo));
+ Assert(IsA(b, JInfo));
+ if (!equal((a->otherrels), (b->otherrels)))
+ return (false);
+ if (!equal((a->jinfoclauseinfo), (b->jinfoclauseinfo)))
+ return (false);
+ if (a->mergesortable != b->mergesortable)
+ return (false);
+ if (a->hashjoinable != b->hashjoinable)
+ return (false);
+ return (true);
}
/*
- * Stuff from execnodes.h
+ * Stuff from execnodes.h
*/
/*
- * EState is a subclass of Node.
+ * EState is a subclass of Node.
*/
-static bool
-_equalEState(EState *a, EState *b)
+static bool
+_equalEState(EState * a, EState * b)
{
- if (a->es_direction != b->es_direction)
- return (false);
-
- if (!equal(a->es_range_table, b->es_range_table))
- return (false);
-
- if (a->es_result_relation_info != b->es_result_relation_info)
- return (false);
-
- return (true);
+ if (a->es_direction != b->es_direction)
+ return (false);
+
+ if (!equal(a->es_range_table, b->es_range_table))
+ return (false);
+
+ if (a->es_result_relation_info != b->es_result_relation_info)
+ return (false);
+
+ return (true);
}
-static bool
-_equalTargetEntry(TargetEntry *a, TargetEntry *b)
+static bool
+_equalTargetEntry(TargetEntry * a, TargetEntry * b)
{
- if (!equal(a->resdom,b->resdom))
- return(false);
- if (!equal(a->fjoin,b->fjoin))
- return(false);
- if (!equal(a->expr,b->expr))
- return(false);
-
- return(true);
+ if (!equal(a->resdom, b->resdom))
+ return (false);
+ if (!equal(a->fjoin, b->fjoin))
+ return (false);
+ if (!equal(a->expr, b->expr))
+ return (false);
+
+ return (true);
}
/*
- * equal -- are two lists equal?
+ * equal -- are two lists equal?
*
- * This is a comparison by value. It would be simpler to write it
- * to be recursive, but it should run faster if we iterate.
+ * This is a comparison by value. It would be simpler to write it
+ * to be recursive, but it should run faster if we iterate.
*/
-static bool
-_equalValue(Value *a, Value *b)
+static bool
+_equalValue(Value * a, Value * b)
{
- if (a->type != b->type)
- return (false);
-
- switch(a->type) {
- case T_String:
- return strcmp(a->val.str, b->val.str);
- case T_Integer:
- return (a->val.ival==b->val.ival);
- case T_Float:
- return (a->val.dval==b->val.dval);
- default:
- break;
- }
-
- return (true);
+ if (a->type != b->type)
+ return (false);
+
+ switch (a->type)
+ {
+ case T_String:
+ return strcmp(a->val.str, b->val.str);
+ case T_Integer:
+ return (a->val.ival == b->val.ival);
+ case T_Float:
+ return (a->val.dval == b->val.dval);
+ default:
+ break;
+ }
+
+ return (true);
}
/*
* equal--
- * returns whether two nodes are equal
+ * returns whether two nodes are equal
*/
bool
equal(void *a, void *b)
{
- bool retval=false;
-
- if (a == b)
- return(true);
- /*
- * note that a!=b, so only one of them can be NULL
- */
- if (a==NULL || b==NULL)
- return (false);
- /*
- * are they the same type of nodes?
- */
- if (nodeTag(a)!=nodeTag(b))
- return (false);
-
- switch(nodeTag(a)) {
- case T_Resdom:
- retval = _equalResdom(a, b);
- break;
- case T_Fjoin:
- retval = _equalFjoin(a, b);
- break;
- case T_Expr:
- retval = _equalExpr(a, b);
- break;
- case T_TargetEntry:
- retval = _equalTargetEntry(a,b);
- break;
- case T_Iter:
- retval = _equalIter(a, b);
- break;
- case T_Stream:
- retval = _equalStream(a, b);
- break;
- case T_Var:
- retval = _equalVar(a, b);
- break;
- case T_Array:
- retval = _equalArray(a, b);
- break;
- case T_ArrayRef:
- retval = _equalArrayRef(a, b);
- break;
- case T_Oper:
- retval = _equalOper(a, b);
- break;
- case T_Const:
- retval = _equalConst(a, b);
- break;
- case T_Param:
- retval = _equalParam(a, b);
- break;
- case T_Func:
- retval = _equalFunc(a, b);
- break;
- case T_CInfo:
- retval = _equalCInfo(a, b);
- break;
- case T_JoinMethod:
- retval = _equalJoinMethod(a, b);
- break;
- case T_Path:
- retval = _equalPath(a, b);
- break;
- case T_IndexPath:
- retval = _equalIndexPath(a, b);
- break;
- case T_JoinPath:
- retval = _equalJoinPath(a, b);
- break;
- case T_MergePath:
- retval = _equalMergePath(a, b);
- break;
- case T_HashPath:
- retval = _equalHashPath(a, b);
- break;
- case T_JoinKey:
- retval = _equalJoinKey(a, b);
- break;
- case T_MergeOrder:
- retval = _equalMergeOrder(a, b);
- break;
- case T_HInfo:
- retval = _equalHInfo(a, b);
- break;
- case T_IndexScan:
- retval = _equalIndexScan(a, b);
- break;
- case T_JInfo:
- retval = _equalJInfo(a, b);
- break;
- case T_EState:
- retval = _equalEState(a, b);
- break;
- case T_Integer: case T_String: case T_Float:
- retval = _equalValue(a, b);
- break;
- case T_List:
- {
- List *la = (List*)a;
- List *lb = (List*)b;
- List *l;
+ bool retval = false;
- if (a==NULL && b==NULL)
+ if (a == b)
return (true);
- if (length(a)!=length(b))
+
+ /*
+ * note that a!=b, so only one of them can be NULL
+ */
+ if (a == NULL || b == NULL)
return (false);
- foreach(l, la) {
- if (!equal(lfirst(l), lfirst(lb)))
- return (false);
- lb = lnext(lb);
- }
- retval = true;
+
+ /*
+ * are they the same type of nodes?
+ */
+ if (nodeTag(a) != nodeTag(b))
+ return (false);
+
+ switch (nodeTag(a))
+ {
+ case T_Resdom:
+ retval = _equalResdom(a, b);
+ break;
+ case T_Fjoin:
+ retval = _equalFjoin(a, b);
+ break;
+ case T_Expr:
+ retval = _equalExpr(a, b);
+ break;
+ case T_TargetEntry:
+ retval = _equalTargetEntry(a, b);
+ break;
+ case T_Iter:
+ retval = _equalIter(a, b);
+ break;
+ case T_Stream:
+ retval = _equalStream(a, b);
+ break;
+ case T_Var:
+ retval = _equalVar(a, b);
+ break;
+ case T_Array:
+ retval = _equalArray(a, b);
+ break;
+ case T_ArrayRef:
+ retval = _equalArrayRef(a, b);
+ break;
+ case T_Oper:
+ retval = _equalOper(a, b);
+ break;
+ case T_Const:
+ retval = _equalConst(a, b);
+ break;
+ case T_Param:
+ retval = _equalParam(a, b);
+ break;
+ case T_Func:
+ retval = _equalFunc(a, b);
+ break;
+ case T_CInfo:
+ retval = _equalCInfo(a, b);
+ break;
+ case T_JoinMethod:
+ retval = _equalJoinMethod(a, b);
+ break;
+ case T_Path:
+ retval = _equalPath(a, b);
+ break;
+ case T_IndexPath:
+ retval = _equalIndexPath(a, b);
+ break;
+ case T_JoinPath:
+ retval = _equalJoinPath(a, b);
+ break;
+ case T_MergePath:
+ retval = _equalMergePath(a, b);
+ break;
+ case T_HashPath:
+ retval = _equalHashPath(a, b);
+ break;
+ case T_JoinKey:
+ retval = _equalJoinKey(a, b);
+ break;
+ case T_MergeOrder:
+ retval = _equalMergeOrder(a, b);
+ break;
+ case T_HInfo:
+ retval = _equalHInfo(a, b);
+ break;
+ case T_IndexScan:
+ retval = _equalIndexScan(a, b);
+ break;
+ case T_JInfo:
+ retval = _equalJInfo(a, b);
+ break;
+ case T_EState:
+ retval = _equalEState(a, b);
+ break;
+ case T_Integer:
+ case T_String:
+ case T_Float:
+ retval = _equalValue(a, b);
+ break;
+ case T_List:
+ {
+ List *la = (List *) a;
+ List *lb = (List *) b;
+ List *l;
+
+ if (a == NULL && b == NULL)
+ return (true);
+ if (length(a) != length(b))
+ return (false);
+ foreach(l, la)
+ {
+ if (!equal(lfirst(l), lfirst(lb)))
+ return (false);
+ lb = lnext(lb);
+ }
+ retval = true;
+ }
+ break;
+ default:
+ elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
+ nodeTag(a));
+ break;
}
- break;
- default:
- elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
- nodeTag(a));
- break;
- }
-
- return retval;
+
+ return retval;
}
/*
* equali--
- * compares two lists of integers
+ * compares two lists of integers
*
* XXX temp hack. needs something like T_IntList
*/
-static bool
-equali(List *a, List *b)
-{
- List *la = (List*)a;
- List *lb = (List*)b;
- List *l;
-
- if (a==NULL && b==NULL)
- return (true);
- if (length(a)!=length(b))
- return (false);
- foreach(l, la) {
- if (lfirsti(l) != lfirsti(lb))
- return (false);
- lb = lnext(lb);
- }
- return true;
+static bool
+equali(List * a, List * b)
+{
+ List *la = (List *) a;
+ List *lb = (List *) b;
+ List *l;
+
+ if (a == NULL && b == NULL)
+ return (true);
+ if (length(a) != length(b))
+ return (false);
+ foreach(l, la)
+ {
+ if (lfirsti(l) != lfirsti(lb))
+ return (false);
+ lb = lnext(lb);
+ }
+ return true;
}
diff --git a/src/backend/nodes/list.c b/src/backend/nodes/list.c
index 6dc010eff65..334030822f7 100644
--- a/src/backend/nodes/list.c
+++ b/src/backend/nodes/list.c
@@ -1,23 +1,23 @@
/*-------------------------------------------------------------------------
*
* list.c--
- * various list handling routines
+ * various list handling routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.4 1997/08/19 21:31:39 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.5 1997/09/07 04:42:46 momjian Exp $
*
* NOTES
- * XXX a few of the following functions are duplicated to handle
- * List of pointers and List of integers separately. Some day,
- * someone should unify them. - ay 11/2/94
- * This file needs cleanup.
+ * XXX a few of the following functions are duplicated to handle
+ * List of pointers and List of integers separately. Some day,
+ * someone should unify them. - ay 11/2/94
+ * This file needs cleanup.
*
* HISTORY
- * AUTHOR DATE MAJOR EVENT
- * Andrew Yu Oct, 1994 file creation
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Oct, 1994 file creation
*
*-------------------------------------------------------------------------
*/
@@ -25,442 +25,483 @@
#include "postgres.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
-#include "utils/builtins.h" /* for namecpy */
+#include "utils/builtins.h" /* for namecpy */
#include "utils/elog.h"
#include "utils/palloc.h"
-List *
-makeList(void *elem, ...)
+List *
+makeList(void *elem,...)
{
- va_list args;
- List *retval = NIL;
- List *temp = NIL;
- List *tempcons = NIL;
-
- va_start(args, elem);
-
- temp = elem;
- while (temp != (void *) -1) {
- temp = lcons(temp, NIL);
- if (tempcons == NIL)
- retval = temp;
- else
- lnext(tempcons) = temp;
- tempcons = temp;
-
- temp = va_arg(args, void *);
- }
+ va_list args;
+ List *retval = NIL;
+ List *temp = NIL;
+ List *tempcons = NIL;
+
+ va_start(args, elem);
+
+ temp = elem;
+ while (temp != (void *) -1)
+ {
+ temp = lcons(temp, NIL);
+ if (tempcons == NIL)
+ retval = temp;
+ else
+ lnext(tempcons) = temp;
+ tempcons = temp;
+
+ temp = va_arg(args, void *);
+ }
- va_end(args);
+ va_end(args);
- return (retval);
+ return (retval);
}
-List *
-lcons(void *obj, List *list)
+List *
+lcons(void *obj, List * list)
{
- List *l = makeNode(List);
- lfirst(l) = obj;
- lnext(l) = list;
- return l;
+ List *l = makeNode(List);
+
+ lfirst(l) = obj;
+ lnext(l) = list;
+ return l;
}
-List *
-lconsi(int datum, List *list)
+List *
+lconsi(int datum, List * list)
{
- List *l = makeNode(List);
- lfirsti(l) = datum;
- lnext(l) = list;
- return l;
+ List *l = makeNode(List);
+
+ lfirsti(l) = datum;
+ lnext(l) = list;
+ return l;
}
-List *
-lappend(List *list, void *obj)
+List *
+lappend(List * list, void *obj)
{
- return nconc(list, lcons(obj, NIL));
+ return nconc(list, lcons(obj, NIL));
}
-List *
-lappendi(List *list, int datum)
+List *
+lappendi(List * list, int datum)
{
- return nconc(list, lconsi(datum, NIL));
+ return nconc(list, lconsi(datum, NIL));
}
-Value *
+Value *
makeInteger(long i)
{
- Value *v = makeNode(Value);
- v->type = T_Integer;
- v->val.ival = i;
- return v;
+ Value *v = makeNode(Value);
+
+ v->type = T_Integer;
+ v->val.ival = i;
+ return v;
}
-Value *
+Value *
makeFloat(double d)
{
- Value *v = makeNode(Value);
- v->type = T_Float;
- v->val.dval = d;
- return v;
+ Value *v = makeNode(Value);
+
+ v->type = T_Float;
+ v->val.dval = d;
+ return v;
}
-Value *
+Value *
makeString(char *str)
{
- Value *v = makeNode(Value);
- v->type = T_String;
- v->val.str = str;
- return v;
+ Value *v = makeNode(Value);
+
+ v->type = T_String;
+ v->val.str = str;
+ return v;
}
/* n starts with 0 */
-void *
-nth(int n, List *l)
+void *
+nth(int n, List * l)
{
- /* XXX assume list is long enough */
- while(n > 0) {
- l = lnext(l);
- n--;
- }
- return lfirst(l);
+ /* XXX assume list is long enough */
+ while (n > 0)
+ {
+ l = lnext(l);
+ n--;
+ }
+ return lfirst(l);
}
int
-nthi(int n, List *l)
+nthi(int n, List * l)
{
- /* XXX assume list is long enough */
- while(n > 0) {
- l = lnext(l);
- n--;
- }
- return lfirsti(l);
+ /* XXX assume list is long enough */
+ while (n > 0)
+ {
+ l = lnext(l);
+ n--;
+ }
+ return lfirsti(l);
}
/* this is here solely for rt_store. Get rid of me some day! */
void
-set_nth(List *l, int n, void *elem)
+set_nth(List * l, int n, void *elem)
{
- /* XXX assume list is long enough */
- while(n > 0) {
- l = lnext(l);
- n--;
- }
- lfirst(l) = elem;
- return;
+ /* XXX assume list is long enough */
+ while (n > 0)
+ {
+ l = lnext(l);
+ n--;
+ }
+ lfirst(l) = elem;
+ return;
}
int
-length(List *l)
+length(List * l)
{
- int i=0;
- while(l!=NIL) {
- l = lnext(l);
- i++;
- }
- return i;
+ int i = 0;
+
+ while (l != NIL)
+ {
+ l = lnext(l);
+ i++;
+ }
+ return i;
}
void
-freeList(List *list)
+freeList(List * list)
{
- while(list!=NIL) {
- List *l = list;
- list = lnext(list);
- pfree(l);
- }
+ while (list != NIL)
+ {
+ List *l = list;
+
+ list = lnext(list);
+ pfree(l);
+ }
}
/*
* below are for backwards compatibility
*/
-List *
-append(List *l1, List *l2)
+List *
+append(List * l1, List * l2)
{
- List *newlist, *newlist2, *p;
+ List *newlist,
+ *newlist2,
+ *p;
- if (l1==NIL)
- return copyObject(l2);
+ if (l1 == NIL)
+ return copyObject(l2);
- newlist = copyObject(l1);
- newlist2 = copyObject(l2);
+ newlist = copyObject(l1);
+ newlist2 = copyObject(l2);
- for (p=newlist; lnext(p)!=NIL; p=lnext(p))
- ;
- lnext(p) = newlist2;
- return newlist;
+ for (p = newlist; lnext(p) != NIL; p = lnext(p))
+ ;
+ lnext(p) = newlist2;
+ return newlist;
}
/*
* below are for backwards compatibility
*/
-List *
-intAppend(List *l1, List *l2)
+List *
+intAppend(List * l1, List * l2)
{
- List *newlist, *newlist2, *p;
+ List *newlist,
+ *newlist2,
+ *p;
- if (l1==NIL)
- return listCopy(l2);
+ if (l1 == NIL)
+ return listCopy(l2);
- newlist = listCopy(l1);
- newlist2 = listCopy(l2);
+ newlist = listCopy(l1);
+ newlist2 = listCopy(l2);
- for (p=newlist; lnext(p)!=NIL; p=lnext(p))
- ;
- lnext(p) = newlist2;
- return newlist;
+ for (p = newlist; lnext(p) != NIL; p = lnext(p))
+ ;
+ lnext(p) = newlist2;
+ return newlist;
}
-List *
-nconc(List *l1, List *l2)
+List *
+nconc(List * l1, List * l2)
{
- List *temp;
-
- if (l1 == NIL)
- return l2;
- if (l2 == NIL)
- return l1;
- if (l1 == l2)
- elog(WARN, "tryout to nconc a list to itself");
-
- for (temp = l1; lnext(temp)!=NULL; temp = lnext(temp))
- ;
-
- lnext(temp) = l2;
- return(l1); /* list1 is now list1[]list2 */
+ List *temp;
+
+ if (l1 == NIL)
+ return l2;
+ if (l2 == NIL)
+ return l1;
+ if (l1 == l2)
+ elog(WARN, "tryout to nconc a list to itself");
+
+ for (temp = l1; lnext(temp) != NULL; temp = lnext(temp))
+ ;
+
+ lnext(temp) = l2;
+ return (l1); /* list1 is now list1[]list2 */
}
-List *
-nreverse(List *list)
+List *
+nreverse(List * list)
{
- List *rlist = NIL;
- List *p = NIL;
-
- if(list==NULL)
- return(NIL);
-
- if (length(list) == 1)
- return(list);
-
- for (p = list; p!=NULL; p = lnext(p)) {
- rlist = lcons(lfirst(p),rlist);
- }
-
- lfirst(list) = lfirst(rlist);
- lnext(list) = lnext(rlist);
- return(list);
+ List *rlist = NIL;
+ List *p = NIL;
+
+ if (list == NULL)
+ return (NIL);
+
+ if (length(list) == 1)
+ return (list);
+
+ for (p = list; p != NULL; p = lnext(p))
+ {
+ rlist = lcons(lfirst(p), rlist);
+ }
+
+ lfirst(list) = lfirst(rlist);
+ lnext(list) = lnext(rlist);
+ return (list);
}
-/*
- * same
- *
- * Returns t if two lists contain the same elements.
- * now defined in lispdep.c
+/*
+ * same
+ *
+ * Returns t if two lists contain the same elements.
+ * now defined in lispdep.c
*
* XXX only good for IntList -ay
*/
bool
-same(List *foo, List *bar)
+same(List * foo, List * bar)
{
- List *temp = NIL;
-
- if (foo == NULL)
- return (bar==NULL);
- if (bar == NULL)
- return (foo==NULL);
- if (length(foo) == length(bar)) {
- foreach (temp,foo) {
- if (!intMember(lfirsti(temp),bar))
- return(false);
+ List *temp = NIL;
+
+ if (foo == NULL)
+ return (bar == NULL);
+ if (bar == NULL)
+ return (foo == NULL);
+ if (length(foo) == length(bar))
+ {
+ foreach(temp, foo)
+ {
+ if (!intMember(lfirsti(temp), bar))
+ return (false);
+ }
+ return (true);
}
- return(true);
- }
- return(false);
-
-}
-
-List *
-LispUnion(List *foo, List *bar)
+ return (false);
+
+}
+
+List *
+LispUnion(List * foo, List * bar)
{
- List *retval = NIL;
- List *i = NIL;
- List *j = NIL;
-
- if (foo==NIL)
- return(bar); /* XXX - should be copy of bar */
-
- if (bar==NIL)
- return(foo); /* XXX - should be copy of foo */
-
- foreach (i,foo) {
- foreach (j,bar) {
- if (! equal(lfirst(i), lfirst(j))) {
- retval = lappend(retval,lfirst(i));
- break;
- }
+ List *retval = NIL;
+ List *i = NIL;
+ List *j = NIL;
+
+ if (foo == NIL)
+ return (bar); /* XXX - should be copy of bar */
+
+ if (bar == NIL)
+ return (foo); /* XXX - should be copy of foo */
+
+ foreach(i, foo)
+ {
+ foreach(j, bar)
+ {
+ if (!equal(lfirst(i), lfirst(j)))
+ {
+ retval = lappend(retval, lfirst(i));
+ break;
+ }
+ }
}
- }
- foreach(i,bar) {
- retval = lappend(retval,lfirst(i));
- }
-
- return(retval);
+ foreach(i, bar)
+ {
+ retval = lappend(retval, lfirst(i));
+ }
+
+ return (retval);
}
-List *
-LispUnioni(List *foo, List *bar)
+List *
+LispUnioni(List * foo, List * bar)
{
- List *retval = NIL;
- List *i = NIL;
- List *j = NIL;
-
- if (foo==NIL)
- return(bar); /* XXX - should be copy of bar */
-
- if (bar==NIL)
- return(foo); /* XXX - should be copy of foo */
-
- foreach (i,foo) {
- foreach (j,bar) {
- if (lfirsti(i) != lfirsti(j)) {
- retval = lappendi(retval,lfirsti(i));
- break;
- }
+ List *retval = NIL;
+ List *i = NIL;
+ List *j = NIL;
+
+ if (foo == NIL)
+ return (bar); /* XXX - should be copy of bar */
+
+ if (bar == NIL)
+ return (foo); /* XXX - should be copy of foo */
+
+ foreach(i, foo)
+ {
+ foreach(j, bar)
+ {
+ if (lfirsti(i) != lfirsti(j))
+ {
+ retval = lappendi(retval, lfirsti(i));
+ break;
+ }
+ }
+ }
+ foreach(i, bar)
+ {
+ retval = lappendi(retval, lfirsti(i));
}
- }
- foreach(i,bar) {
- retval = lappendi(retval, lfirsti(i));
- }
-
- return(retval);
+
+ return (retval);
}
/*
* member()
* - nondestructive, returns t iff foo is a member of the list
- * bar
+ * bar
*/
bool
-member(void *foo, List *bar)
+member(void *foo, List * bar)
{
- List *i;
- foreach (i,bar)
- if (equal((Node*)(lfirst(i)),(Node*)foo))
- return(true);
- return(false);
+ List *i;
+
+ foreach(i, bar)
+ if (equal((Node *) (lfirst(i)), (Node *) foo))
+ return (true);
+ return (false);
}
bool
-intMember(int foo, List *bar)
+intMember(int foo, List * bar)
{
- List *i;
- foreach (i,bar)
- if (foo == lfirsti(i))
- return(true);
- return(false);
+ List *i;
+
+ foreach(i, bar)
+ if (foo == lfirsti(i))
+ return (true);
+ return (false);
}
/*
* lremove -
- * only does pointer comparisons. Removes 'elem' from the the linked list.
+ * only does pointer comparisons. Removes 'elem' from the the linked list.
*/
-List *
-lremove(void *elem, List *list)
+List *
+lremove(void *elem, List * list)
{
- List *l;
- List *prev = NIL;
- List *result = list;
-
- foreach(l, list) {
- if (elem == lfirst(l))
- break;
- prev = l;
- }
- if (l!=NULL) {
- if (prev == NIL) {
- result = lnext(list);
- } else {
- lnext(prev) = lnext(l);
+ List *l;
+ List *prev = NIL;
+ List *result = list;
+
+ foreach(l, list)
+ {
+ if (elem == lfirst(l))
+ break;
+ prev = l;
+ }
+ if (l != NULL)
+ {
+ if (prev == NIL)
+ {
+ result = lnext(list);
+ }
+ else
+ {
+ lnext(prev) = lnext(l);
+ }
}
- }
- return result;
+ return result;
}
-
-List *
-LispRemove(void *elem, List *list)
+
+List *
+LispRemove(void *elem, List * list)
{
- List *temp = NIL;
- List *prev = NIL;
-
- if (equal(elem, lfirst(list)))
- return lnext(list);
-
- temp = lnext(list);
- prev = list;
- while(temp!=NIL) {
- if (equal(elem, lfirst(temp))) {
- lnext(prev) = lnext(temp);
- break;
+ List *temp = NIL;
+ List *prev = NIL;
+
+ if (equal(elem, lfirst(list)))
+ return lnext(list);
+
+ temp = lnext(list);
+ prev = list;
+ while (temp != NIL)
+ {
+ if (equal(elem, lfirst(temp)))
+ {
+ lnext(prev) = lnext(temp);
+ break;
+ }
+ temp = lnext(temp);
+ prev = lnext(prev);
}
- temp = lnext(temp);
- prev = lnext(prev);
- }
- return(list);
+ return (list);
}
#ifdef NOT_USED
-List *
-intLispRemove(int elem, List *list)
+List *
+intLispRemove(int elem, List * list)
{
- List *temp = NIL;
- List *prev = NIL;
-
- if (elem == lfirsti(list))
- return lnext(list);
-
- temp = lnext(list);
- prev = list;
- while(temp!=NIL) {
- if (elem == lfirsti(temp)) {
- lnext(prev) = lnext(temp);
- break;
+ List *temp = NIL;
+ List *prev = NIL;
+
+ if (elem == lfirsti(list))
+ return lnext(list);
+
+ temp = lnext(list);
+ prev = list;
+ while (temp != NIL)
+ {
+ if (elem == lfirsti(temp))
+ {
+ lnext(prev) = lnext(temp);
+ break;
+ }
+ temp = lnext(temp);
+ prev = lnext(prev);
}
- temp = lnext(temp);
- prev = lnext(prev);
- }
- return(list);
+ return (list);
}
+
#endif
-List *
-set_difference(List *list1, List *list2)
+List *
+set_difference(List * list1, List * list2)
{
- List *temp1 = NIL;
- List *result = NIL;
-
- if (list2==NIL)
- return(list1);
-
- foreach (temp1, list1) {
- if (!member(lfirst(temp1), list2))
- result = lappend(result, lfirst(temp1));
- }
- return(result);
+ List *temp1 = NIL;
+ List *result = NIL;
+
+ if (list2 == NIL)
+ return (list1);
+
+ foreach(temp1, list1)
+ {
+ if (!member(lfirst(temp1), list2))
+ result = lappend(result, lfirst(temp1));
+ }
+ return (result);
}
-List *
-set_differencei(List *list1, List *list2)
+List *
+set_differencei(List * list1, List * list2)
{
- List *temp1 = NIL;
- List *result = NIL;
-
- if (list2==NIL)
- return(list1);
-
- foreach (temp1, list1) {
- if (!intMember(lfirsti(temp1), list2))
- result = lappendi(result, lfirsti(temp1));
- }
- return(result);
-}
+ List *temp1 = NIL;
+ List *result = NIL;
+
+ if (list2 == NIL)
+ return (list1);
+ foreach(temp1, list1)
+ {
+ if (!intMember(lfirsti(temp1), list2))
+ result = lappendi(result, lfirsti(temp1));
+ }
+ return (result);
+}
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 18894e8a41c..7c5a9efc1fb 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -1,22 +1,22 @@
/*
* makefuncs.c--
- * creator functions for primitive nodes. The functions here are for
- * the most frequently created nodes.
+ * creator functions for primitive nodes. The functions here are for
+ * the most frequently created nodes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.2 1997/01/22 01:42:26 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.3 1997/09/07 04:42:48 momjian Exp $
*
* NOTES
- * Creator functions in POSTGRES 4.2 are generated automatically. Most of
- * them are rarely used. Now we don't generate them any more. If you want
- * one, you have to write it yourself.
+ * Creator functions in POSTGRES 4.2 are generated automatically. Most of
+ * them are rarely used. Now we don't generate them any more. If you want
+ * one, you have to write it yourself.
*
* HISTORY
- * AUTHOR DATE MAJOR EVENT
- * Andrew Yu Oct 20, 1994 file creation
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Oct 20, 1994 file creation
*/
#include "postgres.h"
#include "nodes/pg_list.h"
@@ -25,95 +25,94 @@
/*
* makeOper -
- * creates an Oper node
+ * creates an Oper node
*/
-Oper *
+Oper *
makeOper(Oid opno,
- Oid opid,
- Oid opresulttype,
- int opsize,
- FunctionCachePtr op_fcache)
+ Oid opid,
+ Oid opresulttype,
+ int opsize,
+ FunctionCachePtr op_fcache)
{
- Oper *oper = makeNode(Oper);
+ Oper *oper = makeNode(Oper);
- oper->opno = opno;
- oper->opid = opid;
- oper->opresulttype = opresulttype;
- oper->opsize = opsize;
- oper->op_fcache = op_fcache;
- return oper;
+ oper->opno = opno;
+ oper->opid = opid;
+ oper->opresulttype = opresulttype;
+ oper->opsize = opsize;
+ oper->op_fcache = op_fcache;
+ return oper;
}
/*
* makeVar -
- * creates a Var node
+ * creates a Var node
*
*/
-Var *
-makeVar(Index varno,
- AttrNumber varattno,
- Oid vartype,
- Index varnoold,
- AttrNumber varoattno)
+Var *
+makeVar(Index varno,
+ AttrNumber varattno,
+ Oid vartype,
+ Index varnoold,
+ AttrNumber varoattno)
{
- Var *var = makeNode(Var);
+ Var *var = makeNode(Var);
- var->varno = varno;
- var->varattno = varattno;
- var->vartype = vartype;
- var->varnoold = varnoold;
- var->varoattno = varoattno;
+ var->varno = varno;
+ var->varattno = varattno;
+ var->vartype = vartype;
+ var->varnoold = varnoold;
+ var->varoattno = varoattno;
- return var;
+ return var;
}
/*
* makeResdom -
- * creates a Resdom (Result Domain) node
+ * creates a Resdom (Result Domain) node
*/
-Resdom *
+Resdom *
makeResdom(AttrNumber resno,
- Oid restype,
- int reslen,
- char *resname,
- Index reskey,
- Oid reskeyop,
- int resjunk)
+ Oid restype,
+ int reslen,
+ char *resname,
+ Index reskey,
+ Oid reskeyop,
+ int resjunk)
{
- Resdom *resdom = makeNode(Resdom);
+ Resdom *resdom = makeNode(Resdom);
- resdom->resno = resno;
- resdom->restype = restype;
- resdom->reslen = reslen;
- resdom->resname = resname;
- resdom->reskey = reskey;
- resdom->reskeyop = reskeyop;
- resdom->resjunk = resjunk;
- return resdom;
+ resdom->resno = resno;
+ resdom->restype = restype;
+ resdom->reslen = reslen;
+ resdom->resname = resname;
+ resdom->reskey = reskey;
+ resdom->reskeyop = reskeyop;
+ resdom->resjunk = resjunk;
+ return resdom;
}
/*
* makeConst -
- * creates a Const node
+ * creates a Const node
*/
-Const *
+Const *
makeConst(Oid consttype,
- Size constlen,
- Datum constvalue,
- bool constisnull,
- bool constbyval,
- bool constisset,
- bool constiscast)
+ Size constlen,
+ Datum constvalue,
+ bool constisnull,
+ bool constbyval,
+ bool constisset,
+ bool constiscast)
{
- Const *cnst = makeNode(Const);
+ Const *cnst = makeNode(Const);
- cnst->consttype = consttype;
- cnst->constlen = constlen;
- cnst->constvalue = constvalue;
- cnst->constisnull = constisnull;
- cnst->constbyval = constbyval;
- cnst->constisset = constisset;
- cnst->constiscast = constiscast;
- return cnst;
+ cnst->consttype = consttype;
+ cnst->constlen = constlen;
+ cnst->constvalue = constvalue;
+ cnst->constisnull = constisnull;
+ cnst->constbyval = constbyval;
+ cnst->constisset = constisset;
+ cnst->constiscast = constiscast;
+ return cnst;
}
-
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index e1e6bc6f140..081760eaca2 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* nodeFuncs.c--
- * All node routines more complicated than simple access/modification
+ * All node routines more complicated than simple access/modification
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.3 1997/08/19 21:31:41 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.4 1997/09/07 04:42:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <sys/types.h>
+#include <sys/types.h>
#include "postgres.h"
@@ -23,99 +23,96 @@
#include "nodes/nodeFuncs.h"
#include "utils/lsyscache.h"
-static bool var_is_inner(Var *var);
+static bool var_is_inner(Var * var);
-/*
+/*
* single_node -
- * Returns t if node corresponds to a single-noded expression
+ * Returns t if node corresponds to a single-noded expression
*/
bool
-single_node(Node *node)
+single_node(Node * node)
{
- if(IsA(node,Ident) || IsA(node,Const) || IsA(node,Var) || IsA(node,Param))
- return(true);
- else
- return(false);
+ if (IsA(node, Ident) || IsA(node, Const) || IsA(node, Var) || IsA(node, Param))
+ return (true);
+ else
+ return (false);
}
/*****************************************************************************
- * VAR nodes
+ * VAR nodes
*****************************************************************************/
-/*
- * var_is_outer
- * var_is_inner
- * var_is_mat
- * var_is_rel
- *
- * Returns t iff the var node corresponds to (respectively):
- * the outer relation in a join
- * the inner relation of a join
- * a materialized relation
- * a base relation (i.e., not an attribute reference, a variable from
- * some lower join level, or a sort result)
- * var node is an array reference
- *
+/*
+ * var_is_outer
+ * var_is_inner
+ * var_is_mat
+ * var_is_rel
+ *
+ * Returns t iff the var node corresponds to (respectively):
+ * the outer relation in a join
+ * the inner relation of a join
+ * a materialized relation
+ * a base relation (i.e., not an attribute reference, a variable from
+ * some lower join level, or a sort result)
+ * var node is an array reference
+ *
*/
bool
-var_is_outer (Var *var)
+var_is_outer(Var * var)
{
- return((bool)(var->varno == OUTER));
+ return ((bool) (var->varno == OUTER));
}
-static bool
-var_is_inner (Var *var)
+static bool
+var_is_inner(Var * var)
{
- return ( (bool) (var->varno == INNER));
+ return ((bool) (var->varno == INNER));
}
bool
-var_is_rel (Var *var)
+var_is_rel(Var * var)
{
- return (bool)
- ! (var_is_inner (var) || var_is_outer (var));
+ return (bool)
+ ! (var_is_inner(var) || var_is_outer(var));
}
/*****************************************************************************
- * OPER nodes
+ * OPER nodes
*****************************************************************************/
-/*
+/*
* replace_opid -
- *
- * Given a oper node, resets the opfid field with the
- * procedure OID (regproc id).
- *
- * Returns the modified oper node.
- *
+ *
+ * Given a oper node, resets the opfid field with the
+ * procedure OID (regproc id).
+ *
+ * Returns the modified oper node.
+ *
*/
-Oper *
-replace_opid (Oper *oper)
+Oper *
+replace_opid(Oper * oper)
{
- oper->opid = get_opcode(oper->opno);
- oper->op_fcache = NULL;
- return(oper);
+ oper->opid = get_opcode(oper->opno);
+ oper->op_fcache = NULL;
+ return (oper);
}
/*****************************************************************************
- * constant (CONST, PARAM) nodes
+ * constant (CONST, PARAM) nodes
*****************************************************************************/
-/*
+/*
* non_null -
- * Returns t if the node is a non-null constant, e.g., if the node has a
- * valid `constvalue' field.
- *
+ * Returns t if the node is a non-null constant, e.g., if the node has a
+ * valid `constvalue' field.
+ *
*/
bool
-non_null (Expr *c)
+non_null(Expr * c)
{
-
- if ( IsA(c,Const) && ! ((Const*)c)->constisnull )
- return(true);
- else
- return(false);
-}
-
-
+ if (IsA(c, Const) && !((Const *) c)->constisnull)
+ return (true);
+ else
+ return (false);
+}
diff --git a/src/backend/nodes/nodes.c b/src/backend/nodes/nodes.c
index 82845cca15c..2af057e5a4c 100644
--- a/src/backend/nodes/nodes.c
+++ b/src/backend/nodes/nodes.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* nodes.c--
- * support code for nodes (now that we get rid of the home-brew
- * inheritance system, our support code for nodes get much simpler)
+ * support code for nodes (now that we get rid of the home-brew
+ * inheritance system, our support code for nodes get much simpler)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.1.1.1 1996/07/09 06:21:33 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/nodes.c,v 1.2 1997/09/07 04:42:52 momjian Exp $
*
* HISTORY
- * Andrew Yu Oct 20, 1994 file creation
+ * Andrew Yu Oct 20, 1994 file creation
*
*-------------------------------------------------------------------------
*/
@@ -19,27 +19,27 @@
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/elog.h"
-#include "nodes/nodes.h" /* where func declarations of this file goes */
+#include "nodes/nodes.h" /* where func declarations of this file
+ * goes */
/*
* newNode -
- * create a new node of the specified size and tag the node with the
- * specified tag.
+ * create a new node of the specified size and tag the node with the
+ * specified tag.
*
* !WARNING!: Avoid using newNode directly. You should be using the
- * macro makeNode. eg. to create a Resdom node, use makeNode(Resdom)
+ * macro makeNode. eg. to create a Resdom node, use makeNode(Resdom)
*
*/
-Node *
+Node *
newNode(Size size, NodeTag tag)
{
- Node *newNode;
-
- Assert(size >= 4); /* need the tag, at least */
-
- newNode = (Node *)palloc(size);
- memset((char *)newNode, 0, size);
- newNode->type = tag;
- return(newNode);
-}
+ Node *newNode;
+
+ Assert(size >= 4); /* need the tag, at least */
+ newNode = (Node *) palloc(size);
+ memset((char *) newNode, 0, size);
+ newNode->type = tag;
+ return (newNode);
+}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index a41848c6188..a1574c8734f 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1,24 +1,24 @@
/*-------------------------------------------------------------------------
*
* outfuncs.c--
- * routines to convert a node to ascii representation
+ * routines to convert a node to ascii representation
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.6 1997/08/18 20:52:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.7 1997/09/07 04:42:53 momjian Exp $
*
* NOTES
- * Every (plan) node in POSTGRES has an associated "out" routine which
- * knows how to create its ascii representation. These functions are
- * useful for debugging as well as for storing plans in the system
- * catalogs (eg. indexes). This is also the plan string sent out in
- * Mariposa.
+ * Every (plan) node in POSTGRES has an associated "out" routine which
+ * knows how to create its ascii representation. These functions are
+ * useful for debugging as well as for storing plans in the system
+ * catalogs (eg. indexes). This is also the plan string sent out in
+ * Mariposa.
*
- * These functions update the in/out argument of type StringInfo
- * passed to them. This argument contains the string holding the ASCII
- * representation plus some other information (string length, etc.)
+ * These functions update the in/out argument of type StringInfo
+ * passed to them. This argument contains the string holding the ASCII
+ * representation plus some other information (string length, etc.)
*
*-------------------------------------------------------------------------
*/
@@ -45,1305 +45,1322 @@
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
-static void _outDatum(StringInfo str, Datum value, Oid type);
-static void _outNode(StringInfo str, void *obj);
+static void _outDatum(StringInfo str, Datum value, Oid type);
+static void _outNode(StringInfo str, void *obj);
/*
* _outIntList -
- * converts a List of integers
+ * converts a List of integers
*/
static void
-_outIntList(StringInfo str, List *list)
+_outIntList(StringInfo str, List * list)
{
- List *l;
- char buf[500];
+ List *l;
+ char buf[500];
- appendStringInfo(str, "(");
- foreach(l, list) {
- sprintf(buf, "%d ", (int)lfirst(l));
- appendStringInfo(str, buf);
- }
- appendStringInfo(str, ")");
+ appendStringInfo(str, "(");
+ foreach(l, list)
+ {
+ sprintf(buf, "%d ", (int) lfirst(l));
+ appendStringInfo(str, buf);
+ }
+ appendStringInfo(str, ")");
}
static void
-_outQuery(StringInfo str, Query *node)
+_outQuery(StringInfo str, Query * node)
{
- char buf[500];
-
- sprintf(buf, "QUERY");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :command %d", node->commandType);
- appendStringInfo(str,buf);
- if (node->utilityStmt &&
- nodeTag(node->utilityStmt) == T_NotifyStmt)
- sprintf(buf," :utility %s",
- ((NotifyStmt*)(node->utilityStmt))->relname);
- else /* use "" to designate */
- sprintf(buf," :utility \"\"");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :resrel %d", node->resultRelation);
- appendStringInfo(str,buf);
- sprintf(buf, " :rtable ");
- appendStringInfo(str,buf);
- _outNode(str, node->rtable);
- if (node->uniqueFlag)
- sprintf(buf, " :unique %s", node->uniqueFlag);
- else /* use "" to designate non-unique */
- sprintf(buf, " :unique \"\"");
- appendStringInfo(str,buf);
- sprintf(buf, " :targetlist ");
- appendStringInfo(str,buf);
- _outNode(str, node->targetList);
- sprintf(buf, " :qual ");
- appendStringInfo(str,buf);
- _outNode(str, node->qual);
-
+ char buf[500];
+
+ sprintf(buf, "QUERY");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :command %d", node->commandType);
+ appendStringInfo(str, buf);
+ if (node->utilityStmt &&
+ nodeTag(node->utilityStmt) == T_NotifyStmt)
+ sprintf(buf, " :utility %s",
+ ((NotifyStmt *) (node->utilityStmt))->relname);
+ else
+/* use "" to designate */
+ sprintf(buf, " :utility \"\"");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :resrel %d", node->resultRelation);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :rtable ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->rtable);
+ if (node->uniqueFlag)
+ sprintf(buf, " :unique %s", node->uniqueFlag);
+ else
+/* use "" to designate non-unique */
+ sprintf(buf, " :unique \"\"");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :targetlist ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->targetList);
+ sprintf(buf, " :qual ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->qual);
+
}
/*
* print the basic stuff of all nodes that inherit from Plan
*/
static void
-_outPlanInfo(StringInfo str, Plan *node)
+_outPlanInfo(StringInfo str, Plan * node)
{
- char buf[500];
-
- sprintf(buf, " :cost %g", node->cost );
- appendStringInfo(str,buf);
- sprintf(buf, " :size %d", node->plan_size);
- appendStringInfo(str,buf);
- sprintf(buf, " :width %d", node->plan_width);
- appendStringInfo(str,buf);
- sprintf(buf, " :state %s", (node->state == (EState*) NULL ?
- "nil" : "non-NIL"));
- appendStringInfo(str,buf);
- sprintf(buf, " :qptargetlist ");
- appendStringInfo(str,buf);
- _outNode(str, node->targetlist);
- sprintf(buf, " :qpqual ");
- appendStringInfo(str,buf);
- _outNode(str, node->qual);
- sprintf(buf, " :lefttree ");
- appendStringInfo(str,buf);
- _outNode(str, node->lefttree);
- sprintf(buf, " :righttree ");
- appendStringInfo(str,buf);
- _outNode(str, node->righttree);
-
+ char buf[500];
+
+ sprintf(buf, " :cost %g", node->cost);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :size %d", node->plan_size);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :width %d", node->plan_width);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :state %s", (node->state == (EState *) NULL ?
+ "nil" : "non-NIL"));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :qptargetlist ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->targetlist);
+ sprintf(buf, " :qpqual ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->qual);
+ sprintf(buf, " :lefttree ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->lefttree);
+ sprintf(buf, " :righttree ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->righttree);
+
}
/*
- * Stuff from plannodes.h
+ * Stuff from plannodes.h
*/
static void
-_outPlan(StringInfo str, Plan *node)
+_outPlan(StringInfo str, Plan * node)
{
- char buf[500];
-
- sprintf(buf, "PLAN");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
+ char buf[500];
+
+ sprintf(buf, "PLAN");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
}
static void
-_outResult(StringInfo str, Result *node)
+_outResult(StringInfo str, Result * node)
{
- char buf[500];
-
- sprintf(buf, "RESULT");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :resconstantqual ");
- appendStringInfo(str,buf);
- _outNode(str, node->resconstantqual);
-
+ char buf[500];
+
+ sprintf(buf, "RESULT");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :resconstantqual ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->resconstantqual);
+
}
/*
- * Existential is a subclass of Plan.
+ * Existential is a subclass of Plan.
*/
static void
-_outExistential(StringInfo str, Existential *node)
+_outExistential(StringInfo str, Existential * node)
{
- char buf[500];
-
- sprintf(buf, "EXISTENTIAL");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
-
+ char buf[500];
+
+ sprintf(buf, "EXISTENTIAL");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+
}
/*
- * Append is a subclass of Plan.
+ * Append is a subclass of Plan.
*/
static void
-_outAppend(StringInfo str, Append *node)
+_outAppend(StringInfo str, Append * node)
{
- char buf[500];
-
- sprintf(buf, "APPEND");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :unionplans ");
- appendStringInfo(str,buf);
- _outNode(str, node->unionplans);
-
- sprintf(buf, " :unionrelid %d", node->unionrelid);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :unionrtentries ");
- appendStringInfo(str,buf);
- _outNode(str, node->unionrtentries);
-
+ char buf[500];
+
+ sprintf(buf, "APPEND");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :unionplans ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->unionplans);
+
+ sprintf(buf, " :unionrelid %d", node->unionrelid);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :unionrtentries ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->unionrtentries);
+
}
/*
- * Join is a subclass of Plan
+ * Join is a subclass of Plan
*/
static void
-_outJoin(StringInfo str, Join *node)
+_outJoin(StringInfo str, Join * node)
{
- char buf[500];
-
- sprintf(buf, "JOIN");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
+ char buf[500];
+
+ sprintf(buf, "JOIN");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
}
/*
- * NestLoop is a subclass of Join
+ * NestLoop is a subclass of Join
*/
static void
-_outNestLoop(StringInfo str, NestLoop *node)
+_outNestLoop(StringInfo str, NestLoop * node)
{
- char buf[500];
-
- sprintf(buf, "NESTLOOP");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
+ char buf[500];
+
+ sprintf(buf, "NESTLOOP");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
}
/*
- * MergeJoin is a subclass of Join
+ * MergeJoin is a subclass of Join
*/
static void
-_outMergeJoin(StringInfo str, MergeJoin *node)
+_outMergeJoin(StringInfo str, MergeJoin * node)
{
- char buf[500];
-
- sprintf(buf, "MERGEJOIN");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :mergeclauses ");
- appendStringInfo(str,buf);
- _outNode(str, node->mergeclauses);
-
- sprintf(buf, " :mergesortop %u", node->mergesortop);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :mergerightorder %u", node->mergerightorder[0]);
- appendStringInfo(str, buf);
-
- sprintf(buf, " :mergeleftorder %u", node->mergeleftorder[0]);
- appendStringInfo(str, buf);
+ char buf[500];
+
+ sprintf(buf, "MERGEJOIN");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :mergeclauses ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->mergeclauses);
+
+ sprintf(buf, " :mergesortop %u", node->mergesortop);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :mergerightorder %u", node->mergerightorder[0]);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :mergeleftorder %u", node->mergeleftorder[0]);
+ appendStringInfo(str, buf);
}
/*
- * HashJoin is a subclass of Join.
+ * HashJoin is a subclass of Join.
*/
static void
-_outHashJoin(StringInfo str, HashJoin *node)
+_outHashJoin(StringInfo str, HashJoin * node)
{
- char buf[500];
-
- sprintf(buf, "HASHJOIN");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :hashclauses ");
- appendStringInfo(str,buf);
- _outNode(str, node->hashclauses);
-
- sprintf(buf, " :hashjoinop %u",node->hashjoinop);
- appendStringInfo(str,buf);
- sprintf(buf, " :hashjointable 0x%x", (int) node->hashjointable);
- appendStringInfo(str,buf);
- sprintf(buf, " :hashjointablekey %d", node->hashjointablekey);
- appendStringInfo(str,buf);
- sprintf(buf, " :hashjointablesize %d", node->hashjointablesize);
- appendStringInfo(str,buf);
- sprintf(buf, " :hashdone %d", node->hashdone);
- appendStringInfo(str,buf);
+ char buf[500];
+
+ sprintf(buf, "HASHJOIN");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :hashclauses ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->hashclauses);
+
+ sprintf(buf, " :hashjoinop %u", node->hashjoinop);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :hashjointable 0x%x", (int) node->hashjointable);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :hashjointablekey %d", node->hashjointablekey);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :hashjointablesize %d", node->hashjointablesize);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :hashdone %d", node->hashdone);
+ appendStringInfo(str, buf);
}
/*
- * Scan is a subclass of Node
+ * Scan is a subclass of Node
*/
static void
-_outScan(StringInfo str, Scan *node)
+_outScan(StringInfo str, Scan * node)
{
- char buf[500];
-
- sprintf(buf, "SCAN");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :scanrelid %d", node->scanrelid);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "SCAN");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :scanrelid %d", node->scanrelid);
+ appendStringInfo(str, buf);
+
}
/*
- * SeqScan is a subclass of Scan
+ * SeqScan is a subclass of Scan
*/
static void
-_outSeqScan(StringInfo str, SeqScan *node)
+_outSeqScan(StringInfo str, SeqScan * node)
{
- char buf[500];
-
- sprintf(buf, "SEQSCAN");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :scanrelid %d", node->scanrelid);
- appendStringInfo(str,buf);
-
-
+ char buf[500];
+
+ sprintf(buf, "SEQSCAN");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :scanrelid %d", node->scanrelid);
+ appendStringInfo(str, buf);
+
+
}
/*
- * IndexScan is a subclass of Scan
+ * IndexScan is a subclass of Scan
*/
static void
-_outIndexScan(StringInfo str, IndexScan *node)
+_outIndexScan(StringInfo str, IndexScan * node)
{
- char buf[500];
-
- sprintf(buf, "INDEXSCAN");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :scanrelid %d", node->scan.scanrelid);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :indxid ");
- appendStringInfo(str,buf);
- _outIntList(str, node->indxid);
-
- sprintf(buf, " :indxqual ");
- appendStringInfo(str,buf);
- _outNode(str, node->indxqual);
-
+ char buf[500];
+
+ sprintf(buf, "INDEXSCAN");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :scanrelid %d", node->scan.scanrelid);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :indxid ");
+ appendStringInfo(str, buf);
+ _outIntList(str, node->indxid);
+
+ sprintf(buf, " :indxqual ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->indxqual);
+
}
/*
- * Temp is a subclass of Plan
+ * Temp is a subclass of Plan
*/
static void
-_outTemp(StringInfo str, Temp *node)
+_outTemp(StringInfo str, Temp * node)
{
- char buf[500];
-
- sprintf(buf, "TEMP");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :tempid %u", node->tempid);
- appendStringInfo(str,buf);
- sprintf(buf, " :keycount %d", node->keycount);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "TEMP");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :tempid %u", node->tempid);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :keycount %d", node->keycount);
+ appendStringInfo(str, buf);
+
}
/*
- * Sort is a subclass of Temp
+ * Sort is a subclass of Temp
*/
static void
-_outSort(StringInfo str, Sort *node)
+_outSort(StringInfo str, Sort * node)
{
- char buf[500];
-
- sprintf(buf, "SORT");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :tempid %u", node->tempid);
- appendStringInfo(str,buf);
- sprintf(buf, " :keycount %d", node->keycount);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "SORT");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :tempid %u", node->tempid);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :keycount %d", node->keycount);
+ appendStringInfo(str, buf);
+
}
static void
-_outAgg(StringInfo str, Agg *node)
+_outAgg(StringInfo str, Agg * node)
{
- char buf[500];
- sprintf(buf, "AGG");
- appendStringInfo(str,buf);
- _outPlanInfo(str,(Plan*)node);
-
- /* the actual Agg fields */
- sprintf(buf, " :numagg %d ", node->numAgg);
- appendStringInfo(str, buf);
+ char buf[500];
+
+ sprintf(buf, "AGG");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ /* the actual Agg fields */
+ sprintf(buf, " :numagg %d ", node->numAgg);
+ appendStringInfo(str, buf);
}
static void
-_outGroup(StringInfo str, Group *node)
+_outGroup(StringInfo str, Group * node)
{
- char buf[500];
- sprintf(buf, "GRP");
- appendStringInfo(str,buf);
- _outPlanInfo(str,(Plan*)node);
-
- /* the actual Group fields */
- sprintf(buf, " :numCols %d ", node->numCols);
- appendStringInfo(str, buf);
- sprintf(buf, " :tuplePerGroup %s", node->tuplePerGroup ? "true" : "nil");
- appendStringInfo(str, buf);
+ char buf[500];
+
+ sprintf(buf, "GRP");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ /* the actual Group fields */
+ sprintf(buf, " :numCols %d ", node->numCols);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :tuplePerGroup %s", node->tuplePerGroup ? "true" : "nil");
+ appendStringInfo(str, buf);
}
-
-
+
+
/*
- * For some reason, unique is a subclass of Temp.
+ * For some reason, unique is a subclass of Temp.
*/
static void
-_outUnique(StringInfo str, Unique *node)
+_outUnique(StringInfo str, Unique * node)
{
- char buf[500];
-
- sprintf(buf, "UNIQUE");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :tempid %u", node->tempid);
- appendStringInfo(str,buf);
- sprintf(buf, " :keycount %d", node->keycount);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "UNIQUE");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :tempid %u", node->tempid);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :keycount %d", node->keycount);
+ appendStringInfo(str, buf);
+
}
/*
- * Hash is a subclass of Temp
+ * Hash is a subclass of Temp
*/
static void
-_outHash(StringInfo str, Hash *node)
+_outHash(StringInfo str, Hash * node)
{
- char buf[500];
-
- sprintf(buf, "HASH");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :hashkey ");
- appendStringInfo(str,buf);
- _outNode(str, node->hashkey);
-
- sprintf(buf, " :hashtable 0x%x", (int) (node->hashtable));
- appendStringInfo(str,buf);
- sprintf(buf, " :hashtablekey %d", node->hashtablekey);
- appendStringInfo(str,buf);
- sprintf(buf, " :hashtablesize %d", node->hashtablesize);
- appendStringInfo(str,buf);
+ char buf[500];
+
+ sprintf(buf, "HASH");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :hashkey ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->hashkey);
+
+ sprintf(buf, " :hashtable 0x%x", (int) (node->hashtable));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :hashtablekey %d", node->hashtablekey);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :hashtablesize %d", node->hashtablesize);
+ appendStringInfo(str, buf);
}
static void
-_outTee(StringInfo str, Tee *node)
+_outTee(StringInfo str, Tee * node)
{
- char buf[500];
-
- sprintf(buf, "TEE");
- appendStringInfo(str,buf);
- _outPlanInfo(str, (Plan*) node);
-
- sprintf(buf, " :leftParent %X", (int) (node->leftParent));
- appendStringInfo(str,buf);
- sprintf(buf, " :rightParent %X", (int) (node->rightParent));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :rtentries ");
- appendStringInfo(str,buf);
- _outNode(str, node->rtentries);
+ char buf[500];
+
+ sprintf(buf, "TEE");
+ appendStringInfo(str, buf);
+ _outPlanInfo(str, (Plan *) node);
+
+ sprintf(buf, " :leftParent %X", (int) (node->leftParent));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :rightParent %X", (int) (node->rightParent));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :rtentries ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->rtentries);
}
/*****************************************************************************
*
- * Stuff from primnodes.h.
+ * Stuff from primnodes.h.
*
*****************************************************************************/
/*
- * Resdom is a subclass of Node
+ * Resdom is a subclass of Node
*/
static void
-_outResdom(StringInfo str, Resdom *node)
+_outResdom(StringInfo str, Resdom * node)
{
- char buf[500];
-
- sprintf(buf, "RESDOM");
- appendStringInfo(str,buf);
- sprintf(buf, " :resno %hd", node->resno);
- appendStringInfo(str,buf);
- sprintf(buf, " :restype %u", node->restype);
- appendStringInfo(str,buf);
- sprintf(buf, " :reslen %d", node->reslen);
- appendStringInfo(str,buf);
- sprintf(buf, " :resname \"%s\"",
- ((node->resname) ? ((char *) node->resname) : "null"));
- appendStringInfo(str,buf);
- sprintf(buf, " :reskey %d", node->reskey);
- appendStringInfo(str,buf);
- sprintf(buf, " :reskeyop %u", node->reskeyop);
- appendStringInfo(str,buf);
- sprintf(buf, " :resjunk %d", node->resjunk);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "RESDOM");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :resno %hd", node->resno);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :restype %u", node->restype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :reslen %d", node->reslen);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :resname \"%s\"",
+ ((node->resname) ? ((char *) node->resname) : "null"));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :reskey %d", node->reskey);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :reskeyop %u", node->reskeyop);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :resjunk %d", node->resjunk);
+ appendStringInfo(str, buf);
+
}
static void
-_outFjoin(StringInfo str, Fjoin *node)
+_outFjoin(StringInfo str, Fjoin * node)
{
- char buf[500];
- int i;
-
- sprintf(buf, "FJOIN");
- appendStringInfo(str,buf);
- sprintf(buf, " :initialized %s", node->fj_initialized ? "true":"nil");
- appendStringInfo(str,buf);
- sprintf(buf, " :nNodes %d", node->fj_nNodes);
- appendStringInfo(str,buf);
-
- appendStringInfo(str," :innerNode ");
- appendStringInfo(str,buf);
- _outNode(str, node->fj_innerNode);
-
- sprintf(buf, " :results @ 0x%x ", (int)(node->fj_results));
- appendStringInfo(str, buf);
-
- appendStringInfo( str, " :alwaysdone ");
- for (i = 0; i<node->fj_nNodes; i++)
+ char buf[500];
+ int i;
+
+ sprintf(buf, "FJOIN");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :initialized %s", node->fj_initialized ? "true" : "nil");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :nNodes %d", node->fj_nNodes);
+ appendStringInfo(str, buf);
+
+ appendStringInfo(str, " :innerNode ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->fj_innerNode);
+
+ sprintf(buf, " :results @ 0x%x ", (int) (node->fj_results));
+ appendStringInfo(str, buf);
+
+ appendStringInfo(str, " :alwaysdone ");
+ for (i = 0; i < node->fj_nNodes; i++)
{
- sprintf(buf, " %s ", ((node->fj_alwaysDone[i]) ? "true" : "nil"));
- appendStringInfo(str, buf);
+ sprintf(buf, " %s ", ((node->fj_alwaysDone[i]) ? "true" : "nil"));
+ appendStringInfo(str, buf);
}
}
/*
- * Expr is a subclass of Node
+ * Expr is a subclass of Node
*/
static void
-_outExpr(StringInfo str, Expr *node)
+_outExpr(StringInfo str, Expr * node)
{
- char buf[500];
- char *opstr = NULL;
-
- sprintf(buf, "EXPR");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :typeOid %u", node->typeOid);
- appendStringInfo(str,buf);
- switch(node->opType) {
- case OP_EXPR:
- opstr = "op";
- break;
- case FUNC_EXPR:
- opstr = "func";
- break;
- case OR_EXPR:
- opstr = "or";
- break;
- case AND_EXPR:
- opstr = "and";
- break;
- case NOT_EXPR:
- opstr = "not";
- break;
- }
- sprintf(buf, " :opType %s", opstr);
- appendStringInfo(str,buf);
- sprintf(buf, " :oper ");
- appendStringInfo(str,buf);
- _outNode(str, node->oper);
- sprintf(buf, " :args ");
- appendStringInfo(str,buf);
- _outNode(str, node->args);
+ char buf[500];
+ char *opstr = NULL;
+
+ sprintf(buf, "EXPR");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :typeOid %u", node->typeOid);
+ appendStringInfo(str, buf);
+ switch (node->opType)
+ {
+ case OP_EXPR:
+ opstr = "op";
+ break;
+ case FUNC_EXPR:
+ opstr = "func";
+ break;
+ case OR_EXPR:
+ opstr = "or";
+ break;
+ case AND_EXPR:
+ opstr = "and";
+ break;
+ case NOT_EXPR:
+ opstr = "not";
+ break;
+ }
+ sprintf(buf, " :opType %s", opstr);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :oper ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->oper);
+ sprintf(buf, " :args ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->args);
}
/*
- * Var is a subclass of Expr
+ * Var is a subclass of Expr
*/
static void
-_outVar(StringInfo str, Var *node)
+_outVar(StringInfo str, Var * node)
{
- char buf[500];
-
- sprintf(buf, "VAR");
- appendStringInfo(str,buf);
- sprintf(buf, " :varno %d", node->varno);
- appendStringInfo(str,buf);
- sprintf(buf, " :varattno %hd", node->varattno);
- appendStringInfo(str,buf);
- sprintf(buf, " :vartype %u", node->vartype);
- appendStringInfo(str,buf);
- sprintf(buf, " :varnoold %d", node->varnoold);
- appendStringInfo(str,buf);
- sprintf(buf, " :varoattno %d", node->varoattno);
- appendStringInfo(str,buf);
+ char buf[500];
+
+ sprintf(buf, "VAR");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :varno %d", node->varno);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :varattno %hd", node->varattno);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :vartype %u", node->vartype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :varnoold %d", node->varnoold);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :varoattno %d", node->varoattno);
+ appendStringInfo(str, buf);
}
/*
- * Const is a subclass of Expr
+ * Const is a subclass of Expr
*/
static void
-_outConst(StringInfo str, Const *node)
+_outConst(StringInfo str, Const * node)
{
- char buf[500];
-
- sprintf(buf, "CONST");
- appendStringInfo(str,buf);
- sprintf(buf, " :consttype %u", node->consttype);
- appendStringInfo(str,buf);
- sprintf(buf, " :constlen %hd", node->constlen);
- appendStringInfo(str,buf);
- sprintf(buf, " :constisnull %s", (node->constisnull ? "true" : "nil"));
- appendStringInfo(str,buf);
- sprintf(buf, " :constvalue ");
- appendStringInfo(str,buf);
- if (node->constisnull) {
- sprintf(buf, "NIL ");
- appendStringInfo(str,buf);
- } else {
- _outDatum(str, node->constvalue, node->consttype);
- }
- sprintf(buf, " :constbyval %s", (node->constbyval ? "true" : "nil"));
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "CONST");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :consttype %u", node->consttype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :constlen %hd", node->constlen);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :constisnull %s", (node->constisnull ? "true" : "nil"));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :constvalue ");
+ appendStringInfo(str, buf);
+ if (node->constisnull)
+ {
+ sprintf(buf, "NIL ");
+ appendStringInfo(str, buf);
+ }
+ else
+ {
+ _outDatum(str, node->constvalue, node->consttype);
+ }
+ sprintf(buf, " :constbyval %s", (node->constbyval ? "true" : "nil"));
+ appendStringInfo(str, buf);
+
}
/*
- * Aggreg
+ * Aggreg
*/
static void
-_outAggreg(StringInfo str, Aggreg *node)
+_outAggreg(StringInfo str, Aggreg * node)
{
- char buf[500];
-
- sprintf(buf, "AGGREG");
- appendStringInfo(str,buf);
- sprintf(buf, " :aggname \"%s\"", (char*)node->aggname);
- appendStringInfo(str,buf);
- sprintf(buf, " :basetype %u", node->basetype);
- appendStringInfo(str,buf);
- sprintf(buf, " :aggtype %u", node->aggtype);
- appendStringInfo(str,buf);
- sprintf(buf, " :aggno %d", node->aggno);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :target ");
- appendStringInfo(str,buf);
- _outNode(str, node->target);
+ char buf[500];
+
+ sprintf(buf, "AGGREG");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :aggname \"%s\"", (char *) node->aggname);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :basetype %u", node->basetype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :aggtype %u", node->aggtype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :aggno %d", node->aggno);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :target ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->target);
}
/*
- * Array is a subclass of Expr
+ * Array is a subclass of Expr
*/
static void
-_outArray(StringInfo str, Array *node)
+_outArray(StringInfo str, Array * node)
{
- char buf[500];
- int i;
- sprintf(buf, "ARRAY");
- appendStringInfo(str, buf);
- sprintf(buf, " :arrayelemtype %u", node->arrayelemtype);
- appendStringInfo(str, buf);
- sprintf(buf, " :arrayelemlength %d", node->arrayelemlength);
- appendStringInfo(str, buf);
- sprintf(buf, " :arrayelembyval %c", (node->arrayelembyval) ? 't' : 'f');
- appendStringInfo(str, buf);
- sprintf(buf, " :arrayndim %d", node->arrayndim);
- appendStringInfo(str, buf);
- sprintf(buf, " :arraylow ");
- appendStringInfo(str, buf);
- for (i = 0; i < node->arrayndim; i++){
- sprintf(buf, " %d", node->arraylow.indx[i]);
- appendStringInfo(str, buf);
- }
- sprintf(buf, " :arrayhigh ");
- appendStringInfo(str, buf);
- for (i = 0; i < node->arrayndim; i++){
- sprintf(buf, " %d", node->arrayhigh.indx[i]);
- appendStringInfo(str, buf);
- }
- sprintf(buf, " :arraylen %d", node->arraylen);
- appendStringInfo(str, buf);
+ char buf[500];
+ int i;
+
+ sprintf(buf, "ARRAY");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayelemtype %u", node->arrayelemtype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayelemlength %d", node->arrayelemlength);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayelembyval %c", (node->arrayelembyval) ? 't' : 'f');
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arrayndim %d", node->arrayndim);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :arraylow ");
+ appendStringInfo(str, buf);
+ for (i = 0; i < node->arrayndim; i++)
+ {
+ sprintf(buf, " %d", node->arraylow.indx[i]);
+ appendStringInfo(str, buf);
+ }
+ sprintf(buf, " :arrayhigh ");
+ appendStringInfo(str, buf);
+ for (i = 0; i < node->arrayndim; i++)
+ {
+ sprintf(buf, " %d", node->arrayhigh.indx[i]);
+ appendStringInfo(str, buf);
+ }
+ sprintf(buf, " :arraylen %d", node->arraylen);
+ appendStringInfo(str, buf);
}
/*
- * ArrayRef is a subclass of Expr
+ * ArrayRef is a subclass of Expr
*/
static void
-_outArrayRef(StringInfo str, ArrayRef *node)
+_outArrayRef(StringInfo str, ArrayRef * node)
{
- char buf[500];
-
- sprintf(buf, "ARRAYREF");
- appendStringInfo(str, buf);
- sprintf(buf, " :refelemtype %u", node->refelemtype);
- appendStringInfo(str, buf);
- sprintf(buf, " :refattrlength %d", node->refattrlength);
- appendStringInfo(str, buf);
- sprintf(buf, " :refelemlength %d", node->refelemlength);
- appendStringInfo(str, buf);
- sprintf(buf, " :refelembyval %c", (node->refelembyval) ? 't' : 'f');
- appendStringInfo(str, buf);
-
- sprintf(buf, " :refupperindex ");
- appendStringInfo(str, buf);
- _outNode(str, node->refupperindexpr);
-
- sprintf(buf, " :reflowerindex ");
- appendStringInfo(str, buf);
- _outNode(str, node->reflowerindexpr);
-
- sprintf(buf, " :refexpr ");
- appendStringInfo(str, buf);
- _outNode(str, node->refexpr);
-
- sprintf(buf, " :refassgnexpr ");
- appendStringInfo(str, buf);
- _outNode(str, node->refassgnexpr);
+ char buf[500];
+
+ sprintf(buf, "ARRAYREF");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refelemtype %u", node->refelemtype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refattrlength %d", node->refattrlength);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refelemlength %d", node->refelemlength);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :refelembyval %c", (node->refelembyval) ? 't' : 'f');
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :refupperindex ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->refupperindexpr);
+
+ sprintf(buf, " :reflowerindex ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->reflowerindexpr);
+
+ sprintf(buf, " :refexpr ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->refexpr);
+
+ sprintf(buf, " :refassgnexpr ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->refassgnexpr);
}
/*
- * Func is a subclass of Expr
+ * Func is a subclass of Expr
*/
static void
-_outFunc(StringInfo str, Func *node)
+_outFunc(StringInfo str, Func * node)
{
- char buf[500];
-
- sprintf(buf, "FUNC");
- appendStringInfo(str,buf);
- sprintf(buf, " :funcid %u", node->funcid);
- appendStringInfo(str,buf);
- sprintf(buf, " :functype %u", node->functype);
- appendStringInfo(str,buf);
- sprintf(buf, " :funcisindex %s",
- (node->funcisindex ? "true" : "nil"));
- appendStringInfo(str,buf);
- sprintf(buf, " :funcsize %d", node->funcsize);
- appendStringInfo(str, buf);
- sprintf(buf, " :func_fcache @ 0x%x", (int)(node->func_fcache));
- appendStringInfo(str, buf);
-
- appendStringInfo(str, " :func_tlist ");
- _outNode(str, node->func_tlist);
-
- appendStringInfo(str, " :func_planlist ");
- _outNode(str, node->func_planlist);
+ char buf[500];
+
+ sprintf(buf, "FUNC");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :funcid %u", node->funcid);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :functype %u", node->functype);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :funcisindex %s",
+ (node->funcisindex ? "true" : "nil"));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :funcsize %d", node->funcsize);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :func_fcache @ 0x%x", (int) (node->func_fcache));
+ appendStringInfo(str, buf);
+
+ appendStringInfo(str, " :func_tlist ");
+ _outNode(str, node->func_tlist);
+
+ appendStringInfo(str, " :func_planlist ");
+ _outNode(str, node->func_planlist);
}
/*
- * Oper is a subclass of Expr
+ * Oper is a subclass of Expr
*/
static void
-_outOper(StringInfo str, Oper *node)
+_outOper(StringInfo str, Oper * node)
{
- char buf[500];
-
- sprintf(buf, "OPER");
- appendStringInfo(str,buf);
- sprintf(buf, " :opno %u", node->opno);
- appendStringInfo(str,buf);
- sprintf(buf, " :opid %u", node->opid);
- appendStringInfo(str,buf);
- sprintf(buf, " :opresulttype %u", node->opresulttype);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "OPER");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :opno %u", node->opno);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :opid %u", node->opid);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :opresulttype %u", node->opresulttype);
+ appendStringInfo(str, buf);
+
}
/*
- * Param is a subclass of Expr
+ * Param is a subclass of Expr
*/
static void
-_outParam(StringInfo str, Param *node)
+_outParam(StringInfo str, Param * node)
{
- char buf[500];
-
- sprintf(buf, "PARAM");
- appendStringInfo(str,buf);
- sprintf(buf, " :paramkind %d", node->paramkind);
- appendStringInfo(str,buf);
- sprintf(buf, " :paramid %hd", node->paramid);
- appendStringInfo(str,buf);
- sprintf(buf, " :paramname \"%s\"", node->paramname);
- appendStringInfo(str,buf);
- sprintf(buf, " :paramtype %u", node->paramtype);
- appendStringInfo(str,buf);
-
- appendStringInfo(str, " :param_tlist ");
- _outNode(str, node->param_tlist);
+ char buf[500];
+
+ sprintf(buf, "PARAM");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :paramkind %d", node->paramkind);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :paramid %hd", node->paramid);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :paramname \"%s\"", node->paramname);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :paramtype %u", node->paramtype);
+ appendStringInfo(str, buf);
+
+ appendStringInfo(str, " :param_tlist ");
+ _outNode(str, node->param_tlist);
}
/*
- * Stuff from execnodes.h
+ * Stuff from execnodes.h
*/
/*
- * EState is a subclass of Node.
+ * EState is a subclass of Node.
*/
static void
-_outEState(StringInfo str, EState *node)
+_outEState(StringInfo str, EState * node)
{
- char buf[500];
-
- sprintf(buf, "ESTATE");
- appendStringInfo(str,buf);
- sprintf(buf, " :direction %d", node->es_direction);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :range_table ");
- appendStringInfo(str,buf);
- _outNode(str, node->es_range_table);
-
- sprintf(buf, " :result_relation_info @ 0x%x",
- (int) (node->es_result_relation_info));
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "ESTATE");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :direction %d", node->es_direction);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :range_table ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->es_range_table);
+
+ sprintf(buf, " :result_relation_info @ 0x%x",
+ (int) (node->es_result_relation_info));
+ appendStringInfo(str, buf);
+
}
/*
- * Stuff from relation.h
+ * Stuff from relation.h
*/
static void
-_outRel(StringInfo str, Rel *node)
+_outRel(StringInfo str, Rel * node)
{
- char buf[500];
-
- sprintf(buf, "REL");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :relids ");
- appendStringInfo(str,buf);
- _outIntList(str, node->relids);
-
- sprintf(buf, " :indexed %s", (node->indexed ? "true" : "nil"));
- appendStringInfo(str,buf);
- sprintf(buf, " :pages %u", node->pages);
- appendStringInfo(str,buf);
- sprintf(buf, " :tuples %u", node->tuples);
- appendStringInfo(str,buf);
- sprintf(buf, " :size %u", node->size);
- appendStringInfo(str,buf);
- sprintf(buf, " :width %u", node->width);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :targetlist ");
- appendStringInfo(str,buf);
- _outNode(str, node->targetlist);
-
- sprintf(buf, " :pathlist ");
- appendStringInfo(str,buf);
- _outNode(str, node->pathlist);
-
- /*
- * Not sure if these are nodes or not. They're declared as
- * struct Path *. Since i don't know, i'll just print the
- * addresses for now. This can be changed later, if necessary.
- */
-
- sprintf(buf, " :unorderedpath @ 0x%x", (int)(node->unorderedpath));
- appendStringInfo(str,buf);
- sprintf(buf, " :cheapestpath @ 0x%x", (int)(node->cheapestpath));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :pruneable %s", (node->pruneable ? "true" : "nil"));
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "REL");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :relids ");
+ appendStringInfo(str, buf);
+ _outIntList(str, node->relids);
+
+ sprintf(buf, " :indexed %s", (node->indexed ? "true" : "nil"));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :pages %u", node->pages);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :tuples %u", node->tuples);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :size %u", node->size);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :width %u", node->width);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :targetlist ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->targetlist);
+
+ sprintf(buf, " :pathlist ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->pathlist);
+
+ /*
+ * Not sure if these are nodes or not. They're declared as struct
+ * Path *. Since i don't know, i'll just print the addresses for now.
+ * This can be changed later, if necessary.
+ */
+
+ sprintf(buf, " :unorderedpath @ 0x%x", (int) (node->unorderedpath));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :cheapestpath @ 0x%x", (int) (node->cheapestpath));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :pruneable %s", (node->pruneable ? "true" : "nil"));
+ appendStringInfo(str, buf);
+
#if 0
- sprintf(buf, " :classlist ");
- appendStringInfo(str,buf);
- _outNode(str, node->classlist);
-
- sprintf(buf, " :indexkeys ");
- appendStringInfo(str,buf);
- _outNode(str, node->indexkeys);
-
- sprintf(buf, " :ordering ");
- appendStringInfo(str,buf);
- _outNode(str, node->ordering);
-#endif
-
- sprintf(buf, " :clauseinfo ");
- appendStringInfo(str,buf);
- _outNode(str, node->clauseinfo);
-
- sprintf(buf, " :joininfo ");
- appendStringInfo(str,buf);
- _outNode(str, node->joininfo);
-
- sprintf(buf, " :innerjoin ");
- appendStringInfo(str,buf);
- _outNode(str, node->innerjoin);
-
+ sprintf(buf, " :classlist ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->classlist);
+
+ sprintf(buf, " :indexkeys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->indexkeys);
+
+ sprintf(buf, " :ordering ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->ordering);
+#endif
+
+ sprintf(buf, " :clauseinfo ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->clauseinfo);
+
+ sprintf(buf, " :joininfo ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->joininfo);
+
+ sprintf(buf, " :innerjoin ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->innerjoin);
+
}
/*
- * TargetEntry is a subclass of Node.
+ * TargetEntry is a subclass of Node.
*/
static void
-_outTargetEntry(StringInfo str, TargetEntry *node)
+_outTargetEntry(StringInfo str, TargetEntry * node)
{
- char buf[500];
-
- sprintf(buf, "TLE");
- appendStringInfo(str,buf);
- sprintf(buf, " :resdom ");
- appendStringInfo(str,buf);
- _outNode(str, node->resdom);
-
- sprintf(buf, " :expr ");
- appendStringInfo(str,buf);
- if (node->expr) {
- _outNode(str, node->expr);
- }else {
- appendStringInfo(str, "nil");
- }
-}
+ char buf[500];
+
+ sprintf(buf, "TLE");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :resdom ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->resdom);
+
+ sprintf(buf, " :expr ");
+ appendStringInfo(str, buf);
+ if (node->expr)
+ {
+ _outNode(str, node->expr);
+ }
+ else
+ {
+ appendStringInfo(str, "nil");
+ }
+}
static void
-_outRangeTblEntry(StringInfo str, RangeTblEntry *node)
+_outRangeTblEntry(StringInfo str, RangeTblEntry * node)
{
- char buf[500];
-
- sprintf(buf, "RTE");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :relname \"%s\"",
- ((node->relname) ? ((char *) node->relname) : "null"));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :inh %d ", node->inh);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :refname \"%s\"",
- ((node->refname) ? ((char *) node->refname) : "null"));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :relid %u ", node->relid);
- appendStringInfo(str,buf);
-}
+ char buf[500];
+
+ sprintf(buf, "RTE");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :relname \"%s\"",
+ ((node->relname) ? ((char *) node->relname) : "null"));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :inh %d ", node->inh);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :refname \"%s\"",
+ ((node->refname) ? ((char *) node->refname) : "null"));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :relid %u ", node->relid);
+ appendStringInfo(str, buf);
+}
/*
- * Path is a subclass of Node.
+ * Path is a subclass of Node.
*/
static void
-_outPath(StringInfo str, Path *node)
+_outPath(StringInfo str, Path * node)
{
- char buf[500];
-
- sprintf(buf, "PATH");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :pathtype %d", node->pathtype);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :cost %f", node->path_cost);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :keys ");
- appendStringInfo(str,buf);
- _outNode(str, node->keys);
-
+ char buf[500];
+
+ sprintf(buf, "PATH");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :pathtype %d", node->pathtype);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :cost %f", node->path_cost);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :keys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->keys);
+
}
/*
- * IndexPath is a subclass of Path.
+ * IndexPath is a subclass of Path.
*/
static void
-_outIndexPath(StringInfo str, IndexPath *node)
+_outIndexPath(StringInfo str, IndexPath * node)
{
- char buf[500];
-
- sprintf(buf, "INDEXPATH");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :pathtype %d", node->path.pathtype);
- appendStringInfo(str,buf);
-
- /* sprintf(buf, " :parent ");
- appendStringInfo(str,buf);
- _outNode(str, node->parent); */
-
- sprintf(buf, " :cost %f", node->path.path_cost);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "INDEXPATH");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :pathtype %d", node->path.pathtype);
+ appendStringInfo(str, buf);
+
+ /*
+ * sprintf(buf, " :parent "); appendStringInfo(str,buf); _outNode(str,
+ * node->parent);
+ */
+
+ sprintf(buf, " :cost %f", node->path.path_cost);
+ appendStringInfo(str, buf);
+
#if 0
- sprintf(buf, " :p_ordering ");
- appendStringInfo(str,buf);
- _outNode(str, node->path.p_ordering);
-#endif
- sprintf(buf, " :keys ");
- appendStringInfo(str,buf);
- _outNode(str, node->path.keys);
-
- sprintf(buf, " :indexid ");
- appendStringInfo(str,buf);
- _outIntList(str, node->indexid);
-
- sprintf(buf, " :indexqual ");
- appendStringInfo(str,buf);
- _outNode(str, node->indexqual);
-
+ sprintf(buf, " :p_ordering ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->path.p_ordering);
+#endif
+ sprintf(buf, " :keys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->path.keys);
+
+ sprintf(buf, " :indexid ");
+ appendStringInfo(str, buf);
+ _outIntList(str, node->indexid);
+
+ sprintf(buf, " :indexqual ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->indexqual);
+
}
/*
- * JoinPath is a subclass of Path
+ * JoinPath is a subclass of Path
*/
static void
-_outJoinPath(StringInfo str, JoinPath *node)
+_outJoinPath(StringInfo str, JoinPath * node)
{
- char buf[500];
-
- sprintf(buf, "JOINPATH");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :pathtype %d", node->path.pathtype);
- appendStringInfo(str,buf);
-
- /* sprintf(buf, " :parent ");
- appendStringInfo(str,buf);
- _outNode(str, node->parent); */
-
- sprintf(buf, " :cost %f", node->path.path_cost);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "JOINPATH");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :pathtype %d", node->path.pathtype);
+ appendStringInfo(str, buf);
+
+ /*
+ * sprintf(buf, " :parent "); appendStringInfo(str,buf); _outNode(str,
+ * node->parent);
+ */
+
+ sprintf(buf, " :cost %f", node->path.path_cost);
+ appendStringInfo(str, buf);
+
#if 0
- sprintf(buf, " :p_ordering ");
- appendStringInfo(str,buf);
- _outNode(str, node->path.p_ordering);
-#endif
- sprintf(buf, " :keys ");
- appendStringInfo(str,buf);
- _outNode(str, node->path.keys);
-
- sprintf(buf, " :pathclauseinfo ");
- appendStringInfo(str,buf);
- _outNode(str, node->pathclauseinfo);
-
- /*
- * Not sure if these are nodes; they're declared as "struct path *".
- * For now, i'll just print the addresses.
- */
-
- sprintf(buf, " :outerjoinpath @ 0x%x", (int)(node->outerjoinpath));
- appendStringInfo(str,buf);
- sprintf(buf, " :innerjoinpath @ 0x%x", (int)(node->innerjoinpath));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :outerjoincost %f", node->path.outerjoincost);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :joinid ");
- appendStringInfo(str,buf);
- _outIntList(str, node->path.joinid);
-
+ sprintf(buf, " :p_ordering ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->path.p_ordering);
+#endif
+ sprintf(buf, " :keys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->path.keys);
+
+ sprintf(buf, " :pathclauseinfo ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->pathclauseinfo);
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ */
+
+ sprintf(buf, " :outerjoinpath @ 0x%x", (int) (node->outerjoinpath));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :innerjoinpath @ 0x%x", (int) (node->innerjoinpath));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :outerjoincost %f", node->path.outerjoincost);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :joinid ");
+ appendStringInfo(str, buf);
+ _outIntList(str, node->path.joinid);
+
}
/*
- * MergePath is a subclass of JoinPath.
+ * MergePath is a subclass of JoinPath.
*/
static void
-_outMergePath(StringInfo str, MergePath *node)
+_outMergePath(StringInfo str, MergePath * node)
{
- char buf[500];
-
- sprintf(buf, "MERGEPATH");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :pathtype %d", node->jpath.path.pathtype);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :cost %f", node->jpath.path.path_cost);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :keys ");
- appendStringInfo(str,buf);
- _outNode(str, node->jpath.path.keys);
-
- sprintf(buf, " :pathclauseinfo ");
- appendStringInfo(str,buf);
- _outNode(str, node->jpath.pathclauseinfo);
-
- /*
- * Not sure if these are nodes; they're declared as "struct path *".
- * For now, i'll just print the addresses.
- */
-
- sprintf(buf, " :outerjoinpath @ 0x%x", (int)(node->jpath.outerjoinpath));
- appendStringInfo(str,buf);
- sprintf(buf, " :innerjoinpath @ 0x%x", (int)(node->jpath.innerjoinpath));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :outerjoincost %f", node->jpath.path.outerjoincost);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :joinid ");
- appendStringInfo(str,buf);
- _outIntList(str, node->jpath.path.joinid);
-
- sprintf(buf, " :path_mergeclauses ");
- appendStringInfo(str,buf);
- _outNode(str, node->path_mergeclauses);
-
- sprintf(buf, " :outersortkeys ");
- appendStringInfo(str,buf);
- _outNode(str, node->outersortkeys);
-
- sprintf(buf, " :innersortkeys ");
- appendStringInfo(str,buf);
- _outNode(str, node->innersortkeys);
-
+ char buf[500];
+
+ sprintf(buf, "MERGEPATH");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :pathtype %d", node->jpath.path.pathtype);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :cost %f", node->jpath.path.path_cost);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :keys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jpath.path.keys);
+
+ sprintf(buf, " :pathclauseinfo ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jpath.pathclauseinfo);
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ */
+
+ sprintf(buf, " :outerjoinpath @ 0x%x", (int) (node->jpath.outerjoinpath));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :innerjoinpath @ 0x%x", (int) (node->jpath.innerjoinpath));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :outerjoincost %f", node->jpath.path.outerjoincost);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :joinid ");
+ appendStringInfo(str, buf);
+ _outIntList(str, node->jpath.path.joinid);
+
+ sprintf(buf, " :path_mergeclauses ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->path_mergeclauses);
+
+ sprintf(buf, " :outersortkeys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->outersortkeys);
+
+ sprintf(buf, " :innersortkeys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->innersortkeys);
+
}
/*
- * HashPath is a subclass of JoinPath.
+ * HashPath is a subclass of JoinPath.
*/
static void
-_outHashPath(StringInfo str, HashPath *node)
+_outHashPath(StringInfo str, HashPath * node)
{
- char buf[500];
-
- sprintf(buf, "HASHPATH");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :pathtype %d", node->jpath.path.pathtype);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :cost %f", node->jpath.path.path_cost);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :keys ");
- appendStringInfo(str,buf);
- _outNode(str, node->jpath.path.keys);
-
- sprintf(buf, " :pathclauseinfo ");
- appendStringInfo(str,buf);
- _outNode(str, node->jpath.pathclauseinfo);
-
- /*
- * Not sure if these are nodes; they're declared as "struct path *".
- * For now, i'll just print the addresses.
- */
-
- sprintf(buf, " :outerjoinpath @ 0x%x", (int) (node->jpath.outerjoinpath));
- appendStringInfo(str,buf);
- sprintf(buf, " :innerjoinpath @ 0x%x", (int) (node->jpath.innerjoinpath));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :outerjoincost %f", node->jpath.path.outerjoincost);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :joinid ");
- appendStringInfo(str,buf);
- _outIntList(str, node->jpath.path.joinid);
-
- sprintf(buf, " :path_hashclauses ");
- appendStringInfo(str,buf);
- _outNode(str, node->path_hashclauses);
-
- sprintf(buf, " :outerhashkeys ");
- appendStringInfo(str,buf);
- _outNode(str, node->outerhashkeys);
-
- sprintf(buf, " :innerhashkeys ");
- appendStringInfo(str,buf);
- _outNode(str, node->innerhashkeys);
-
+ char buf[500];
+
+ sprintf(buf, "HASHPATH");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :pathtype %d", node->jpath.path.pathtype);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :cost %f", node->jpath.path.path_cost);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :keys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jpath.path.keys);
+
+ sprintf(buf, " :pathclauseinfo ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jpath.pathclauseinfo);
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ */
+
+ sprintf(buf, " :outerjoinpath @ 0x%x", (int) (node->jpath.outerjoinpath));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :innerjoinpath @ 0x%x", (int) (node->jpath.innerjoinpath));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :outerjoincost %f", node->jpath.path.outerjoincost);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :joinid ");
+ appendStringInfo(str, buf);
+ _outIntList(str, node->jpath.path.joinid);
+
+ sprintf(buf, " :path_hashclauses ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->path_hashclauses);
+
+ sprintf(buf, " :outerhashkeys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->outerhashkeys);
+
+ sprintf(buf, " :innerhashkeys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->innerhashkeys);
+
}
/*
- * OrderKey is a subclass of Node.
+ * OrderKey is a subclass of Node.
*/
static void
-_outOrderKey(StringInfo str, OrderKey *node)
+_outOrderKey(StringInfo str, OrderKey * node)
{
- char buf[500];
-
- sprintf(buf, "ORDERKEY");
- appendStringInfo(str,buf);
- sprintf(buf, " :attribute_number %d", node->attribute_number);
- appendStringInfo(str,buf);
- sprintf(buf, " :array_index %d", node->array_index);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "ORDERKEY");
+ appendStringInfo(str, buf);
+ sprintf(buf, " :attribute_number %d", node->attribute_number);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :array_index %d", node->array_index);
+ appendStringInfo(str, buf);
+
}
/*
- * JoinKey is a subclass of Node.
+ * JoinKey is a subclass of Node.
*/
static void
-_outJoinKey(StringInfo str, JoinKey *node)
+_outJoinKey(StringInfo str, JoinKey * node)
{
- char buf[500];
-
- sprintf(buf, "JOINKEY");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :outer ");
- appendStringInfo(str,buf);
- _outNode(str, node->outer);
-
- sprintf(buf, " :inner ");
- appendStringInfo(str,buf);
- _outNode(str, node->inner);
-
+ char buf[500];
+
+ sprintf(buf, "JOINKEY");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :outer ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->outer);
+
+ sprintf(buf, " :inner ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->inner);
+
}
/*
- * MergeOrder is a subclass of Node.
+ * MergeOrder is a subclass of Node.
*/
static void
-_outMergeOrder(StringInfo str, MergeOrder *node)
+_outMergeOrder(StringInfo str, MergeOrder * node)
{
- char buf[500];
-
- sprintf(buf, "MERGEORDER");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :join_operator %d", node->join_operator);
- appendStringInfo(str,buf);
- sprintf(buf, " :left_operator %d", node->left_operator);
- appendStringInfo(str,buf);
- sprintf(buf, " :right_operator %d", node->right_operator);
- appendStringInfo(str,buf);
- sprintf(buf, " :left_type %d", node->left_type);
- appendStringInfo(str,buf);
- sprintf(buf, " :right_type %d", node->right_type);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "MERGEORDER");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :join_operator %d", node->join_operator);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :left_operator %d", node->left_operator);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :right_operator %d", node->right_operator);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :left_type %d", node->left_type);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :right_type %d", node->right_type);
+ appendStringInfo(str, buf);
+
}
/*
- * CInfo is a subclass of Node.
+ * CInfo is a subclass of Node.
*/
static void
-_outCInfo(StringInfo str, CInfo *node)
+_outCInfo(StringInfo str, CInfo * node)
{
- char buf[500];
-
- sprintf(buf, "CINFO");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :clause ");
- appendStringInfo(str,buf);
- _outNode(str, node->clause);
-
- sprintf(buf, " :selectivity %f", node->selectivity);
- appendStringInfo(str,buf);
- sprintf(buf, " :notclause %s", (node->notclause ? "true" : "nil"));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :indexids ");
- appendStringInfo(str,buf);
- _outNode(str, node->indexids);
-
- sprintf(buf, " :mergesortorder ");
- appendStringInfo(str,buf);
- _outNode(str, node->mergesortorder);
-
- sprintf(buf, " :hashjoinoperator %u", node->hashjoinoperator);
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "CINFO");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :clause ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->clause);
+
+ sprintf(buf, " :selectivity %f", node->selectivity);
+ appendStringInfo(str, buf);
+ sprintf(buf, " :notclause %s", (node->notclause ? "true" : "nil"));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :indexids ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->indexids);
+
+ sprintf(buf, " :mergesortorder ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->mergesortorder);
+
+ sprintf(buf, " :hashjoinoperator %u", node->hashjoinoperator);
+ appendStringInfo(str, buf);
+
}
/*
- * JoinMethod is a subclass of Node.
+ * JoinMethod is a subclass of Node.
*/
static void
-_outJoinMethod(StringInfo str, JoinMethod *node)
+_outJoinMethod(StringInfo str, JoinMethod * node)
{
- char buf[500];
-
- sprintf(buf, "JOINMETHOD");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :jmkeys ");
- appendStringInfo(str,buf);
- _outNode(str, node->jmkeys);
-
- sprintf(buf, " :clauses ");
- appendStringInfo(str,buf);
- _outNode(str, node->clauses);
-
-
+ char buf[500];
+
+ sprintf(buf, "JOINMETHOD");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :jmkeys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jmkeys);
+
+ sprintf(buf, " :clauses ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->clauses);
+
+
}
/*
* HInfo is a subclass of JoinMethod.
*/
static void
-_outHInfo(StringInfo str, HInfo *node)
+_outHInfo(StringInfo str, HInfo * node)
{
- char buf[500];
-
- sprintf(buf, "HASHINFO");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :hashop ");
- appendStringInfo(str,buf);
- sprintf(buf, "%u",node->hashop);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :jmkeys ");
- appendStringInfo(str,buf);
- _outNode(str, node->jmethod.jmkeys);
-
- sprintf(buf, " :clauses ");
- appendStringInfo(str,buf);
- _outNode(str, node->jmethod.clauses);
-
+ char buf[500];
+
+ sprintf(buf, "HASHINFO");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :hashop ");
+ appendStringInfo(str, buf);
+ sprintf(buf, "%u", node->hashop);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :jmkeys ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jmethod.jmkeys);
+
+ sprintf(buf, " :clauses ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jmethod.clauses);
+
}
/*
- * JInfo is a subclass of Node.
+ * JInfo is a subclass of Node.
*/
static void
-_outJInfo(StringInfo str, JInfo *node)
+_outJInfo(StringInfo str, JInfo * node)
{
- char buf[500];
-
- sprintf(buf, "JINFO");
- appendStringInfo(str,buf);
-
- sprintf(buf, " :otherrels ");
- appendStringInfo(str,buf);
- _outIntList(str, node->otherrels);
-
- sprintf(buf, " :jinfoclauseinfo ");
- appendStringInfo(str,buf);
- _outNode(str, node->jinfoclauseinfo);
-
- sprintf(buf, " :mergesortable %s",
- (node->mergesortable ? "true" : "nil"));
- appendStringInfo(str,buf);
- sprintf(buf, " :hashjoinable %s",
- (node->hashjoinable ? "true" : "nil"));
- appendStringInfo(str,buf);
-
+ char buf[500];
+
+ sprintf(buf, "JINFO");
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :otherrels ");
+ appendStringInfo(str, buf);
+ _outIntList(str, node->otherrels);
+
+ sprintf(buf, " :jinfoclauseinfo ");
+ appendStringInfo(str, buf);
+ _outNode(str, node->jinfoclauseinfo);
+
+ sprintf(buf, " :mergesortable %s",
+ (node->mergesortable ? "true" : "nil"));
+ appendStringInfo(str, buf);
+ sprintf(buf, " :hashjoinable %s",
+ (node->hashjoinable ? "true" : "nil"));
+ appendStringInfo(str, buf);
+
}
/*
@@ -1352,319 +1369,340 @@ _outJInfo(StringInfo str, JInfo *node)
static void
_outDatum(StringInfo str, Datum value, Oid type)
{
- char buf[500];
- Size length, typeLength;
- bool byValue;
- int i;
- char *s;
-
- /*
- * find some information about the type and the "real" length
- * of the datum.
- */
- byValue = get_typbyval(type);
- typeLength = get_typlen(type);
- length = datumGetSize(value, type, byValue, typeLength);
-
- if (byValue) {
- s = (char *) (&value);
- sprintf(buf, " %d [ ", length);
- appendStringInfo(str,buf);
- for (i=0; i<sizeof(Datum); i++) {
- sprintf(buf, "%d ", (int) (s[i]) );
- appendStringInfo(str,buf);
+ char buf[500];
+ Size length,
+ typeLength;
+ bool byValue;
+ int i;
+ char *s;
+
+ /*
+ * find some information about the type and the "real" length of the
+ * datum.
+ */
+ byValue = get_typbyval(type);
+ typeLength = get_typlen(type);
+ length = datumGetSize(value, type, byValue, typeLength);
+
+ if (byValue)
+ {
+ s = (char *) (&value);
+ sprintf(buf, " %d [ ", length);
+ appendStringInfo(str, buf);
+ for (i = 0; i < sizeof(Datum); i++)
+ {
+ sprintf(buf, "%d ", (int) (s[i]));
+ appendStringInfo(str, buf);
+ }
+ sprintf(buf, "] ");
+ appendStringInfo(str, buf);
}
- sprintf(buf, "] ");
- appendStringInfo(str,buf);
- } else { /* !byValue */
- s = (char *) DatumGetPointer(value);
- if (!PointerIsValid(s)) {
- sprintf(buf, " 0 [ ] ");
- appendStringInfo(str,buf);
- } else {
- /*
- * length is unsigned - very bad to do < comparison to -1 without
- * casting it to int first!! -mer 8 Jan 1991
- */
- if (((int)length) <= -1) {
- length = VARSIZE(s);
- }
- sprintf(buf, " %d [ ", length);
- appendStringInfo(str,buf);
- for (i=0; i<length; i++) {
- sprintf(buf, "%d ", (int) (s[i]) );
- appendStringInfo(str,buf);
- }
- sprintf(buf, "] ");
- appendStringInfo(str,buf);
+ else
+ { /* !byValue */
+ s = (char *) DatumGetPointer(value);
+ if (!PointerIsValid(s))
+ {
+ sprintf(buf, " 0 [ ] ");
+ appendStringInfo(str, buf);
+ }
+ else
+ {
+
+ /*
+ * length is unsigned - very bad to do < comparison to -1
+ * without casting it to int first!! -mer 8 Jan 1991
+ */
+ if (((int) length) <= -1)
+ {
+ length = VARSIZE(s);
+ }
+ sprintf(buf, " %d [ ", length);
+ appendStringInfo(str, buf);
+ for (i = 0; i < length; i++)
+ {
+ sprintf(buf, "%d ", (int) (s[i]));
+ appendStringInfo(str, buf);
+ }
+ sprintf(buf, "] ");
+ appendStringInfo(str, buf);
+ }
}
- }
-
+
}
static void
-_outIter(StringInfo str, Iter *node)
+_outIter(StringInfo str, Iter * node)
{
- appendStringInfo(str,"ITER");
-
- appendStringInfo(str," :iterexpr ");
- _outNode(str, node->iterexpr);
+ appendStringInfo(str, "ITER");
+
+ appendStringInfo(str, " :iterexpr ");
+ _outNode(str, node->iterexpr);
}
static void
-_outStream(StringInfo str, Stream *node)
+_outStream(StringInfo str, Stream * node)
{
- char buf[500];
-
- appendStringInfo(str,"STREAM");
-
- sprintf(buf, " :pathptr @ 0x%x", (int)(node->pathptr));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :cinfo @ 0x%x", (int)(node->cinfo));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :clausetype %d", (int)(node->clausetype));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :upstream @ 0x%x", (int)(node->upstream));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :downstream @ 0x%x", (int)(node->downstream));
- appendStringInfo(str,buf);
-
- sprintf(buf, " :groupup %d", node->groupup);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :groupcost %f", node->groupcost);
- appendStringInfo(str,buf);
-
- sprintf(buf, " :groupsel %f", node->groupsel);
- appendStringInfo(str,buf);
-}
+ char buf[500];
+
+ appendStringInfo(str, "STREAM");
+
+ sprintf(buf, " :pathptr @ 0x%x", (int) (node->pathptr));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :cinfo @ 0x%x", (int) (node->cinfo));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :clausetype %d", (int) (node->clausetype));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :upstream @ 0x%x", (int) (node->upstream));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :downstream @ 0x%x", (int) (node->downstream));
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :groupup %d", node->groupup);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :groupcost %f", node->groupcost);
+ appendStringInfo(str, buf);
+
+ sprintf(buf, " :groupsel %f", node->groupsel);
+ appendStringInfo(str, buf);
+}
static void
-_outValue(StringInfo str, Value *value)
+_outValue(StringInfo str, Value * value)
{
- char buf[500];
-
- switch(value->type) {
- case T_String:
- sprintf(buf, "\"%s\"", value->val.str);
- appendStringInfo(str, buf);
- break;
- case T_Integer:
- sprintf(buf, "%ld", value->val.ival);
- appendStringInfo(str, buf);
- break;
- case T_Float:
- sprintf(buf, "%f", value->val.dval);
- appendStringInfo(str, buf);
- break;
- default:
- break;
- }
- return;
+ char buf[500];
+
+ switch (value->type)
+ {
+ case T_String:
+ sprintf(buf, "\"%s\"", value->val.str);
+ appendStringInfo(str, buf);
+ break;
+ case T_Integer:
+ sprintf(buf, "%ld", value->val.ival);
+ appendStringInfo(str, buf);
+ break;
+ case T_Float:
+ sprintf(buf, "%f", value->val.dval);
+ appendStringInfo(str, buf);
+ break;
+ default:
+ break;
+ }
+ return;
}
/*
* _outNode -
- * converts a Node into ascii string and append it to 'str'
+ * converts a Node into ascii string and append it to 'str'
*/
static void
_outNode(StringInfo str, void *obj)
{
- if (obj==NULL) {
- appendStringInfo(str, "nil");
- return;
- }
+ if (obj == NULL)
+ {
+ appendStringInfo(str, "nil");
+ return;
+ }
- if (nodeTag(obj)==T_List) {
- List *l;
- appendStringInfo(str, "(");
- foreach(l, (List*)obj) {
- _outNode(str, lfirst(l));
- if (lnext(l))
- appendStringInfo(str, " ");
+ if (nodeTag(obj) == T_List)
+ {
+ List *l;
+
+ appendStringInfo(str, "(");
+ foreach(l, (List *) obj)
+ {
+ _outNode(str, lfirst(l));
+ if (lnext(l))
+ appendStringInfo(str, " ");
+ }
+ appendStringInfo(str, ")");
}
- appendStringInfo(str, ")");
- }else {
- appendStringInfo(str, "{");
- switch(nodeTag(obj)) {
- case T_Query:
- _outQuery(str, obj);
- break;
- case T_Plan:
- _outPlan(str, obj);
- break;
- case T_Result:
- _outResult(str, obj);
- break;
- case T_Existential:
- _outExistential(str, obj);
- break;
- case T_Append:
- _outAppend(str, obj);
- break;
- case T_Join:
- _outJoin(str, obj);
- break;
- case T_NestLoop:
- _outNestLoop(str, obj);
- break;
- case T_MergeJoin:
- _outMergeJoin(str, obj);
- break;
- case T_HashJoin:
- _outHashJoin(str, obj);
- break;
- case T_Scan:
- _outScan(str, obj);
- break;
- case T_SeqScan:
- _outSeqScan(str, obj);
- break;
- case T_IndexScan:
- _outIndexScan(str, obj);
- break;
- case T_Temp:
- _outTemp(str, obj);
- break;
- case T_Sort:
- _outSort(str, obj);
- break;
- case T_Agg:
- _outAgg(str, obj);
- break;
- case T_Group:
- _outGroup(str, obj);
- break;
- case T_Unique:
- _outUnique(str, obj);
- break;
- case T_Hash:
- _outHash(str, obj);
- break;
- case T_Tee:
- _outTee(str, obj);
- break;
- case T_Resdom:
- _outResdom(str, obj);
- break;
- case T_Fjoin:
- _outFjoin(str, obj);
- break;
- case T_Expr:
- _outExpr(str, obj);
- break;
- case T_Var:
- _outVar(str, obj);
- break;
- case T_Const:
- _outConst(str, obj);
- break;
- case T_Aggreg:
- _outAggreg(str, obj);
- break;
- case T_Array:
- _outArray(str, obj);
- break;
- case T_ArrayRef:
- _outArrayRef(str, obj);
- break;
- case T_Func:
- _outFunc(str, obj);
- break;
- case T_Oper:
- _outOper(str, obj);
- break;
- case T_Param:
- _outParam(str, obj);
- break;
- case T_EState:
- _outEState(str, obj);
- break;
- case T_Rel:
- _outRel(str, obj);
- break;
- case T_TargetEntry:
- _outTargetEntry(str, obj);
- break;
- case T_RangeTblEntry:
- _outRangeTblEntry(str, obj);
- break;
- case T_Path:
- _outPath(str, obj);
- break;
- case T_IndexPath:
- _outIndexPath (str, obj);
- break;
- case T_JoinPath:
- _outJoinPath(str, obj);
- break;
- case T_MergePath:
- _outMergePath(str, obj);
- break;
- case T_HashPath:
- _outHashPath(str, obj);
- break;
- case T_OrderKey:
- _outOrderKey(str, obj);
- break;
- case T_JoinKey:
- _outJoinKey(str, obj);
- break;
- case T_MergeOrder:
- _outMergeOrder(str, obj);
- break;
- case T_CInfo:
- _outCInfo(str, obj);
- break;
- case T_JoinMethod:
- _outJoinMethod(str, obj);
- break;
- case T_HInfo:
- _outHInfo(str, obj);
- break;
- case T_JInfo:
- _outJInfo(str, obj);
- break;
- case T_Iter:
- _outIter(str, obj);
- break;
- case T_Stream:
- _outStream(str, obj);
- break;
- case T_Integer: case T_String: case T_Float:
- _outValue(str, obj);
- break;
- default:
- elog(NOTICE, "_outNode: don't know how to print type %d",
- nodeTag(obj));
- break;
+ else
+ {
+ appendStringInfo(str, "{");
+ switch (nodeTag(obj))
+ {
+ case T_Query:
+ _outQuery(str, obj);
+ break;
+ case T_Plan:
+ _outPlan(str, obj);
+ break;
+ case T_Result:
+ _outResult(str, obj);
+ break;
+ case T_Existential:
+ _outExistential(str, obj);
+ break;
+ case T_Append:
+ _outAppend(str, obj);
+ break;
+ case T_Join:
+ _outJoin(str, obj);
+ break;
+ case T_NestLoop:
+ _outNestLoop(str, obj);
+ break;
+ case T_MergeJoin:
+ _outMergeJoin(str, obj);
+ break;
+ case T_HashJoin:
+ _outHashJoin(str, obj);
+ break;
+ case T_Scan:
+ _outScan(str, obj);
+ break;
+ case T_SeqScan:
+ _outSeqScan(str, obj);
+ break;
+ case T_IndexScan:
+ _outIndexScan(str, obj);
+ break;
+ case T_Temp:
+ _outTemp(str, obj);
+ break;
+ case T_Sort:
+ _outSort(str, obj);
+ break;
+ case T_Agg:
+ _outAgg(str, obj);
+ break;
+ case T_Group:
+ _outGroup(str, obj);
+ break;
+ case T_Unique:
+ _outUnique(str, obj);
+ break;
+ case T_Hash:
+ _outHash(str, obj);
+ break;
+ case T_Tee:
+ _outTee(str, obj);
+ break;
+ case T_Resdom:
+ _outResdom(str, obj);
+ break;
+ case T_Fjoin:
+ _outFjoin(str, obj);
+ break;
+ case T_Expr:
+ _outExpr(str, obj);
+ break;
+ case T_Var:
+ _outVar(str, obj);
+ break;
+ case T_Const:
+ _outConst(str, obj);
+ break;
+ case T_Aggreg:
+ _outAggreg(str, obj);
+ break;
+ case T_Array:
+ _outArray(str, obj);
+ break;
+ case T_ArrayRef:
+ _outArrayRef(str, obj);
+ break;
+ case T_Func:
+ _outFunc(str, obj);
+ break;
+ case T_Oper:
+ _outOper(str, obj);
+ break;
+ case T_Param:
+ _outParam(str, obj);
+ break;
+ case T_EState:
+ _outEState(str, obj);
+ break;
+ case T_Rel:
+ _outRel(str, obj);
+ break;
+ case T_TargetEntry:
+ _outTargetEntry(str, obj);
+ break;
+ case T_RangeTblEntry:
+ _outRangeTblEntry(str, obj);
+ break;
+ case T_Path:
+ _outPath(str, obj);
+ break;
+ case T_IndexPath:
+ _outIndexPath(str, obj);
+ break;
+ case T_JoinPath:
+ _outJoinPath(str, obj);
+ break;
+ case T_MergePath:
+ _outMergePath(str, obj);
+ break;
+ case T_HashPath:
+ _outHashPath(str, obj);
+ break;
+ case T_OrderKey:
+ _outOrderKey(str, obj);
+ break;
+ case T_JoinKey:
+ _outJoinKey(str, obj);
+ break;
+ case T_MergeOrder:
+ _outMergeOrder(str, obj);
+ break;
+ case T_CInfo:
+ _outCInfo(str, obj);
+ break;
+ case T_JoinMethod:
+ _outJoinMethod(str, obj);
+ break;
+ case T_HInfo:
+ _outHInfo(str, obj);
+ break;
+ case T_JInfo:
+ _outJInfo(str, obj);
+ break;
+ case T_Iter:
+ _outIter(str, obj);
+ break;
+ case T_Stream:
+ _outStream(str, obj);
+ break;
+ case T_Integer:
+ case T_String:
+ case T_Float:
+ _outValue(str, obj);
+ break;
+ default:
+ elog(NOTICE, "_outNode: don't know how to print type %d",
+ nodeTag(obj));
+ break;
+ }
+ appendStringInfo(str, "}");
}
- appendStringInfo(str, "}");
- }
- return;
+ return;
}
/*
* nodeToString -
- * returns the ascii representation of the Node
+ * returns the ascii representation of the Node
*/
-char *
+char *
nodeToString(void *obj)
{
- StringInfo str;
- char *s;
-
- if (obj==NULL)
- return "";
- Assert(obj!=NULL);
- str = makeStringInfo();
- _outNode(str, obj);
- s = str->data;
- pfree(str);
-
- return s;
+ StringInfo str;
+ char *s;
+
+ if (obj == NULL)
+ return "";
+ Assert(obj != NULL);
+ str = makeStringInfo();
+ _outNode(str, obj);
+ s = str->data;
+ pfree(str);
+
+ return s;
}
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 0f92c189e51..9fb61ed3ea7 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* print.c--
- * various print routines (used mostly for debugging)
+ * various print routines (used mostly for debugging)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.6 1997/08/19 21:31:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.7 1997/09/07 04:42:55 momjian Exp $
*
* HISTORY
- * AUTHOR DATE MAJOR EVENT
- * Andrew Yu Oct 26, 1994 file creation
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Oct 26, 1994 file creation
*
*-------------------------------------------------------------------------
*/
@@ -33,21 +33,21 @@
#include "nodes/plannodes.h"
#include "optimizer/clauses.h"
-static char *plannode_type (Plan* p);
+static char *plannode_type(Plan * p);
/*
* print--
- * print contents of Node to stdout
+ * print contents of Node to stdout
*/
void
print(void *obj)
{
- char *s;
+ char *s;
- s = nodeToString(obj);
- printf("%s\n", s);
- fflush(stdout);
- return;
+ s = nodeToString(obj);
+ printf("%s\n", s);
+ fflush(stdout);
+ return;
}
/*
@@ -56,327 +56,365 @@ print(void *obj)
void
pprint(void *obj)
{
- char *s;
- int i;
- char line[80];
- int indentLev;
- int j;
-
- s = nodeToString(obj);
-
- indentLev = 0;
- i = 0;
- for(;;) {
- for(j=0; j<indentLev*3; j++) {
- line[j] = ' ';
- }
- for( ; j<75 && s[i]!='\0'; i++, j++) {
- line[j] = s[i];
- switch (line[j]) {
- case '}':
- if (j != indentLev*3) {
- line[j] = '\0';
- printf("%s\n",line);
- line[indentLev*3] = '\0';
- printf("%s}\n",line);
- }else {
- line[j] = '\0';
- printf("%s}\n",line);
- }
- indentLev--;
- j = indentLev*3-1; /* print the line before : and resets */
- break;
- case ')':
- line[j+1] = '\0';
- printf("%s\n", line);
- j = indentLev*3-1;
- break;
- case '{':
- indentLev++;
- /* !!! FALLS THROUGH */
- case ':':
- if (j != 0) {
- line[j] = '\0';
- printf("%s\n",line);
- /* print the line before : and resets */
- for(j=0; j<indentLev*3; j++) {
+ char *s;
+ int i;
+ char line[80];
+ int indentLev;
+ int j;
+
+ s = nodeToString(obj);
+
+ indentLev = 0;
+ i = 0;
+ for (;;)
+ {
+ for (j = 0; j < indentLev * 3; j++)
+ {
line[j] = ' ';
- }
}
- line[j] = s[i];
- break;
- }
+ for (; j < 75 && s[i] != '\0'; i++, j++)
+ {
+ line[j] = s[i];
+ switch (line[j])
+ {
+ case '}':
+ if (j != indentLev * 3)
+ {
+ line[j] = '\0';
+ printf("%s\n", line);
+ line[indentLev * 3] = '\0';
+ printf("%s}\n", line);
+ }
+ else
+ {
+ line[j] = '\0';
+ printf("%s}\n", line);
+ }
+ indentLev--;
+ j = indentLev * 3 - 1; /* print the line before : and
+ * resets */
+ break;
+ case ')':
+ line[j + 1] = '\0';
+ printf("%s\n", line);
+ j = indentLev * 3 - 1;
+ break;
+ case '{':
+ indentLev++;
+ /* !!! FALLS THROUGH */
+ case ':':
+ if (j != 0)
+ {
+ line[j] = '\0';
+ printf("%s\n", line);
+ /* print the line before : and resets */
+ for (j = 0; j < indentLev * 3; j++)
+ {
+ line[j] = ' ';
+ }
+ }
+ line[j] = s[i];
+ break;
+ }
+ }
+ line[j] = '\0';
+ if (s[i] == '\0')
+ break;
+ printf("%s\n", line);
}
- line[j] = '\0';
- if (s[i]=='\0')
- break;
- printf("%s\n", line);
- }
- if (j!=0) {
- printf("%s\n", line);
- }
- fflush(stdout);
- return;
+ if (j != 0)
+ {
+ printf("%s\n", line);
+ }
+ fflush(stdout);
+ return;
}
/*
* print_rt--
- * print contents of range table
+ * print contents of range table
*/
void
-print_rt(List *rtable)
+print_rt(List * rtable)
{
- List *l;
- int i=1;
-
- printf("resno\trelname(refname)\trelid\tinFromCl\n");
- printf("-----\t----------------\t-----\t--------\n");
- foreach(l, rtable) {
- RangeTblEntry *rte = lfirst(l);
- printf("%d\t%s(%s)\t%d\t%d\t%s\n",
- i,rte->relname,rte->refname,rte->relid,
- rte->inFromCl,
- (rte->inh?"inh":""));
- i++;
- }
+ List *l;
+ int i = 1;
+
+ printf("resno\trelname(refname)\trelid\tinFromCl\n");
+ printf("-----\t----------------\t-----\t--------\n");
+ foreach(l, rtable)
+ {
+ RangeTblEntry *rte = lfirst(l);
+
+ printf("%d\t%s(%s)\t%d\t%d\t%s\n",
+ i, rte->relname, rte->refname, rte->relid,
+ rte->inFromCl,
+ (rte->inh ? "inh" : ""));
+ i++;
+ }
}
/*
* print_expr--
- * print an expression
+ * print an expression
*/
void
-print_expr(Node *expr, List *rtable)
+print_expr(Node * expr, List * rtable)
{
- if (expr==NULL) {
- printf("nil");
- return;
- }
-
- if (IsA(expr,Var)) {
- Var *var = (Var*)expr;
- RangeTblEntry *rt;
- char *relname, *attname;
-
- switch (var->varno) {
- case INNER:
- relname = "INNER";
- attname = "?";
- break;
- case OUTER:
- relname = "OUTER";
- attname = "?";
- break;
- default:
- {
- Relation r;
- rt = rt_fetch(var->varno, rtable);
- relname = rt->relname;
- r = heap_openr(relname);
- if (rt->refname)
- relname = rt->refname; /* table renamed */
- attname = getAttrName(r, var->varattno);
- heap_close(r);
- }
- break;
+ if (expr == NULL)
+ {
+ printf("nil");
+ return;
}
- printf("%s.%s",relname,attname);
- } else if (IsA(expr,Expr)) {
- Expr *e = (Expr*)expr;
- if (is_opclause(expr)) {
- char *opname;
-
- print_expr((Node*)get_leftop(e), rtable);
- opname = get_opname(((Oper*)e->oper)->opno);
- printf(" %s ", opname);
- print_expr((Node*)get_rightop(e), rtable);
- } else {
- printf("an expr");
+
+ if (IsA(expr, Var))
+ {
+ Var *var = (Var *) expr;
+ RangeTblEntry *rt;
+ char *relname,
+ *attname;
+
+ switch (var->varno)
+ {
+ case INNER:
+ relname = "INNER";
+ attname = "?";
+ break;
+ case OUTER:
+ relname = "OUTER";
+ attname = "?";
+ break;
+ default:
+ {
+ Relation r;
+
+ rt = rt_fetch(var->varno, rtable);
+ relname = rt->relname;
+ r = heap_openr(relname);
+ if (rt->refname)
+ relname = rt->refname; /* table renamed */
+ attname = getAttrName(r, var->varattno);
+ heap_close(r);
+ }
+ break;
+ }
+ printf("%s.%s", relname, attname);
+ }
+ else if (IsA(expr, Expr))
+ {
+ Expr *e = (Expr *) expr;
+
+ if (is_opclause(expr))
+ {
+ char *opname;
+
+ print_expr((Node *) get_leftop(e), rtable);
+ opname = get_opname(((Oper *) e->oper)->opno);
+ printf(" %s ", opname);
+ print_expr((Node *) get_rightop(e), rtable);
+ }
+ else
+ {
+ printf("an expr");
+ }
+ }
+ else
+ {
+ printf("not an expr");
}
- } else {
- printf("not an expr");
- }
}
/*
* print_keys -
- * temporary here. where is keys list of list??
+ * temporary here. where is keys list of list??
*/
void
-print_keys(List *keys, List *rtable)
+print_keys(List * keys, List * rtable)
{
- List *k;
-
- printf("(");
- foreach(k, keys) {
- Node *var = lfirst((List*)lfirst(k));
- print_expr(var, rtable);
- if (lnext(k)) printf(", ");
- }
- printf(")\n");
+ List *k;
+
+ printf("(");
+ foreach(k, keys)
+ {
+ Node *var = lfirst((List *) lfirst(k));
+
+ print_expr(var, rtable);
+ if (lnext(k))
+ printf(", ");
+ }
+ printf(")\n");
}
/*
* print_tl --
- * print targetlist in a more legible way.
+ * print targetlist in a more legible way.
*/
-void
-print_tl(List *tlist, List *rtable)
+void
+print_tl(List * tlist, List * rtable)
{
- List *tl;
+ List *tl;
- printf("(\n");
- foreach(tl, tlist) {
- TargetEntry *tle = lfirst(tl);
+ printf("(\n");
+ foreach(tl, tlist)
+ {
+ TargetEntry *tle = lfirst(tl);
- printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname);
- if (tle->resdom->reskey!=0) {
- printf("(%d):\t", tle->resdom->reskey);
- } else {
- printf(" :\t");
+ printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname);
+ if (tle->resdom->reskey != 0)
+ {
+ printf("(%d):\t", tle->resdom->reskey);
+ }
+ else
+ {
+ printf(" :\t");
+ }
+ print_expr(tle->expr, rtable);
+ printf("\n");
}
- print_expr(tle->expr, rtable);
- printf("\n");
- }
- printf(")\n");
+ printf(")\n");
}
/*
* print_slot--
- * print out the tuple with the given TupleTableSlot
+ * print out the tuple with the given TupleTableSlot
*/
void
-print_slot(TupleTableSlot *slot)
+print_slot(TupleTableSlot * slot)
{
- if (!slot->val) {
- printf("tuple is null.\n");
- return;
- }
- if (!slot->ttc_tupleDescriptor) {
- printf("no tuple descriptor.\n");
- return;
- }
-
- debugtup(slot->val, slot->ttc_tupleDescriptor);
+ if (!slot->val)
+ {
+ printf("tuple is null.\n");
+ return;
+ }
+ if (!slot->ttc_tupleDescriptor)
+ {
+ printf("no tuple descriptor.\n");
+ return;
+ }
+
+ debugtup(slot->val, slot->ttc_tupleDescriptor);
}
-static char *
-plannode_type (Plan* p)
+static char *
+plannode_type(Plan * p)
{
- switch(nodeTag(p)) {
- case T_Plan:
- return "PLAN";
- break;
- case T_Existential:
- return "EXISTENTIAL";
- break;
- case T_Result:
- return "RESULT";
- break;
- case T_Append:
- return "APPEND";
- break;
- case T_Scan:
- return "SCAN";
- break;
- case T_SeqScan:
- return "SEQSCAN";
- break;
- case T_IndexScan:
- return "INDEXSCAN";
- break;
- case T_Join:
- return "JOIN";
- break;
- case T_NestLoop:
- return "NESTLOOP";
- break;
- case T_MergeJoin:
- return "MERGEJOIN";
- break;
- case T_HashJoin:
- return "HASHJOIN";
- break;
- case T_Temp:
- return "TEMP";
- break;
- case T_Material:
- return "MATERIAL";
- break;
- case T_Sort:
- return "SORT";
- break;
- case T_Agg:
- return "AGG";
- break;
- case T_Unique:
- return "UNIQUE";
- break;
- case T_Hash:
- return "HASH";
- break;
- case T_Tee:
- return "TEE";
- break;
- case T_Choose:
- return "CHOOSE";
- break;
- case T_Group:
- return "GROUP";
- break;
- default:
- return "UNKNOWN";
- break;
- }
+ switch (nodeTag(p))
+ {
+ case T_Plan:
+ return "PLAN";
+ break;
+ case T_Existential:
+ return "EXISTENTIAL";
+ break;
+ case T_Result:
+ return "RESULT";
+ break;
+ case T_Append:
+ return "APPEND";
+ break;
+ case T_Scan:
+ return "SCAN";
+ break;
+ case T_SeqScan:
+ return "SEQSCAN";
+ break;
+ case T_IndexScan:
+ return "INDEXSCAN";
+ break;
+ case T_Join:
+ return "JOIN";
+ break;
+ case T_NestLoop:
+ return "NESTLOOP";
+ break;
+ case T_MergeJoin:
+ return "MERGEJOIN";
+ break;
+ case T_HashJoin:
+ return "HASHJOIN";
+ break;
+ case T_Temp:
+ return "TEMP";
+ break;
+ case T_Material:
+ return "MATERIAL";
+ break;
+ case T_Sort:
+ return "SORT";
+ break;
+ case T_Agg:
+ return "AGG";
+ break;
+ case T_Unique:
+ return "UNIQUE";
+ break;
+ case T_Hash:
+ return "HASH";
+ break;
+ case T_Tee:
+ return "TEE";
+ break;
+ case T_Choose:
+ return "CHOOSE";
+ break;
+ case T_Group:
+ return "GROUP";
+ break;
+ default:
+ return "UNKNOWN";
+ break;
+ }
}
+
/*
prints the ascii description of the plan nodes
does this recursively by doing a depth-first traversal of the
plan tree. for SeqScan and IndexScan, the name of the table is also
- printed out
+ printed out
*/
void
-print_plan_recursive (Plan* p, Query *parsetree, int indentLevel, char* label)
+print_plan_recursive(Plan * p, Query * parsetree, int indentLevel, char *label)
{
- int i;
- char extraInfo[100];
+ int i;
+ char extraInfo[100];
- if (!p)
- return;
- for (i=0;i<indentLevel;i++)
- printf(" ");
- printf("%s%s :c=%.4f :s=%d :w=%d ",label, plannode_type(p),
- p->cost, p->plan_size, p->plan_width);
- if (IsA(p,Scan) || IsA(p,SeqScan)) {
- RangeTblEntry *rte;
- rte = rt_fetch(((Scan*)p)->scanrelid, parsetree->rtable);
- strNcpy(extraInfo, rte->relname, NAMEDATALEN-1);
- } else
- if (IsA(p,IndexScan)) {
- strNcpy(extraInfo,
- ((RangeTblEntry*)(nth(((IndexScan*)p)->scan.scanrelid - 1,
- parsetree->rtable)))->relname,
- NAMEDATALEN-1);
- } else
- extraInfo[0] = '\0';
- if (extraInfo[0] != '\0')
- printf(" ( %s )\n", extraInfo);
- else
- printf("\n");
- print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
- print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
+ if (!p)
+ return;
+ for (i = 0; i < indentLevel; i++)
+ printf(" ");
+ printf("%s%s :c=%.4f :s=%d :w=%d ", label, plannode_type(p),
+ p->cost, p->plan_size, p->plan_width);
+ if (IsA(p, Scan) || IsA(p, SeqScan))
+ {
+ RangeTblEntry *rte;
+
+ rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
+ strNcpy(extraInfo, rte->relname, NAMEDATALEN - 1);
+ }
+ else if (IsA(p, IndexScan))
+ {
+ strNcpy(extraInfo,
+ ((RangeTblEntry *) (nth(((IndexScan *) p)->scan.scanrelid - 1,
+ parsetree->rtable)))->relname,
+ NAMEDATALEN - 1);
+ }
+ else
+ extraInfo[0] = '\0';
+ if (extraInfo[0] != '\0')
+ printf(" ( %s )\n", extraInfo);
+ else
+ printf("\n");
+ print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
+ print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
}
-/* print_plan
+/* print_plan
prints just the plan node types */
void
-print_plan (Plan* p, Query* parsetree)
+print_plan(Plan * p, Query * parsetree)
{
- print_plan_recursive(p, parsetree, 0, "");
+ print_plan_recursive(p, parsetree, 0, "");
}
-
-
-
diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c
index 7e89f9d74d3..f0baa4f14d7 100644
--- a/src/backend/nodes/read.c
+++ b/src/backend/nodes/read.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* read.c--
- * routines to convert a string (legal ascii representation of node) back
- * to nodes
+ * routines to convert a string (legal ascii representation of node) back
+ * to nodes
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.3 1997/08/12 22:53:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.4 1997/09/07 04:42:56 momjian Exp $
*
* HISTORY
- * AUTHOR DATE MAJOR EVENT
- * Andrew Yu Nov 2, 1994 file creation
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Nov 2, 1994 file creation
*
*-------------------------------------------------------------------------
*/
@@ -26,17 +26,17 @@
/*
* stringToNode -
- * returns a Node with a given legal ascii representation
+ * returns a Node with a given legal ascii representation
*/
-void *
+void *
stringToNode(char *str)
{
- void *retval;
+ void *retval;
- lsptok(str, NULL); /* set the string used in lsptok */
- retval = nodeRead(true); /* start reading */
+ lsptok(str, NULL); /* set the string used in lsptok */
+ retval = nodeRead(true); /* start reading */
- return retval;
+ return retval;
}
/*****************************************************************************
@@ -46,115 +46,126 @@ stringToNode(char *str)
*****************************************************************************/
#define RIGHT_PAREN (1000000 + 1)
-#define LEFT_PAREN (1000000 + 2)
-#define PLAN_SYM (1000000 + 3)
-#define AT_SYMBOL (1000000 + 4)
-#define ATOM_TOKEN (1000000 + 5)
+#define LEFT_PAREN (1000000 + 2)
+#define PLAN_SYM (1000000 + 3)
+#define AT_SYMBOL (1000000 + 4)
+#define ATOM_TOKEN (1000000 + 5)
/*
* nodeTokenType -
- * returns the type of the node token contained in token.
- * It returns one of the following valid NodeTags:
- * T_Integer, T_Float, T_String
- * and some of its own:
- * RIGHT_PAREN, LEFT_PAREN, PLAN_SYM, AT_SYMBOL, ATOM_TOKEN
+ * returns the type of the node token contained in token.
+ * It returns one of the following valid NodeTags:
+ * T_Integer, T_Float, T_String
+ * and some of its own:
+ * RIGHT_PAREN, LEFT_PAREN, PLAN_SYM, AT_SYMBOL, ATOM_TOKEN
*
- * Assumption: the ascii representation is legal
+ * Assumption: the ascii representation is legal
*/
-static NodeTag
+static NodeTag
nodeTokenType(char *token, int length)
{
- NodeTag retval = 0;
-
- /*
- * Check if the token is a number (decimal or integer,
- * positive or negative
- */
- if (isdigit(*token) ||
- (length>=2 && *token=='-' && isdigit(*(token+1)) ))
+ NodeTag retval = 0;
+
+ /*
+ * Check if the token is a number (decimal or integer, positive or
+ * negative
+ */
+ if (isdigit(*token) ||
+ (length >= 2 && *token == '-' && isdigit(*(token + 1))))
{
- /*
- * skip the optional '-' (i.e. negative number)
- */
- if (*token == '-') {
- token++;
- }
-
- /*
- * See if there is a decimal point
- */
-
- for (; length && *token != '.'; token++, length--);
-
- /*
- * if there isn't, token's an int, otherwise it's a float.
- */
-
- retval = (*token != '.') ? T_Integer : T_Float;
+
+ /*
+ * skip the optional '-' (i.e. negative number)
+ */
+ if (*token == '-')
+ {
+ token++;
+ }
+
+ /*
+ * See if there is a decimal point
+ */
+
+ for (; length && *token != '.'; token++, length--);
+
+ /*
+ * if there isn't, token's an int, otherwise it's a float.
+ */
+
+ retval = (*token != '.') ? T_Integer : T_Float;
}
- else if (isalpha(*token))
- retval = ATOM_TOKEN;
- else if (*token == '(')
- retval = LEFT_PAREN;
- else if (*token == ')')
- retval = RIGHT_PAREN;
- else if (*token == '@')
- retval = AT_SYMBOL;
- else if (*token == '\"')
- retval = T_String;
- else if (*token == '{')
- retval = PLAN_SYM;
- return(retval);
+ else if (isalpha(*token))
+ retval = ATOM_TOKEN;
+ else if (*token == '(')
+ retval = LEFT_PAREN;
+ else if (*token == ')')
+ retval = RIGHT_PAREN;
+ else if (*token == '@')
+ retval = AT_SYMBOL;
+ else if (*token == '\"')
+ retval = T_String;
+ else if (*token == '{')
+ retval = PLAN_SYM;
+ return (retval);
}
/*
* Works kinda like strtok, except it doesn't put nulls into string.
- *
+ *
* Returns the length in length instead. The string can be set without
* returning a token by calling lsptok with length == NULL.
*
*/
-char *
+char *
lsptok(char *string, int *length)
{
- static char *local_str;
- char *ret_string;
-
- if (string != NULL) {
- local_str = string;
- if (length == NULL) {
- return(NULL);
+ static char *local_str;
+ char *ret_string;
+
+ if (string != NULL)
+ {
+ local_str = string;
+ if (length == NULL)
+ {
+ return (NULL);
+ }
+ }
+
+ for (; *local_str == ' '
+ || *local_str == '\n'
+ || *local_str == '\t'; local_str++);
+
+ /*
+ * Now pointing at next token.
+ */
+ ret_string = local_str;
+ if (*local_str == '\0')
+ return (NULL);
+ *length = 1;
+
+ if (*local_str == '\"')
+ {
+ for (local_str++; *local_str != '\"'; (*length)++, local_str++);
+ (*length)++;
+ local_str++;
+ }
+ else if (*local_str == ')' || *local_str == '(' ||
+ *local_str == '}' || *local_str == '{')
+ {
+ local_str++;
+ }
+ else
+ {
+ for (; *local_str != ' '
+ && *local_str != '\n'
+ && *local_str != '\t'
+ && *local_str != '{'
+ && *local_str != '}'
+ && *local_str != '('
+ && *local_str != ')'; local_str++, (*length)++);
+ (*length)--;
}
- }
-
- for (; *local_str == ' '
- || *local_str == '\n'
- || *local_str == '\t'; local_str++);
-
- /*
- * Now pointing at next token.
- */
- ret_string = local_str;
- if (*local_str == '\0') return(NULL);
- *length = 1;
-
- if (*local_str == '\"') {
- for (local_str++; *local_str != '\"'; (*length)++, local_str++);
- (*length)++; local_str++;
- }else if (*local_str == ')' || *local_str == '(' ||
- *local_str == '}' || *local_str == '{') {
- local_str++;
- }else {
- for (; *local_str != ' '
- && *local_str != '\n'
- && *local_str != '\t'
- && *local_str != '{'
- && *local_str != '}'
- && *local_str != '('
- && *local_str != ')'; local_str++, (*length)++);
- (*length)--;
- }
- return(ret_string);
+ return (ret_string);
}
/*
@@ -163,108 +174,128 @@ lsptok(char *string, int *length)
* Secrets: He assumes that lsptok already has the string (see below).
* Any callers should set read_car_only to true.
*/
-void *
+void *
nodeRead(bool read_car_only)
{
- char *token;
- NodeTag type;
- Node *this_value = NULL, *return_value = NULL;
- int tok_len;
- char tmp;
- bool make_dotted_pair_cell = false;
-
- token = lsptok(NULL, &tok_len);
-
- if (token == NULL) return(NULL);
-
- type = nodeTokenType(token, tok_len);
-
- switch(type) {
- case PLAN_SYM:
- this_value = parsePlanString();
+ char *token;
+ NodeTag type;
+ Node *this_value = NULL,
+ *return_value = NULL;
+ int tok_len;
+ char tmp;
+ bool make_dotted_pair_cell = false;
+
token = lsptok(NULL, &tok_len);
- if (token[0] != '}') return(NULL);
- if (!read_car_only)
- make_dotted_pair_cell = true;
- else
- make_dotted_pair_cell = false;
- break;
- case LEFT_PAREN:
- if (!read_car_only) {
- List *l = makeNode(List);
+ if (token == NULL)
+ return (NULL);
- lfirst(l) = nodeRead(false);
- lnext(l) = nodeRead(false);
- this_value = (Node*)l;
- }else {
- this_value = nodeRead(false);
- }
- break;
- case RIGHT_PAREN:
- this_value = NULL;
- break;
- case AT_SYMBOL:
- break;
- case ATOM_TOKEN:
- if (!strncmp(token, "nil", 3)) {
- this_value = NULL;
- /*
- * It might be "nil" but it is an atom!
- */
- if (read_car_only) {
- make_dotted_pair_cell = false;
- } else {
+ type = nodeTokenType(token, tok_len);
+
+ switch (type)
+ {
+ case PLAN_SYM:
+ this_value = parsePlanString();
+ token = lsptok(NULL, &tok_len);
+ if (token[0] != '}')
+ return (NULL);
+
+ if (!read_car_only)
+ make_dotted_pair_cell = true;
+ else
+ make_dotted_pair_cell = false;
+ break;
+ case LEFT_PAREN:
+ if (!read_car_only)
+ {
+ List *l = makeNode(List);
+
+ lfirst(l) = nodeRead(false);
+ lnext(l) = nodeRead(false);
+ this_value = (Node *) l;
+ }
+ else
+ {
+ this_value = nodeRead(false);
+ }
+ break;
+ case RIGHT_PAREN:
+ this_value = NULL;
+ break;
+ case AT_SYMBOL:
+ break;
+ case ATOM_TOKEN:
+ if (!strncmp(token, "nil", 3))
+ {
+ this_value = NULL;
+
+ /*
+ * It might be "nil" but it is an atom!
+ */
+ if (read_car_only)
+ {
+ make_dotted_pair_cell = false;
+ }
+ else
+ {
+ make_dotted_pair_cell = true;
+ }
+ }
+ else
+ {
+ tmp = token[tok_len];
+ token[tok_len] = '\0';
+ this_value = (Node *) pstrdup(token); /* !attention! not a
+ * Node. use with
+ * caution */
+ token[tok_len] = tmp;
+ make_dotted_pair_cell = true;
+ }
+ break;
+ case T_Float:
+ tmp = token[tok_len];
+ token[tok_len] = '\0';
+ this_value = (Node *) makeFloat(atof(token));
+ token[tok_len] = tmp;
+ make_dotted_pair_cell = true;
+ break;
+ case T_Integer:
+ tmp = token[tok_len];
+ token[tok_len] = '\0';
+ this_value = (Node *) makeInteger(atoi(token));
+ token[tok_len] = tmp;
make_dotted_pair_cell = true;
- }
- }else {
- tmp = token[tok_len];
- token[tok_len] = '\0';
- this_value = (Node*)pstrdup(token); /* !attention! not a Node.
- use with caution */
- token[tok_len] = tmp;
- make_dotted_pair_cell = true;
+ break;
+ case T_String:
+ tmp = token[tok_len - 1];
+ token[tok_len - 1] = '\0';
+ token++;
+ this_value = (Node *) makeString(token); /* !! not strdup'd */
+ token[tok_len - 2] = tmp;
+ make_dotted_pair_cell = true;
+ break;
+ default:
+ elog(WARN, "nodeRead: Bad type %d", type);
+ break;
}
- break;
- case T_Float:
- tmp = token[tok_len];
- token[tok_len] = '\0';
- this_value = (Node*)makeFloat(atof(token));
- token[tok_len] = tmp;
- make_dotted_pair_cell = true;
- break;
- case T_Integer:
- tmp = token[tok_len];
- token[tok_len] = '\0';
- this_value = (Node*)makeInteger(atoi(token));
- token[tok_len] = tmp;
- make_dotted_pair_cell = true;
- break;
- case T_String:
- tmp = token[tok_len - 1];
- token[tok_len - 1] = '\0';
- token++;
- this_value = (Node*)makeString(token); /* !! not strdup'd */
- token[tok_len - 2] = tmp;
- make_dotted_pair_cell = true;
- break;
- default:
- elog(WARN, "nodeRead: Bad type %d", type);
- break;
- }
- if (make_dotted_pair_cell) {
- List *l = makeNode(List);
+ if (make_dotted_pair_cell)
+ {
+ List *l = makeNode(List);
- lfirst(l) = this_value;
- if (!read_car_only) {
- lnext(l) = nodeRead(false);
- }else {
- lnext(l) = NULL;
+ lfirst(l) = this_value;
+ if (!read_car_only)
+ {
+ lnext(l) = nodeRead(false);
+ }
+ else
+ {
+ lnext(l) = NULL;
+ }
+ return_value = (Node *) l;
}
- return_value = (Node*)l;
- }else {
- return_value = this_value;
- }
- return(return_value);
+ else
+ {
+ return_value = this_value;
+ }
+ return (return_value);
}
-
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 736873bcba2..f42d5d536ee 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* readfuncs.c--
- * Reader functions for Postgres tree nodes.
+ * Reader functions for Postgres tree nodes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.6 1997/08/12 20:15:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.7 1997/09/07 04:42:57 momjian Exp $
*
* NOTES
- * Most of the read functions for plan nodes are tested. (In fact, they
- * pass the regression test as of 11/8/94.) The rest (for path selection)
- * are probably never used. No effort has been made to get them to work.
- * The simplest way to test these functions is by doing the following in
- * ProcessQuery (before executing the plan):
- * plan = stringToNode(nodeToString(plan));
- * Then, run the regression test. Let's just say you'll notice if either
- * of the above function are not properly done.
- * - ay 11/94
- *
+ * Most of the read functions for plan nodes are tested. (In fact, they
+ * pass the regression test as of 11/8/94.) The rest (for path selection)
+ * are probably never used. No effort has been made to get them to work.
+ * The simplest way to test these functions is by doing the following in
+ * ProcessQuery (before executing the plan):
+ * plan = stringToNode(nodeToString(plan));
+ * Then, run the regression test. Let's just say you'll notice if either
+ * of the above function are not properly done.
+ * - ay 11/94
+ *
*-------------------------------------------------------------------------
*/
#include <stdio.h>
@@ -47,697 +47,720 @@
#include "nodes/readfuncs.h"
/* ----------------
- * node creator declarations
+ * node creator declarations
* ----------------
*/
-static Datum readDatum(Oid type);
+static Datum readDatum(Oid type);
-static List *toIntList(List *list)
+static List *
+toIntList(List * list)
{
- List *l;
- foreach(l, list) {
- /* ugly manipulation, should probably free the Value node too */
- lfirst(l) = (void*)intVal(lfirst(l));
- }
- return list;
+ List *l;
+
+ foreach(l, list)
+ {
+ /* ugly manipulation, should probably free the Value node too */
+ lfirst(l) = (void *) intVal(lfirst(l));
+ }
+ return list;
}
/* ----------------
- * _readQuery
+ * _readQuery
* ----------------
*/
-static Query *
+static Query *
_readQuery()
{
- Query *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Query);
-
- token = lsptok(NULL, &length); /* skip the :command */
- token = lsptok(NULL, &length); /* get the commandType */
- local_node->commandType = atoi(token);
-
- token = lsptok(NULL, &length); /* skip the :utility */
- token = lsptok(NULL, &length); /* get the notify name if any*/
- if (token[0] == '"' && token[1] == '"')
- local_node->utilityStmt = NULL;
- else {
- NotifyStmt *n = makeNode(NotifyStmt);
- n->relname = palloc(length + 1);
- strNcpy(n->relname,token,length);
- local_node->utilityStmt = (Node*)n;
- }
-
- token = lsptok(NULL, &length); /* skip the :resrel */
- token = lsptok(NULL, &length); /* get the resultRelation */
- local_node->resultRelation = atoi(token);
-
- token = lsptok(NULL, &length); /* skip :rtable */
- local_node->rtable = nodeRead(true);
-
- token = lsptok(NULL, &length); /* skip the :unique */
- token = lsptok(NULL, &length); /* get the uniqueFlag */
-/* local_node->uniqueFlag = (bool)atoi(token); */
- if (token[0]=='"' && token[1] == '"') /* non-unique */
- local_node->uniqueFlag = NULL;
- else {
- local_node->uniqueFlag = palloc(length + 1);
- strNcpy(local_node->uniqueFlag,token,length);
- }
-
- token = lsptok(NULL, &length); /* skip :targetlist */
- local_node->targetList = nodeRead(true);
-
- token = lsptok(NULL, &length); /* skip :qual */
- local_node->qual = nodeRead(true);
-
- return (local_node);
+ Query *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Query);
+
+ token = lsptok(NULL, &length); /* skip the :command */
+ token = lsptok(NULL, &length); /* get the commandType */
+ local_node->commandType = atoi(token);
+
+ token = lsptok(NULL, &length); /* skip the :utility */
+ token = lsptok(NULL, &length); /* get the notify name if any */
+ if (token[0] == '"' && token[1] == '"')
+ local_node->utilityStmt = NULL;
+ else
+ {
+ NotifyStmt *n = makeNode(NotifyStmt);
+
+ n->relname = palloc(length + 1);
+ strNcpy(n->relname, token, length);
+ local_node->utilityStmt = (Node *) n;
+ }
+
+ token = lsptok(NULL, &length); /* skip the :resrel */
+ token = lsptok(NULL, &length); /* get the resultRelation */
+ local_node->resultRelation = atoi(token);
+
+ token = lsptok(NULL, &length); /* skip :rtable */
+ local_node->rtable = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* skip the :unique */
+ token = lsptok(NULL, &length); /* get the uniqueFlag */
+/* local_node->uniqueFlag = (bool)atoi(token); */
+ if (token[0] == '"' && token[1] == '"') /* non-unique */
+ local_node->uniqueFlag = NULL;
+ else
+ {
+ local_node->uniqueFlag = palloc(length + 1);
+ strNcpy(local_node->uniqueFlag, token, length);
+ }
+
+ token = lsptok(NULL, &length); /* skip :targetlist */
+ local_node->targetList = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* skip :qual */
+ local_node->qual = nodeRead(true);
+
+ return (local_node);
}
/* ----------------
- * _getPlan
+ * _getPlan
* ----------------
*/
static void
-_getPlan(Plan *node)
+_getPlan(Plan * node)
{
- char *token;
- int length;
-
- token = lsptok(NULL, &length); /* first token is :cost */
- token = lsptok(NULL, &length); /* next is the actual cost */
- node->cost = (Cost) atof(token);
-
- token = lsptok(NULL, &length); /* skip the :size */
- token = lsptok(NULL, &length); /* get the plan_size */
- node->plan_size = atoi(token);
-
- token = lsptok(NULL, &length); /* skip the :width */
- token = lsptok(NULL, &length); /* get the plan_width */
- node->plan_width = atoi(token);
-
- token = lsptok(NULL, &length); /* eat the :state stuff */
- token = lsptok(NULL, &length); /* now get the state */
-
- if (!strncmp(token, "nil", 3)) {
- node->state = (EState*) NULL;
- }else { /* Disgusting hack until I figure out what to do here */
- node->state = (EState*) ! NULL;
- }
-
- token = lsptok(NULL, &length); /* eat :qptargetlist */
- node->targetlist = nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :qpqual */
- node->qual = nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :lefttree */
- node->lefttree = (Plan*) nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :righttree */
- node->righttree = (Plan*) nodeRead(true);
-
- return;
+ char *token;
+ int length;
+
+ token = lsptok(NULL, &length); /* first token is :cost */
+ token = lsptok(NULL, &length); /* next is the actual cost */
+ node->cost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* skip the :size */
+ token = lsptok(NULL, &length); /* get the plan_size */
+ node->plan_size = atoi(token);
+
+ token = lsptok(NULL, &length); /* skip the :width */
+ token = lsptok(NULL, &length); /* get the plan_width */
+ node->plan_width = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat the :state stuff */
+ token = lsptok(NULL, &length); /* now get the state */
+
+ if (!strncmp(token, "nil", 3))
+ {
+ node->state = (EState *) NULL;
+ }
+ else
+ { /* Disgusting hack until I figure out what
+ * to do here */
+ node->state = (EState *) ! NULL;
+ }
+
+ token = lsptok(NULL, &length); /* eat :qptargetlist */
+ node->targetlist = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :qpqual */
+ node->qual = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :lefttree */
+ node->lefttree = (Plan *) nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :righttree */
+ node->righttree = (Plan *) nodeRead(true);
+
+ return;
}
/*
- * Stuff from plannodes.h
+ * Stuff from plannodes.h
*/
/* ----------------
- * _readPlan
+ * _readPlan
* ----------------
*/
-static Plan *
+static Plan *
_readPlan()
{
- Plan *local_node;
-
- local_node = makeNode(Plan);
-
- _getPlan(local_node);
-
- return (local_node);
+ Plan *local_node;
+
+ local_node = makeNode(Plan);
+
+ _getPlan(local_node);
+
+ return (local_node);
}
/* ----------------
- * _readResult
+ * _readResult
*
- * Does some obscene, possibly unportable, magic with
- * sizes of things.
+ * Does some obscene, possibly unportable, magic with
+ * sizes of things.
* ----------------
*/
-static Result *
+static Result *
_readResult()
{
- Result *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Result);
-
- _getPlan((Plan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :resconstantqual */
- local_node->resconstantqual = nodeRead(true); /* now read it */
-
- return( local_node );
+ Result *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Result);
+
+ _getPlan((Plan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :resconstantqual */
+ local_node->resconstantqual = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readExistential
+ * _readExistential
*
- * Existential nodes are only used by the planner.
+ * Existential nodes are only used by the planner.
* ----------------
*/
static Existential *
_readExistential()
{
- Existential *local_node;
-
- local_node = makeNode(Existential);
-
- _getPlan((Plan*)local_node);
-
- return( local_node );
+ Existential *local_node;
+
+ local_node = makeNode(Existential);
+
+ _getPlan((Plan *) local_node);
+
+ return (local_node);
}
/* ----------------
- * _readAppend
+ * _readAppend
*
- * Append is a subclass of Plan.
+ * Append is a subclass of Plan.
* ----------------
*/
-static Append *
+static Append *
_readAppend()
{
- Append *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Append);
-
- _getPlan((Plan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :unionplans */
- local_node->unionplans = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* eat :unionrelid */
- token = lsptok(NULL, &length); /* get unionrelid */
- local_node->unionrelid = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :unionrtentries */
- local_node->unionrtentries = nodeRead(true); /* now read it */
-
- return(local_node);
+ Append *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Append);
+
+ _getPlan((Plan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :unionplans */
+ local_node->unionplans = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :unionrelid */
+ token = lsptok(NULL, &length); /* get unionrelid */
+ local_node->unionrelid = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :unionrtentries */
+ local_node->unionrtentries = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _getJoin
+ * _getJoin
*
* In case Join is not the same structure as Plan someday.
* ----------------
*/
static void
-_getJoin(Join *node)
+_getJoin(Join * node)
{
- _getPlan((Plan*)node);
+ _getPlan((Plan *) node);
}
/* ----------------
- * _readJoin
+ * _readJoin
*
- * Join is a subclass of Plan
+ * Join is a subclass of Plan
* ----------------
*/
-static Join *
+static Join *
_readJoin()
{
- Join *local_node;
-
- local_node = makeNode(Join);
-
- _getJoin(local_node);
-
- return( local_node );
+ Join *local_node;
+
+ local_node = makeNode(Join);
+
+ _getJoin(local_node);
+
+ return (local_node);
}
/* ----------------
- * _readNestLoop
- *
- * NestLoop is a subclass of Join
+ * _readNestLoop
+ *
+ * NestLoop is a subclass of Join
* ----------------
*/
static NestLoop *
_readNestLoop()
{
- NestLoop *local_node;
-
- local_node = makeNode(NestLoop);
-
- _getJoin((Join*)local_node);
-
- return( local_node );
+ NestLoop *local_node;
+
+ local_node = makeNode(NestLoop);
+
+ _getJoin((Join *) local_node);
+
+ return (local_node);
}
/* ----------------
- * _readMergeJoin
- *
- * MergeJoin is a subclass of Join
+ * _readMergeJoin
+ *
+ * MergeJoin is a subclass of Join
* ----------------
*/
static MergeJoin *
_readMergeJoin()
{
- MergeJoin *local_node;
- char *token;
- int length;
-
- local_node = makeNode(MergeJoin);
-
- _getJoin((Join*)local_node);
- token = lsptok(NULL, &length); /* eat :mergeclauses */
- local_node->mergeclauses = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* eat :mergesortop */
- token = lsptok(NULL, &length); /* get mergesortop */
- local_node->mergesortop = atol(token);
-
- return( local_node );
+ MergeJoin *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(MergeJoin);
+
+ _getJoin((Join *) local_node);
+ token = lsptok(NULL, &length); /* eat :mergeclauses */
+ local_node->mergeclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :mergesortop */
+ token = lsptok(NULL, &length); /* get mergesortop */
+ local_node->mergesortop = atol(token);
+
+ return (local_node);
}
/* ----------------
- * _readHashJoin
- *
- * HashJoin is a subclass of Join.
+ * _readHashJoin
+ *
+ * HashJoin is a subclass of Join.
* ----------------
*/
static HashJoin *
_readHashJoin()
{
- HashJoin *local_node;
- char *token;
- int length;
-
- local_node = makeNode(HashJoin);
-
- _getJoin((Join*)local_node);
-
- token = lsptok(NULL, &length); /* eat :hashclauses */
- local_node->hashclauses = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* eat :hashjoinop */
- token = lsptok(NULL, &length); /* get hashjoinop */
- local_node->hashjoinop = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :hashjointable */
- token = lsptok(NULL, &length); /* eat hashjointable */
- local_node->hashjointable = NULL;
-
- token = lsptok(NULL, &length); /* eat :hashjointablekey */
- token = lsptok(NULL, &length); /* eat hashjointablekey */
- local_node->hashjointablekey = 0;
-
- token = lsptok(NULL, &length); /* eat :hashjointablesize */
- token = lsptok(NULL, &length); /* eat hashjointablesize */
- local_node->hashjointablesize = 0;
-
- token = lsptok(NULL, &length); /* eat :hashdone */
- token = lsptok(NULL, &length); /* eat hashdone */
- local_node->hashdone = false;
-
- return( local_node );
+ HashJoin *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(HashJoin);
+
+ _getJoin((Join *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :hashclauses */
+ local_node->hashclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :hashjoinop */
+ token = lsptok(NULL, &length); /* get hashjoinop */
+ local_node->hashjoinop = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :hashjointable */
+ token = lsptok(NULL, &length); /* eat hashjointable */
+ local_node->hashjointable = NULL;
+
+ token = lsptok(NULL, &length); /* eat :hashjointablekey */
+ token = lsptok(NULL, &length); /* eat hashjointablekey */
+ local_node->hashjointablekey = 0;
+
+ token = lsptok(NULL, &length); /* eat :hashjointablesize */
+ token = lsptok(NULL, &length); /* eat hashjointablesize */
+ local_node->hashjointablesize = 0;
+
+ token = lsptok(NULL, &length); /* eat :hashdone */
+ token = lsptok(NULL, &length); /* eat hashdone */
+ local_node->hashdone = false;
+
+ return (local_node);
}
/* ----------------
- * _getScan
+ * _getScan
*
- * Scan is a subclass of Node
- * (Actually, according to the plannodes.h include file, it is a
- * subclass of Plan. This is why _getPlan is used here.)
+ * Scan is a subclass of Node
+ * (Actually, according to the plannodes.h include file, it is a
+ * subclass of Plan. This is why _getPlan is used here.)
*
- * Scan gets its own get function since stuff inherits it.
+ * Scan gets its own get function since stuff inherits it.
* ----------------
*/
-static void
-_getScan(Scan *node)
+static void
+_getScan(Scan * node)
{
- char *token;
- int length;
-
- _getPlan((Plan*)node);
-
- token = lsptok(NULL, &length); /* eat :scanrelid */
- token = lsptok(NULL, &length); /* get scanrelid */
- node->scanrelid = atoi(token);
+ char *token;
+ int length;
+
+ _getPlan((Plan *) node);
+
+ token = lsptok(NULL, &length); /* eat :scanrelid */
+ token = lsptok(NULL, &length); /* get scanrelid */
+ node->scanrelid = atoi(token);
}
/* ----------------
- * _readScan
- *
+ * _readScan
+ *
* Scan is a subclass of Plan (Not Node, see above).
* ----------------
*/
-static Scan *
+static Scan *
_readScan()
{
- Scan *local_node;
-
- local_node = makeNode(Scan);
-
- _getScan(local_node);
-
- return(local_node);
+ Scan *local_node;
+
+ local_node = makeNode(Scan);
+
+ _getScan(local_node);
+
+ return (local_node);
}
/* ----------------
- * _readSeqScan
- *
- * SeqScan is a subclass of Scan
+ * _readSeqScan
+ *
+ * SeqScan is a subclass of Scan
* ----------------
*/
static SeqScan *
_readSeqScan()
{
- SeqScan *local_node;
-
- local_node = makeNode(SeqScan);
-
- _getScan((Scan*)local_node);
-
- return(local_node);
+ SeqScan *local_node;
+
+ local_node = makeNode(SeqScan);
+
+ _getScan((Scan *) local_node);
+
+ return (local_node);
}
/* ----------------
- * _readIndexScan
- *
- * IndexScan is a subclass of Scan
+ * _readIndexScan
+ *
+ * IndexScan is a subclass of Scan
* ----------------
*/
static IndexScan *
_readIndexScan()
{
- IndexScan *local_node;
- char *token;
- int length;
-
- local_node = makeNode(IndexScan);
-
- _getScan((Scan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :indxid */
- local_node->indxid =
- toIntList(nodeRead(true)); /* now read it */
-
- token = lsptok(NULL, &length); /* eat :indxqual */
- local_node->indxqual = nodeRead(true); /* now read it */
-
- return(local_node);
+ IndexScan *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(IndexScan);
+
+ _getScan((Scan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :indxid */
+ local_node->indxid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* eat :indxqual */
+ local_node->indxqual = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readTemp
- *
- * Temp is a subclass of Plan
+ * _readTemp
+ *
+ * Temp is a subclass of Plan
* ----------------
*/
-static Temp *
+static Temp *
_readTemp()
{
- Temp *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Temp);
-
- _getPlan((Plan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :tempid */
- token = lsptok(NULL, &length); /* get tempid */
- local_node->tempid = atol(token);
-
- token = lsptok(NULL, &length); /* eat :keycount */
- token = lsptok(NULL, &length); /* get keycount */
- local_node->keycount = atoi(token);
-
- return(local_node);
+ Temp *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Temp);
+
+ _getPlan((Plan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :tempid */
+ token = lsptok(NULL, &length); /* get tempid */
+ local_node->tempid = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :keycount */
+ token = lsptok(NULL, &length); /* get keycount */
+ local_node->keycount = atoi(token);
+
+ return (local_node);
}
/* ----------------
- * _readSort
- *
- * Sort is a subclass of Temp
+ * _readSort
+ *
+ * Sort is a subclass of Temp
* ----------------
*/
-static Sort *
+static Sort *
_readSort()
{
- Sort *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Sort);
-
- _getPlan((Plan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :tempid */
- token = lsptok(NULL, &length); /* get tempid */
- local_node->tempid = atol(token);
-
- token = lsptok(NULL, &length); /* eat :keycount */
- token = lsptok(NULL, &length); /* get keycount */
- local_node->keycount = atoi(token);
-
- return(local_node);
+ Sort *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Sort);
+
+ _getPlan((Plan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :tempid */
+ token = lsptok(NULL, &length); /* get tempid */
+ local_node->tempid = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :keycount */
+ token = lsptok(NULL, &length); /* get keycount */
+ local_node->keycount = atoi(token);
+
+ return (local_node);
}
-static Agg *
+static Agg *
_readAgg()
{
- Agg *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Agg);
- _getPlan((Plan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :numagg */
- token = lsptok(NULL, &length); /* get numagg */
- local_node->numAgg = atoi(token);
-
- return(local_node);
+ Agg *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Agg);
+ _getPlan((Plan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :numagg */
+ token = lsptok(NULL, &length); /* get numagg */
+ local_node->numAgg = atoi(token);
+
+ return (local_node);
}
/* ----------------
- * _readUnique
+ * _readUnique
*
* For some reason, unique is a subclass of Temp.
*/
-static Unique *
+static Unique *
_readUnique()
{
- Unique *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Unique);
-
- _getPlan((Plan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :tempid */
- token = lsptok(NULL, &length); /* get :tempid */
- local_node->tempid = atol(token);
-
- token = lsptok(NULL, &length); /* eat :keycount */
- token = lsptok(NULL, &length); /* get :keycount */
- local_node->keycount = atoi(token);
-
- return(local_node);
+ Unique *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Unique);
+
+ _getPlan((Plan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :tempid */
+ token = lsptok(NULL, &length); /* get :tempid */
+ local_node->tempid = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :keycount */
+ token = lsptok(NULL, &length); /* get :keycount */
+ local_node->keycount = atoi(token);
+
+ return (local_node);
}
/* ----------------
- * _readHash
- *
- * Hash is a subclass of Temp
+ * _readHash
+ *
+ * Hash is a subclass of Temp
* ----------------
*/
-static Hash *
+static Hash *
_readHash()
{
- Hash *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Hash);
-
- _getPlan((Plan*)local_node);
-
- token = lsptok(NULL, &length); /* eat :hashkey */
- local_node->hashkey = (Var*) nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :hashtable */
- token = lsptok(NULL, &length); /* eat hashtable address*/
- local_node->hashtable = NULL;
-
- token = lsptok(NULL, &length); /* eat :hashtablekey*/
- token = lsptok(NULL, &length); /* get hashtablekey */
- local_node->hashtablekey = 0;
-
- token = lsptok(NULL, &length); /* eat :hashtablesize*/
- token = lsptok(NULL, &length); /* get hashtablesize */
- local_node->hashtablesize = 0;
-
- return(local_node);
+ Hash *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Hash);
+
+ _getPlan((Plan *) local_node);
+
+ token = lsptok(NULL, &length); /* eat :hashkey */
+ local_node->hashkey = (Var *) nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :hashtable */
+ token = lsptok(NULL, &length); /* eat hashtable address */
+ local_node->hashtable = NULL;
+
+ token = lsptok(NULL, &length); /* eat :hashtablekey */
+ token = lsptok(NULL, &length); /* get hashtablekey */
+ local_node->hashtablekey = 0;
+
+ token = lsptok(NULL, &length); /* eat :hashtablesize */
+ token = lsptok(NULL, &length); /* get hashtablesize */
+ local_node->hashtablesize = 0;
+
+ return (local_node);
}
/*
- * Stuff from primnodes.h.
+ * Stuff from primnodes.h.
*/
/* ----------------
- * _readResdom
- *
- * Resdom is a subclass of Node
+ * _readResdom
+ *
+ * Resdom is a subclass of Node
* ----------------
*/
-static Resdom *
+static Resdom *
_readResdom()
{
- Resdom *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Resdom);
-
- token = lsptok(NULL, &length); /* eat :resno */
- token = lsptok(NULL, &length); /* get resno */
- local_node->resno = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :restype */
- token = lsptok(NULL, &length); /* get restype */
- local_node->restype = atol(token);
-
- token = lsptok(NULL, &length); /* eat :reslen */
- token = lsptok(NULL, &length); /* get reslen */
- local_node->reslen = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :resname */
- token = lsptok(NULL, &length); /* get the name */
-
- if (!strncmp(token, "\"null\"", 5)) {
- local_node->resname = NULL;
- }else {
- /*
- * Peel off ""'s, then make a true copy.
- */
-
- token++;
- token[length - 2] = '\0';
-
- local_node->resname = palloc(length);
- strcpy(local_node->resname, token);
- token[length - 2] = '\"';
- }
-
- token = lsptok(NULL, &length); /* eat :reskey */
- token = lsptok(NULL, &length); /* get reskey */
- local_node->reskey = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :reskeyop */
- token = lsptok(NULL, &length); /* get reskeyop */
- local_node->reskeyop = (Oid) atol(token);
-
- token = lsptok(NULL, &length); /* eat :resjunk */
- token = lsptok(NULL, &length); /* get resjunk */
- local_node->resjunk = atoi(token);
-
- return(local_node);
+ Resdom *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Resdom);
+
+ token = lsptok(NULL, &length); /* eat :resno */
+ token = lsptok(NULL, &length); /* get resno */
+ local_node->resno = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :restype */
+ token = lsptok(NULL, &length); /* get restype */
+ local_node->restype = atol(token);
+
+ token = lsptok(NULL, &length); /* eat :reslen */
+ token = lsptok(NULL, &length); /* get reslen */
+ local_node->reslen = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :resname */
+ token = lsptok(NULL, &length); /* get the name */
+
+ if (!strncmp(token, "\"null\"", 5))
+ {
+ local_node->resname = NULL;
+ }
+ else
+ {
+
+ /*
+ * Peel off ""'s, then make a true copy.
+ */
+
+ token++;
+ token[length - 2] = '\0';
+
+ local_node->resname = palloc(length);
+ strcpy(local_node->resname, token);
+ token[length - 2] = '\"';
+ }
+
+ token = lsptok(NULL, &length); /* eat :reskey */
+ token = lsptok(NULL, &length); /* get reskey */
+ local_node->reskey = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :reskeyop */
+ token = lsptok(NULL, &length); /* get reskeyop */
+ local_node->reskeyop = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :resjunk */
+ token = lsptok(NULL, &length); /* get resjunk */
+ local_node->resjunk = atoi(token);
+
+ return (local_node);
}
/* ----------------
- * _readExpr
- *
- * Expr is a subclass of Node
+ * _readExpr
+ *
+ * Expr is a subclass of Node
* ----------------
*/
-static Expr *
+static Expr *
_readExpr()
{
- Expr *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Expr);
-
- token = lsptok(NULL, &length); /* eat :typeOid */
- token = lsptok(NULL, &length); /* get typeOid */
- local_node->typeOid = (Oid)atol(token);
-
- token = lsptok(NULL, &length); /* eat :opType */
- token = lsptok(NULL, &length); /* get opType */
- if (!strncmp(token, "op", 2)) {
- local_node->opType = OP_EXPR;
- } else if (!strncmp(token, "func", 4)) {
- local_node->opType = FUNC_EXPR;
- } else if (!strncmp(token, "or", 2)) {
- local_node->opType = OR_EXPR;
- } else if (!strncmp(token, "and", 3)) {
- local_node->opType = AND_EXPR;
- } else if (!strncmp(token, "not", 3)) {
- local_node->opType = NOT_EXPR;
- }
-
- token = lsptok(NULL, &length); /* eat :oper */
- local_node->oper = nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :args */
- local_node->args = nodeRead(true); /* now read it */
-
- return(local_node);
+ Expr *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Expr);
+
+ token = lsptok(NULL, &length); /* eat :typeOid */
+ token = lsptok(NULL, &length); /* get typeOid */
+ local_node->typeOid = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :opType */
+ token = lsptok(NULL, &length); /* get opType */
+ if (!strncmp(token, "op", 2))
+ {
+ local_node->opType = OP_EXPR;
+ }
+ else if (!strncmp(token, "func", 4))
+ {
+ local_node->opType = FUNC_EXPR;
+ }
+ else if (!strncmp(token, "or", 2))
+ {
+ local_node->opType = OR_EXPR;
+ }
+ else if (!strncmp(token, "and", 3))
+ {
+ local_node->opType = AND_EXPR;
+ }
+ else if (!strncmp(token, "not", 3))
+ {
+ local_node->opType = NOT_EXPR;
+ }
+
+ token = lsptok(NULL, &length); /* eat :oper */
+ local_node->oper = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :args */
+ local_node->args = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readVar
- *
- * Var is a subclass of Expr
+ * _readVar
+ *
+ * Var is a subclass of Expr
* ----------------
*/
-static Var *
+static Var *
_readVar()
{
- Var *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Var);
-
- token = lsptok(NULL, &length); /* eat :varno */
- token = lsptok(NULL, &length); /* get varno */
- local_node->varno = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :varattno */
- token = lsptok(NULL, &length); /* get varattno */
- local_node->varattno = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :vartype */
- token = lsptok(NULL, &length); /* get vartype */
- local_node->vartype = (Oid) atol(token);
-
- token = lsptok(NULL, &length); /* eat :varnoold */
- token = lsptok(NULL, &length); /* get varnoold */
- local_node->varnoold = (Oid) atol(token);
-
- token = lsptok(NULL, &length); /* eat :varoattno */
- token = lsptok(NULL, &length); /* eat :varoattno */
- local_node->varoattno = (int) atol(token);
-
- return(local_node);
+ Var *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Var);
+
+ token = lsptok(NULL, &length); /* eat :varno */
+ token = lsptok(NULL, &length); /* get varno */
+ local_node->varno = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :varattno */
+ token = lsptok(NULL, &length); /* get varattno */
+ local_node->varattno = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :vartype */
+ token = lsptok(NULL, &length); /* get vartype */
+ local_node->vartype = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :varnoold */
+ token = lsptok(NULL, &length); /* get varnoold */
+ local_node->varnoold = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :varoattno */
+ token = lsptok(NULL, &length); /* eat :varoattno */
+ local_node->varoattno = (int) atol(token);
+
+ return (local_node);
}
/* ----------------
@@ -746,40 +769,40 @@ _readVar()
* Array is a subclass of Expr
* ----------------
*/
-static Array *
+static Array *
_readArray()
{
- Array *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Array);
-
- token = lsptok(NULL, &length); /* eat :arrayelemtype */
- token = lsptok(NULL, &length); /* get arrayelemtype */
- local_node->arrayelemtype = (Oid) atoi(token);
-
- token = lsptok(NULL, &length); /* eat :arrayelemlength */
- token = lsptok(NULL, &length); /* get arrayelemlength */
- local_node->arrayelemlength = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :arrayelembyval */
- token = lsptok(NULL, &length); /* get arrayelembyval */
- local_node->arrayelembyval = (token[0] == 't') ? true : false;
-
- token = lsptok(NULL, &length); /* eat :arraylow */
- token = lsptok(NULL, &length); /* get arraylow */
- local_node->arraylow.indx[0] = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :arrayhigh */
- token = lsptok(NULL, &length); /* get arrayhigh */
- local_node->arrayhigh.indx[0] = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :arraylen */
- token = lsptok(NULL, &length); /* get arraylen */
- local_node->arraylen = atoi(token);
-
- return(local_node);
+ Array *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Array);
+
+ token = lsptok(NULL, &length); /* eat :arrayelemtype */
+ token = lsptok(NULL, &length); /* get arrayelemtype */
+ local_node->arrayelemtype = (Oid) atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arrayelemlength */
+ token = lsptok(NULL, &length); /* get arrayelemlength */
+ local_node->arrayelemlength = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arrayelembyval */
+ token = lsptok(NULL, &length); /* get arrayelembyval */
+ local_node->arrayelembyval = (token[0] == 't') ? true : false;
+
+ token = lsptok(NULL, &length); /* eat :arraylow */
+ token = lsptok(NULL, &length); /* get arraylow */
+ local_node->arraylow.indx[0] = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arrayhigh */
+ token = lsptok(NULL, &length); /* get arrayhigh */
+ local_node->arrayhigh.indx[0] = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :arraylen */
+ token = lsptok(NULL, &length); /* get arraylen */
+ local_node->arraylen = atoi(token);
+
+ return (local_node);
}
/* ----------------
@@ -791,1031 +814,1052 @@ _readArray()
static ArrayRef *
_readArrayRef()
{
- ArrayRef *local_node;
- char *token;
- int length;
-
- local_node = makeNode(ArrayRef);
-
- token = lsptok(NULL, &length); /* eat :refelemtype */
- token = lsptok(NULL, &length); /* get refelemtype */
- local_node->refelemtype = (Oid) atoi(token);
-
- token = lsptok(NULL, &length); /* eat :refattrlength */
- token = lsptok(NULL, &length); /* get refattrlength */
- local_node->refattrlength = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :refelemlength */
- token = lsptok(NULL, &length); /* get refelemlength */
- local_node->refelemlength = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :refelembyval */
- token = lsptok(NULL, &length); /* get refelembyval */
- local_node->refelembyval = (token[0] == 't') ? true : false;
-
- token = lsptok(NULL, &length); /* eat :refupperindex */
- local_node->refupperindexpr = nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :reflowerindex */
- local_node->reflowerindexpr = nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :refexpr */
- local_node->refexpr = nodeRead(true);
-
- token = lsptok(NULL, &length); /* eat :refassgnexpr */
- local_node->refassgnexpr = nodeRead(true);
-
- return(local_node);
+ ArrayRef *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(ArrayRef);
+
+ token = lsptok(NULL, &length); /* eat :refelemtype */
+ token = lsptok(NULL, &length); /* get refelemtype */
+ local_node->refelemtype = (Oid) atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refattrlength */
+ token = lsptok(NULL, &length); /* get refattrlength */
+ local_node->refattrlength = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refelemlength */
+ token = lsptok(NULL, &length); /* get refelemlength */
+ local_node->refelemlength = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refelembyval */
+ token = lsptok(NULL, &length); /* get refelembyval */
+ local_node->refelembyval = (token[0] == 't') ? true : false;
+
+ token = lsptok(NULL, &length); /* eat :refupperindex */
+ local_node->refupperindexpr = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :reflowerindex */
+ local_node->reflowerindexpr = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :refexpr */
+ local_node->refexpr = nodeRead(true);
+
+ token = lsptok(NULL, &length); /* eat :refassgnexpr */
+ local_node->refassgnexpr = nodeRead(true);
+
+ return (local_node);
}
/* ----------------
- * _readConst
- *
- * Const is a subclass of Expr
+ * _readConst
+ *
+ * Const is a subclass of Expr
* ----------------
*/
-static Const *
+static Const *
_readConst()
{
- Const *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Const);
-
- token = lsptok(NULL, &length); /* get :consttype */
- token = lsptok(NULL, &length); /* now read it */
- local_node->consttype = atol(token);
-
-
- token = lsptok(NULL, &length); /* get :constlen */
- token = lsptok(NULL, &length); /* now read it */
- local_node->constlen = atoi(token);
-
- token = lsptok(NULL, &length); /* get :constisnull */
- token = lsptok(NULL, &length); /* now read it */
-
- if (!strncmp(token, "true", 4)) {
- local_node->constisnull = true;
- }else {
- local_node->constisnull = false;
- }
-
-
- token = lsptok(NULL, &length); /* get :constvalue */
-
- if (local_node->constisnull) {
- token = lsptok(NULL, &length); /* skip "NIL" */
- }else {
- /*
- * read the value
- */
- local_node->constvalue = readDatum(local_node->consttype);
- }
-
- token = lsptok(NULL, &length); /* get :constbyval */
- token = lsptok(NULL, &length); /* now read it */
-
- if (!strncmp(token, "true", 4)) {
- local_node->constbyval = true;
- }else {
- local_node->constbyval = false;
- }
-
- return(local_node);
+ Const *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Const);
+
+ token = lsptok(NULL, &length); /* get :consttype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->consttype = atol(token);
+
+
+ token = lsptok(NULL, &length); /* get :constlen */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->constlen = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :constisnull */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->constisnull = true;
+ }
+ else
+ {
+ local_node->constisnull = false;
+ }
+
+
+ token = lsptok(NULL, &length); /* get :constvalue */
+
+ if (local_node->constisnull)
+ {
+ token = lsptok(NULL, &length); /* skip "NIL" */
+ }
+ else
+ {
+
+ /*
+ * read the value
+ */
+ local_node->constvalue = readDatum(local_node->consttype);
+ }
+
+ token = lsptok(NULL, &length); /* get :constbyval */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->constbyval = true;
+ }
+ else
+ {
+ local_node->constbyval = false;
+ }
+
+ return (local_node);
}
/* ----------------
- * _readFunc
- *
- * Func is a subclass of Expr
+ * _readFunc
+ *
+ * Func is a subclass of Expr
* ----------------
*/
-static Func *
+static Func *
_readFunc()
{
- Func *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Func);
-
- token = lsptok(NULL, &length); /* get :funcid */
- token = lsptok(NULL, &length); /* now read it */
- local_node->funcid = atol(token);
-
- token = lsptok(NULL, &length); /* get :functype */
- token = lsptok(NULL, &length); /* now read it */
- local_node->functype = atol(token);
-
- token = lsptok(NULL, &length); /* get :funcisindex */
- token = lsptok(NULL, &length); /* now read it */
-
- if (!strncmp(token, "true", 4)) {
- local_node->funcisindex = true;
- }else {
- local_node->funcisindex = false;
- }
-
- token = lsptok(NULL, &length); /* get :funcsize */
- token = lsptok(NULL, &length); /* now read it */
- local_node->funcsize = atol(token);
-
- token = lsptok(NULL, &length); /* get :func_fcache */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->func_fcache = (FunctionCache *) NULL;
-
- token = lsptok(NULL, &length); /* get :func_tlist */
- local_node->func_tlist = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :func_planlist */
- local_node->func_planlist = nodeRead(true); /* now read it */
-
- return(local_node);
+ Func *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Func);
+
+ token = lsptok(NULL, &length); /* get :funcid */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->funcid = atol(token);
+
+ token = lsptok(NULL, &length); /* get :functype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->functype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :funcisindex */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->funcisindex = true;
+ }
+ else
+ {
+ local_node->funcisindex = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :funcsize */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->funcsize = atol(token);
+
+ token = lsptok(NULL, &length); /* get :func_fcache */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->func_fcache = (FunctionCache *) NULL;
+
+ token = lsptok(NULL, &length); /* get :func_tlist */
+ local_node->func_tlist = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :func_planlist */
+ local_node->func_planlist = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readOper
- *
- * Oper is a subclass of Expr
+ * _readOper
+ *
+ * Oper is a subclass of Expr
* ----------------
*/
-static Oper *
+static Oper *
_readOper()
{
- Oper *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Oper);
-
- token = lsptok(NULL, &length); /* get :opno */
- token = lsptok(NULL, &length); /* now read it */
- local_node->opno = atol(token);
-
- token = lsptok(NULL, &length); /* get :opid */
- token = lsptok(NULL, &length); /* now read it */
- local_node->opid = atol(token);
-
- token = lsptok(NULL, &length); /* get :opresulttype */
- token = lsptok(NULL, &length); /* now read it */
- local_node->opresulttype = atol(token);
-
- /*
- * NOTE: Alternatively we can call 'replace_opid'
- * which initializes both 'opid' and 'op_fcache'.
- */
- local_node->op_fcache = (FunctionCache *) NULL;
-
- return(local_node);
+ Oper *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Oper);
+
+ token = lsptok(NULL, &length); /* get :opno */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->opno = atol(token);
+
+ token = lsptok(NULL, &length); /* get :opid */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->opid = atol(token);
+
+ token = lsptok(NULL, &length); /* get :opresulttype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->opresulttype = atol(token);
+
+ /*
+ * NOTE: Alternatively we can call 'replace_opid' which initializes
+ * both 'opid' and 'op_fcache'.
+ */
+ local_node->op_fcache = (FunctionCache *) NULL;
+
+ return (local_node);
}
/* ----------------
- * _readParam
- *
- * Param is a subclass of Expr
+ * _readParam
+ *
+ * Param is a subclass of Expr
* ----------------
*/
-static Param *
+static Param *
_readParam()
{
- Param *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Param);
-
- token = lsptok(NULL, &length); /* get :paramkind */
- token = lsptok(NULL, &length); /* now read it */
- local_node->paramkind = atoi(token);
-
- token = lsptok(NULL, &length); /* get :paramid */
- token = lsptok(NULL, &length); /* now read it */
- local_node->paramid = atol(token);
-
- token = lsptok(NULL, &length); /* get :paramname */
- token = lsptok(NULL, &length); /* now read it */
- token++; /* skip the first `"' */
- token[length - 2] = '\0'; /* this is the 2nd `"' */
-
- local_node->paramname = pstrdup(token);
- token[length - 2] = '\"'; /* restore the 2nd `"' */
-
- token = lsptok(NULL, &length); /* get :paramtype */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->paramtype = atol(token);
- token = lsptok(NULL, &length); /* get :param_tlist */
- local_node->param_tlist = nodeRead(true); /* now read it */
-
- return(local_node);
+ Param *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Param);
+
+ token = lsptok(NULL, &length); /* get :paramkind */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->paramkind = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :paramid */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->paramid = atol(token);
+
+ token = lsptok(NULL, &length); /* get :paramname */
+ token = lsptok(NULL, &length); /* now read it */
+ token++; /* skip the first `"' */
+ token[length - 2] = '\0'; /* this is the 2nd `"' */
+
+ local_node->paramname = pstrdup(token);
+ token[length - 2] = '\"'; /* restore the 2nd `"' */
+
+ token = lsptok(NULL, &length); /* get :paramtype */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->paramtype = atol(token);
+ token = lsptok(NULL, &length); /* get :param_tlist */
+ local_node->param_tlist = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readAggreg
- *
- * Aggreg is a subclass of Node
+ * _readAggreg
+ *
+ * Aggreg is a subclass of Node
* ----------------
*/
-static Aggreg *
+static Aggreg *
_readAggreg()
{
- Aggreg *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Aggreg);
-
- token = lsptok(NULL, &length); /* eat :aggname */
- token = lsptok(NULL, &length); /* get aggname */
- local_node->aggname = (char*) palloc (length + 1);
- strNcpy (local_node->aggname, token, length);
-
- token = lsptok(NULL, &length); /* eat :basetype */
- token = lsptok(NULL, &length); /* get basetype */
- local_node->basetype = (Oid)atol(token);
-
- token = lsptok(NULL, &length); /* eat :aggtype */
- token = lsptok(NULL, &length); /* get aggtype */
- local_node->aggtype = (Oid)atol(token);
-
- token = lsptok(NULL, &length); /* eat :aggno */
- token = lsptok(NULL, &length); /* get aggno */
- local_node->aggno = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :target */
- local_node->target = nodeRead(true); /* now read it */
-
- return(local_node);
+ Aggreg *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Aggreg);
+
+ token = lsptok(NULL, &length); /* eat :aggname */
+ token = lsptok(NULL, &length); /* get aggname */
+ local_node->aggname = (char *) palloc(length + 1);
+ strNcpy(local_node->aggname, token, length);
+
+ token = lsptok(NULL, &length); /* eat :basetype */
+ token = lsptok(NULL, &length); /* get basetype */
+ local_node->basetype = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :aggtype */
+ token = lsptok(NULL, &length); /* get aggtype */
+ local_node->aggtype = (Oid) atol(token);
+
+ token = lsptok(NULL, &length); /* eat :aggno */
+ token = lsptok(NULL, &length); /* get aggno */
+ local_node->aggno = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :target */
+ local_node->target = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/*
- * Stuff from execnodes.h
+ * Stuff from execnodes.h
*/
/* ----------------
- * _readEState
- *
- * EState is a subclass of Node.
+ * _readEState
+ *
+ * EState is a subclass of Node.
* ----------------
*/
-static EState *
+static EState *
_readEState()
{
- EState *local_node;
- char *token;
- int length;
-
- local_node = makeNode(EState);
-
- token = lsptok(NULL, &length); /* get :direction */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->es_direction = atoi(token);
-
- token = lsptok(NULL, &length); /* get :range_table */
-
- local_node->es_range_table = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :result_relation_info */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- sscanf(token, "%x",(unsigned int *)&local_node->es_result_relation_info);
-
- return(local_node);
+ EState *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(EState);
+
+ token = lsptok(NULL, &length); /* get :direction */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->es_direction = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :range_table */
+
+ local_node->es_range_table = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :result_relation_info */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ sscanf(token, "%x", (unsigned int *) &local_node->es_result_relation_info);
+
+ return (local_node);
}
/*
- * Stuff from relation.h
+ * Stuff from relation.h
*/
/* ----------------
- * _readRel
+ * _readRel
* ----------------
*/
-static Rel *
+static Rel *
_readRel()
{
- Rel *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Rel);
-
- token = lsptok(NULL, &length); /* get :relids */
- local_node->relids =
- toIntList(nodeRead(true)); /* now read it */
-
- token = lsptok(NULL, &length); /* get :indexed */
- token = lsptok(NULL, &length); /* now read it */
-
- if (!strncmp(token, "true", 4))
- {
- local_node->indexed = true;
- }
- else
- {
- local_node->indexed = false;
- }
-
- token = lsptok(NULL, &length); /* get :pages */
- token = lsptok(NULL, &length); /* now read it */
- local_node->pages = (unsigned int) atoi(token);
-
- token = lsptok(NULL, &length); /* get :tuples */
- token = lsptok(NULL, &length); /* now read it */
- local_node->tuples = (unsigned int) atoi(token);
-
- token = lsptok(NULL, &length); /* get :size */
- token = lsptok(NULL, &length); /* now read it */
- local_node->size = (unsigned int) atoi(token);
-
- token = lsptok(NULL, &length); /* get :width */
- token = lsptok(NULL, &length); /* now read it */
- local_node->width = (unsigned int) atoi(token);
-
- token = lsptok(NULL, &length); /* get :targetlist */
- local_node->targetlist = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :pathlist */
- local_node->pathlist = nodeRead(true); /* now read it */
-
- /*
- * Not sure if these are nodes or not. They're declared as
- * struct Path *. Since i don't know, i'll just print the
- * addresses for now. This can be changed later, if necessary.
- */
-
- token = lsptok(NULL, &length); /* get :unorderpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- sscanf(token, "%x", (unsigned int *)&local_node->unorderedpath);
-
- token = lsptok(NULL, &length); /* get :cheapestpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- sscanf(token, "%x", (unsigned int *)&local_node->cheapestpath);
-
-
- token = lsptok(NULL, &length); /* get :clauseinfo */
- local_node->clauseinfo = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :joininfo */
- local_node->joininfo = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :innerjoin */
- local_node->innerjoin = nodeRead(true); /* now read it */
-
- return(local_node);
+ Rel *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Rel);
+
+ token = lsptok(NULL, &length); /* get :relids */
+ local_node->relids =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :indexed */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->indexed = true;
+ }
+ else
+ {
+ local_node->indexed = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :pages */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->pages = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :tuples */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->tuples = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :size */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->size = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :width */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->width = (unsigned int) atoi(token);
+
+ token = lsptok(NULL, &length); /* get :targetlist */
+ local_node->targetlist = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathlist */
+ local_node->pathlist = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes or not. They're declared as struct
+ * Path *. Since i don't know, i'll just print the addresses for now.
+ * This can be changed later, if necessary.
+ */
+
+ token = lsptok(NULL, &length); /* get :unorderpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ sscanf(token, "%x", (unsigned int *) &local_node->unorderedpath);
+
+ token = lsptok(NULL, &length); /* get :cheapestpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ sscanf(token, "%x", (unsigned int *) &local_node->cheapestpath);
+
+
+ token = lsptok(NULL, &length); /* get :clauseinfo */
+ local_node->clauseinfo = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :joininfo */
+ local_node->joininfo = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :innerjoin */
+ local_node->innerjoin = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readTargetEntry
+ * _readTargetEntry
* ----------------
*/
static TargetEntry *
_readTargetEntry()
{
- TargetEntry *local_node;
- char *token;
- int length;
+ TargetEntry *local_node;
+ char *token;
+ int length;
- local_node = makeNode(TargetEntry);
+ local_node = makeNode(TargetEntry);
- token = lsptok(NULL, &length); /* get :resdom */
- local_node->resdom = nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* get :resdom */
+ local_node->resdom = nodeRead(true); /* now read it */
- token = lsptok(NULL, &length); /* get :expr */
- local_node->expr = nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* get :expr */
+ local_node->expr = nodeRead(true); /* now read it */
- return (local_node);
+ return (local_node);
}
/* ----------------
- * _readTargetEntry
+ * _readTargetEntry
* ----------------
*/
static RangeTblEntry *
_readRangeTblEntry()
{
- RangeTblEntry *local_node;
- char *token;
- int length;
+ RangeTblEntry *local_node;
+ char *token;
+ int length;
- local_node = makeNode(RangeTblEntry);
+ local_node = makeNode(RangeTblEntry);
- token = lsptok(NULL, &length); /* eat :relname */
- token = lsptok(NULL, &length); /* get :relname */
- if (!strncmp(token, "\"null\"", 5)) {
- local_node->relname = NULL;
- }else {
- /*
- * Peel off ""'s, then make a true copy.
- */
-
- token++;
- token[length - 2] = '\0';
-
- local_node->relname = (char *) palloc(NAMEDATALEN);
- strcpy(local_node->relname, token);
- token[length - 2] = '\"';
- }
-
- token = lsptok(NULL, &length); /* eat :inh */
- token = lsptok(NULL, &length); /* get :inh */
- local_node->inh = atoi(token);
-
- token = lsptok(NULL, &length); /* eat :refname */
- token = lsptok(NULL, &length); /* get :refname */
- if (!strncmp(token, "\"null\"", 5)) {
- local_node->refname = NULL;
- }else {
- /*
- * Peel off ""'s, then make a true copy.
- */
-
- token++;
- token[length - 2] = '\0';
-
- local_node->refname = (char*)pstrdup(token);
- token[length - 2] = '\"';
- }
-
- token = lsptok(NULL, &length); /* eat :relid */
- token = lsptok(NULL, &length); /* get :relid */
- local_node->relid = atoi(token);
-
- return (local_node);
+ token = lsptok(NULL, &length); /* eat :relname */
+ token = lsptok(NULL, &length); /* get :relname */
+ if (!strncmp(token, "\"null\"", 5))
+ {
+ local_node->relname = NULL;
+ }
+ else
+ {
+
+ /*
+ * Peel off ""'s, then make a true copy.
+ */
+
+ token++;
+ token[length - 2] = '\0';
+
+ local_node->relname = (char *) palloc(NAMEDATALEN);
+ strcpy(local_node->relname, token);
+ token[length - 2] = '\"';
+ }
+
+ token = lsptok(NULL, &length); /* eat :inh */
+ token = lsptok(NULL, &length); /* get :inh */
+ local_node->inh = atoi(token);
+
+ token = lsptok(NULL, &length); /* eat :refname */
+ token = lsptok(NULL, &length); /* get :refname */
+ if (!strncmp(token, "\"null\"", 5))
+ {
+ local_node->refname = NULL;
+ }
+ else
+ {
+
+ /*
+ * Peel off ""'s, then make a true copy.
+ */
+
+ token++;
+ token[length - 2] = '\0';
+
+ local_node->refname = (char *) pstrdup(token);
+ token[length - 2] = '\"';
+ }
+
+ token = lsptok(NULL, &length); /* eat :relid */
+ token = lsptok(NULL, &length); /* get :relid */
+ local_node->relid = atoi(token);
+
+ return (local_node);
}
/* ----------------
- * _readPath
- *
- * Path is a subclass of Node.
+ * _readPath
+ *
+ * Path is a subclass of Node.
* ----------------
*/
-static Path *
+static Path *
_readPath()
{
- Path *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Path);
-
- token = lsptok(NULL, &length); /* get :pathtype */
- token = lsptok(NULL, &length); /* now read it */
- local_node->pathtype = atol(token);
-
- token = lsptok(NULL, &length); /* get :cost */
- token = lsptok(NULL, &length); /* now read it */
- local_node->path_cost = (Cost) atof(token);
-
+ Path *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Path);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path_cost = (Cost) atof(token);
+
#if 0
- token = lsptok(NULL, &length); /* get :p_ordering */
- local_node->p_ordering =
- nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->p_ordering =
+ nodeRead(true); /* now read it */
#endif
-
- token = lsptok(NULL, &length); /* get :keys */
- local_node->keys = nodeRead(true); /* now read it */
-
- return(local_node);
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->keys = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readIndexPath
- *
- * IndexPath is a subclass of Path.
+ * _readIndexPath
+ *
+ * IndexPath is a subclass of Path.
* ----------------
*/
static IndexPath *
_readIndexPath()
{
- IndexPath *local_node;
- char *token;
- int length;
-
- local_node = makeNode(IndexPath);
-
- token = lsptok(NULL, &length); /* get :pathtype */
- token = lsptok(NULL, &length); /* now read it */
- local_node->path.pathtype = atol(token);
-
- token = lsptok(NULL, &length); /* get :cost */
- token = lsptok(NULL, &length); /* now read it */
- local_node->path.path_cost = (Cost) atof(token);
-
+ IndexPath *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(IndexPath);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path.pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path.path_cost = (Cost) atof(token);
+
#if 0
- token = lsptok(NULL, &length); /* get :p_ordering */
- local_node->path.p_ordering = nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->path.p_ordering = nodeRead(true); /* now read it */
#endif
-
- token = lsptok(NULL, &length); /* get :keys */
- local_node->path.keys = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :indexid */
- local_node->indexid =
- toIntList(nodeRead(true));
-
- token = lsptok(NULL, &length); /* get :indexqual */
- local_node->indexqual = nodeRead(true); /* now read it */
-
- return(local_node);
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :indexid */
+ local_node->indexid =
+ toIntList(nodeRead(true));
+
+ token = lsptok(NULL, &length); /* get :indexqual */
+ local_node->indexqual = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readJoinPath
- *
- * JoinPath is a subclass of Path
+ * _readJoinPath
+ *
+ * JoinPath is a subclass of Path
* ----------------
*/
static JoinPath *
_readJoinPath()
{
- JoinPath *local_node;
- char *token;
- int length;
-
-
- local_node = makeNode(JoinPath);
-
- token = lsptok(NULL, &length); /* get :pathtype */
- token = lsptok(NULL, &length); /* now read it */
- local_node->path.pathtype = atol(token);
-
- token = lsptok(NULL, &length); /* get :cost */
- token = lsptok(NULL, &length); /* now read it */
- local_node->path.path_cost = (Cost) atof(token);
-
+ JoinPath *local_node;
+ char *token;
+ int length;
+
+
+ local_node = makeNode(JoinPath);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path.pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+ local_node->path.path_cost = (Cost) atof(token);
+
#if 0
- token = lsptok(NULL, &length); /* get :p_ordering */
- local_node->path.p_ordering = nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->path.p_ordering = nodeRead(true); /* now read it */
#endif
-
- token = lsptok(NULL, &length); /* get :keys */
- local_node->path.keys = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :pathclauseinfo */
- local_node->pathclauseinfo = nodeRead(true); /* now read it */
-
- /*
- * Not sure if these are nodes; they're declared as "struct path *".
- * For now, i'll just print the addresses.
- *
- * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
- * and initialize these pointers to NULL.
- */
-
- token = lsptok(NULL, &length); /* get :outerjoinpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->outerjoinpath = NULL;
-
- token = lsptok(NULL, &length); /* get :innerjoinpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->innerjoinpath = NULL;
-
- token = lsptok(NULL, &length); /* get :outerjoincost */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->path.outerjoincost = (Cost) atof(token);
-
- token = lsptok(NULL, &length); /* get :joinid */
- local_node->path.joinid =
- toIntList(nodeRead(true)); /* now read it */
-
- return(local_node);
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathclauseinfo */
+ local_node->pathclauseinfo = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ *
+ * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
+ * and initialize these pointers to NULL.
+ */
+
+ token = lsptok(NULL, &length); /* get :outerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->outerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :innerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->innerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :outerjoincost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->path.outerjoincost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :joinid */
+ local_node->path.joinid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readMergePath
- *
- * MergePath is a subclass of JoinPath.
+ * _readMergePath
+ *
+ * MergePath is a subclass of JoinPath.
* ----------------
*/
static MergePath *
_readMergePath()
{
- MergePath *local_node;
- char *token;
- int length;
-
- local_node = makeNode(MergePath);
-
- token = lsptok(NULL, &length); /* get :pathtype */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.path.pathtype = atol(token);
-
- token = lsptok(NULL, &length); /* get :cost */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.path.path_cost = (Cost) atof(token);
-
+ MergePath *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(MergePath);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.path_cost = (Cost) atof(token);
+
#if 0
- token = lsptok(NULL, &length); /* get :p_ordering */
- local_node->jpath.path.p_ordering = nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->jpath.path.p_ordering = nodeRead(true); /* now read it */
#endif
-
- token = lsptok(NULL, &length); /* get :keys */
- local_node->jpath.path.keys = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :pathclauseinfo */
- local_node->jpath.pathclauseinfo = nodeRead(true); /* now read it */
-
- /*
- * Not sure if these are nodes; they're declared as "struct path *".
- * For now, i'll just print the addresses.
- *
- * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
- * and initialize these pointers to NULL.
- */
-
- token = lsptok(NULL, &length); /* get :outerjoinpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.outerjoinpath = NULL;
-
- token = lsptok(NULL, &length); /* get :innerjoinpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.innerjoinpath = NULL;
-
- token = lsptok(NULL, &length); /* get :outerjoincost */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.path.outerjoincost = (Cost) atof(token);
-
- token = lsptok(NULL, &length); /* get :joinid */
- local_node->jpath.path.joinid =
- toIntList(nodeRead(true)); /* now read it */
-
- token = lsptok(NULL, &length); /* get :path_mergeclauses */
- local_node->path_mergeclauses = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :outersortkeys */
- local_node->outersortkeys = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :innersortkeys */
- local_node->innersortkeys = nodeRead(true); /* now read it */
-
- return(local_node);
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->jpath.path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathclauseinfo */
+ local_node->jpath.pathclauseinfo = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ *
+ * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
+ * and initialize these pointers to NULL.
+ */
+
+ token = lsptok(NULL, &length); /* get :outerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.outerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :innerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.innerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :outerjoincost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.outerjoincost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :joinid */
+ local_node->jpath.path.joinid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :path_mergeclauses */
+ local_node->path_mergeclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :outersortkeys */
+ local_node->outersortkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :innersortkeys */
+ local_node->innersortkeys = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readHashPath
- *
- * HashPath is a subclass of JoinPath.
+ * _readHashPath
+ *
+ * HashPath is a subclass of JoinPath.
* ----------------
*/
static HashPath *
_readHashPath()
{
- HashPath *local_node;
- char *token;
- int length;
-
- local_node = makeNode(HashPath);
-
- token = lsptok(NULL, &length); /* get :pathtype */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.path.pathtype = atol(token);
-
- token = lsptok(NULL, &length); /* get :cost */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.path.path_cost = (Cost) atof(token);
-
+ HashPath *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(HashPath);
+
+ token = lsptok(NULL, &length); /* get :pathtype */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.pathtype = atol(token);
+
+ token = lsptok(NULL, &length); /* get :cost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.path_cost = (Cost) atof(token);
+
#if 0
- token = lsptok(NULL, &length); /* get :p_ordering */
- local_node->jpath.path.p_ordering = nodeRead(true); /* now read it */
+ token = lsptok(NULL, &length); /* get :p_ordering */
+ local_node->jpath.path.p_ordering = nodeRead(true); /* now read it */
#endif
-
- token = lsptok(NULL, &length); /* get :keys */
- local_node->jpath.path.keys = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :pathclauseinfo */
- local_node->jpath.pathclauseinfo = nodeRead(true); /* now read it */
-
- /*
- * Not sure if these are nodes; they're declared as "struct path *".
- * For now, i'll just print the addresses.
- *
- * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
- * and initialize these pointers to NULL.
- */
-
- token = lsptok(NULL, &length); /* get :outerjoinpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.outerjoinpath = NULL;
-
- token = lsptok(NULL, &length); /* get :innerjoinpath */
- token = lsptok(NULL, &length); /* get @ */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.innerjoinpath = NULL;
-
- token = lsptok(NULL, &length); /* get :outerjoincost */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->jpath.path.outerjoincost = (Cost) atof(token);
-
- token = lsptok(NULL, &length); /* get :joinid */
- local_node->jpath.path.joinid =
- toIntList(nodeRead(true)); /* now read it */
-
- token = lsptok(NULL, &length); /* get :path_hashclauses */
- local_node->path_hashclauses = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :outerhashkeys */
- local_node->outerhashkeys = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :innerhashkeys */
- local_node->innerhashkeys = nodeRead(true); /* now read it */
-
- return(local_node);
+
+ token = lsptok(NULL, &length); /* get :keys */
+ local_node->jpath.path.keys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :pathclauseinfo */
+ local_node->jpath.pathclauseinfo = nodeRead(true); /* now read it */
+
+ /*
+ * Not sure if these are nodes; they're declared as "struct path *".
+ * For now, i'll just print the addresses.
+ *
+ * GJK: Since I am parsing this stuff, I'll just ignore the addresses,
+ * and initialize these pointers to NULL.
+ */
+
+ token = lsptok(NULL, &length); /* get :outerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.outerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :innerjoinpath */
+ token = lsptok(NULL, &length); /* get @ */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.innerjoinpath = NULL;
+
+ token = lsptok(NULL, &length); /* get :outerjoincost */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->jpath.path.outerjoincost = (Cost) atof(token);
+
+ token = lsptok(NULL, &length); /* get :joinid */
+ local_node->jpath.path.joinid =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :path_hashclauses */
+ local_node->path_hashclauses = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :outerhashkeys */
+ local_node->outerhashkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :innerhashkeys */
+ local_node->innerhashkeys = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readOrderKey
- *
- * OrderKey is a subclass of Node.
+ * _readOrderKey
+ *
+ * OrderKey is a subclass of Node.
* ----------------
*/
static OrderKey *
_readOrderKey()
{
- OrderKey *local_node;
- char *token;
- int length;
-
- local_node = makeNode(OrderKey);
-
- token = lsptok(NULL, &length); /* get :attribute_number */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->attribute_number = atoi(token);
-
- token = lsptok(NULL, &length); /* get :array_index */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->array_index = atoi(token);
-
- return(local_node);
+ OrderKey *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(OrderKey);
+
+ token = lsptok(NULL, &length); /* get :attribute_number */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->attribute_number = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :array_index */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->array_index = atoi(token);
+
+ return (local_node);
}
/* ----------------
- * _readJoinKey
- *
- * JoinKey is a subclass of Node.
+ * _readJoinKey
+ *
+ * JoinKey is a subclass of Node.
* ----------------
*/
static JoinKey *
_readJoinKey()
{
- JoinKey *local_node;
- char *token;
- int length;
-
- local_node = makeNode(JoinKey);
-
- token = lsptok(NULL, &length); /* get :outer */
- local_node->outer = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :inner */
- local_node->inner = nodeRead(true); /* now read it */
-
- return(local_node);
+ JoinKey *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(JoinKey);
+
+ token = lsptok(NULL, &length); /* get :outer */
+ local_node->outer = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :inner */
+ local_node->inner = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readMergeOrder
- *
- * MergeOrder is a subclass of Node.
+ * _readMergeOrder
+ *
+ * MergeOrder is a subclass of Node.
* ----------------
*/
static MergeOrder *
_readMergeOrder()
{
- MergeOrder *local_node;
- char *token;
- int length;
-
- local_node = makeNode(MergeOrder);
- token = lsptok(NULL, &length); /* get :join_operator */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->join_operator = atol(token);
-
- token = lsptok(NULL, &length); /* get :left_operator */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->left_operator = atol(token);
-
- token = lsptok(NULL, &length); /* get :right_operator */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->right_operator = atol(token);
-
- token = lsptok(NULL, &length); /* get :left_type */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->left_type = atol(token);
-
- token = lsptok(NULL, &length); /* get :right_type */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->right_type = atol(token);
-
- return(local_node);
+ MergeOrder *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(MergeOrder);
+ token = lsptok(NULL, &length); /* get :join_operator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->join_operator = atol(token);
+
+ token = lsptok(NULL, &length); /* get :left_operator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->left_operator = atol(token);
+
+ token = lsptok(NULL, &length); /* get :right_operator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->right_operator = atol(token);
+
+ token = lsptok(NULL, &length); /* get :left_type */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->left_type = atol(token);
+
+ token = lsptok(NULL, &length); /* get :right_type */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->right_type = atol(token);
+
+ return (local_node);
}
/* ----------------
- * _readCInfo
- *
- * CInfo is a subclass of Node.
+ * _readCInfo
+ *
+ * CInfo is a subclass of Node.
* ----------------
*/
-static CInfo *
+static CInfo *
_readCInfo()
{
- CInfo *local_node;
- char *token;
- int length;
-
- local_node = makeNode(CInfo);
-
- token = lsptok(NULL, &length); /* get :clause */
- local_node->clause = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :selectivity */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->selectivity = atof(token);
-
- token = lsptok(NULL, &length); /* get :notclause */
- token = lsptok(NULL, &length); /* now read it */
-
- if (!strncmp(token, "true", 4))
- {
- local_node->notclause = true;
- }
- else
- {
- local_node->notclause = false;
- }
-
- token = lsptok(NULL, &length); /* get :indexids */
- local_node->indexids = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :mergesortorder */
- local_node->mergesortorder = (MergeOrder*) nodeRead(true);
-
- token = lsptok(NULL, &length); /* get :hashjoinoperator */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->hashjoinoperator = atol(token);
-
- return(local_node);
+ CInfo *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(CInfo);
+
+ token = lsptok(NULL, &length); /* get :clause */
+ local_node->clause = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :selectivity */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->selectivity = atof(token);
+
+ token = lsptok(NULL, &length); /* get :notclause */
+ token = lsptok(NULL, &length); /* now read it */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->notclause = true;
+ }
+ else
+ {
+ local_node->notclause = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :indexids */
+ local_node->indexids = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :mergesortorder */
+ local_node->mergesortorder = (MergeOrder *) nodeRead(true);
+
+ token = lsptok(NULL, &length); /* get :hashjoinoperator */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->hashjoinoperator = atol(token);
+
+ return (local_node);
}
/* ----------------
- * _readJoinMethod
- *
- * JoinMethod is a subclass of Node.
+ * _readJoinMethod
+ *
+ * JoinMethod is a subclass of Node.
* ----------------
*/
static JoinMethod *
_readJoinMethod()
{
- JoinMethod *local_node;
- char *token;
- int length;
-
- local_node = makeNode(JoinMethod);
-
- token = lsptok(NULL, &length); /* get :jmkeys */
- local_node->jmkeys = nodeRead(true);/* now read it */
-
- token = lsptok(NULL, &length); /* get :clauses */
- local_node->clauses = nodeRead(true); /* now read it */
-
- return(local_node);
+ JoinMethod *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(JoinMethod);
+
+ token = lsptok(NULL, &length); /* get :jmkeys */
+ local_node->jmkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :clauses */
+ local_node->clauses = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readHInfo
- *
+ * _readHInfo
+ *
* HInfo is a subclass of JoinMethod.
* ----------------
*/
-static HInfo *
+static HInfo *
_readHInfo()
{
- HInfo *local_node;
- char *token;
- int length;
-
- local_node = makeNode(HInfo);
-
- token = lsptok(NULL, &length); /* get :hashop */
- token = lsptok(NULL, &length); /* now read it */
-
- local_node->hashop = atoi(token);
-
- token = lsptok(NULL, &length); /* get :jmkeys */
- local_node->jmethod.jmkeys = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :clauses */
- local_node->jmethod.clauses = nodeRead(true); /* now read it */
-
- return(local_node);
+ HInfo *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(HInfo);
+
+ token = lsptok(NULL, &length); /* get :hashop */
+ token = lsptok(NULL, &length); /* now read it */
+
+ local_node->hashop = atoi(token);
+
+ token = lsptok(NULL, &length); /* get :jmkeys */
+ local_node->jmethod.jmkeys = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :clauses */
+ local_node->jmethod.clauses = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * _readJInfo()
- *
- * JInfo is a subclass of Node.
+ * _readJInfo()
+ *
+ * JInfo is a subclass of Node.
* ----------------
*/
-static JInfo *
+static JInfo *
_readJInfo()
{
- JInfo *local_node;
- char *token;
- int length;
-
- local_node = makeNode(JInfo);
-
- token = lsptok(NULL, &length); /* get :otherrels */
- local_node->otherrels =
- toIntList(nodeRead(true)); /* now read it */
-
- token = lsptok(NULL, &length); /* get :jinfoclauseinfo */
- local_node->jinfoclauseinfo = nodeRead(true); /* now read it */
-
- token = lsptok(NULL, &length); /* get :mergesortable */
-
- if (!strncmp(token, "true", 4))
- {
- local_node->mergesortable = true;
- }
- else
- {
- local_node->mergesortable = false;
- }
-
- token = lsptok(NULL, &length); /* get :hashjoinable */
-
- if (!strncmp(token, "true", 4))
- {
- local_node->hashjoinable = true;
- }
- else
- {
- local_node->hashjoinable = false;
- }
-
- return(local_node);
+ JInfo *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(JInfo);
+
+ token = lsptok(NULL, &length); /* get :otherrels */
+ local_node->otherrels =
+ toIntList(nodeRead(true)); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :jinfoclauseinfo */
+ local_node->jinfoclauseinfo = nodeRead(true); /* now read it */
+
+ token = lsptok(NULL, &length); /* get :mergesortable */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->mergesortable = true;
+ }
+ else
+ {
+ local_node->mergesortable = false;
+ }
+
+ token = lsptok(NULL, &length); /* get :hashjoinable */
+
+ if (!strncmp(token, "true", 4))
+ {
+ local_node->hashjoinable = true;
+ }
+ else
+ {
+ local_node->hashjoinable = false;
+ }
+
+ return (local_node);
}
/* ----------------
- * _readIter()
+ * _readIter()
*
* ----------------
*/
-static Iter *
+static Iter *
_readIter()
{
- Iter *local_node;
- char *token;
- int length;
-
- local_node = makeNode(Iter);
-
- token = lsptok(NULL, &length); /* eat :iterexpr */
- local_node->iterexpr = nodeRead(true); /* now read it */
-
- return(local_node);
+ Iter *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Iter);
+
+ token = lsptok(NULL, &length); /* eat :iterexpr */
+ local_node->iterexpr = nodeRead(true); /* now read it */
+
+ return (local_node);
}
/* ----------------
- * parsePlanString
+ * parsePlanString
*
* Given a character string containing a plan, parsePlanString sets up the
* plan structure representing that plan.
@@ -1823,164 +1867,263 @@ _readIter()
* The string passed to parsePlanString must be null-terminated.
* ----------------
*/
-Node *
+Node *
parsePlanString(void)
{
- char *token;
- int length;
- void *return_value = NULL;
-
- token = lsptok(NULL, &length);
-
- if (!strncmp(token, "PLAN", 4)) {
- return_value = _readPlan();
- }else if (!strncmp(token, "RESULT", 6)) {
- return_value = _readResult();
- }else if (!strncmp(token, "EXISTENTIAL", 11)) {
- return_value = _readExistential();
- }else if (!strncmp(token, "APPEND", 6)) {
- return_value = _readAppend();
- }else if (!strncmp(token, "JOIN", 4)) {
- return_value = _readJoin();
- }else if (!strncmp(token, "NESTLOOP", 8)) {
- return_value = _readNestLoop();
- }else if (!strncmp(token, "MERGEJOIN", 9)) {
- return_value = _readMergeJoin();
- }else if (!strncmp(token, "HASHJOIN", 8)) {
- return_value = _readHashJoin();
- }else if (!strncmp(token, "SCAN", 4)) {
- return_value = _readScan();
- }else if (!strncmp(token, "SEQSCAN", 7)) {
- return_value = _readSeqScan();
- }else if (!strncmp(token, "INDEXSCAN", 9)) {
- return_value = _readIndexScan();
- }else if (!strncmp(token, "TEMP", 4)) {
- return_value = _readTemp();
- }else if (!strncmp(token, "SORT", 4)) {
- return_value = _readSort();
- }else if (!strncmp(token, "AGGREG", 6)) {
- return_value = _readAggreg();
- }else if (!strncmp(token, "AGG", 3)) {
- return_value = _readAgg();
- }else if (!strncmp(token, "UNIQUE", 4)) {
- return_value = _readUnique();
- }else if (!strncmp(token, "HASH", 4)) {
- return_value = _readHash();
- }else if (!strncmp(token, "RESDOM", 6)) {
- return_value = _readResdom();
- }else if (!strncmp(token, "EXPR", 4)) {
- return_value = _readExpr();
- }else if (!strncmp(token, "ARRAYREF", 7)) {
- /* make sure this strncmp is done before that of ARRAY */
- return_value = _readArrayRef();
- }else if (!strncmp(token, "ARRAY", 5)) {
- return_value = _readArray();
- }else if (!strncmp(token, "VAR", 3)) {
- return_value = _readVar();
- }else if (!strncmp(token, "CONST", 5)) {
- return_value = _readConst();
- }else if (!strncmp(token, "FUNC", 4)) {
- return_value = _readFunc();
- }else if (!strncmp(token, "OPER", 4)) {
- return_value = _readOper();
- }else if (!strncmp(token, "PARAM", 5)) {
- return_value = _readParam();
- }else if (!strncmp(token, "ESTATE", 6)) {
- return_value = _readEState();
- }else if (!strncmp(token, "REL", 3)) {
- return_value = _readRel();
- }else if (!strncmp(token, "TLE", 3)) {
- return_value = _readTargetEntry();
- }else if (!strncmp(token, "RTE", 3)) {
- return_value = _readRangeTblEntry();
- }else if (!strncmp(token, "PATH", 4)) {
- return_value = _readPath();
- }else if (!strncmp(token, "INDEXPATH", 9)) {
- return_value = _readIndexPath();
- }else if (!strncmp(token, "JOINPATH", 8)) {
- return_value = _readJoinPath();
- }else if (!strncmp(token, "MERGEPATH", 9)) {
- return_value = _readMergePath();
- }else if (!strncmp(token, "HASHPATH", 8)) {
- return_value = _readHashPath();
- }else if (!strncmp(token, "ORDERKEY", 8)) {
- return_value = _readOrderKey();
- }else if (!strncmp(token, "JOINKEY", 7)) {
- return_value = _readJoinKey();
- }else if (!strncmp(token, "MERGEORDER", 10)) {
- return_value = _readMergeOrder();
- }else if (!strncmp(token, "CINFO", 5)) {
- return_value = _readCInfo();
- }else if (!strncmp(token, "JOINMETHOD", 10)) {
- return_value = _readJoinMethod();
- }else if (!strncmp(token, "JINFO", 5)) {
- return_value = _readJInfo();
- }else if (!strncmp(token, "HINFO", 5)) {
- return_value = _readHInfo();
- }else if (!strncmp(token, "ITER", 4)) {
- return_value = _readIter();
- }else if (!strncmp(token, "QUERY", 5)) {
- return_value = _readQuery();
- }else {
- elog(WARN, "badly formatted planstring \"%.10s\"...\n", token);
- }
-
- return ((Node*)return_value);
+ char *token;
+ int length;
+ void *return_value = NULL;
+
+ token = lsptok(NULL, &length);
+
+ if (!strncmp(token, "PLAN", 4))
+ {
+ return_value = _readPlan();
+ }
+ else if (!strncmp(token, "RESULT", 6))
+ {
+ return_value = _readResult();
+ }
+ else if (!strncmp(token, "EXISTENTIAL", 11))
+ {
+ return_value = _readExistential();
+ }
+ else if (!strncmp(token, "APPEND", 6))
+ {
+ return_value = _readAppend();
+ }
+ else if (!strncmp(token, "JOIN", 4))
+ {
+ return_value = _readJoin();
+ }
+ else if (!strncmp(token, "NESTLOOP", 8))
+ {
+ return_value = _readNestLoop();
+ }
+ else if (!strncmp(token, "MERGEJOIN", 9))
+ {
+ return_value = _readMergeJoin();
+ }
+ else if (!strncmp(token, "HASHJOIN", 8))
+ {
+ return_value = _readHashJoin();
+ }
+ else if (!strncmp(token, "SCAN", 4))
+ {
+ return_value = _readScan();
+ }
+ else if (!strncmp(token, "SEQSCAN", 7))
+ {
+ return_value = _readSeqScan();
+ }
+ else if (!strncmp(token, "INDEXSCAN", 9))
+ {
+ return_value = _readIndexScan();
+ }
+ else if (!strncmp(token, "TEMP", 4))
+ {
+ return_value = _readTemp();
+ }
+ else if (!strncmp(token, "SORT", 4))
+ {
+ return_value = _readSort();
+ }
+ else if (!strncmp(token, "AGGREG", 6))
+ {
+ return_value = _readAggreg();
+ }
+ else if (!strncmp(token, "AGG", 3))
+ {
+ return_value = _readAgg();
+ }
+ else if (!strncmp(token, "UNIQUE", 4))
+ {
+ return_value = _readUnique();
+ }
+ else if (!strncmp(token, "HASH", 4))
+ {
+ return_value = _readHash();
+ }
+ else if (!strncmp(token, "RESDOM", 6))
+ {
+ return_value = _readResdom();
+ }
+ else if (!strncmp(token, "EXPR", 4))
+ {
+ return_value = _readExpr();
+ }
+ else if (!strncmp(token, "ARRAYREF", 7))
+ {
+ /* make sure this strncmp is done before that of ARRAY */
+ return_value = _readArrayRef();
+ }
+ else if (!strncmp(token, "ARRAY", 5))
+ {
+ return_value = _readArray();
+ }
+ else if (!strncmp(token, "VAR", 3))
+ {
+ return_value = _readVar();
+ }
+ else if (!strncmp(token, "CONST", 5))
+ {
+ return_value = _readConst();
+ }
+ else if (!strncmp(token, "FUNC", 4))
+ {
+ return_value = _readFunc();
+ }
+ else if (!strncmp(token, "OPER", 4))
+ {
+ return_value = _readOper();
+ }
+ else if (!strncmp(token, "PARAM", 5))
+ {
+ return_value = _readParam();
+ }
+ else if (!strncmp(token, "ESTATE", 6))
+ {
+ return_value = _readEState();
+ }
+ else if (!strncmp(token, "REL", 3))
+ {
+ return_value = _readRel();
+ }
+ else if (!strncmp(token, "TLE", 3))
+ {
+ return_value = _readTargetEntry();
+ }
+ else if (!strncmp(token, "RTE", 3))
+ {
+ return_value = _readRangeTblEntry();
+ }
+ else if (!strncmp(token, "PATH", 4))
+ {
+ return_value = _readPath();
+ }
+ else if (!strncmp(token, "INDEXPATH", 9))
+ {
+ return_value = _readIndexPath();
+ }
+ else if (!strncmp(token, "JOINPATH", 8))
+ {
+ return_value = _readJoinPath();
+ }
+ else if (!strncmp(token, "MERGEPATH", 9))
+ {
+ return_value = _readMergePath();
+ }
+ else if (!strncmp(token, "HASHPATH", 8))
+ {
+ return_value = _readHashPath();
+ }
+ else if (!strncmp(token, "ORDERKEY", 8))
+ {
+ return_value = _readOrderKey();
+ }
+ else if (!strncmp(token, "JOINKEY", 7))
+ {
+ return_value = _readJoinKey();
+ }
+ else if (!strncmp(token, "MERGEORDER", 10))
+ {
+ return_value = _readMergeOrder();
+ }
+ else if (!strncmp(token, "CINFO", 5))
+ {
+ return_value = _readCInfo();
+ }
+ else if (!strncmp(token, "JOINMETHOD", 10))
+ {
+ return_value = _readJoinMethod();
+ }
+ else if (!strncmp(token, "JINFO", 5))
+ {
+ return_value = _readJInfo();
+ }
+ else if (!strncmp(token, "HINFO", 5))
+ {
+ return_value = _readHInfo();
+ }
+ else if (!strncmp(token, "ITER", 4))
+ {
+ return_value = _readIter();
+ }
+ else if (!strncmp(token, "QUERY", 5))
+ {
+ return_value = _readQuery();
+ }
+ else
+ {
+ elog(WARN, "badly formatted planstring \"%.10s\"...\n", token);
+ }
+
+ return ((Node *) return_value);
}
+
/*------------------------------------------------------------*/
/* ----------------
- * readDatum
+ * readDatum
*
* given a string representation of the value of the given type,
* create the appropriate Datum
* ----------------
*/
-static Datum
+static Datum
readDatum(Oid type)
{
- int length;
- int tokenLength;
- char *token;
- bool byValue;
- Datum res;
- char *s;
- int i;
-
- byValue = get_typbyval(type);
-
- /*
- * read the actual length of the value
- */
- token = lsptok(NULL, &tokenLength);
- length = atoi(token);
- token = lsptok(NULL, &tokenLength); /* skip the '[' */
-
- if (byValue) {
- if (length > sizeof(Datum)) {
- elog(WARN, "readValue: byval & length = %d", length);
- }
- s = (char *) (&res);
- for (i=0; i<sizeof(Datum); i++) {
- token = lsptok(NULL, &tokenLength);
- s[i] = (char) atoi(token);
- }
- } else if (length <= 0) {
- s = NULL;
- } else if (length >= 1) {
- s = (char*)palloc(length);
- Assert( s!=NULL );
- for (i=0; i<length; i++) {
- token = lsptok(NULL, &tokenLength);
- s[i] = (char) atoi(token);
- }
- res = PointerGetDatum(s);
- }
-
- token = lsptok(NULL, &tokenLength); /* skip the ']' */
- if (token[0] != ']') {
- elog(WARN, "readValue: ']' expected, length =%d", length);
- }
-
- return(res);
+ int length;
+ int tokenLength;
+ char *token;
+ bool byValue;
+ Datum res;
+ char *s;
+ int i;
+
+ byValue = get_typbyval(type);
+
+ /*
+ * read the actual length of the value
+ */
+ token = lsptok(NULL, &tokenLength);
+ length = atoi(token);
+ token = lsptok(NULL, &tokenLength); /* skip the '[' */
+
+ if (byValue)
+ {
+ if (length > sizeof(Datum))
+ {
+ elog(WARN, "readValue: byval & length = %d", length);
+ }
+ s = (char *) (&res);
+ for (i = 0; i < sizeof(Datum); i++)
+ {
+ token = lsptok(NULL, &tokenLength);
+ s[i] = (char) atoi(token);
+ }
+ }
+ else if (length <= 0)
+ {
+ s = NULL;
+ }
+ else if (length >= 1)
+ {
+ s = (char *) palloc(length);
+ Assert(s != NULL);
+ for (i = 0; i < length; i++)
+ {
+ token = lsptok(NULL, &tokenLength);
+ s[i] = (char) atoi(token);
+ }
+ res = PointerGetDatum(s);
+ }
+
+ token = lsptok(NULL, &tokenLength); /* skip the ']' */
+ if (token[0] != ']')
+ {
+ elog(WARN, "readValue: ']' expected, length =%d", length);
+ }
+
+ return (res);
}
diff --git a/src/backend/optimizer/geqo/geqo_copy.c b/src/backend/optimizer/geqo/geqo_copy.c
index 3356f8d5475..4c35f99f9f5 100644
--- a/src/backend/optimizer/geqo/geqo_copy.c
+++ b/src/backend/optimizer/geqo/geqo_copy.c
@@ -4,32 +4,32 @@
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: geqo_copy.c,v 1.1 1997/02/19 12:56:40 scrappy Exp $
+ * $Id: geqo_copy.c,v 1.2 1997/09/07 04:43:01 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* this is adopted from D. Whitley's Genitor algorithm */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
#include "postgres.h"
@@ -52,16 +52,16 @@
/* geqo_copy--
*
- * copies one gene to another
+ * copies one gene to another
*
*/
void
-geqo_copy (Chromosome *chromo1, Chromosome *chromo2, int string_length)
+geqo_copy(Chromosome * chromo1, Chromosome * chromo2, int string_length)
{
- int i;
+ int i;
- for (i=0; i<string_length; i++)
- chromo1->string[i] = chromo2->string[i];
+ for (i = 0; i < string_length; i++)
+ chromo1->string[i] = chromo2->string[i];
- chromo1->worth = chromo2->worth;
+ chromo1->worth = chromo2->worth;
}
diff --git a/src/backend/optimizer/geqo/geqo_cx.c b/src/backend/optimizer/geqo/geqo_cx.c
index a3aa6fce4f4..dfde1bdc530 100644
--- a/src/backend/optimizer/geqo/geqo_cx.c
+++ b/src/backend/optimizer/geqo/geqo_cx.c
@@ -2,35 +2,35 @@
*
* geqo_cx.c--
*
-* cycle crossover [CX] routines;
-* CX operator according to Oliver et al
-* (Proc 2nd Int'l Conf on GA's)
+* cycle crossover [CX] routines;
+* CX operator according to Oliver et al
+* (Proc 2nd Int'l Conf on GA's)
*
-* $Id: geqo_cx.c,v 1.1 1997/02/19 12:56:48 scrappy Exp $
+* $Id: geqo_cx.c,v 1.2 1997/09/07 04:43:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* the cx algorithm is adopted from Genitor : */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
@@ -57,73 +57,81 @@
/* cx--
*
- * cycle crossover
+ * cycle crossover
*/
int
-cx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+cx(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table)
{
- int i, start_pos, curr_pos;
- int count = 0;
- int num_diffs = 0;
+ int i,
+ start_pos,
+ curr_pos;
+ int count = 0;
+ int num_diffs = 0;
- /* initialize city table */
- for (i=1; i<=num_gene; i++) {
- city_table[i].used = 0;
- city_table[tour2[i-1]].tour2_position = i-1;
- city_table[tour1[i-1]].tour1_position = i-1;
- }
+ /* initialize city table */
+ for (i = 1; i <= num_gene; i++)
+ {
+ city_table[i].used = 0;
+ city_table[tour2[i - 1]].tour2_position = i - 1;
+ city_table[tour1[i - 1]].tour1_position = i - 1;
+ }
- /* choose random cycle starting position */
- start_pos = geqo_randint(num_gene - 1, 0);
+ /* choose random cycle starting position */
+ start_pos = geqo_randint(num_gene - 1, 0);
- /* child inherits first city */
- offspring[start_pos] = tour1[start_pos];
+ /* child inherits first city */
+ offspring[start_pos] = tour1[start_pos];
- /* begin cycle with tour1 */
- curr_pos = start_pos;
- city_table[(int) tour1[start_pos]].used = 1;
+ /* begin cycle with tour1 */
+ curr_pos = start_pos;
+ city_table[(int) tour1[start_pos]].used = 1;
- count++;
+ count++;
- /* cx main part */
+ /* cx main part */
/* STEP 1 */
- while (tour2[curr_pos] != tour1[start_pos]) {
- city_table[(int) tour2[curr_pos]].used = 1;
- curr_pos = city_table[(int) tour2[curr_pos]].tour1_position;
- offspring[curr_pos] = tour1[curr_pos];
- count++;
- }
+ while (tour2[curr_pos] != tour1[start_pos])
+ {
+ city_table[(int) tour2[curr_pos]].used = 1;
+ curr_pos = city_table[(int) tour2[curr_pos]].tour1_position;
+ offspring[curr_pos] = tour1[curr_pos];
+ count++;
+ }
/* STEP 2 */
- /* failed to create a complete tour */
- if (count < num_gene) {
- for (i=1; i<=num_gene; i++) {
- if (!city_table[i].used) {
- offspring[city_table[i].tour2_position] =
- tour2[(int) city_table[i].tour2_position];
- count++;
- }
- }
- }
+ /* failed to create a complete tour */
+ if (count < num_gene)
+ {
+ for (i = 1; i <= num_gene; i++)
+ {
+ if (!city_table[i].used)
+ {
+ offspring[city_table[i].tour2_position] =
+ tour2[(int) city_table[i].tour2_position];
+ count++;
+ }
+ }
+ }
/* STEP 3 */
- /* still failed to create a complete tour */
- if (count < num_gene) {
+ /* still failed to create a complete tour */
+ if (count < num_gene)
+ {
- /* count the number of differences between mom and offspring */
- for (i=0; i<num_gene; i++)
- if (tour1[i] != offspring[i]) num_diffs++;
+ /* count the number of differences between mom and offspring */
+ for (i = 0; i < num_gene; i++)
+ if (tour1[i] != offspring[i])
+ num_diffs++;
- }
-
- return(num_diffs);
- }
+ }
+ return (num_diffs);
+}
diff --git a/src/backend/optimizer/geqo/geqo_erx.c b/src/backend/optimizer/geqo/geqo_erx.c
index 8c3c63d755c..9d0f93efe8c 100644
--- a/src/backend/optimizer/geqo/geqo_erx.c
+++ b/src/backend/optimizer/geqo/geqo_erx.c
@@ -1,33 +1,33 @@
/*------------------------------------------------------------------------
*
* geqo_erx.c--
-* edge recombination crossover [ER]
+* edge recombination crossover [ER]
*
-* $Id: geqo_erx.c,v 1.2 1997/06/06 00:37:23 scrappy Exp $
+* $Id: geqo_erx.c,v 1.3 1997/09/07 04:43:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* the edge recombination algorithm is adopted from Genitor : */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
@@ -52,384 +52,441 @@
#include "optimizer/geqo_random.h"
-static int gimme_edge (Gene gene1, Gene gene2, Edge *edge_table);
-static void remove_gene(Gene gene, Edge edge, Edge *edge_table);
-static Gene gimme_gene(Edge edge, Edge *edge_table);
+static int gimme_edge(Gene gene1, Gene gene2, Edge * edge_table);
+static void remove_gene(Gene gene, Edge edge, Edge * edge_table);
+static Gene gimme_gene(Edge edge, Edge * edge_table);
-static Gene edge_failure(Gene *gene, int index, Edge *edge_table, int num_gene);
+static Gene edge_failure(Gene * gene, int index, Edge * edge_table, int num_gene);
/* alloc_edge_table--
*
- * allocate memory for edge table
+ * allocate memory for edge table
*
*/
-Edge *
+Edge *
alloc_edge_table(int num_gene)
{
- Edge *edge_table;
+ Edge *edge_table;
- /* palloc one extra location so that nodes numbered
- 1..n can be indexed directly; 0 will not be used */
+ /*
+ * palloc one extra location so that nodes numbered 1..n can be
+ * indexed directly; 0 will not be used
+ */
- edge_table = (Edge *) palloc ((num_gene+1)*sizeof(Edge));
+ edge_table = (Edge *) palloc((num_gene + 1) * sizeof(Edge));
- return (edge_table);
- }
+ return (edge_table);
+}
/* free_edge_table--
*
- * deallocate memory of edge table
+ * deallocate memory of edge table
*
*/
- void
- free_edge_table(Edge *edge_table)
- {
- pfree(edge_table);
- }
+void
+free_edge_table(Edge * edge_table)
+{
+ pfree(edge_table);
+}
/* gimme_edge_table--
*
- * fills a data structure which represents the set of explicit
- * edges between points in the (2) input genes
+ * fills a data structure which represents the set of explicit
+ * edges between points in the (2) input genes
+ *
+ * assumes circular tours and bidirectional edges
*
- * assumes circular tours and bidirectional edges
- *
- * gimme_edge() will set "shared" edges to negative values
+ * gimme_edge() will set "shared" edges to negative values
*
- * returns average number edges/city in range 2.0 - 4.0
- * where 2.0=homogeneous; 4.0=diverse
+ * returns average number edges/city in range 2.0 - 4.0
+ * where 2.0=homogeneous; 4.0=diverse
*
*/
float
-gimme_edge_table (Gene *tour1, Gene *tour2, int num_gene, Edge *edge_table)
+gimme_edge_table(Gene * tour1, Gene * tour2, int num_gene, Edge * edge_table)
{
- int i, index1, index2;
- int edge_total; /* total number of unique edges in two genes */
-
- /* at first clear the edge table's old data */
- for (i = 1; i <= num_gene; i++) {
- edge_table[i].total_edges = 0;
- edge_table[i].unused_edges = 0;
+ int i,
+ index1,
+ index2;
+ int edge_total; /* total number of unique edges in two
+ * genes */
+
+ /* at first clear the edge table's old data */
+ for (i = 1; i <= num_gene; i++)
+ {
+ edge_table[i].total_edges = 0;
+ edge_table[i].unused_edges = 0;
}
- /* fill edge table with new data */
+ /* fill edge table with new data */
- edge_total = 0;
+ edge_total = 0;
- for (index1 = 0; index1 < num_gene; index1++) {
+ for (index1 = 0; index1 < num_gene; index1++)
+ {
- /* presume the tour is circular, i.e. 1->2, 2->3, 3->1
- this operaton maps n back to 1 */
+ /*
+ * presume the tour is circular, i.e. 1->2, 2->3, 3->1 this
+ * operaton maps n back to 1
+ */
- index2 = (index1 + 1) % num_gene;
+ index2 = (index1 + 1) % num_gene;
- /* edges are bidirectional, i.e. 1->2 is same as 2->1
- call gimme_edge twice per edge */
+ /*
+ * edges are bidirectional, i.e. 1->2 is same as 2->1 call
+ * gimme_edge twice per edge
+ */
- edge_total += gimme_edge(tour1[index1], tour1[index2], edge_table);
- gimme_edge(tour1[index2], tour1[index1], edge_table);
+ edge_total += gimme_edge(tour1[index1], tour1[index2], edge_table);
+ gimme_edge(tour1[index2], tour1[index1], edge_table);
- edge_total += gimme_edge(tour2[index1], tour2[index2], edge_table);
- gimme_edge(tour2[index2], tour2[index1], edge_table);
- }
+ edge_total += gimme_edge(tour2[index1], tour2[index2], edge_table);
+ gimme_edge(tour2[index2], tour2[index1], edge_table);
+ }
- /* return average number of edges per index */
- return (((float) (edge_total * 2)/ (float) num_gene));
+ /* return average number of edges per index */
+ return (((float) (edge_total * 2) / (float) num_gene));
}
/* gimme_edge--
*
- * registers edge from city1 to city2 in input edge table
+ * registers edge from city1 to city2 in input edge table
*
- * no assumptions about directionality are made;
- * therefor it is up to the calling routine to
- * call gimme_edge twice to make a bi-directional edge
- * between city1 and city2;
- * uni-directional edges are possible as well (just call gimme_edge
- * once with the direction from city1 to city2)
+ * no assumptions about directionality are made;
+ * therefor it is up to the calling routine to
+ * call gimme_edge twice to make a bi-directional edge
+ * between city1 and city2;
+ * uni-directional edges are possible as well (just call gimme_edge
+ * once with the direction from city1 to city2)
*
- * returns 1 if edge was not already registered and was just added;
- * 0 if edge was already registered and edge_table is unchanged
+ * returns 1 if edge was not already registered and was just added;
+ * 0 if edge was already registered and edge_table is unchanged
*/
static int
-gimme_edge (Gene gene1, Gene gene2, Edge *edge_table)
+gimme_edge(Gene gene1, Gene gene2, Edge * edge_table)
{
- int i;
- int edges;
- int city1 = (int) gene1;
- int city2 = (int) gene2;
+ int i;
+ int edges;
+ int city1 = (int) gene1;
+ int city2 = (int) gene2;
- /* check whether edge city1->city2 already exists */
- edges = edge_table[city1].total_edges;
+ /* check whether edge city1->city2 already exists */
+ edges = edge_table[city1].total_edges;
- for (i=0; i<edges; i++) {
- if ((Gene) Abs(edge_table[city1].edge_list[i]) == city2) {
+ for (i = 0; i < edges; i++)
+ {
+ if ((Gene) Abs(edge_table[city1].edge_list[i]) == city2)
+ {
- /* mark shared edges as negative */
- edge_table[city1].edge_list[i] = 0-city2;
+ /* mark shared edges as negative */
+ edge_table[city1].edge_list[i] = 0 - city2;
- return (0);
- }
- }
+ return (0);
+ }
+ }
- /* add city1->city2; */
- edge_table[city1].edge_list[edges] = city2;
+ /* add city1->city2; */
+ edge_table[city1].edge_list[edges] = city2;
- /* increment the number of edges from city1 */
- edge_table[city1].total_edges++;
- edge_table[city1].unused_edges++;
+ /* increment the number of edges from city1 */
+ edge_table[city1].total_edges++;
+ edge_table[city1].unused_edges++;
- return (1);
+ return (1);
}
/* gimme_tour--
*
- * creates a new tour using edges from the edge table.
- * priority is given to "shared" edges (i.e. edges which
- * all parent genes possess and are marked as negative
- * in the edge table.)
+ * creates a new tour using edges from the edge table.
+ * priority is given to "shared" edges (i.e. edges which
+ * all parent genes possess and are marked as negative
+ * in the edge table.)
*
*/
int
-gimme_tour (Edge *edge_table, Gene *new_gene, int num_gene)
+gimme_tour(Edge * edge_table, Gene * new_gene, int num_gene)
{
- int i;
- int edge_failures=0;
+ int i;
+ int edge_failures = 0;
- new_gene[0] = (Gene) geqo_randint(num_gene, 1); /* choose int between 1 and num_gene */
+ new_gene[0] = (Gene) geqo_randint(num_gene, 1); /* choose int between 1
+ * and num_gene */
- for (i=1; i<num_gene; i++) {
-
- /* as each point is entered into the tour,
- remove it from the edge table */
+ for (i = 1; i < num_gene; i++)
+ {
- remove_gene(new_gene[i-1], edge_table[(int) new_gene[i-1]], edge_table);
-
- /* find destination for the newly entered point */
+ /*
+ * as each point is entered into the tour, remove it from the edge
+ * table
+ */
- if (edge_table[new_gene[i-1]].unused_edges > 0) {
- new_gene[i] = gimme_gene(edge_table[(int) new_gene[i-1]], edge_table);
- }
+ remove_gene(new_gene[i - 1], edge_table[(int) new_gene[i - 1]], edge_table);
- else { /* cope with fault */
- edge_failures++;
+ /* find destination for the newly entered point */
- new_gene[i] = edge_failure(new_gene, i-1, edge_table, num_gene);
- }
+ if (edge_table[new_gene[i - 1]].unused_edges > 0)
+ {
+ new_gene[i] = gimme_gene(edge_table[(int) new_gene[i - 1]], edge_table);
+ }
- /* mark this node as incorporated */
- edge_table[(int) new_gene[i-1]].unused_edges = -1;
+ else
+ { /* cope with fault */
+ edge_failures++;
- } /* for (i=1; i<num_gene; i++) */
+ new_gene[i] = edge_failure(new_gene, i - 1, edge_table, num_gene);
+ }
-return(edge_failures);
+ /* mark this node as incorporated */
+ edge_table[(int) new_gene[i - 1]].unused_edges = -1;
+
+ } /* for (i=1; i<num_gene; i++) */
+
+ return (edge_failures);
}
/* remove_gene--
*
- * removes input gene from edge_table.
- * input edge is used
- * to identify deletion locations within edge table.
+ * removes input gene from edge_table.
+ * input edge is used
+ * to identify deletion locations within edge table.
*
*/
static void
-remove_gene (Gene gene, Edge edge, Edge *edge_table)
+remove_gene(Gene gene, Edge edge, Edge * edge_table)
{
- int i,j;
- int possess_edge;
- int genes_remaining;
+ int i,
+ j;
+ int possess_edge;
+ int genes_remaining;
- /* do for every gene known to have an edge to input gene
- (i.e. in edge_list for input edge) */
+ /*
+ * do for every gene known to have an edge to input gene (i.e. in
+ * edge_list for input edge)
+ */
- for (i=0; i<edge.unused_edges; i++) {
- possess_edge = (int) Abs(edge.edge_list[i]);
- genes_remaining = edge_table[possess_edge].unused_edges;
+ for (i = 0; i < edge.unused_edges; i++)
+ {
+ possess_edge = (int) Abs(edge.edge_list[i]);
+ genes_remaining = edge_table[possess_edge].unused_edges;
- /* find the input gene in all edge_lists and delete it */
- for (j=0; j<genes_remaining; j++) {
+ /* find the input gene in all edge_lists and delete it */
+ for (j = 0; j < genes_remaining; j++)
+ {
- if ( (Gene) Abs(edge_table[possess_edge].edge_list[j]) == gene) {
+ if ((Gene) Abs(edge_table[possess_edge].edge_list[j]) == gene)
+ {
- edge_table[possess_edge].unused_edges--;
+ edge_table[possess_edge].unused_edges--;
- edge_table[possess_edge].edge_list[j] =
- edge_table[possess_edge].edge_list[genes_remaining-1];
+ edge_table[possess_edge].edge_list[j] =
+ edge_table[possess_edge].edge_list[genes_remaining - 1];
- break;
- }
+ break;
+ }
}
- }
+ }
}
/* gimme_gene--
*
- * priority is given to "shared" edges
- * (i.e. edges which both genes possess)
+ * priority is given to "shared" edges
+ * (i.e. edges which both genes possess)
*
*/
-static Gene
-gimme_gene (Edge edge, Edge *edge_table)
+static Gene
+gimme_gene(Edge edge, Edge * edge_table)
{
- int i;
- Gene friend;
- int minimum_edges;
- int minimum_count = -1;
- int rand_decision;
-
- /* no point has edges to more than 4 other points
- thus, this contrived minimum will be replaced */
-
- minimum_edges = 5;
-
- /* consider candidate destination points in edge list */
-
- for (i=0; i<edge.unused_edges; i++) {
- friend = (Gene) edge.edge_list[i];
-
- /* give priority to shared edges that are negative;
- so return 'em */
-
- /* negative values are caught here
- so we need not worry about converting to absolute values */
- if (friend < 0) return ( (Gene) Abs(friend));
-
-
- /* give priority to candidates with fewest remaining unused edges;
- find out what the minimum number of unused edges is (minimum_edges);
- if there is more than one cadidate with the minimum number
- of unused edges keep count of this number (minimum_count); */
-
- /* The test for minimum_count can probably be removed at some
- point but comments should probably indicate exactly why it
- is guaranteed that the test will always succeed the first
- time around. If it can fail then the code is in error */
-
-
- if (edge_table[(int) friend].unused_edges < minimum_edges) {
- minimum_edges = edge_table[(int) friend].unused_edges;
- minimum_count = 1;
+ int i;
+ Gene friend;
+ int minimum_edges;
+ int minimum_count = -1;
+ int rand_decision;
+
+ /*
+ * no point has edges to more than 4 other points thus, this contrived
+ * minimum will be replaced
+ */
+
+ minimum_edges = 5;
+
+ /* consider candidate destination points in edge list */
+
+ for (i = 0; i < edge.unused_edges; i++)
+ {
+ friend = (Gene) edge.edge_list[i];
+
+ /*
+ * give priority to shared edges that are negative; so return 'em
+ */
+
+ /*
+ * negative values are caught here so we need not worry about
+ * converting to absolute values
+ */
+ if (friend < 0)
+ return ((Gene) Abs(friend));
+
+
+ /*
+ * give priority to candidates with fewest remaining unused edges;
+ * find out what the minimum number of unused edges is
+ * (minimum_edges); if there is more than one cadidate with the
+ * minimum number of unused edges keep count of this number
+ * (minimum_count);
+ */
+
+ /*
+ * The test for minimum_count can probably be removed at some
+ * point but comments should probably indicate exactly why it is
+ * guaranteed that the test will always succeed the first time
+ * around. If it can fail then the code is in error
+ */
+
+
+ if (edge_table[(int) friend].unused_edges < minimum_edges)
+ {
+ minimum_edges = edge_table[(int) friend].unused_edges;
+ minimum_count = 1;
}
- else
- if (minimum_count == -1)
- elog(WARN, "gimme_gene: Internal error - minimum_count not set");
- else
- if (edge_table[(int) friend].unused_edges == minimum_edges)
- minimum_count++;
+ else if (minimum_count == -1)
+ elog(WARN, "gimme_gene: Internal error - minimum_count not set");
+ else if (edge_table[(int) friend].unused_edges == minimum_edges)
+ minimum_count++;
+
+ } /* for (i=0; i<edge.unused_edges; i++) */
- } /* for (i=0; i<edge.unused_edges; i++) */
-
- /* random decision of the possible candidates to use */
- rand_decision = (int) geqo_randint(minimum_count-1, 0);
+ /* random decision of the possible candidates to use */
+ rand_decision = (int) geqo_randint(minimum_count - 1, 0);
-
- for (i=0; i<edge.unused_edges; i++) {
- friend = (Gene) edge.edge_list[i];
- /* return the chosen candidate point */
- if (edge_table[(int) friend].unused_edges == minimum_edges) {
- minimum_count--;
+ for (i = 0; i < edge.unused_edges; i++)
+ {
+ friend = (Gene) edge.edge_list[i];
- if ( minimum_count == rand_decision ) return (friend);
+ /* return the chosen candidate point */
+ if (edge_table[(int) friend].unused_edges == minimum_edges)
+ {
+ minimum_count--;
+
+ if (minimum_count == rand_decision)
+ return (friend);
}
}
- /* ... should never be reached */
- elog(WARN,"gimme_gene: neither shared nor minimum number nor random edge found");
- return 0; /* to keep the compiler quiet */
+ /* ... should never be reached */
+ elog(WARN, "gimme_gene: neither shared nor minimum number nor random edge found");
+ return 0; /* to keep the compiler quiet */
}
/* edge_failure--
*
- * routine for handling edge failure
+ * routine for handling edge failure
*
*/
-static Gene
-edge_failure (Gene *gene, int index, Edge *edge_table, int num_gene)
+static Gene
+edge_failure(Gene * gene, int index, Edge * edge_table, int num_gene)
{
- int i;
- Gene fail_gene = gene[index];
- int remaining_edges = 0;
- int four_count = 0;
- int rand_decision;
-
-
- /* how many edges remain?
- how many gene with four total (initial) edges remain? */
-
- for (i=1; i<=num_gene; i++) {
- if ( (edge_table[i].unused_edges != -1) && (i != (int) fail_gene) ) {
- remaining_edges++;
-
- if (edge_table[i].total_edges == 4) four_count++;
- }
- }
+ int i;
+ Gene fail_gene = gene[index];
+ int remaining_edges = 0;
+ int four_count = 0;
+ int rand_decision;
+
+
+ /*
+ * how many edges remain? how many gene with four total (initial)
+ * edges remain?
+ */
+
+ for (i = 1; i <= num_gene; i++)
+ {
+ if ((edge_table[i].unused_edges != -1) && (i != (int) fail_gene))
+ {
+ remaining_edges++;
+
+ if (edge_table[i].total_edges == 4)
+ four_count++;
+ }
+ }
- /* random decision of the gene
- with remaining edges and whose total_edges == 4 */
+ /*
+ * random decision of the gene with remaining edges and whose
+ * total_edges == 4
+ */
- if (four_count != 0 ) {
+ if (four_count != 0)
+ {
- rand_decision = (int) geqo_randint(four_count-1, 0);
+ rand_decision = (int) geqo_randint(four_count - 1, 0);
- for (i=1; i<=num_gene; i++) {
+ for (i = 1; i <= num_gene; i++)
+ {
- if ((Gene) i != fail_gene &&
+ if ((Gene) i != fail_gene &&
edge_table[i].unused_edges != -1 &&
- edge_table[i].total_edges==4) {
+ edge_table[i].total_edges == 4)
+ {
four_count--;
- if (rand_decision == four_count) return ((Gene) i);
- }
+ if (rand_decision == four_count)
+ return ((Gene) i);
}
+ }
- elog(DEBUG,"edge_failure(1): no edge found via random decision and total_edges == 4");
+ elog(DEBUG, "edge_failure(1): no edge found via random decision and total_edges == 4");
}
- else /* random decision of the gene with remaining edges */
+ else
+/* random decision of the gene with remaining edges */
- if (remaining_edges != 0) {
+ if (remaining_edges != 0)
+ {
- rand_decision = (int) geqo_randint(remaining_edges-1, 0);
+ rand_decision = (int) geqo_randint(remaining_edges - 1, 0);
- for (i=1; i<=num_gene; i++) {
+ for (i = 1; i <= num_gene; i++)
+ {
- if ((Gene) i != fail_gene &&
- edge_table[i].unused_edges != -1) {
+ if ((Gene) i != fail_gene &&
+ edge_table[i].unused_edges != -1)
+ {
remaining_edges--;
- if (rand_decision == remaining_edges) return (i);
- }
+ if (rand_decision == remaining_edges)
+ return (i);
}
-
- elog(DEBUG,"edge_failure(2): no edge found via random decision and remainig edges");
}
- /* edge table seems to be empty; this happens sometimes on
- the last point due to the fact that the first point is
- removed from the table even though only one of its edges
- has been determined */
+ elog(DEBUG, "edge_failure(2): no edge found via random decision and remainig edges");
+ }
- else { /* occurs only at the last point in the tour;
- simply look for the point which is not yet used */
+ /*
+ * edge table seems to be empty; this happens sometimes on the last
+ * point due to the fact that the first point is removed from the
+ * table even though only one of its edges has been determined
+ */
- for (i=1; i<=num_gene; i++)
- if (edge_table[i].unused_edges >= 0)
- return ((Gene) i);
-
- elog(DEBUG,"edge_failure(3): no edge found via looking for the last ununsed point");
+ else
+ { /* occurs only at the last point in the
+ * tour; simply look for the point which
+ * is not yet used */
+
+ for (i = 1; i <= num_gene; i++)
+ if (edge_table[i].unused_edges >= 0)
+ return ((Gene) i);
+
+ elog(DEBUG, "edge_failure(3): no edge found via looking for the last ununsed point");
}
/* ... should never be reached */
- elog(WARN,"edge_failure: no edge detected");
- return 0; /* to keep the compiler quiet */
+ elog(WARN, "edge_failure: no edge detected");
+ return 0; /* to keep the compiler quiet */
}
-
diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c
index 7ec449f2e94..ba34d8f3e02 100644
--- a/src/backend/optimizer/geqo/geqo_eval.c
+++ b/src/backend/optimizer/geqo/geqo_eval.c
@@ -1,20 +1,20 @@
/*------------------------------------------------------------------------
*
* geqo_eval.c--
- * Routines to evaluate query trees
+ * Routines to evaluate query trees
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: geqo_eval.c,v 1.12 1997/08/12 22:53:07 momjian Exp $
+ * $Id: geqo_eval.c,v 1.13 1997/09/07 04:43:06 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
@@ -22,13 +22,13 @@
#include <math.h>
#ifdef HAVE_LIMITS_H
-# include <limits.h>
-# ifndef MAXINT
-# define MAXINT INT_MAX
-# endif
+#include <limits.h>
+#ifndef MAXINT
+#define MAXINT INT_MAX
+#endif
#else
-# include <values.h>
-#endif
+#include <values.h>
+#endif
#include "nodes/pg_list.h"
#include "nodes/relation.h"
@@ -50,548 +50,598 @@
#include "optimizer/geqo_paths.h"
-static List *gimme_clause_joins(Query *root, Rel *outer_rel, Rel *inner_rel);
-static Rel *gimme_clauseless_join(Rel *outer_rel, Rel *inner_rel);
-static Rel *init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo);
-static List *new_join_tlist(List *tlist, List *other_relids, int first_resdomno);
-static List *new_joininfo_list(List *joininfo_list, List *join_relids);
-static void geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel);
-static Rel *geqo_nth(int stop, List *rels);
+static List *gimme_clause_joins(Query * root, Rel * outer_rel, Rel * inner_rel);
+static Rel *gimme_clauseless_join(Rel * outer_rel, Rel * inner_rel);
+static Rel *init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo);
+static List *new_join_tlist(List * tlist, List * other_relids, int first_resdomno);
+static List *new_joininfo_list(List * joininfo_list, List * join_relids);
+static void geqo_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel);
+static Rel *geqo_nth(int stop, List * rels);
-/*
+/*
* geqo_eval--
- *
+ *
* Returns cost of a query tree as an individual of the population.
*/
Cost
-geqo_eval (Query *root, Gene *tour, int num_gene)
+geqo_eval(Query * root, Gene * tour, int num_gene)
{
- Rel *joinrel;
- Cost fitness;
- List *temp;
+ Rel *joinrel;
+ Cost fitness;
+ List *temp;
/* remember root->join_relation_list_ ... */
/* because root->join_relation_list_ will be changed during the following */
- temp = listCopy(root->join_relation_list_);
+ temp = listCopy(root->join_relation_list_);
/* joinrel is readily processed query tree -- left-sided ! */
- joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
+ joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
/* compute fitness */
- fitness = (Cost) joinrel->cheapestpath->path_cost;
+ fitness = (Cost) joinrel->cheapestpath->path_cost;
- root->join_relation_list_ = listCopy(temp);
+ root->join_relation_list_ = listCopy(temp);
- pfree(joinrel);
- freeList(temp);
+ pfree(joinrel);
+ freeList(temp);
- return(fitness);
+ return (fitness);
}
-/*
+/*
* gimme-tree --
- * this program presumes that only LEFT-SIDED TREES are considered!
- *
+ * this program presumes that only LEFT-SIDED TREES are considered!
+ *
* 'outer_rel' is the preceeding join
- *
+ *
* Returns a new join relation incorporating all joins in a left-sided tree.
*/
-Rel *
-gimme_tree (Query *root, Gene *tour, int rel_count, int num_gene, Rel *outer_rel)
+Rel *
+gimme_tree(Query * root, Gene * tour, int rel_count, int num_gene, Rel * outer_rel)
{
- Rel *inner_rel; /* current relation */
- int base_rel_index;
+ Rel *inner_rel; /* current relation */
+ int base_rel_index;
- List *new_rels = NIL;
- Rel *new_rel = NULL;
+ List *new_rels = NIL;
+ Rel *new_rel = NULL;
- if (rel_count < num_gene ) { /* tree not yet finished */
+ if (rel_count < num_gene)
+ { /* tree not yet finished */
- /* tour[0] = 3; tour[1] = 1; tour[2] = 2 */
- base_rel_index = (int) tour[rel_count];
+ /* tour[0] = 3; tour[1] = 1; tour[2] = 2 */
+ base_rel_index = (int) tour[rel_count];
- inner_rel = (Rel *) geqo_nth(base_rel_index,root->base_relation_list_);
+ inner_rel = (Rel *) geqo_nth(base_rel_index, root->base_relation_list_);
- if (rel_count == 0) { /* processing first join with base_rel_index = (int) tour[0] */
- rel_count++;
- return gimme_tree(root, tour, rel_count, num_gene, inner_rel);
+ if (rel_count == 0)
+ { /* processing first join with
+ * base_rel_index = (int) tour[0] */
+ rel_count++;
+ return gimme_tree(root, tour, rel_count, num_gene, inner_rel);
}
- else { /* tree main part */
-
- if(!(new_rels = gimme_clause_joins(root, outer_rel,inner_rel))) {
- if (BushyPlanFlag) {
- new_rels = lcons(gimme_clauseless_join(outer_rel,outer_rel),NIL); /* ??? MAU */
+ else
+ { /* tree main part */
+
+ if (!(new_rels = gimme_clause_joins(root, outer_rel, inner_rel)))
+ {
+ if (BushyPlanFlag)
+ {
+ new_rels = lcons(gimme_clauseless_join(outer_rel, outer_rel), NIL); /* ??? MAU */
}
- else {
- new_rels = lcons(gimme_clauseless_join(outer_rel,inner_rel),NIL);
+ else
+ {
+ new_rels = lcons(gimme_clauseless_join(outer_rel, inner_rel), NIL);
}
}
- /* process new_rel->pathlist */
- find_all_join_paths(root, new_rels);
+ /* process new_rel->pathlist */
+ find_all_join_paths(root, new_rels);
- /* prune new_rels */
- /* MAU: is this necessary? */
- /* what's the matter if more than one new rel is left till now? */
- /* joinrels in newrels with different ordering of relids are not possible */
- if (length(new_rels) > 1) new_rels = geqo_prune_rels(new_rels);
+ /* prune new_rels */
+ /* MAU: is this necessary? */
- if (length(new_rels) > 1) { /* should never be reached ... */
- elog(DEBUG,"gimme_tree: still %d relations left", length(new_rels));
+ /*
+ * what's the matter if more than one new rel is left till
+ * now?
+ */
+
+ /*
+ * joinrels in newrels with different ordering of relids are
+ * not possible
+ */
+ if (length(new_rels) > 1)
+ new_rels = geqo_prune_rels(new_rels);
+
+ if (length(new_rels) > 1)
+ { /* should never be reached ... */
+ elog(DEBUG, "gimme_tree: still %d relations left", length(new_rels));
}
- /* get essential new relation */
- new_rel = (Rel *) lfirst(new_rels);
- rel_count++;
+ /* get essential new relation */
+ new_rel = (Rel *) lfirst(new_rels);
+ rel_count++;
- /* process new_rel->cheapestpath, new_rel->unorderedpath */
- geqo_rel_paths(new_rel);
+ /* process new_rel->cheapestpath, new_rel->unorderedpath */
+ geqo_rel_paths(new_rel);
- /* processing of other new_rel attributes */
- if ( new_rel->size <= 0 )
- new_rel->size = compute_rel_size(new_rel);
- new_rel->width = compute_rel_width(new_rel);
+ /* processing of other new_rel attributes */
+ if (new_rel->size <= 0)
+ new_rel->size = compute_rel_size(new_rel);
+ new_rel->width = compute_rel_width(new_rel);
- root->join_relation_list_ = lcons(new_rel, NIL);
+ root->join_relation_list_ = lcons(new_rel, NIL);
- return gimme_tree(root, tour, rel_count, num_gene, new_rel);
+ return gimme_tree(root, tour, rel_count, num_gene, new_rel);
}
}
- return (outer_rel); /* tree finished ... */
+ return (outer_rel); /* tree finished ... */
}
-/*
+/*
* gimme-clause-joins--
*
* 'outer-rel' is the relation entry for the outer relation
* 'inner-rel' is the relation entry for the inner relation
- *
+ *
* Returns a list of new join relations.
*/
-static List *
-gimme_clause_joins(Query *root, Rel *outer_rel, Rel *inner_rel)
+static List *
+gimme_clause_joins(Query * root, Rel * outer_rel, Rel * inner_rel)
{
- List *join_list = NIL;
- List *i = NIL;
- List *joininfo_list = (List *) outer_rel->joininfo;
-
- foreach (i, joininfo_list) {
- JInfo *joininfo = (JInfo*)lfirst(i);
- Rel *rel = NULL;
-
- if(!joininfo->inactive) {
- List *other_rels = (List *)joininfo->otherrels;
-
- if(other_rels != NIL) {
- if( (length(other_rels) == 1) ) {
-
- if( same(other_rels, inner_rel->relids) ) { /* look if inner_rel is it...*/
- rel = init_join_rel(outer_rel, inner_rel, joininfo);
+ List *join_list = NIL;
+ List *i = NIL;
+ List *joininfo_list = (List *) outer_rel->joininfo;
+
+ foreach(i, joininfo_list)
+ {
+ JInfo *joininfo = (JInfo *) lfirst(i);
+ Rel *rel = NULL;
+
+ if (!joininfo->inactive)
+ {
+ List *other_rels = (List *) joininfo->otherrels;
+
+ if (other_rels != NIL)
+ {
+ if ((length(other_rels) == 1))
+ {
+
+ if (same(other_rels, inner_rel->relids))
+ { /* look if inner_rel is it... */
+ rel = init_join_rel(outer_rel, inner_rel, joininfo);
}
}
- else if (BushyPlanFlag) { /* ?!? MAU */
- rel = init_join_rel(outer_rel, get_join_rel(root, other_rels), joininfo);
- }
- else {
- rel = NULL;
- }
+ else if (BushyPlanFlag)
+ { /* ?!? MAU */
+ rel = init_join_rel(outer_rel, get_join_rel(root, other_rels), joininfo);
+ }
+ else
+ {
+ rel = NULL;
+ }
- if (rel != NULL)
- join_list = lappend(join_list, rel);
+ if (rel != NULL)
+ join_list = lappend(join_list, rel);
}
}
}
- return(join_list);
+ return (join_list);
}
-/*
+/*
* gimme-clauseless-join--
- * Given an outer relation 'outer-rel' and an inner relation
- * 'inner-rel', create a join relation between 'outer-rel' and 'inner-rel'
- *
+ * Given an outer relation 'outer-rel' and an inner relation
+ * 'inner-rel', create a join relation between 'outer-rel' and 'inner-rel'
+ *
* Returns a new join relation.
*/
-static Rel *
-gimme_clauseless_join(Rel *outer_rel, Rel *inner_rel)
+static Rel *
+gimme_clauseless_join(Rel * outer_rel, Rel * inner_rel)
{
- return(init_join_rel(outer_rel, inner_rel, (JInfo*)NULL));
+ return (init_join_rel(outer_rel, inner_rel, (JInfo *) NULL));
}
-/*
+/*
* init-join-rel--
- * Creates and initializes a new join relation.
- *
+ * Creates and initializes a new join relation.
+ *
* 'outer-rel' and 'inner-rel' are relation nodes for the relations to be
- * joined
+ * joined
* 'joininfo' is the joininfo node(join clause) containing both
- * 'outer-rel' and 'inner-rel', if any exists
- *
+ * 'outer-rel' and 'inner-rel', if any exists
+ *
* Returns the new join relation node.
*/
-static Rel *
-init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo)
+static Rel *
+init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo)
{
- Rel *joinrel = makeNode(Rel);
- List *joinrel_joininfo_list = NIL;
- List *new_outer_tlist;
- List *new_inner_tlist;
-
- /*
- * Create a new tlist by removing irrelevant elements from both
- * tlists of the outer and inner join relations and then merging
- * the results together.
- */
- new_outer_tlist =
- new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */
- inner_rel->relids, 1);
- new_inner_tlist =
- new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */
- outer_rel->relids,
- length(new_outer_tlist) + 1);
-
- joinrel->relids = NIL;
- joinrel->indexed = false;
- joinrel->pages = 0;
- joinrel->tuples = 0;
- joinrel->width = 0;
-/* joinrel->targetlist = NIL;*/
- joinrel->pathlist = NIL;
- joinrel->unorderedpath = (Path *)NULL;
- joinrel->cheapestpath = (Path *)NULL;
- joinrel->pruneable = true;
- joinrel->classlist = NULL;
- joinrel->relam = InvalidOid;
- joinrel->ordering = NULL;
- joinrel->clauseinfo = NIL;
- joinrel->joininfo = NULL;
- joinrel->innerjoin = NIL;
- joinrel->superrels = NIL;
-
- joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL));
-
- new_outer_tlist = nconc(new_outer_tlist,new_inner_tlist);
- joinrel->targetlist = new_outer_tlist;
-
- if (joininfo) {
- joinrel->clauseinfo = joininfo->jinfoclauseinfo;
- if (BushyPlanFlag) joininfo->inactive = true;
- }
-
- joinrel_joininfo_list =
- new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo),
- intAppend(outer_rel->relids, inner_rel->relids));
-
- joinrel->joininfo = joinrel_joininfo_list;
-
- geqo_joinrel_size(joinrel, outer_rel, inner_rel);
-
- return(joinrel);
+ Rel *joinrel = makeNode(Rel);
+ List *joinrel_joininfo_list = NIL;
+ List *new_outer_tlist;
+ List *new_inner_tlist;
+
+ /*
+ * Create a new tlist by removing irrelevant elements from both tlists
+ * of the outer and inner join relations and then merging the results
+ * together.
+ */
+ new_outer_tlist =
+ new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */
+ inner_rel->relids, 1);
+ new_inner_tlist =
+ new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */
+ outer_rel->relids,
+ length(new_outer_tlist) + 1);
+
+ joinrel->relids = NIL;
+ joinrel->indexed = false;
+ joinrel->pages = 0;
+ joinrel->tuples = 0;
+ joinrel->width = 0;
+/* joinrel->targetlist = NIL;*/
+ joinrel->pathlist = NIL;
+ joinrel->unorderedpath = (Path *) NULL;
+ joinrel->cheapestpath = (Path *) NULL;
+ joinrel->pruneable = true;
+ joinrel->classlist = NULL;
+ joinrel->relam = InvalidOid;
+ joinrel->ordering = NULL;
+ joinrel->clauseinfo = NIL;
+ joinrel->joininfo = NULL;
+ joinrel->innerjoin = NIL;
+ joinrel->superrels = NIL;
+
+ joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL));
+
+ new_outer_tlist = nconc(new_outer_tlist, new_inner_tlist);
+ joinrel->targetlist = new_outer_tlist;
+
+ if (joininfo)
+ {
+ joinrel->clauseinfo = joininfo->jinfoclauseinfo;
+ if (BushyPlanFlag)
+ joininfo->inactive = true;
+ }
+
+ joinrel_joininfo_list =
+ new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo),
+ intAppend(outer_rel->relids, inner_rel->relids));
+
+ joinrel->joininfo = joinrel_joininfo_list;
+
+ geqo_joinrel_size(joinrel, outer_rel, inner_rel);
+
+ return (joinrel);
}
-/*
+/*
* new-join-tlist--
- * Builds a join relations's target list by keeping those elements that
- * will be in the final target list and any other elements that are still
- * needed for future joins. For a target list entry to still be needed
- * for future joins, its 'joinlist' field must not be empty after removal
- * of all relids in 'other-relids'.
- *
+ * Builds a join relations's target list by keeping those elements that
+ * will be in the final target list and any other elements that are still
+ * needed for future joins. For a target list entry to still be needed
+ * for future joins, its 'joinlist' field must not be empty after removal
+ * of all relids in 'other-relids'.
+ *
* 'tlist' is the target list of one of the join relations
* 'other-relids' is a list of relids contained within the other
- * join relation
+ * join relation
* 'first-resdomno' is the resdom number to use for the first created
- * target list entry
- *
+ * target list entry
+ *
* Returns the new target list.
*/
-static List *
-new_join_tlist(List *tlist,
- List *other_relids,
- int first_resdomno)
+static List *
+new_join_tlist(List * tlist,
+ List * other_relids,
+ int first_resdomno)
{
- int resdomno = first_resdomno - 1;
- TargetEntry *xtl = NULL;
- List *temp_node = NIL;
- List *t_list = NIL;
- List *i = NIL;
- List *join_list = NIL;
- bool in_final_tlist =false;
-
-
- foreach(i,tlist) {
- xtl= lfirst(i);
- in_final_tlist = (join_list==NIL);
- if( in_final_tlist) {
- resdomno += 1;
- temp_node =
- lcons(create_tl_element(get_expr(xtl),
- resdomno),
- NIL);
- t_list = nconc(t_list,temp_node);
- }
- }
-
- return(t_list);
+ int resdomno = first_resdomno - 1;
+ TargetEntry *xtl = NULL;
+ List *temp_node = NIL;
+ List *t_list = NIL;
+ List *i = NIL;
+ List *join_list = NIL;
+ bool in_final_tlist = false;
+
+
+ foreach(i, tlist)
+ {
+ xtl = lfirst(i);
+ in_final_tlist = (join_list == NIL);
+ if (in_final_tlist)
+ {
+ resdomno += 1;
+ temp_node =
+ lcons(create_tl_element(get_expr(xtl),
+ resdomno),
+ NIL);
+ t_list = nconc(t_list, temp_node);
+ }
+ }
+
+ return (t_list);
}
-/*
+/*
* new-joininfo-list--
- * Builds a join relation's joininfo list by checking for join clauses
- * which still need to used in future joins involving this relation. A
- * join clause is still needed if there are still relations in the clause
- * not contained in the list of relations comprising this join relation.
- * New joininfo nodes are only created and added to
- * 'current-joininfo-list' if a node for a particular join hasn't already
- * been created.
+ * Builds a join relation's joininfo list by checking for join clauses
+ * which still need to used in future joins involving this relation. A
+ * join clause is still needed if there are still relations in the clause
+ * not contained in the list of relations comprising this join relation.
+ * New joininfo nodes are only created and added to
+ * 'current-joininfo-list' if a node for a particular join hasn't already
+ * been created.
*
- * 'current-joininfo-list' contains a list of those joininfo nodes that
- * have already been built
+ * 'current-joininfo-list' contains a list of those joininfo nodes that
+ * have already been built
* 'joininfo-list' is the list of join clauses involving this relation
- * 'join-relids' is a list of relids corresponding to the relations
- * currently being joined
- *
+ * 'join-relids' is a list of relids corresponding to the relations
+ * currently being joined
+ *
* Returns a list of joininfo nodes, new and old.
*/
-static List *
-new_joininfo_list(List *joininfo_list, List *join_relids)
+static List *
+new_joininfo_list(List * joininfo_list, List * join_relids)
{
- List *current_joininfo_list = NIL;
- List *new_otherrels = NIL;
- JInfo *other_joininfo = (JInfo*)NULL;
- List *xjoininfo = NIL;
-
- foreach (xjoininfo, joininfo_list) {
- List *or;
- JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
-
- new_otherrels = joininfo->otherrels;
- foreach (or, new_otherrels)
- {
- if ( intMember (lfirsti(or), join_relids) )
- new_otherrels = lremove ((void*)lfirst(or), new_otherrels);
- }
- joininfo->otherrels = new_otherrels;
- if ( new_otherrels != NIL )
+ List *current_joininfo_list = NIL;
+ List *new_otherrels = NIL;
+ JInfo *other_joininfo = (JInfo *) NULL;
+ List *xjoininfo = NIL;
+
+ foreach(xjoininfo, joininfo_list)
{
- other_joininfo = joininfo_member(new_otherrels,
- current_joininfo_list);
- if(other_joininfo) {
- other_joininfo->jinfoclauseinfo =
- (List*)LispUnion(joininfo->jinfoclauseinfo,
- other_joininfo->jinfoclauseinfo);
- }else {
- other_joininfo = makeNode(JInfo);
-
- other_joininfo->otherrels =
- joininfo->otherrels;
- other_joininfo->jinfoclauseinfo =
- joininfo->jinfoclauseinfo;
- other_joininfo->mergesortable =
- joininfo->mergesortable;
- other_joininfo->hashjoinable =
- joininfo->hashjoinable;
- other_joininfo->inactive = false;
-
- current_joininfo_list = lcons(other_joininfo,
- current_joininfo_list);
- }
+ List *or;
+ JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
+
+ new_otherrels = joininfo->otherrels;
+ foreach(or, new_otherrels)
+ {
+ if (intMember(lfirsti(or), join_relids))
+ new_otherrels = lremove((void *) lfirst(or), new_otherrels);
+ }
+ joininfo->otherrels = new_otherrels;
+ if (new_otherrels != NIL)
+ {
+ other_joininfo = joininfo_member(new_otherrels,
+ current_joininfo_list);
+ if (other_joininfo)
+ {
+ other_joininfo->jinfoclauseinfo =
+ (List *) LispUnion(joininfo->jinfoclauseinfo,
+ other_joininfo->jinfoclauseinfo);
+ }
+ else
+ {
+ other_joininfo = makeNode(JInfo);
+
+ other_joininfo->otherrels =
+ joininfo->otherrels;
+ other_joininfo->jinfoclauseinfo =
+ joininfo->jinfoclauseinfo;
+ other_joininfo->mergesortable =
+ joininfo->mergesortable;
+ other_joininfo->hashjoinable =
+ joininfo->hashjoinable;
+ other_joininfo->inactive = false;
+
+ current_joininfo_list = lcons(other_joininfo,
+ current_joininfo_list);
+ }
+ }
}
- }
- return(current_joininfo_list);
+ return (current_joininfo_list);
}
#ifdef NOTUSED
/*
* add-new-joininfos--
- * For each new join relation, create new joininfos that
- * use the join relation as inner relation, and add
- * the new joininfos to those rel nodes that still
- * have joins with the join relation.
+ * For each new join relation, create new joininfos that
+ * use the join relation as inner relation, and add
+ * the new joininfos to those rel nodes that still
+ * have joins with the join relation.
*
* 'joinrels' is a list of join relations.
*
* Modifies the joininfo field of appropriate rel nodes.
*/
static void
-geqo_add_new_joininfos(Query *root, List *joinrels, List *outerrels)
+geqo_add_new_joininfos(Query * root, List * joinrels, List * outerrels)
{
- List *xjoinrel = NIL;
- List *xrelid = NIL;
- List *xrel = NIL;
- List *xjoininfo = NIL;
-
- Rel *rel;
- List *relids;
-
- List *super_rels;
- List *xsuper_rel = NIL;
- JInfo *new_joininfo;
-
- foreach(xjoinrel, joinrels) {
- Rel *joinrel = (Rel *)lfirst(xjoinrel);
- foreach(xrelid, joinrel->relids) {
- /* length(joinrel->relids) should always be greater that 1, because of *JOIN* */
- /* ! BUG BUG !
- Relid relid = (Relid)lfirst(xrelid);
- Rel *rel = get_join_rel(root, relid);
- */
-
- /*
- if ( (root->join_relation_list_) != NIL ) {
- rel = get_join_rel(root, xrelid);
- }
- else {
- rel = get_base_rel(root, lfirsti(xrelid));
- }
- */
-
- /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */
- /*
- relids = lconsi(lfirsti(xrelid), NIL);
- rel = rel_member(relids, outerrels);
- */
+ List *xjoinrel = NIL;
+ List *xrelid = NIL;
+ List *xrel = NIL;
+ List *xjoininfo = NIL;
+
+ Rel *rel;
+ List *relids;
+
+ List *super_rels;
+ List *xsuper_rel = NIL;
+ JInfo *new_joininfo;
+
+ foreach(xjoinrel, joinrels)
+ {
+ Rel *joinrel = (Rel *) lfirst(xjoinrel);
+
+ foreach(xrelid, joinrel->relids)
+ {
+
+ /*
+ * length(joinrel->relids) should always be greater that 1,
+ * because of *JOIN*
+ */
+
+ /*
+ * ! BUG BUG ! Relid relid = (Relid)lfirst(xrelid); Rel *rel =
+ * get_join_rel(root, relid);
+ */
- relids = lconsi(lfirsti(xrelid), NIL);
- rel = rel_member(relids, root->base_relation_list_);
+ /*
+ * if ( (root->join_relation_list_) != NIL ) { rel =
+ * get_join_rel(root, xrelid); } else { rel =
+ * get_base_rel(root, lfirsti(xrelid)); }
+ */
- add_superrels(rel,joinrel);
+ /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */
+
+ /*
+ * relids = lconsi(lfirsti(xrelid), NIL); rel =
+ * rel_member(relids, outerrels);
+ */
+
+ relids = lconsi(lfirsti(xrelid), NIL);
+ rel = rel_member(relids, root->base_relation_list_);
+
+ add_superrels(rel, joinrel);
+ }
}
- }
- foreach(xjoinrel, joinrels) {
- Rel *joinrel = (Rel *)lfirst(xjoinrel);
-
- foreach(xjoininfo, joinrel->joininfo) {
- JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
- List *other_rels = joininfo->otherrels;
- List *clause_info = joininfo->jinfoclauseinfo;
- bool mergesortable = joininfo->mergesortable;
- bool hashjoinable = joininfo->hashjoinable;
-
- foreach(xrelid, other_rels) {
- /* ! BUG BUG !
- Relid relid = (Relid)lfirst(xrelid);
- Rel *rel = get_join_rel(root, relid);
- */
-
- /*
- if ( (root->join_relation_list_) != NIL ) {
- rel = get_join_rel(root, xrelid);
- }
- else {
- rel = get_base_rel(root, lfirsti(xrelid));
- }
- */
-
- /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */
- /*
- relids = lconsi(lfirsti(xrelid), NIL);
- rel = rel_member(relids, outerrels);
- */
-
- relids = lconsi(lfirsti(xrelid), NIL);
- rel = rel_member(relids, root->base_relation_list_);
-
- super_rels = rel->superrels;
- new_joininfo = makeNode(JInfo);
-
- new_joininfo->otherrels = joinrel->relids;
- new_joininfo->jinfoclauseinfo = clause_info;
- new_joininfo->mergesortable = mergesortable;
- new_joininfo->hashjoinable = hashjoinable;
- new_joininfo->inactive = false;
- rel->joininfo =
- lappend(rel->joininfo, new_joininfo);
-
- foreach(xsuper_rel, super_rels) {
- Rel *super_rel = (Rel *)lfirst(xsuper_rel);
-
- if( nonoverlap_rels(super_rel,joinrel) ) {
- List *new_relids = super_rel->relids;
- JInfo *other_joininfo =
- joininfo_member(new_relids,
- joinrel->joininfo);
-
- if (other_joininfo) {
- other_joininfo->jinfoclauseinfo =
- (List*)LispUnion(clause_info,
- other_joininfo->jinfoclauseinfo);
- } else {
- JInfo *new_joininfo = makeNode(JInfo);
-
- new_joininfo->otherrels = new_relids;
- new_joininfo->jinfoclauseinfo = clause_info;
- new_joininfo->mergesortable = mergesortable;
- new_joininfo->hashjoinable = hashjoinable;
- new_joininfo->inactive = false;
- joinrel->joininfo =
- lappend(joinrel->joininfo,
- new_joininfo);
+ foreach(xjoinrel, joinrels)
+ {
+ Rel *joinrel = (Rel *) lfirst(xjoinrel);
+
+ foreach(xjoininfo, joinrel->joininfo)
+ {
+ JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
+ List *other_rels = joininfo->otherrels;
+ List *clause_info = joininfo->jinfoclauseinfo;
+ bool mergesortable = joininfo->mergesortable;
+ bool hashjoinable = joininfo->hashjoinable;
+
+ foreach(xrelid, other_rels)
+ {
+
+ /*
+ * ! BUG BUG ! Relid relid = (Relid)lfirst(xrelid); Rel
+ * *rel = get_join_rel(root, relid);
+ */
+
+ /*
+ * if ( (root->join_relation_list_) != NIL ) { rel =
+ * get_join_rel(root, xrelid); } else { rel =
+ * get_base_rel(root, lfirsti(xrelid)); }
+ */
+
+ /* NOTE: STILL BUGGY FOR CLAUSE-JOINS: */
+
+ /*
+ * relids = lconsi(lfirsti(xrelid), NIL); rel =
+ * rel_member(relids, outerrels);
+ */
+
+ relids = lconsi(lfirsti(xrelid), NIL);
+ rel = rel_member(relids, root->base_relation_list_);
+
+ super_rels = rel->superrels;
+ new_joininfo = makeNode(JInfo);
+
+ new_joininfo->otherrels = joinrel->relids;
+ new_joininfo->jinfoclauseinfo = clause_info;
+ new_joininfo->mergesortable = mergesortable;
+ new_joininfo->hashjoinable = hashjoinable;
+ new_joininfo->inactive = false;
+ rel->joininfo =
+ lappend(rel->joininfo, new_joininfo);
+
+ foreach(xsuper_rel, super_rels)
+ {
+ Rel *super_rel = (Rel *) lfirst(xsuper_rel);
+
+ if (nonoverlap_rels(super_rel, joinrel))
+ {
+ List *new_relids = super_rel->relids;
+ JInfo *other_joininfo =
+ joininfo_member(new_relids,
+ joinrel->joininfo);
+
+ if (other_joininfo)
+ {
+ other_joininfo->jinfoclauseinfo =
+ (List *) LispUnion(clause_info,
+ other_joininfo->jinfoclauseinfo);
+ }
+ else
+ {
+ JInfo *new_joininfo = makeNode(JInfo);
+
+ new_joininfo->otherrels = new_relids;
+ new_joininfo->jinfoclauseinfo = clause_info;
+ new_joininfo->mergesortable = mergesortable;
+ new_joininfo->hashjoinable = hashjoinable;
+ new_joininfo->inactive = false;
+ joinrel->joininfo =
+ lappend(joinrel->joininfo,
+ new_joininfo);
+ }
+ }
+ }
}
- }
}
- }
}
- }
- foreach(xrel, outerrels) {
- rel = (Rel *)lfirst(xrel);
- rel->superrels = NIL;
- }
+ foreach(xrel, outerrels)
+ {
+ rel = (Rel *) lfirst(xrel);
+ rel->superrels = NIL;
+ }
}
/*
* final-join-rels--
- * Find the join relation that includes all the original
- * relations, i.e. the final join result.
+ * Find the join relation that includes all the original
+ * relations, i.e. the final join result.
*
* 'join-rel-list' is a list of join relations.
*
* Returns the list of final join relations.
*/
-static List *
-geqo_final_join_rels(List *join_rel_list)
+static List *
+geqo_final_join_rels(List * join_rel_list)
{
- List *xrel = NIL;
- List *temp = NIL;
- List *t_list = NIL;
-
- /*
- * find the relations that has no further joins,
- * i.e., its joininfos all have otherrels nil.
- */
- foreach(xrel,join_rel_list) {
- Rel *rel = (Rel *)lfirst(xrel);
- List *xjoininfo = NIL;
- bool final = true;
-
- foreach (xjoininfo, rel->joininfo) {
- JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
-
- if (joininfo->otherrels != NIL) {
- final = false;
- break;
- }
- }
- if (final) {
- temp = lcons(rel, NIL);
- t_list = nconc(t_list, temp);
+ List *xrel = NIL;
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ /*
+ * find the relations that has no further joins, i.e., its joininfos
+ * all have otherrels nil.
+ */
+ foreach(xrel, join_rel_list)
+ {
+ Rel *rel = (Rel *) lfirst(xrel);
+ List *xjoininfo = NIL;
+ bool final = true;
+
+ foreach(xjoininfo, rel->joininfo)
+ {
+ JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
+
+ if (joininfo->otherrels != NIL)
+ {
+ final = false;
+ break;
+ }
+ }
+ if (final)
+ {
+ temp = lcons(rel, NIL);
+ t_list = nconc(t_list, temp);
+ }
}
- }
- return(t_list);
+ return (t_list);
}
/*
* add_superrels--
- * add rel to the temporary property list superrels.
+ * add rel to the temporary property list superrels.
*
* 'rel' a rel node
* 'super-rel' rel node of a join relation that includes rel
@@ -599,65 +649,72 @@ geqo_final_join_rels(List *join_rel_list)
* Modifies the superrels field of rel
*/
static void
-add_superrels(Rel *rel, Rel *super_rel)
+add_superrels(Rel * rel, Rel * super_rel)
{
- rel->superrels = lappend(rel->superrels, super_rel);
+ rel->superrels = lappend(rel->superrels, super_rel);
}
/*
* nonoverlap-rels--
- * test if two join relations overlap, i.e., includes the same
- * relation.
+ * test if two join relations overlap, i.e., includes the same
+ * relation.
*
* 'rel1' and 'rel2' are two join relations
*
* Returns non-nil if rel1 and rel2 do not overlap.
*/
-static bool
-nonoverlap_rels(Rel *rel1, Rel *rel2)
+static bool
+nonoverlap_rels(Rel * rel1, Rel * rel2)
{
- return(nonoverlap_sets(rel1->relids, rel2->relids));
+ return (nonoverlap_sets(rel1->relids, rel2->relids));
}
-static bool
-nonoverlap_sets(List *s1, List *s2)
+static bool
+nonoverlap_sets(List * s1, List * s2)
{
- List *x = NIL;
-
- foreach(x,s1) {
- int e = lfirsti(x);
- if(intMember(e,s2))
- return(false);
- }
- return(true);
+ List *x = NIL;
+
+ foreach(x, s1)
+ {
+ int e = lfirsti(x);
+
+ if (intMember(e, s2))
+ return (false);
+ }
+ return (true);
}
-#endif /* NOTUSED */
+
+#endif /* NOTUSED */
/*
* geqo_joinrel_size--
- * compute estimate for join relation tuples, even for
- * long join queries; so get logarithm of size when MAXINT overflow;
+ * compute estimate for join relation tuples, even for
+ * long join queries; so get logarithm of size when MAXINT overflow;
*/
static void
-geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel)
+geqo_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel)
{
- Cost temp;
- int ntuples;
-
+ Cost temp;
+ int ntuples;
+
temp = (Cost) inner_rel->tuples * (Cost) outer_rel->tuples; /* cartesian product */
- if (joinrel->clauseinfo) {
+ if (joinrel->clauseinfo)
+ {
temp = temp * product_selec(joinrel->clauseinfo);
- }
-
- if (temp >= (MAXINT -1)) {
- ntuples = ceil( geqo_log((double)temp, (double) GEQO_LOG_BASE) );
- }
- else {
- ntuples = ceil((double)temp);
- }
+ }
- if (ntuples < 1) ntuples = 1; /* make the best case 1 instead of 0 */
+ if (temp >= (MAXINT - 1))
+ {
+ ntuples = ceil(geqo_log((double) temp, (double) GEQO_LOG_BASE));
+ }
+ else
+ {
+ ntuples = ceil((double) temp);
+ }
+
+ if (ntuples < 1)
+ ntuples = 1; /* make the best case 1 instead of 0 */
joinrel->tuples = ntuples;
}
@@ -665,19 +722,21 @@ geqo_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel)
double
geqo_log(double x, double b)
{
- return(log(x)/log(b));
+ return (log(x) / log(b));
}
-static Rel *
-geqo_nth(int stop, List *rels)
+static Rel *
+geqo_nth(int stop, List * rels)
{
- List *r;
- int i=1;
+ List *r;
+ int i = 1;
- foreach(r, rels) {
- if (i == stop) return lfirst(r);
+ foreach(r, rels)
+ {
+ if (i == stop)
+ return lfirst(r);
i++;
- }
- elog(WARN,"geqo_nth: Internal error - ran off end of list");
- return NULL; /* to keep compiler happy */
+ }
+ elog(WARN, "geqo_nth: Internal error - ran off end of list");
+ return NULL; /* to keep compiler happy */
}
diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c
index 4b450002885..eab939c03e6 100644
--- a/src/backend/optimizer/geqo/geqo_main.c
+++ b/src/backend/optimizer/geqo/geqo_main.c
@@ -1,21 +1,21 @@
/*------------------------------------------------------------------------
*
* geqo_main.c--
- * solution of the query optimization problem
- * by means of a Genetic Algorithm (GA)
+ * solution of the query optimization problem
+ * by means of a Genetic Algorithm (GA)
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: geqo_main.c,v 1.3 1997/03/14 16:02:51 scrappy Exp $
+ * $Id: geqo_main.c,v 1.4 1997/09/07 04:43:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
@@ -48,228 +48,241 @@
/* define edge recombination crossover [ERX] per default */
#if !defined(ERX) && \
- !defined(PMX) && \
- !defined(CX) && \
- !defined(PX) && \
- !defined(OX1) && \
- !defined(OX2)
+ !defined(PMX) && \
+ !defined(CX) && \
+ !defined(PX) && \
+ !defined(OX1) && \
+ !defined(OX2)
#define ERX
#endif
/*
* geqo--
- * solution of the query optimization problem
- * similar to a constrained Traveling Salesman Problem (TSP)
+ * solution of the query optimization problem
+ * similar to a constrained Traveling Salesman Problem (TSP)
*/
-Rel *
-geqo(Query *root)
+Rel *
+geqo(Query * root)
{
- int generation;
- Chromosome *momma;
- Chromosome *daddy;
- Chromosome *kid;
+ int generation;
+ Chromosome *momma;
+ Chromosome *daddy;
+ Chromosome *kid;
#if defined(ERX)
- Edge *edge_table; /* list of edges */
- int edge_failures=0;
- float difference;
-#endif
+ Edge *edge_table; /* list of edges */
+ int edge_failures = 0;
+ float difference;
+
+#endif
#if defined(CX) || defined(PX) || defined(OX1) || defined(OX2)
- City *city_table; /* list of cities */
+ City *city_table; /* list of cities */
+
#endif
#if defined(CX)
- int cycle_diffs=0;
- int mutations=0;
+ int cycle_diffs = 0;
+ int mutations = 0;
+
#endif
- int number_of_rels;
+ int number_of_rels;
- Pool *pool;
- int pool_size, number_generations, status_interval;
+ Pool *pool;
+ int pool_size,
+ number_generations,
+ status_interval;
- Gene *best_tour;
- Rel *best_rel;
-/* Plan *best_plan; */
+ Gene *best_tour;
+ Rel *best_rel;
+
+/* Plan *best_plan; */
/* set tour size */
- number_of_rels = length(root->base_relation_list_);
+ number_of_rels = length(root->base_relation_list_);
/* set GA parameters */
- geqo_params(number_of_rels) ; /* out of "$PGDATA/pg_geqo" file */
- pool_size = PoolSize;
- number_generations = Generations;
- status_interval = 10;
+ geqo_params(number_of_rels);/* out of "$PGDATA/pg_geqo" file */
+ pool_size = PoolSize;
+ number_generations = Generations;
+ status_interval = 10;
/* seed random number generator */
- srandom(RandomSeed);
+ srandom(RandomSeed);
/* allocate genetic pool memory */
- pool = alloc_pool(pool_size, number_of_rels);
+ pool = alloc_pool(pool_size, number_of_rels);
/* random initialization of the pool */
- random_init_pool (root, pool, 0, pool->size);
+ random_init_pool(root, pool, 0, pool->size);
/* sort the pool according to cheapest path as fitness */
- sort_pool (pool); /* we have to do it only one time, since all kids replace the worst individuals in future (-> geqo_pool.c:spread_chromo ) */
+ sort_pool(pool); /* we have to do it only one time, since
+ * all kids replace the worst individuals
+ * in future (-> geqo_pool.c:spread_chromo
+ * ) */
/* allocate chromosome momma and daddy memory */
- momma = alloc_chromo(pool->string_length);
- daddy = alloc_chromo(pool->string_length);
+ momma = alloc_chromo(pool->string_length);
+ daddy = alloc_chromo(pool->string_length);
#if defined (ERX)
- elog(DEBUG,"geqo_main: using edge recombination crossover [ERX]");
+ elog(DEBUG, "geqo_main: using edge recombination crossover [ERX]");
/* allocate edge table memory */
- edge_table = alloc_edge_table(pool->string_length);
+ edge_table = alloc_edge_table(pool->string_length);
#elif defined(PMX)
- elog(DEBUG,"geqo_main: using partially matched crossover [PMX]");
+ elog(DEBUG, "geqo_main: using partially matched crossover [PMX]");
/* allocate chromosome kid memory */
- kid = alloc_chromo(pool->string_length);
+ kid = alloc_chromo(pool->string_length);
#elif defined(CX)
- elog(DEBUG,"geqo_main: using cycle crossover [CX]");
+ elog(DEBUG, "geqo_main: using cycle crossover [CX]");
/* allocate city table memory */
- kid = alloc_chromo(pool->string_length);
- city_table = alloc_city_table(pool->string_length);
+ kid = alloc_chromo(pool->string_length);
+ city_table = alloc_city_table(pool->string_length);
#elif defined(PX)
- elog(DEBUG,"geqo_main: using position crossover [PX]");
+ elog(DEBUG, "geqo_main: using position crossover [PX]");
/* allocate city table memory */
- kid = alloc_chromo(pool->string_length);
- city_table = alloc_city_table(pool->string_length);
+ kid = alloc_chromo(pool->string_length);
+ city_table = alloc_city_table(pool->string_length);
#elif defined(OX1)
- elog(DEBUG,"geqo_main: using order crossover [OX1]");
+ elog(DEBUG, "geqo_main: using order crossover [OX1]");
/* allocate city table memory */
- kid = alloc_chromo(pool->string_length);
- city_table = alloc_city_table(pool->string_length);
+ kid = alloc_chromo(pool->string_length);
+ city_table = alloc_city_table(pool->string_length);
#elif defined(OX2)
- elog(DEBUG,"geqo_main: using order crossover [OX2]");
+ elog(DEBUG, "geqo_main: using order crossover [OX2]");
/* allocate city table memory */
- kid = alloc_chromo(pool->string_length);
- city_table = alloc_city_table(pool->string_length);
+ kid = alloc_chromo(pool->string_length);
+ city_table = alloc_city_table(pool->string_length);
#endif
/* my pain main part: */
/* iterative optimization */
- for (generation = 0; generation < number_generations; generation++) {
+ for (generation = 0; generation < number_generations; generation++)
+ {
- /* SELECTION */
- geqo_selection(momma, daddy, pool, SelectionBias); /* using linear bias function */
+ /* SELECTION */
+ geqo_selection(momma, daddy, pool, SelectionBias); /* using linear bias
+ * function */
#if defined (ERX)
- /* EDGE RECOMBINATION CROSSOVER */
- difference = gimme_edge_table(momma->string, daddy->string, pool->string_length, edge_table);
+ /* EDGE RECOMBINATION CROSSOVER */
+ difference = gimme_edge_table(momma->string, daddy->string, pool->string_length, edge_table);
- /* let the kid grow in momma's womb (storage) for nine months ;-) */
- /* sleep(23328000) -- har har har */
- kid = momma;
+ /* let the kid grow in momma's womb (storage) for nine months ;-) */
+ /* sleep(23328000) -- har har har */
+ kid = momma;
- /* are there any edge failures ? */
- edge_failures += gimme_tour(edge_table, kid->string, pool->string_length);
+ /* are there any edge failures ? */
+ edge_failures += gimme_tour(edge_table, kid->string, pool->string_length);
#elif defined(PMX)
- /* PARTIALLY MATCHED CROSSOVER */
- pmx(momma->string, daddy->string, kid->string, pool->string_length);
+ /* PARTIALLY MATCHED CROSSOVER */
+ pmx(momma->string, daddy->string, kid->string, pool->string_length);
#elif defined(CX)
- /* CYCLE CROSSOVER */
- cycle_diffs =
- cx(momma->string, daddy->string, kid->string, pool->string_length, city_table);
- /* mutate the child */
- if (cycle_diffs == 0) {
- mutations++;
- geqo_mutation (kid->string, pool->string_length);
- }
+ /* CYCLE CROSSOVER */
+ cycle_diffs =
+ cx(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+ /* mutate the child */
+ if (cycle_diffs == 0)
+ {
+ mutations++;
+ geqo_mutation(kid->string, pool->string_length);
+ }
#elif defined(PX)
- /* POSITION CROSSOVER */
- px(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+ /* POSITION CROSSOVER */
+ px(momma->string, daddy->string, kid->string, pool->string_length, city_table);
#elif defined(OX1)
- /* ORDER CROSSOVER */
- ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+ /* ORDER CROSSOVER */
+ ox1(momma->string, daddy->string, kid->string, pool->string_length, city_table);
#elif defined(OX2)
- /* ORDER CROSSOVER */
- ox2(momma->string, daddy->string, kid->string, pool->string_length, city_table);
+ /* ORDER CROSSOVER */
+ ox2(momma->string, daddy->string, kid->string, pool->string_length, city_table);
#endif
- /* EVALUATE FITNESS */
- kid->worth = geqo_eval (root, kid->string, pool->string_length);
+ /* EVALUATE FITNESS */
+ kid->worth = geqo_eval(root, kid->string, pool->string_length);
- /* push the kid into the wilderness of life according to its worth */
- spread_chromo (kid, pool);
+ /* push the kid into the wilderness of life according to its worth */
+ spread_chromo(kid, pool);
#ifdef GEQO_DEBUG
- if (status_interval && !(generation % status_interval))
- print_gen (stdout, pool, generation);
+ if (status_interval && !(generation % status_interval))
+ print_gen(stdout, pool, generation);
#endif
- } /* end of iterative optimization */
+ } /* end of iterative optimization */
#if defined(ERX) && defined(GEQO_DEBUG)
-if (edge_failures != 0)
- fprintf (stdout, "\nFailures: %d Avg: %d\n", edge_failures, (int) generation/edge_failures);
+ if (edge_failures != 0)
+ fprintf(stdout, "\nFailures: %d Avg: %d\n", edge_failures, (int) generation / edge_failures);
-else fprintf (stdout, "No edge failures detected.\n");
+ else
+ fprintf(stdout, "No edge failures detected.\n");
#endif
#if defined(CX) && defined(GEQO_DEBUG)
-if (mutations != 0)
- fprintf (stdout, "\nMutations: %d Generations: %d\n", mutations, generation);
+ if (mutations != 0)
+ fprintf(stdout, "\nMutations: %d Generations: %d\n", mutations, generation);
-else fprintf (stdout, "No mutations processed.\n");
+ else
+ fprintf(stdout, "No mutations processed.\n");
#endif
-
+
#ifdef GEQO_DEBUG
-fprintf (stdout, "\n");
-print_pool (stdout, pool, 0, pool_size-1);
+ fprintf(stdout, "\n");
+ print_pool(stdout, pool, 0, pool_size - 1);
#endif
/* got the cheapest query tree processed by geqo;
first element of the population indicates the best query tree */
-best_tour = (Gene *) pool->data[0].string;
+ best_tour = (Gene *) pool->data[0].string;
/* root->join_relation_list_ will be modified during this ! */
-best_rel = (Rel *) gimme_tree(root, best_tour, 0, pool->string_length, NULL);
+ best_rel = (Rel *) gimme_tree(root, best_tour, 0, pool->string_length, NULL);
/* DBG: show the query plan
print_plan(best_plan, root);
DBG */
/* ... free memory stuff */
-free_chromo(momma);
-free_chromo(daddy);
+ free_chromo(momma);
+ free_chromo(daddy);
#if defined (ERX)
-free_edge_table(edge_table);
+ free_edge_table(edge_table);
#elif defined(PMX)
-free_chromo(kid);
+ free_chromo(kid);
#elif defined(CX)
-free_chromo(kid);
-free_city_table(city_table);
+ free_chromo(kid);
+ free_city_table(city_table);
#elif defined(PX)
-free_chromo(kid);
-free_city_table(city_table);
+ free_chromo(kid);
+ free_city_table(city_table);
#elif defined(OX1)
-free_chromo(kid);
-free_city_table(city_table);
+ free_chromo(kid);
+ free_city_table(city_table);
#elif defined(OX2)
-free_chromo(kid);
-free_city_table(city_table);
+ free_chromo(kid);
+ free_city_table(city_table);
#endif
-free_pool(pool);
+ free_pool(pool);
-return(best_rel);
+ return (best_rel);
}
-
diff --git a/src/backend/optimizer/geqo/geqo_misc.c b/src/backend/optimizer/geqo/geqo_misc.c
index 48ae78bdcda..67e810d87ca 100644
--- a/src/backend/optimizer/geqo/geqo_misc.c
+++ b/src/backend/optimizer/geqo/geqo_misc.c
@@ -1,20 +1,20 @@
/*------------------------------------------------------------------------
*
* geqo_misc.c--
- * misc. printout and debug stuff
+ * misc. printout and debug stuff
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: geqo_misc.c,v 1.2 1997/02/19 14:52:01 scrappy Exp $
+ * $Id: geqo_misc.c,v 1.3 1997/09/07 04:43:10 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
@@ -41,91 +41,97 @@
#include "optimizer/geqo_recombination.h"
#include "optimizer/geqo_misc.h"
-static float avg_pool (Pool *pool);
+static float avg_pool(Pool * pool);
/* avg_pool--
*
*/
static float
-avg_pool (Pool *pool)
+avg_pool(Pool * pool)
{
- int i;
- double cumulative = 0.0;
-
- if (pool->size==0)
- elog(WARN,"avg_pool: pool_size of zero");
-
- for (i=0; i<pool->size; i++)
- cumulative = cumulative + pool->data[i].worth;
-
- return ((float) cumulative/pool->size);
+ int i;
+ double cumulative = 0.0;
+
+ if (pool->size == 0)
+ elog(WARN, "avg_pool: pool_size of zero");
+
+ for (i = 0; i < pool->size; i++)
+ cumulative = cumulative + pool->data[i].worth;
+
+ return ((float) cumulative / pool->size);
}
/* print_pool--
*/
void
-print_pool (FILE *fp, Pool *pool, int start, int stop)
+print_pool(FILE * fp, Pool * pool, int start, int stop)
{
- int i, j;
+ int i,
+ j;
- /* be extra careful that start and stop are valid inputs */
+ /* be extra careful that start and stop are valid inputs */
- if (start < 0) start = 0;
- if (stop > pool->size) stop = pool->size;
+ if (start < 0)
+ start = 0;
+ if (stop > pool->size)
+ stop = pool->size;
- if (start+stop > pool->size) {
- start = 0;
- stop = pool->size;
+ if (start + stop > pool->size)
+ {
+ start = 0;
+ stop = pool->size;
}
- for (i=start; i<stop; i++) {
- fprintf (fp, "%d)\t", i);
- for (j=0; j<pool->string_length; j++)
- fprintf (fp, "%d ", pool->data[i].string[j]);
- fprintf (fp, "%f\n", pool->data[i].worth);
+ for (i = start; i < stop; i++)
+ {
+ fprintf(fp, "%d)\t", i);
+ for (j = 0; j < pool->string_length; j++)
+ fprintf(fp, "%d ", pool->data[i].string[j]);
+ fprintf(fp, "%f\n", pool->data[i].worth);
}
}
/* print_gen--
*
- * printout for chromosome: best, worst, mean, average
+ * printout for chromosome: best, worst, mean, average
*
*/
void
-print_gen(FILE *fp, Pool *pool, int generation)
+print_gen(FILE * fp, Pool * pool, int generation)
{
- int lowest;
-
- /* Get index to lowest ranking gene in poplulation. */
- /* Use 2nd to last since last is buffer. */
- lowest = pool->size > 1 ? pool->size-2 : 0;
-
- fprintf (fp,
- "%5d | Bst: %f Wst: %f Mean: %f Avg: %f\n",
- generation,
- pool->data[0].worth,
- pool->data[lowest].worth,
- pool->data[pool->size/2].worth,
- avg_pool(pool));
+ int lowest;
+
+ /* Get index to lowest ranking gene in poplulation. */
+ /* Use 2nd to last since last is buffer. */
+ lowest = pool->size > 1 ? pool->size - 2 : 0;
+
+ fprintf(fp,
+ "%5d | Bst: %f Wst: %f Mean: %f Avg: %f\n",
+ generation,
+ pool->data[0].worth,
+ pool->data[lowest].worth,
+ pool->data[pool->size / 2].worth,
+ avg_pool(pool));
}
void
-print_edge_table (FILE *fp, Edge *edge_table, int num_gene)
+print_edge_table(FILE * fp, Edge * edge_table, int num_gene)
{
- int i,j;
-
- fprintf (fp, "\nEDGE TABLE\n");
-
- for (i=1; i<=num_gene; i++)
- {
- fprintf (fp, "%d :", i);
- for (j=0; j<edge_table[i].unused_edges; j++)
- fprintf (fp, " %d", edge_table[i].edge_list[j]);
- fprintf (fp, "\n");
- }
-
- fprintf (fp, "\n");
+ int i,
+ j;
+
+ fprintf(fp, "\nEDGE TABLE\n");
+
+ for (i = 1; i <= num_gene; i++)
+ {
+ fprintf(fp, "%d :", i);
+ for (j = 0; j < edge_table[i].unused_edges; j++)
+ fprintf(fp, " %d", edge_table[i].edge_list[j]);
+ fprintf(fp, "\n");
+ }
+
+ fprintf(fp, "\n");
}
/*************************************************************
@@ -133,116 +139,147 @@ print_edge_table (FILE *fp, Edge *edge_table, int num_gene)
*************************************************************/
void
-geqo_print_joinclauses(Query *root, List *clauses)
+geqo_print_joinclauses(Query * root, List * clauses)
{
- List *l;
- extern void print_expr(Node *expr, List *rtable); /* in print.c */
+ List *l;
+ extern void print_expr(Node * expr, List * rtable); /* in print.c */
- foreach(l, clauses) {
- CInfo *c = lfirst(l);
+ foreach(l, clauses)
+ {
+ CInfo *c = lfirst(l);
- print_expr((Node*)c->clause, root->rtable);
- if (lnext(l)) printf(" ");
- }
+ print_expr((Node *) c->clause, root->rtable);
+ if (lnext(l))
+ printf(" ");
+ }
}
void
-geqo_print_path(Query *root, Path *path, int indent)
+geqo_print_path(Query * root, Path * path, int indent)
{
- char *ptype = NULL;
- JoinPath *jp;
- bool join = false;
- int i;
-
- for(i=0; i < indent; i++)
- printf("\t");
-
- switch(nodeTag(path)) {
- case T_Path:
- ptype = "SeqScan"; join=false; break;
- case T_IndexPath:
- ptype = "IdxScan"; join=false; break;
- case T_JoinPath:
- ptype = "Nestloop"; join=true; break;
- case T_MergePath:
- ptype = "MergeJoin"; join=true; break;
- case T_HashPath:
- ptype = "HashJoin"; join=true; break;
- default:
- break;
- }
- if (join) {
- int size = path->parent->size;
- jp = (JoinPath*)path;
- printf("%s size=%d cost=%f\n", ptype, size, path->path_cost);
- switch(nodeTag(path)) {
+ char *ptype = NULL;
+ JoinPath *jp;
+ bool join = false;
+ int i;
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+
+ switch (nodeTag(path))
+ {
+ case T_Path:
+ ptype = "SeqScan";
+ join = false;
+ break;
+ case T_IndexPath:
+ ptype = "IdxScan";
+ join = false;
+ break;
+ case T_JoinPath:
+ ptype = "Nestloop";
+ join = true;
+ break;
case T_MergePath:
+ ptype = "MergeJoin";
+ join = true;
+ break;
case T_HashPath:
- for(i=0; i < indent+1; i++)
- printf("\t");
- printf(" clauses=(");
- geqo_print_joinclauses(root,
- ((JoinPath*)path)->pathclauseinfo);
- printf(")\n");
-
- if (nodeTag(path)==T_MergePath) {
- MergePath *mp = (MergePath*)path;
- if (mp->outersortkeys || mp->innersortkeys) {
- for(i=0; i < indent+1; i++)
- printf("\t");
- printf(" sortouter=%d sortinner=%d\n",
- ((mp->outersortkeys)?1:0),
- ((mp->innersortkeys)?1:0));
- }
- }
- break;
+ ptype = "HashJoin";
+ join = true;
+ break;
default:
- break;
+ break;
}
- geqo_print_path(root, jp->outerjoinpath, indent+1);
- geqo_print_path(root, jp->innerjoinpath, indent+1);
- } else {
- int size = path->parent->size;
- int relid = lfirsti(path->parent->relids);
- printf("%s(%d) size=%d cost=%f",
- ptype, relid, size, path->path_cost);
-
- if (nodeTag(path)==T_IndexPath) {
- List *k, *l;
-
- printf(" keys=");
- foreach (k, path->keys) {
- printf("(");
- foreach (l, lfirst(k)) {
- Var *var = lfirst(l);
- printf("%d.%d", var->varnoold, var->varoattno);
- if (lnext(l)) printf(", ");
+ if (join)
+ {
+ int size = path->parent->size;
+
+ jp = (JoinPath *) path;
+ printf("%s size=%d cost=%f\n", ptype, size, path->path_cost);
+ switch (nodeTag(path))
+ {
+ case T_MergePath:
+ case T_HashPath:
+ for (i = 0; i < indent + 1; i++)
+ printf("\t");
+ printf(" clauses=(");
+ geqo_print_joinclauses(root,
+ ((JoinPath *) path)->pathclauseinfo);
+ printf(")\n");
+
+ if (nodeTag(path) == T_MergePath)
+ {
+ MergePath *mp = (MergePath *) path;
+
+ if (mp->outersortkeys || mp->innersortkeys)
+ {
+ for (i = 0; i < indent + 1; i++)
+ printf("\t");
+ printf(" sortouter=%d sortinner=%d\n",
+ ((mp->outersortkeys) ? 1 : 0),
+ ((mp->innersortkeys) ? 1 : 0));
+ }
+ }
+ break;
+ default:
+ break;
}
- printf(")");
- if (lnext(k)) printf(", ");
- }
+ geqo_print_path(root, jp->outerjoinpath, indent + 1);
+ geqo_print_path(root, jp->innerjoinpath, indent + 1);
+ }
+ else
+ {
+ int size = path->parent->size;
+ int relid = lfirsti(path->parent->relids);
+
+ printf("%s(%d) size=%d cost=%f",
+ ptype, relid, size, path->path_cost);
+
+ if (nodeTag(path) == T_IndexPath)
+ {
+ List *k,
+ *l;
+
+ printf(" keys=");
+ foreach(k, path->keys)
+ {
+ printf("(");
+ foreach(l, lfirst(k))
+ {
+ Var *var = lfirst(l);
+
+ printf("%d.%d", var->varnoold, var->varoattno);
+ if (lnext(l))
+ printf(", ");
+ }
+ printf(")");
+ if (lnext(k))
+ printf(", ");
+ }
+ }
+ printf("\n");
}
- printf("\n");
- }
}
-void
-geqo_print_rel(Query *root, Rel *rel)
+void
+geqo_print_rel(Query * root, Rel * rel)
{
- List *l;
-
- printf("______________________________\n");
- printf("(");
- foreach(l, rel->relids) {
- printf("%d ", lfirsti(l));
- }
- printf("): size=%d width=%d\n", rel->size, rel->width);
-
- printf("\tpath list:\n");
- foreach (l, rel->pathlist) {
- geqo_print_path(root, lfirst(l), 1);
- }
-
- printf("\tcheapest path:\n");
- geqo_print_path(root, rel->cheapestpath, 1);
+ List *l;
+
+ printf("______________________________\n");
+ printf("(");
+ foreach(l, rel->relids)
+ {
+ printf("%d ", lfirsti(l));
+ }
+ printf("): size=%d width=%d\n", rel->size, rel->width);
+
+ printf("\tpath list:\n");
+ foreach(l, rel->pathlist)
+ {
+ geqo_print_path(root, lfirst(l), 1);
+ }
+
+ printf("\tcheapest path:\n");
+ geqo_print_path(root, rel->cheapestpath, 1);
}
diff --git a/src/backend/optimizer/geqo/geqo_mutation.c b/src/backend/optimizer/geqo/geqo_mutation.c
index 9d544564210..a5a43e6e2b9 100644
--- a/src/backend/optimizer/geqo/geqo_mutation.c
+++ b/src/backend/optimizer/geqo/geqo_mutation.c
@@ -2,33 +2,33 @@
*
* geqo_mutation.c--
*
-* TSP mutation routines
+* TSP mutation routines
*
-* $Id: geqo_mutation.c,v 1.1 1997/02/19 12:57:13 scrappy Exp $
+* $Id: geqo_mutation.c,v 1.2 1997/09/07 04:43:13 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* this is adopted from Genitor : */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
#include "postgres.h"
@@ -50,27 +50,28 @@
#include "optimizer/geqo_random.h"
#include "optimizer/geqo_mutation.h"
- void
- geqo_mutation (Gene *tour, int num_gene)
- {
- int swap1;
- int swap2;
- int num_swaps = geqo_randint (num_gene/3, 0);
- Gene temp;
+void
+geqo_mutation(Gene * tour, int num_gene)
+{
+ int swap1;
+ int swap2;
+ int num_swaps = geqo_randint(num_gene / 3, 0);
+ Gene temp;
- while (num_swaps > 0) {
- swap1 = geqo_randint (num_gene-1, 0);
- swap2 = geqo_randint (num_gene-1, 0);
+ while (num_swaps > 0)
+ {
+ swap1 = geqo_randint(num_gene - 1, 0);
+ swap2 = geqo_randint(num_gene - 1, 0);
- while (swap1 == swap2)
- swap2 = geqo_randint (num_gene-1, 0);
+ while (swap1 == swap2)
+ swap2 = geqo_randint(num_gene - 1, 0);
- temp = tour[swap1];
- tour[swap1] = tour[swap2];
- tour[swap2] = temp;
+ temp = tour[swap1];
+ tour[swap1] = tour[swap2];
+ tour[swap2] = temp;
- num_swaps -= 1;
- }
+ num_swaps -= 1;
+ }
}
diff --git a/src/backend/optimizer/geqo/geqo_ox1.c b/src/backend/optimizer/geqo/geqo_ox1.c
index 329554f9aae..b88b8950673 100644
--- a/src/backend/optimizer/geqo/geqo_ox1.c
+++ b/src/backend/optimizer/geqo/geqo_ox1.c
@@ -2,35 +2,35 @@
*
* geqo_ox1.c--
*
-* order crossover [OX] routines;
-* OX1 operator according to Davis
-* (Proc Int'l Joint Conf on AI)
+* order crossover [OX] routines;
+* OX1 operator according to Davis
+* (Proc Int'l Joint Conf on AI)
*
-* $Id: geqo_ox1.c,v 1.1 1997/03/14 16:02:58 scrappy Exp $
+* $Id: geqo_ox1.c,v 1.2 1997/09/07 04:43:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* the ox algorithm is adopted from Genitor : */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
#include "postgres.h"
@@ -56,48 +56,52 @@
/* ox1--
*
- * position crossover
+ * position crossover
*/
void
-ox1(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+ox1(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table)
{
- int left, right, k, p, temp;
-
- /* initialize city table */
- for (k = 1; k <= num_gene; k++)
- city_table[k].used = 0;
-
- /* select portion to copy from tour1 */
- left = geqo_randint (num_gene - 1, 0);
- right = geqo_randint (num_gene - 1, 0);
-
- if (left > right)
- {
- temp = left;
- left = right;
- right = temp;
- }
-
- /* copy portion from tour1 to offspring */
- for (k = left; k <= right; k++)
- {
- offspring[k] = tour1[k];
- city_table[(int) tour1[k]].used = 1;
- }
-
- k = (right + 1) % num_gene; /* index into offspring */
- p = k; /* index into tour2 */
-
- /* copy stuff from tour2 to offspring */
- while (k != left)
- {
- if (!city_table[(int) tour2[p]].used)
- {
- offspring[k] = tour2[p];
- k = (k + 1) % num_gene;
- city_table[(int) tour2[p]].used = 1;
- }
- p = (p + 1) % num_gene; /* increment tour2-index */
- }
-
- }
+ int left,
+ right,
+ k,
+ p,
+ temp;
+
+ /* initialize city table */
+ for (k = 1; k <= num_gene; k++)
+ city_table[k].used = 0;
+
+ /* select portion to copy from tour1 */
+ left = geqo_randint(num_gene - 1, 0);
+ right = geqo_randint(num_gene - 1, 0);
+
+ if (left > right)
+ {
+ temp = left;
+ left = right;
+ right = temp;
+ }
+
+ /* copy portion from tour1 to offspring */
+ for (k = left; k <= right; k++)
+ {
+ offspring[k] = tour1[k];
+ city_table[(int) tour1[k]].used = 1;
+ }
+
+ k = (right + 1) % num_gene; /* index into offspring */
+ p = k; /* index into tour2 */
+
+ /* copy stuff from tour2 to offspring */
+ while (k != left)
+ {
+ if (!city_table[(int) tour2[p]].used)
+ {
+ offspring[k] = tour2[p];
+ k = (k + 1) % num_gene;
+ city_table[(int) tour2[p]].used = 1;
+ }
+ p = (p + 1) % num_gene; /* increment tour2-index */
+ }
+
+}
diff --git a/src/backend/optimizer/geqo/geqo_ox2.c b/src/backend/optimizer/geqo/geqo_ox2.c
index 2afcece01ff..ef09925b4fa 100644
--- a/src/backend/optimizer/geqo/geqo_ox2.c
+++ b/src/backend/optimizer/geqo/geqo_ox2.c
@@ -2,35 +2,35 @@
*
* geqo_ox2.c--
*
-* order crossover [OX] routines;
-* OX2 operator according to Syswerda
-* (The Genetic Algorithms Handbook, ed L Davis)
+* order crossover [OX] routines;
+* OX2 operator according to Syswerda
+* (The Genetic Algorithms Handbook, ed L Davis)
*
-* $Id: geqo_ox2.c,v 1.1 1997/03/14 16:03:02 scrappy Exp $
+* $Id: geqo_ox2.c,v 1.2 1997/09/07 04:43:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* the ox algorithm is adopted from Genitor : */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
#include "postgres.h"
@@ -56,58 +56,70 @@
/* ox2--
*
- * position crossover
+ * position crossover
*/
void
-ox2(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+ox2(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table)
{
- int k, j, count, pos, select, num_positions;
-
- /* initialize city table */
- for (k = 1; k <= num_gene; k++) {
- city_table[k].used = 0;
- city_table[k-1].select_list = -1;
- }
-
- /* determine the number of positions to be inherited from tour1 */
- num_positions = geqo_randint (2*num_gene/3, num_gene/3);
-
- /* make a list of selected cities */
- for (k=0; k<num_positions; k++) {
- pos = geqo_randint (num_gene - 1, 0);
- city_table[pos].select_list = (int) tour1[pos];
- city_table[(int) tour1[pos]].used = 1; /* mark used */
- }
-
-
- count = 0;
- k = 0;
-
- /* consolidate the select list to adjacent positions */
- while (count < num_positions) {
- if (city_table[k].select_list == -1) {
- j = k + 1;
- while ((city_table[j].select_list == -1) && (j < num_gene))
- j++;
-
- city_table[k].select_list = city_table[j].select_list;
- city_table[j].select_list = -1;
- count ++;
- }
- else
- count ++;
- k++;
- }
-
- select = 0;
-
- for (k=0; k<num_gene; k++) {
- if (city_table[(int) tour2[k]].used) {
- offspring[k] = (Gene) city_table[select].select_list;
- select ++; /* next city in the select list */
- }
- else /* city isn't used yet, so inherit from tour2 */
- offspring[k] = tour2[k];
- }
+ int k,
+ j,
+ count,
+ pos,
+ select,
+ num_positions;
+
+ /* initialize city table */
+ for (k = 1; k <= num_gene; k++)
+ {
+ city_table[k].used = 0;
+ city_table[k - 1].select_list = -1;
+ }
+
+ /* determine the number of positions to be inherited from tour1 */
+ num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3);
+
+ /* make a list of selected cities */
+ for (k = 0; k < num_positions; k++)
+ {
+ pos = geqo_randint(num_gene - 1, 0);
+ city_table[pos].select_list = (int) tour1[pos];
+ city_table[(int) tour1[pos]].used = 1; /* mark used */
+ }
+
+
+ count = 0;
+ k = 0;
+
+ /* consolidate the select list to adjacent positions */
+ while (count < num_positions)
+ {
+ if (city_table[k].select_list == -1)
+ {
+ j = k + 1;
+ while ((city_table[j].select_list == -1) && (j < num_gene))
+ j++;
+
+ city_table[k].select_list = city_table[j].select_list;
+ city_table[j].select_list = -1;
+ count++;
+ }
+ else
+ count++;
+ k++;
+ }
+
+ select = 0;
+
+ for (k = 0; k < num_gene; k++)
+ {
+ if (city_table[(int) tour2[k]].used)
+ {
+ offspring[k] = (Gene) city_table[select].select_list;
+ select++; /* next city in the select list */
+ }
+ else
+/* city isn't used yet, so inherit from tour2 */
+ offspring[k] = tour2[k];
+ }
}
diff --git a/src/backend/optimizer/geqo/geqo_params.c b/src/backend/optimizer/geqo/geqo_params.c
index 52c57c45378..45f7dfd5ddc 100644
--- a/src/backend/optimizer/geqo/geqo_params.c
+++ b/src/backend/optimizer/geqo/geqo_params.c
@@ -1,20 +1,20 @@
/*------------------------------------------------------------------------
*
* geqo_params.c--
-* routines for determining necessary genetic optimization parameters
+* routines for determining necessary genetic optimization parameters
*
* Copyright (c) 1994, Regents of the University of California
*
-* $Id: geqo_params.c,v 1.5 1997/08/18 02:14:41 momjian Exp $
+* $Id: geqo_params.c,v 1.6 1997/09/07 04:43:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
@@ -45,48 +45,48 @@
#include "storage/fd.h"
-#define POOL_TAG "Pool_Size"
-#define TRIAL_TAG "Generations"
-#define RAND_TAG "Random_Seed"
-#define BIAS_TAG "Selection_Bias"
+#define POOL_TAG "Pool_Size"
+#define TRIAL_TAG "Generations"
+#define RAND_TAG "Random_Seed"
+#define BIAS_TAG "Selection_Bias"
-#define EFFORT_TAG "Effort" /* optimization effort and */
-#define LOW "low" /* corresponding tags */
-#define MEDIUM "medium"
-#define HIGH "high"
+#define EFFORT_TAG "Effort"/* optimization effort and */
+#define LOW "low" /* corresponding tags */
+#define MEDIUM "medium"
+#define HIGH "high"
-#define MAX_TOKEN 80 /* Maximum size of one token in the *
- * configuration file */
+#define MAX_TOKEN 80 /* Maximum size of one token in the *
+ * configuration file */
-static int gimme_pool_size(int string_length);
-static int gimme_number_generations(int pool_size, int effort);
-static int next_token(FILE *, char *, int);
+static int gimme_pool_size(int string_length);
+static int gimme_number_generations(int pool_size, int effort);
+static int next_token(FILE *, char *, int);
/*
* geqo_param--
- * get ga parameters out of "$PGDATA/pg_geqo" file.
+ * get ga parameters out of "$PGDATA/pg_geqo" file.
*/
void
geqo_params(int string_length)
{
- int i;
+ int i;
- char buf[MAX_TOKEN];
- FILE *file;
+ char buf[MAX_TOKEN];
+ FILE *file;
- char *conf_file;
+ char *conf_file;
/* these static variables are used to signal that a value has been set */
- int pool_size = 0;
- int number_trials = 0;
- int random_seed = 0;
- int selection_bias = 0;
- int effort = 0;
+ int pool_size = 0;
+ int number_trials = 0;
+ int random_seed = 0;
+ int selection_bias = 0;
+ int effort = 0;
/* put together the full pathname to the config file */
conf_file =
- (char *) palloc((strlen(DataDir)+strlen(GEQO_FILE)+2)*sizeof(char));
+ (char *) palloc((strlen(DataDir) + strlen(GEQO_FILE) + 2) * sizeof(char));
sprintf(conf_file, "%s/%s", DataDir, GEQO_FILE);
@@ -94,99 +94,109 @@ geqo_params(int string_length)
file = AllocateFile(conf_file, "r");
if (file)
{
+
/*
* empty and comment line stuff
*/
while ((i = next_token(file, buf, sizeof(buf))) != EOF)
{
- /* If only token on the line, ignore */
- if (i == '\n') continue;
-
- /* Comment -- read until end of line then next line */
- if (buf[0] == '#')
- {
- while (next_token(file, buf, sizeof(buf)) == 0) ;
- continue;
- }
+ /* If only token on the line, ignore */
+ if (i == '\n')
+ continue;
+
+ /* Comment -- read until end of line then next line */
+ if (buf[0] == '#')
+ {
+ while (next_token(file, buf, sizeof(buf)) == 0);
+ continue;
+ }
/*
* get ga parameters by parsing
*/
-
+
/*------------------------------------------------- pool size */
- if ( strcmp(buf, POOL_TAG) == 0 )
+ if (strcmp(buf, POOL_TAG) == 0)
{
i = next_token(file, buf, sizeof(buf)); /* get next token */
-
- if (i != EOF) /* only ignore if we got no text at all */
+
+ if (i != EOF) /* only ignore if we got no text at all */
{
- if (sscanf (buf, "%d", &PoolSize) == 1) pool_size = 1;
+ if (sscanf(buf, "%d", &PoolSize) == 1)
+ pool_size = 1;
}
-
+
}
-
+
/*------------------------------------------------- number of trials */
- else if ( strcmp(buf, TRIAL_TAG) == 0 )
+ else if (strcmp(buf, TRIAL_TAG) == 0)
{
i = next_token(file, buf, sizeof(buf));
-
+
if (i != EOF)
{
- if (sscanf (buf, "%d", &Generations) == 1) number_trials = 1;
+ if (sscanf(buf, "%d", &Generations) == 1)
+ number_trials = 1;
}
-
+
}
-
+
/*------------------------------------------------- optimization effort */
- else if ( strcmp(buf, EFFORT_TAG) == 0 )
+ else if (strcmp(buf, EFFORT_TAG) == 0)
{
i = next_token(file, buf, sizeof(buf));
-
+
if (i != EOF)
{
- if (strcmp (buf, LOW) == 0) effort = LOW_EFFORT;
- else if (strcmp (buf, MEDIUM) == 0) effort = MEDIUM_EFFORT;
- else if (strcmp (buf, HIGH) == 0) effort = HIGH_EFFORT;
+ if (strcmp(buf, LOW) == 0)
+ effort = LOW_EFFORT;
+ else if (strcmp(buf, MEDIUM) == 0)
+ effort = MEDIUM_EFFORT;
+ else if (strcmp(buf, HIGH) == 0)
+ effort = HIGH_EFFORT;
}
-
+
}
-
+
/*------------------------------------------- random seed */
- else if ( strcmp(buf, RAND_TAG) == 0 )
- {
+ else if (strcmp(buf, RAND_TAG) == 0)
+ {
i = next_token(file, buf, sizeof(buf));
-
+
if (i != EOF)
{
- if (sscanf (buf, "%ld", &RandomSeed) == 1) random_seed = 1;
+ if (sscanf(buf, "%ld", &RandomSeed) == 1)
+ random_seed = 1;
}
-
+
}
-
+
/*------------------------------------------- selection bias */
- else if ( strcmp(buf, BIAS_TAG) == 0 )
+ else if (strcmp(buf, BIAS_TAG) == 0)
{
i = next_token(file, buf, sizeof(buf));
-
+
if (i != EOF)
{
- if (sscanf (buf, "%lf", &SelectionBias) == 1) selection_bias = 1;
+ if (sscanf(buf, "%lf", &SelectionBias) == 1)
+ selection_bias = 1;
}
-
+
}
-
+
/* unrecognized tags */
else
{
if (i != EOF)
{
}
-
- elog(DEBUG,"geqo_params: unknown parameter type \"%s\"\nin file \'%s\'", buf, conf_file);
+
+ elog(DEBUG, "geqo_params: unknown parameter type \"%s\"\nin file \'%s\'", buf, conf_file);
/* if not at end-of-line, keep reading til we are */
- while (i == 0) i = next_token(file, buf, sizeof(buf));
- }
+ while (i == 0)
+ i = next_token(file, buf, sizeof(buf));
+ }
}
FreeFile(file);
@@ -194,9 +204,9 @@ geqo_params(int string_length)
pfree(conf_file);
}
- else
+ else
{
- elog(DEBUG,"geqo_params: ga parameter file\n\'%s\'\ndoes not exist or permissions are not setup correctly", conf_file);
+ elog(DEBUG, "geqo_params: ga parameter file\n\'%s\'\ndoes not exist or permissions are not setup correctly", conf_file);
}
/*
@@ -204,49 +214,49 @@ geqo_params(int string_length)
*/
/**************** PoolSize: essential ****************/
- if ( !(pool_size) )
+ if (!(pool_size))
{
PoolSize = gimme_pool_size(string_length);
- elog(DEBUG,"geqo_params: no pool size specified;\nusing computed value of %d", PoolSize);
+ elog(DEBUG, "geqo_params: no pool size specified;\nusing computed value of %d", PoolSize);
}
-
-
+
+
/**************** Effort: essential ****************/
- if ( !(effort) )
+ if (!(effort))
{
if (PoolSize == MAX_POOL)
effort = HIGH_EFFORT;
else
effort = MEDIUM_EFFORT;
-
- elog(DEBUG,"geqo_params: no optimization effort specified;\nusing value of %d", effort);
+
+ elog(DEBUG, "geqo_params: no optimization effort specified;\nusing value of %d", effort);
}
/**************** Generations: essential ****************/
- if ( !(number_trials) )
+ if (!(number_trials))
{
Generations = gimme_number_generations(PoolSize, effort);
-
- elog(DEBUG,"geqo_params: no number of trials specified;\nusing computed value of %d", Generations);
+
+ elog(DEBUG, "geqo_params: no number of trials specified;\nusing computed value of %d", Generations);
}
/* RandomSeed: */
- if ( !(random_seed) )
+ if (!(random_seed))
{
RandomSeed = (long) time(NULL);
- elog(DEBUG,"geqo_params: no random seed specified;\nusing computed value of %ld", RandomSeed);
+ elog(DEBUG, "geqo_params: no random seed specified;\nusing computed value of %ld", RandomSeed);
}
/* SelectionBias: */
- if ( !(selection_bias) )
+ if (!(selection_bias))
{
SelectionBias = SELECTION_BIAS;
- elog(DEBUG,"geqo_params: no selection bias specified;\nusing default value of %f", SelectionBias);
+ elog(DEBUG, "geqo_params: no selection bias specified;\nusing default value of %f", SelectionBias);
}
}
@@ -255,73 +265,79 @@ geqo_params(int string_length)
/*
* Grab one token out of fp. Defined as the next string of non-whitespace
* in the file. After we get the token, continue reading until EOF, end of
- * line or the next token. If it's the last token on the line, return '\n'
+ * line or the next token. If it's the last token on the line, return '\n'
* for the value. If we get EOF before reading a token, return EOF. In all
* other cases return 0.
*/
-static int
-next_token(FILE *fp, char *buf, int bufsz)
+static int
+next_token(FILE * fp, char *buf, int bufsz)
{
- int c;
- char *eb = buf+(bufsz-1);
+ int c;
+ char *eb = buf + (bufsz - 1);
- /* Discard inital whitespace */
- while (isspace(c = getc(fp))) ;
+ /* Discard inital whitespace */
+ while (isspace(c = getc(fp)));
- /* EOF seen before any token so return EOF */
- if (c == EOF) return -1;
+ /* EOF seen before any token so return EOF */
+ if (c == EOF)
+ return -1;
- /* Form a token in buf */
- do {
- if (buf < eb) *buf++ = c;
- c = getc(fp);
- } while (!isspace(c) && c != EOF);
- *buf = '\0';
+ /* Form a token in buf */
+ do
+ {
+ if (buf < eb)
+ *buf++ = c;
+ c = getc(fp);
+ } while (!isspace(c) && c != EOF);
+ *buf = '\0';
- /* Discard trailing tabs and spaces */
- while (c == ' ' || c == '\t') c = getc(fp);
+ /* Discard trailing tabs and spaces */
+ while (c == ' ' || c == '\t')
+ c = getc(fp);
- /* Put back the char that was non-whitespace (putting back EOF is ok) */
- ungetc(c, fp);
+ /* Put back the char that was non-whitespace (putting back EOF is ok) */
+ ungetc(c, fp);
- /* If we ended with a newline, return that, otherwise return 0 */
- return (c == '\n' ? '\n' : 0);
+ /* If we ended with a newline, return that, otherwise return 0 */
+ return (c == '\n' ? '\n' : 0);
}
/* gimme_pool_size--
- * compute good estimation for pool size
- * according to number of involved rels in a query
+ * compute good estimation for pool size
+ * according to number of involved rels in a query
*/
-static int
+static int
gimme_pool_size(int string_length)
{
- double exponent;
- double size;
+ double exponent;
+ double size;
exponent = (double) string_length + 1.0;
- size = pow (2.0, exponent);
+ size = pow(2.0, exponent);
- if (size < MIN_POOL) {
+ if (size < MIN_POOL)
+ {
return (MIN_POOL);
- }
- else if (size > MAX_POOL) {
+ }
+ else if (size > MAX_POOL)
+ {
return (MAX_POOL);
- }
- else
- return ( (int) ceil(size) );
+ }
+ else
+ return ((int) ceil(size));
}
/* gimme_number_generations--
- * compute good estimation for number of generations size
- * for convergence
+ * compute good estimation for number of generations size
+ * for convergence
*/
-static int
+static int
gimme_number_generations(int pool_size, int effort)
{
- int number_gens;
+ int number_gens;
- number_gens = (int) ceil ( geqo_log((double) pool_size, 2.0) );
+ number_gens = (int) ceil(geqo_log((double) pool_size, 2.0));
return (effort * number_gens);
}
diff --git a/src/backend/optimizer/geqo/geqo_paths.c b/src/backend/optimizer/geqo/geqo_paths.c
index a22be406f5a..d98855d2887 100644
--- a/src/backend/optimizer/geqo/geqo_paths.c
+++ b/src/backend/optimizer/geqo/geqo_paths.c
@@ -1,11 +1,11 @@
/*-------------------------------------------------------------------------
*
* geqo_paths.c--
- * Routines to process redundant paths and relations
+ * Routines to process redundant paths and relations
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: geqo_paths.c,v 1.4 1997/06/11 02:44:12 vadim Exp $
+ * $Id: geqo_paths.c,v 1.5 1997/09/07 04:43:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,120 +28,128 @@
#include "optimizer/geqo_paths.h"
-static List *geqo_prune_rel(Rel *rel, List *other_rels);
-static Path *set_paths(Rel *rel, Path *unorderedpath);
+static List *geqo_prune_rel(Rel * rel, List * other_rels);
+static Path *set_paths(Rel * rel, Path * unorderedpath);
-/*
+/*
* geqo-prune-rels--
- * Removes any redundant relation entries from a list of rel nodes
- * 'rel-list'.
- *
- * Returns the resulting list.
- *
+ * Removes any redundant relation entries from a list of rel nodes
+ * 'rel-list'.
+ *
+ * Returns the resulting list.
+ *
*/
-List *geqo_prune_rels(List *rel_list)
+List *
+geqo_prune_rels(List * rel_list)
{
- List *temp_list = NIL;
-
- if (rel_list != NIL) {
- temp_list = lcons(lfirst(rel_list),
- geqo_prune_rels(geqo_prune_rel((Rel*)lfirst(rel_list),
- lnext(rel_list))));
- }
- return(temp_list);
+ List *temp_list = NIL;
+
+ if (rel_list != NIL)
+ {
+ temp_list = lcons(lfirst(rel_list),
+ geqo_prune_rels(geqo_prune_rel((Rel *) lfirst(rel_list),
+ lnext(rel_list))));
+ }
+ return (temp_list);
}
-/*
+/*
* geqo-prune-rel--
- * Prunes those relations from 'other-rels' that are redundant with
- * 'rel'. A relation is redundant if it is built up of the same
- * relations as 'rel'. Paths for the redundant relation are merged into
- * the pathlist of 'rel'.
- *
+ * Prunes those relations from 'other-rels' that are redundant with
+ * 'rel'. A relation is redundant if it is built up of the same
+ * relations as 'rel'. Paths for the redundant relation are merged into
+ * the pathlist of 'rel'.
+ *
* Returns a list of non-redundant relations, and sets the pathlist field
* of 'rel' appropriately.
- *
+ *
*/
-static List *
-geqo_prune_rel(Rel *rel, List *other_rels)
+static List *
+geqo_prune_rel(Rel * rel, List * other_rels)
{
- List *i = NIL;
- List *t_list = NIL;
- List *temp_node = NIL;
- Rel *other_rel = (Rel *)NULL;
-
- foreach(i, other_rels) {
- other_rel = (Rel*)lfirst(i);
- if(same(rel->relids, other_rel->relids)) {
- rel->pathlist = add_pathlist(rel,
- rel->pathlist,
- other_rel->pathlist);
- t_list = nconc(t_list, NIL); /* XXX is this right ? */
- } else {
- temp_node = lcons(other_rel, NIL);
- t_list = nconc(t_list,temp_node);
- }
- }
- return(t_list);
+ List *i = NIL;
+ List *t_list = NIL;
+ List *temp_node = NIL;
+ Rel *other_rel = (Rel *) NULL;
+
+ foreach(i, other_rels)
+ {
+ other_rel = (Rel *) lfirst(i);
+ if (same(rel->relids, other_rel->relids))
+ {
+ rel->pathlist = add_pathlist(rel,
+ rel->pathlist,
+ other_rel->pathlist);
+ t_list = nconc(t_list, NIL); /* XXX is this right ? */
+ }
+ else
+ {
+ temp_node = lcons(other_rel, NIL);
+ t_list = nconc(t_list, temp_node);
+ }
+ }
+ return (t_list);
}
-/*
+/*
* geqo-rel-paths--
- * For a relation 'rel' (which corresponds to a join
- * relation), set pointers to the unordered path and cheapest paths
- * (if the unordered path isn't the cheapest, it is pruned), and
- * reset the relation's size field to reflect the join.
- *
+ * For a relation 'rel' (which corresponds to a join
+ * relation), set pointers to the unordered path and cheapest paths
+ * (if the unordered path isn't the cheapest, it is pruned), and
+ * reset the relation's size field to reflect the join.
+ *
* Returns nothing of interest.
- *
+ *
*/
void
-geqo_rel_paths(Rel *rel)
+geqo_rel_paths(Rel * rel)
{
- List *y = NIL;
- Path *path = (Path*)NULL;
- JoinPath *cheapest = (JoinPath*)NULL;
-
- rel->size = 0;
- foreach(y, rel->pathlist)
- {
- path = (Path*)lfirst(y);
-
- if(!path->p_ordering.ord.sortop)
+ List *y = NIL;
+ Path *path = (Path *) NULL;
+ JoinPath *cheapest = (JoinPath *) NULL;
+
+ rel->size = 0;
+ foreach(y, rel->pathlist)
+ {
+ path = (Path *) lfirst(y);
+
+ if (!path->p_ordering.ord.sortop)
break;
- }
+ }
- cheapest = (JoinPath*)set_paths(rel, path);
- if ( IsA_JoinPath (cheapest) )
- rel->size = compute_joinrel_size(cheapest);
+ cheapest = (JoinPath *) set_paths(rel, path);
+ if (IsA_JoinPath(cheapest))
+ rel->size = compute_joinrel_size(cheapest);
}
-/*
+/*
* set-path--
- * Compares the unordered path for a relation with the cheapest path. If
- * the unordered path is not cheapest, it is pruned.
- *
- * Resets the pointers in 'rel' for unordered and cheapest paths.
- *
+ * Compares the unordered path for a relation with the cheapest path. If
+ * the unordered path is not cheapest, it is pruned.
+ *
+ * Resets the pointers in 'rel' for unordered and cheapest paths.
+ *
* Returns the cheapest path.
- *
+ *
*/
-static Path *
-set_paths(Rel *rel, Path *unorderedpath)
+static Path *
+set_paths(Rel * rel, Path * unorderedpath)
{
- Path *cheapest = set_cheapest(rel, rel->pathlist);
-
- /* don't prune if not pruneable -- JMH, 11/23/92 */
- if(unorderedpath != cheapest
- && rel->pruneable) {
-
- rel->unorderedpath = (Path *)NULL;
- rel->pathlist = lremove(unorderedpath, rel->pathlist);
- } else {
- rel->unorderedpath = (Path *)unorderedpath;
- }
-
- return(cheapest);
+ Path *cheapest = set_cheapest(rel, rel->pathlist);
+
+ /* don't prune if not pruneable -- JMH, 11/23/92 */
+ if (unorderedpath != cheapest
+ && rel->pruneable)
+ {
+
+ rel->unorderedpath = (Path *) NULL;
+ rel->pathlist = lremove(unorderedpath, rel->pathlist);
+ }
+ else
+ {
+ rel->unorderedpath = (Path *) unorderedpath;
+ }
+
+ return (cheapest);
}
-
diff --git a/src/backend/optimizer/geqo/geqo_pmx.c b/src/backend/optimizer/geqo/geqo_pmx.c
index c6e699cfa9f..c9187fec54b 100644
--- a/src/backend/optimizer/geqo/geqo_pmx.c
+++ b/src/backend/optimizer/geqo/geqo_pmx.c
@@ -2,35 +2,35 @@
*
* geqo_pmx.c--
*
-* partially matched crossover [PMX] routines;
-* PMX operator according to Goldberg & Lingle
-* (Proc Int'l Conf on GA's)
+* partially matched crossover [PMX] routines;
+* PMX operator according to Goldberg & Lingle
+* (Proc Int'l Conf on GA's)
*
-* $Id: geqo_pmx.c,v 1.1 1997/02/19 12:57:28 scrappy Exp $
+* $Id: geqo_pmx.c,v 1.2 1997/09/07 04:43:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* the pmx algorithm is adopted from Genitor : */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
#include "postgres.h"
@@ -56,155 +56,182 @@
/* pmx--
*
- * partially matched crossover
+ * partially matched crossover
*/
void
-pmx(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene)
+pmx(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene)
{
- int *failed = (int *) palloc ((num_gene+1)*sizeof(int));
- int *from = (int *) palloc ((num_gene+1)*sizeof(int));
- int *indx = (int *) palloc ((num_gene+1)*sizeof(int));
- int *check_list = (int *) palloc ((num_gene+1)*sizeof(int));
+ int *failed = (int *) palloc((num_gene + 1) * sizeof(int));
+ int *from = (int *) palloc((num_gene + 1) * sizeof(int));
+ int *indx = (int *) palloc((num_gene + 1) * sizeof(int));
+ int *check_list = (int *) palloc((num_gene + 1) * sizeof(int));
+
+ int left,
+ right,
+ temp,
+ i,
+ j,
+ k;
+ int mx_fail,
+ found,
+ mx_hold;
- int left, right, temp, i, j, k;
- int mx_fail, found, mx_hold;
-
/* no mutation so start up the pmx replacement algorithm */
/* initialize failed[], from[], check_list[] */
- for (k = 0; k < num_gene; k++) {
- failed[k] = -1;
- from[k] = -1;
- check_list[k+1] = 0;
- }
-
+ for (k = 0; k < num_gene; k++)
+ {
+ failed[k] = -1;
+ from[k] = -1;
+ check_list[k + 1] = 0;
+ }
+
/* locate crossover points */
- left = geqo_randint(num_gene-1, 0);
- right = geqo_randint(num_gene-1, 0);
+ left = geqo_randint(num_gene - 1, 0);
+ right = geqo_randint(num_gene - 1, 0);
- if (left > right) {
- temp = left;
- left = right;
- right = temp;
- }
+ if (left > right)
+ {
+ temp = left;
+ left = right;
+ right = temp;
+ }
/* copy tour2 into offspring */
- for (k = 0; k < num_gene; k++) {
- offspring[k] = tour2[k];
- from[k] = DAD;
- check_list[tour2[k]]++;
- }
-
+ for (k = 0; k < num_gene; k++)
+ {
+ offspring[k] = tour2[k];
+ from[k] = DAD;
+ check_list[tour2[k]]++;
+ }
+
/* copy tour1 into offspring */
- for (k = left; k <= right; k++) {
- check_list[offspring[k]]--;
- offspring[k] = tour1[k];
- from[k] = MOM;
- check_list[tour1[k]]++;
- }
+ for (k = left; k <= right; k++)
+ {
+ check_list[offspring[k]]--;
+ offspring[k] = tour1[k];
+ from[k] = MOM;
+ check_list[tour1[k]]++;
+ }
/* pmx main part */
- mx_fail = 0;
+ mx_fail = 0;
/* STEP 1 */
- for (k = left; k <= right; k++) { /* for all elements in the tour1-2 */
-
- if (tour1[k] == tour2[k]) found = 1; /* find match in tour2 */
+ for (k = left; k <= right; k++)
+ { /* for all elements in the tour1-2 */
- else {
- found = 0; /* substitute elements */
+ if (tour1[k] == tour2[k])
+ found = 1; /* find match in tour2 */
- j = 0;
- while ( !(found) && (j < num_gene) ) {
- if ( (offspring[j] == tour1[k]) && (from[j] == DAD) ) {
+ else
+ {
+ found = 0; /* substitute elements */
- check_list[offspring[j]]--;
- offspring[j] = tour2[k];
- found = 1;
- check_list[tour2[k]]++;
- }
+ j = 0;
+ while (!(found) && (j < num_gene))
+ {
+ if ((offspring[j] == tour1[k]) && (from[j] == DAD))
+ {
- j++;
- }
+ check_list[offspring[j]]--;
+ offspring[j] = tour2[k];
+ found = 1;
+ check_list[tour2[k]]++;
+ }
- }
+ j++;
+ }
- if ( !(found) ) { /* failed to replace gene */
- failed[mx_fail] = (int) tour1[k];
- indx[mx_fail] = k;
- mx_fail++;
- }
-
- } /* ... for */
-
-
-/* STEP 2 */
+ }
- /* see if any genes could not be replaced */
- if (mx_fail > 0) {
- mx_hold = mx_fail;
+ if (!(found))
+ { /* failed to replace gene */
+ failed[mx_fail] = (int) tour1[k];
+ indx[mx_fail] = k;
+ mx_fail++;
+ }
- for (k = 0; k < mx_hold; k++) {
- found = 0;
+ } /* ... for */
- j = 0;
- while ( !(found) && (j < num_gene) ) {
- if ( (failed[k] == (int) offspring[j]) && (from[j] == DAD) ) {
- check_list[offspring[j]]--;
- offspring[j] = tour2[indx[k]];
- check_list[tour2[indx[k]]]++;
-
- found = 1;
- failed[k] = -1;
- mx_fail--;
- }
+/* STEP 2 */
- j++;
- }
+ /* see if any genes could not be replaced */
+ if (mx_fail > 0)
+ {
+ mx_hold = mx_fail;
- } /* ... for */
+ for (k = 0; k < mx_hold; k++)
+ {
+ found = 0;
- } /* ... if */
-
+ j = 0;
+ while (!(found) && (j < num_gene))
+ {
-/* STEP 3 */
+ if ((failed[k] == (int) offspring[j]) && (from[j] == DAD))
+ {
+ check_list[offspring[j]]--;
+ offspring[j] = tour2[indx[k]];
+ check_list[tour2[indx[k]]]++;
- for (k = 1; k <= num_gene; k++) {
+ found = 1;
+ failed[k] = -1;
+ mx_fail--;
+ }
- if (check_list[k] > 1) {
- i = 0;
+ j++;
+ }
- while (i < num_gene) {
- if ( (offspring[i] == (Gene) k) && (from[i] == DAD) ) {
- j = 1;
+ } /* ... for */
- while (j <= num_gene) {
- if (check_list[j] == 0) {
- offspring[i] = (Gene) j;
- check_list[k]--;
- check_list[j]++;
- i = num_gene + 1;
- j = i;
- }
+ } /* ... if */
- j++;
- }
- } /* ... if */
-
- i++;
- } /* end while */
+/* STEP 3 */
- }
- } /* ... for */
-
- pfree(failed);
- pfree(from);
- pfree(indx);
- pfree(check_list);
+ for (k = 1; k <= num_gene; k++)
+ {
+
+ if (check_list[k] > 1)
+ {
+ i = 0;
+
+ while (i < num_gene)
+ {
+ if ((offspring[i] == (Gene) k) && (from[i] == DAD))
+ {
+ j = 1;
+
+ while (j <= num_gene)
+ {
+ if (check_list[j] == 0)
+ {
+ offspring[i] = (Gene) j;
+ check_list[k]--;
+ check_list[j]++;
+ i = num_gene + 1;
+ j = i;
+ }
+
+ j++;
+ }
+
+ } /* ... if */
+
+ i++;
+ } /* end while */
+
+ }
+ } /* ... for */
+
+ pfree(failed);
+ pfree(from);
+ pfree(indx);
+ pfree(check_list);
}
diff --git a/src/backend/optimizer/geqo/geqo_pool.c b/src/backend/optimizer/geqo/geqo_pool.c
index 98a1a6e2a06..89c945d4ef4 100644
--- a/src/backend/optimizer/geqo/geqo_pool.c
+++ b/src/backend/optimizer/geqo/geqo_pool.c
@@ -1,20 +1,20 @@
/*------------------------------------------------------------------------
*
* geqo_pool.c--
- * Genetic Algorithm (GA) pool stuff
+ * Genetic Algorithm (GA) pool stuff
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: geqo_pool.c,v 1.1 1997/02/19 12:57:31 scrappy Exp $
+ * $Id: geqo_pool.c,v 1.2 1997/09/07 04:43:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
@@ -44,205 +44,220 @@
#include "optimizer/geqo_recombination.h"
-static int compare(void *arg1, void *arg2);
+static int compare(void *arg1, void *arg2);
/*
* alloc-pool--
- * allocates memory for GA pool
+ * allocates memory for GA pool
*/
-Pool *
+Pool *
alloc_pool(int pool_size, int string_length)
{
- Pool *new_pool;
- Chromosome *chromo;
- int i;
-
- /* pool */
- new_pool = (Pool *) palloc (sizeof(Pool));
- new_pool->size = (int) pool_size;
- new_pool->string_length = (int) string_length;
-
- /* all chromosome */
- new_pool->data = (Chromosome *) palloc (pool_size * sizeof(Chromosome));
-
- /* all gene */
- chromo = (Chromosome *) new_pool->data; /* vector of all chromos */
- for (i=0; i<pool_size; i++) {
- chromo[i].string = palloc((string_length+1)*sizeof(Gene));
+ Pool *new_pool;
+ Chromosome *chromo;
+ int i;
+
+ /* pool */
+ new_pool = (Pool *) palloc(sizeof(Pool));
+ new_pool->size = (int) pool_size;
+ new_pool->string_length = (int) string_length;
+
+ /* all chromosome */
+ new_pool->data = (Chromosome *) palloc(pool_size * sizeof(Chromosome));
+
+ /* all gene */
+ chromo = (Chromosome *) new_pool->data; /* vector of all chromos */
+ for (i = 0; i < pool_size; i++)
+ {
+ chromo[i].string = palloc((string_length + 1) * sizeof(Gene));
}
- return (new_pool);
+ return (new_pool);
}
/*
* free-pool--
- * deallocates memory for GA pool
+ * deallocates memory for GA pool
*/
void
-free_pool (Pool *pool)
+free_pool(Pool * pool)
{
- Chromosome *chromo;
- int i;
+ Chromosome *chromo;
+ int i;
- /* all gene */
- chromo = (Chromosome *) pool->data; /* vector of all chromos */
- for (i=0; i<pool->size; i++) pfree(chromo[i].string);
+ /* all gene */
+ chromo = (Chromosome *) pool->data; /* vector of all chromos */
+ for (i = 0; i < pool->size; i++)
+ pfree(chromo[i].string);
- /* all chromosome */
- pfree (pool->data);
+ /* all chromosome */
+ pfree(pool->data);
- /* pool */
- pfree (pool);
+ /* pool */
+ pfree(pool);
}
/*
* random-init-pool--
- * initialize genetic pool
+ * initialize genetic pool
*/
void
-random_init_pool (Query *root, Pool *pool, int strt, int stp)
+random_init_pool(Query * root, Pool * pool, int strt, int stp)
{
- Chromosome *chromo = (Chromosome *) pool->data;
- int i;
+ Chromosome *chromo = (Chromosome *) pool->data;
+ int i;
- for (i=strt; i<stp; i++) {
- init_tour(chromo[i].string, pool->string_length); /* from "geqo_recombination.c" */
+ for (i = strt; i < stp; i++)
+ {
+ init_tour(chromo[i].string, pool->string_length); /* from
+ * "geqo_recombination.c"
+ * */
- pool->data[i].worth =
- geqo_eval(root, chromo[i].string, pool->string_length); /* "from geqo_eval.c" */
+ pool->data[i].worth =
+ geqo_eval(root, chromo[i].string, pool->string_length); /* "from geqo_eval.c" */
}
}
/*
* sort-pool--
- * sorts input pool according to worth, from smallest to largest
+ * sorts input pool according to worth, from smallest to largest
*
- * maybe you have to change compare() for different ordering ...
+ * maybe you have to change compare() for different ordering ...
*/
void
-sort_pool(Pool *pool)
-{
- pg_qsort(pool->data, pool->size, sizeof(Chromosome), compare);
+sort_pool(Pool * pool)
+{
+ pg_qsort(pool->data, pool->size, sizeof(Chromosome), compare);
}
/*
* compare--
- * static input function for pg_sort
+ * static input function for pg_sort
*
- * return values for sort from smallest to largest are prooved!
- * don't change them!
+ * return values for sort from smallest to largest are prooved!
+ * don't change them!
*/
static int
compare(void *arg1, void *arg2)
{
- Chromosome chromo1 = *(Chromosome *) arg1;
- Chromosome chromo2 = *(Chromosome *) arg2;
-
- if (chromo1.worth == chromo2.worth)
- return(0);
- else if (chromo1.worth > chromo2.worth)
- return(1);
- else
- return(-1);
+ Chromosome chromo1 = *(Chromosome *) arg1;
+ Chromosome chromo2 = *(Chromosome *) arg2;
+
+ if (chromo1.worth == chromo2.worth)
+ return (0);
+ else if (chromo1.worth > chromo2.worth)
+ return (1);
+ else
+ return (-1);
}
/* alloc_chromo--
- * allocates a chromosome and string space
+ * allocates a chromosome and string space
*/
-Chromosome *
-alloc_chromo (int string_length)
+Chromosome *
+alloc_chromo(int string_length)
{
- Chromosome *chromo;
+ Chromosome *chromo;
+
+ chromo = (Chromosome *) palloc(sizeof(Chromosome));
+ chromo->string = (Gene *) palloc((string_length + 1) * sizeof(Gene));
- chromo = (Chromosome *) palloc (sizeof(Chromosome));
- chromo->string = (Gene *) palloc ((string_length+1)*sizeof(Gene));
-
- return (chromo);
+ return (chromo);
}
/* free_chromo--
- * deallocates a chromosome and string space
+ * deallocates a chromosome and string space
*/
void
-free_chromo (Chromosome *chromo)
+free_chromo(Chromosome * chromo)
{
- pfree(chromo->string);
- pfree(chromo);
+ pfree(chromo->string);
+ pfree(chromo);
}
/* spread_chromo--
- * inserts a new chromosome into the pool, displacing worst gene in pool
- * assumes best->worst = smallest->largest
+ * inserts a new chromosome into the pool, displacing worst gene in pool
+ * assumes best->worst = smallest->largest
*/
void
-spread_chromo (Chromosome *chromo, Pool *pool)
+spread_chromo(Chromosome * chromo, Pool * pool)
{
- int top, mid, bot;
- int i, index;
- Chromosome swap_chromo, tmp_chromo;
-
- /* new chromo is so bad we can't use it */
- if (chromo->worth > pool->data[pool->size-1].worth) return;
-
- /* do a binary search to find the index of the new chromo */
-
- top = 0;
- mid = pool->size/2;
- bot = pool->size-1;
- index = -1;
-
- while (index == -1) {
- /* these 4 cases find a new location */
-
- if (chromo->worth <= pool->data[top].worth)
- index = top;
- else
- if (chromo->worth == pool->data[mid].worth)
- index = mid;
- else
- if (chromo->worth == pool->data[bot].worth)
- index = bot;
- else
- if (bot-top <=1)
- index = bot;
-
-
- /* these 2 cases move the search indices since
- a new location has not yet been found. */
-
- else
- if (chromo->worth < pool->data[mid].worth) {
- bot = mid;
- mid = top + ( (bot-top)/2 );
- }
- else { /* (chromo->worth > pool->data[mid].worth) */
- top = mid;
- mid = top + ( (bot-top)/2 );
- }
- } /* ... while */
-
- /* now we have index for chromo */
-
- /* move every gene from index on down
- one position to make room for chromo */
-
- /* copy new gene into pool storage;
- always replace worst gene in pool */
-
- geqo_copy (&pool->data[pool->size-1], chromo, pool->string_length);
-
- swap_chromo.string = pool->data[pool->size-1].string;
- swap_chromo.worth = pool->data[pool->size-1].worth;
-
- for (i=index; i<pool->size; i++) {
- tmp_chromo.string = pool->data[i].string;
- tmp_chromo.worth = pool->data[i].worth;
-
- pool->data[i].string = swap_chromo.string;
- pool->data[i].worth = swap_chromo.worth;
-
- swap_chromo.string = tmp_chromo.string;
- swap_chromo.worth = tmp_chromo.worth;
- }
+ int top,
+ mid,
+ bot;
+ int i,
+ index;
+ Chromosome swap_chromo,
+ tmp_chromo;
+
+ /* new chromo is so bad we can't use it */
+ if (chromo->worth > pool->data[pool->size - 1].worth)
+ return;
+
+ /* do a binary search to find the index of the new chromo */
+
+ top = 0;
+ mid = pool->size / 2;
+ bot = pool->size - 1;
+ index = -1;
+
+ while (index == -1)
+ {
+ /* these 4 cases find a new location */
+
+ if (chromo->worth <= pool->data[top].worth)
+ index = top;
+ else if (chromo->worth == pool->data[mid].worth)
+ index = mid;
+ else if (chromo->worth == pool->data[bot].worth)
+ index = bot;
+ else if (bot - top <= 1)
+ index = bot;
+
+
+ /*
+ * these 2 cases move the search indices since a new location has
+ * not yet been found.
+ */
+
+ else if (chromo->worth < pool->data[mid].worth)
+ {
+ bot = mid;
+ mid = top + ((bot - top) / 2);
+ }
+ else
+ { /* (chromo->worth > pool->data[mid].worth) */
+ top = mid;
+ mid = top + ((bot - top) / 2);
+ }
+ } /* ... while */
+
+ /* now we have index for chromo */
+
+ /*
+ * move every gene from index on down one position to make room for
+ * chromo
+ */
+
+ /*
+ * copy new gene into pool storage; always replace worst gene in pool
+ */
+
+ geqo_copy(&pool->data[pool->size - 1], chromo, pool->string_length);
+
+ swap_chromo.string = pool->data[pool->size - 1].string;
+ swap_chromo.worth = pool->data[pool->size - 1].worth;
+
+ for (i = index; i < pool->size; i++)
+ {
+ tmp_chromo.string = pool->data[i].string;
+ tmp_chromo.worth = pool->data[i].worth;
+
+ pool->data[i].string = swap_chromo.string;
+ pool->data[i].worth = swap_chromo.worth;
+
+ swap_chromo.string = tmp_chromo.string;
+ swap_chromo.worth = tmp_chromo.worth;
+ }
}
diff --git a/src/backend/optimizer/geqo/geqo_px.c b/src/backend/optimizer/geqo/geqo_px.c
index f060561b516..71aa2415b55 100644
--- a/src/backend/optimizer/geqo/geqo_px.c
+++ b/src/backend/optimizer/geqo/geqo_px.c
@@ -2,35 +2,35 @@
*
* geqo_px.c--
*
-* position crossover [PX] routines;
-* PX operator according to Syswerda
-* (The Genetic Algorithms Handbook, L Davis, ed)
+* position crossover [PX] routines;
+* PX operator according to Syswerda
+* (The Genetic Algorithms Handbook, L Davis, ed)
*
-* $Id: geqo_px.c,v 1.1 1997/02/19 12:57:37 scrappy Exp $
+* $Id: geqo_px.c,v 1.2 1997/09/07 04:43:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* the px algorithm is adopted from Genitor : */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
#include "postgres.h"
@@ -56,61 +56,70 @@
/* px--
*
- * position crossover
+ * position crossover
*/
void
-px(Gene *tour1, Gene *tour2, Gene *offspring, int num_gene, City *city_table)
+px(Gene * tour1, Gene * tour2, Gene * offspring, int num_gene, City * city_table)
{
- int num_positions;
- int i, pos, tour2_index, offspring_index;
+ int num_positions;
+ int i,
+ pos,
+ tour2_index,
+ offspring_index;
- /* initialize city table */
- for (i=1; i<=num_gene; i++) {
- city_table[i].used = 0;
- }
+ /* initialize city table */
+ for (i = 1; i <= num_gene; i++)
+ {
+ city_table[i].used = 0;
+ }
- /* choose random positions that will be inherited directly from parent */
- num_positions = geqo_randint (2*num_gene/3, num_gene/3);
+ /* choose random positions that will be inherited directly from parent */
+ num_positions = geqo_randint(2 * num_gene / 3, num_gene / 3);
- /* choose random position */
- for (i=0; i<num_positions; i++) {
- pos = geqo_randint (num_gene - 1, 0);
+ /* choose random position */
+ for (i = 0; i < num_positions; i++)
+ {
+ pos = geqo_randint(num_gene - 1, 0);
- offspring[pos] = tour1[pos]; /* transfer cities to child */
- city_table[(int) tour1[pos]].used = 1; /* mark city used */
- }
+ offspring[pos] = tour1[pos]; /* transfer cities to child */
+ city_table[(int) tour1[pos]].used = 1; /* mark city used */
+ }
- tour2_index = 0;
- offspring_index = 0;
+ tour2_index = 0;
+ offspring_index = 0;
- /* px main part */
+ /* px main part */
- while (offspring_index < num_gene) {
+ while (offspring_index < num_gene)
+ {
- /* next position in offspring filled */
- if (!city_table[(int) tour1[offspring_index]].used) {
+ /* next position in offspring filled */
+ if (!city_table[(int) tour1[offspring_index]].used)
+ {
- /* next city in tour1 not used */
- if (!city_table[(int) tour2[tour2_index]].used) {
+ /* next city in tour1 not used */
+ if (!city_table[(int) tour2[tour2_index]].used)
+ {
- /* inherit from tour1 */
- offspring[offspring_index] = tour2[tour2_index];
+ /* inherit from tour1 */
+ offspring[offspring_index] = tour2[tour2_index];
- tour2_index++;
- offspring_index++;
- }
- else { /* next city in tour2 has been used */
- tour2_index++;
- }
+ tour2_index++;
+ offspring_index++;
+ }
+ else
+ { /* next city in tour2 has been used */
+ tour2_index++;
+ }
- }
- else { /* next position in offspring is filled */
- offspring_index++;
- }
+ }
+ else
+ { /* next position in offspring is filled */
+ offspring_index++;
+ }
- }
-
- }
+ }
+}
diff --git a/src/backend/optimizer/geqo/geqo_recombination.c b/src/backend/optimizer/geqo/geqo_recombination.c
index df175dcb866..53803079819 100644
--- a/src/backend/optimizer/geqo/geqo_recombination.c
+++ b/src/backend/optimizer/geqo/geqo_recombination.c
@@ -1,18 +1,18 @@
/*------------------------------------------------------------------------
*
* geqo_recombination.c--
-* misc recombination procedures
+* misc recombination procedures
*
-* $Id: geqo_recombination.c,v 1.1 1997/02/19 12:57:42 scrappy Exp $
+* $Id: geqo_recombination.c,v 1.2 1997/09/07 04:43:21 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
@@ -42,65 +42,70 @@
/*
* init_tour--
*
- * Randomly generates a legal "traveling salesman" tour
- * (i.e. where each point is visited only once.)
- * Essentially, this routine fills an array with all possible
- * points on the tour and randomly chooses the 'next' city from
- * this array. When a city is chosen, the array is shortened
- * and the procedure repeated.
+ * Randomly generates a legal "traveling salesman" tour
+ * (i.e. where each point is visited only once.)
+ * Essentially, this routine fills an array with all possible
+ * points on the tour and randomly chooses the 'next' city from
+ * this array. When a city is chosen, the array is shortened
+ * and the procedure repeated.
*
*/
void
-init_tour(Gene *tour, int num_gene)
+init_tour(Gene * tour, int num_gene)
{
-Gene *tmp;
-int remainder;
-int next, i;
+ Gene *tmp;
+ int remainder;
+ int next,
+ i;
-tmp = (Gene *) palloc (num_gene*sizeof(Gene));
-
-for(i = 0; i < num_gene; i++) {
- tmp[i] = (Gene) i+1; /* builds tours "1 - 2 - 3" etc. */
- }
+ tmp = (Gene *) palloc(num_gene * sizeof(Gene));
-remainder = num_gene - 1;
+ for (i = 0; i < num_gene; i++)
+ {
+ tmp[i] = (Gene) i + 1; /* builds tours "1 - 2 - 3" etc. */
+ }
-for(i = 0; i < num_gene; i++) {
- next = (int) geqo_randint(remainder, 0); /* choose city between 0 and remainder */
- tour[i] = tmp[next];
- tmp[next] = tmp[remainder];
- remainder--;
- }
+ remainder = num_gene - 1;
-pfree(tmp);
-}
+ for (i = 0; i < num_gene; i++)
+ {
+ next = (int) geqo_randint(remainder, 0); /* choose city between 0
+ * and remainder */
+ tour[i] = tmp[next];
+ tmp[next] = tmp[remainder];
+ remainder--;
+ }
+
+ pfree(tmp);
+}
/* alloc_city_table--
*
- * allocate memory for city table
+ * allocate memory for city table
*
*/
-City *
+City *
alloc_city_table(int num_gene)
{
- City *city_table;
+ City *city_table;
- /* palloc one extra location so that nodes numbered
- 1..n can be indexed directly; 0 will not be used */
+ /*
+ * palloc one extra location so that nodes numbered 1..n can be
+ * indexed directly; 0 will not be used
+ */
- city_table = (City *) palloc ((num_gene+1)*sizeof(City));
+ city_table = (City *) palloc((num_gene + 1) * sizeof(City));
- return (city_table);
- }
+ return (city_table);
+}
/* free_city_table--
*
- * deallocate memory of city table
+ * deallocate memory of city table
*
*/
- void
- free_city_table(City *city_table)
- {
- pfree(city_table);
- }
-
+void
+free_city_table(City * city_table)
+{
+ pfree(city_table);
+}
diff --git a/src/backend/optimizer/geqo/geqo_selection.c b/src/backend/optimizer/geqo/geqo_selection.c
index 0c6502003bd..820de485fe4 100644
--- a/src/backend/optimizer/geqo/geqo_selection.c
+++ b/src/backend/optimizer/geqo/geqo_selection.c
@@ -1,36 +1,36 @@
/*-------------------------------------------------------------------------
*
* geqo_selection.c--
- * linear selection scheme for the genetic query optimizer
+ * linear selection scheme for the genetic query optimizer
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: geqo_selection.c,v 1.1 1997/02/19 12:57:46 scrappy Exp $
+ * $Id: geqo_selection.c,v 1.2 1997/09/07 04:43:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* contributed by:
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- * Martin Utesch * Institute of Automatic Control *
- = = University of Mining and Technology =
- * [email protected] * Freiberg, Germany *
+ * Martin Utesch * Institute of Automatic Control *
+ = = University of Mining and Technology =
+ * [email protected] * Freiberg, Germany *
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
*/
/* this is adopted from D. Whitley's Genitor algorithm */
/*************************************************************/
-/* */
-/* Copyright (c) 1990 */
-/* Darrell L. Whitley */
-/* Computer Science Department */
-/* Colorado State University */
-/* */
-/* Permission is hereby granted to copy all or any part of */
-/* this program for free distribution. The author's name */
-/* and this copyright notice must be included in any copy. */
-/* */
+/* */
+/* Copyright (c) 1990 */
+/* Darrell L. Whitley */
+/* Computer Science Department */
+/* Colorado State University */
+/* */
+/* Permission is hereby granted to copy all or any part of */
+/* this program for free distribution. The author's name */
+/* and this copyright notice must be included in any copy. */
+/* */
/*************************************************************/
#include <math.h>
@@ -55,49 +55,51 @@
#include "optimizer/geqo_copy.h"
#include "optimizer/geqo_random.h"
-static int linear(int max, double bias);
+static int linear(int max, double bias);
/* geqo_selection--
*
- * according to bias described by input parameters,
- * second genes are selected from the pool
+ * according to bias described by input parameters,
+ * second genes are selected from the pool
*/
void
-geqo_selection (Chromosome *momma, Chromosome *daddy, Pool *pool, double bias)
+geqo_selection(Chromosome * momma, Chromosome * daddy, Pool * pool, double bias)
{
- int first, second;
-
- first = (int) linear(pool->size, bias);
- second = (int) linear(pool->size, bias);
-
- if (pool->size > 1) {
- while(first==second)
- second = (int) linear(pool->size, bias);
- }
-
- geqo_copy (momma, &pool->data[first], pool->string_length);
- geqo_copy (daddy, &pool->data[second], pool->string_length);
+ int first,
+ second;
+
+ first = (int) linear(pool->size, bias);
+ second = (int) linear(pool->size, bias);
+
+ if (pool->size > 1)
+ {
+ while (first == second)
+ second = (int) linear(pool->size, bias);
+ }
+
+ geqo_copy(momma, &pool->data[first], pool->string_length);
+ geqo_copy(daddy, &pool->data[second], pool->string_length);
}
/* linear--
- * generates random integer between 0 and input max number
- * using input linear bias
+ * generates random integer between 0 and input max number
+ * using input linear bias
*
- * probability distribution function is: f(x) = bias - 2(bias - 1)x
- * bias = (prob of first rule) / (prob of middle rule)
+ * probability distribution function is: f(x) = bias - 2(bias - 1)x
+ * bias = (prob of first rule) / (prob of middle rule)
*
*/
static int
-linear(int pool_size, double bias) /* bias is y-intercept of linear distribution */
+linear(int pool_size, double bias) /* bias is y-intercept of linear
+ * distribution */
{
- double index; /* index between 0 and pop_size */
- double max = (double) pool_size;
+ double index; /* index between 0 and pop_size */
+ double max = (double) pool_size;
- index =
- max*( bias - sqrt ( (bias*bias) - 4.0*(bias-1.0)*geqo_rand() ) )
- / 2.0 / (bias-1.0);
+ index =
+ max * (bias - sqrt((bias * bias) - 4.0 * (bias - 1.0) * geqo_rand()))
+ / 2.0 / (bias - 1.0);
- return((int) index);
+ return ((int) index);
}
-
diff --git a/src/backend/optimizer/geqo/minspantree.c b/src/backend/optimizer/geqo/minspantree.c
index 4e4c2ad11b4..1fcc2569478 100644
--- a/src/backend/optimizer/geqo/minspantree.c
+++ b/src/backend/optimizer/geqo/minspantree.c
@@ -1,13 +1,13 @@
/*------------------------------------------------------------------------
*
* minspantree.c--
-* routine to sort a join graph which is including cycles
+* routine to sort a join graph which is including cycles
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
-* $Header: /cvsroot/pgsql/src/backend/optimizer/geqo/Attic/minspantree.c,v 1.1 1997/02/19 12:57:50 scrappy Exp $
+* $Header: /cvsroot/pgsql/src/backend/optimizer/geqo/Attic/minspantree.c,v 1.2 1997/09/07 04:43:25 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,166 +33,181 @@
/*
* minspantree--
- * The function minspantree computes the minimum spanning tree
- * for a given number of nodes and a given distance function.
- * For each pair of nodes found to be connected, a given
- * function is called. Nodes are denoted by the integer numbers
- * 1 .. number_of_joins, where number_of_joins is the number of nodes.
+ * The function minspantree computes the minimum spanning tree
+ * for a given number of nodes and a given distance function.
+ * For each pair of nodes found to be connected, a given
+ * function is called. Nodes are denoted by the integer numbers
+ * 1 .. number_of_joins, where number_of_joins is the number of nodes.
*/
void
-minspantree(Query *root, List *join_rels, Rel *garel)
+minspantree(Query * root, List * join_rels, Rel * garel)
{
- int number_of_rels = length(root->base_relation_list_);
- int number_of_joins = length(join_rels);
- int *connectto;
- /* connectto[i] = 0, if node i is already connected */
- /* to the tree, otherwise connectto[i] is the node */
- /* nearest to i, which is already connected. */
-
- Cost *disttoconnect; /* disttoconnect[i]: distance between i and connectto[i] */
-
- Cost dist, /* temporary */
- mindist; /* minimal distance between connected and unconnected node */
-
- Cost mstlength = 0.0; /* the total length of the minimum spanning tree */
-
- int count;
- int n, /* newly attached node */
- nextn, /* next node to be attached */
- tempn;
-
- int i, id1, id2;
- List *r = NIL;
- Rel *joinrel = NULL;
- Rel **tmprel_array;
-
-
- /* allocate memory for matrix tmprel_array[x][y] */
- tmprel_array = (Rel **) palloc((number_of_rels+1)*sizeof(Rel *));
- for (i=0; i<=number_of_rels; i++)
- (tmprel_array[i] = (Rel *) palloc ((number_of_rels+1)*sizeof(Rel)));
-
- /* read relations of join-relations into tmprel_array */
-
- foreach(r, join_rels) {
- joinrel = (Rel *)lfirst(r);
- id1 = (int)lfirst(joinrel->relids);
- id2 = (int)lsecond(joinrel->relids);
-
- if (id1 > id2) {
- tmprel_array[id2][id1] = *(Rel *)joinrel;
- }
- else {
- tmprel_array[id1][id2] = *(Rel *)joinrel; /* ever reached? */
- }
- }
-
- /* Trivial special cases handled first */
- /* garel is global in "tsp.h" */
-
- if (number_of_joins <= 2)
- {
- i=1;
- foreach(r, join_rels) {
- garel[i] = *(Rel *)lfirst(r);
- i++;
- }
- }
-
-
- else if (number_of_joins == 3)
- {
- Rel *rel12 = (Rel *) &tmprel_array[1][2];
- Rel *rel13 = (Rel *) &tmprel_array[1][3];
- Rel *rel23 = (Rel *) &tmprel_array[2][3];
- if (rel12->cheapestpath->path_cost > rel13->cheapestpath->path_cost)
- {
- garel[1] = tmprel_array[1][3];
- if (rel12->cheapestpath->path_cost > rel23->cheapestpath->path_cost)
+ int number_of_rels = length(root->base_relation_list_);
+ int number_of_joins = length(join_rels);
+ int *connectto;
+
+ /* connectto[i] = 0, if node i is already connected */
+ /* to the tree, otherwise connectto[i] is the node */
+ /* nearest to i, which is already connected. */
+
+ Cost *disttoconnect; /* disttoconnect[i]: distance
+ * between i and connectto[i] */
+
+ Cost dist, /* temporary */
+ mindist; /* minimal distance between connected and
+ * unconnected node */
+
+ Cost mstlength = 0.0; /* the total length of the minimum
+ * spanning tree */
+
+ int count;
+ int n, /* newly attached node */
+ nextn, /* next node to be attached */
+ tempn;
+
+ int i,
+ id1,
+ id2;
+ List *r = NIL;
+ Rel *joinrel = NULL;
+ Rel **tmprel_array;
+
+
+ /* allocate memory for matrix tmprel_array[x][y] */
+ tmprel_array = (Rel **) palloc((number_of_rels + 1) * sizeof(Rel *));
+ for (i = 0; i <= number_of_rels; i++)
+ (tmprel_array[i] = (Rel *) palloc((number_of_rels + 1) * sizeof(Rel)));
+
+ /* read relations of join-relations into tmprel_array */
+
+ foreach(r, join_rels)
{
- garel[2] = tmprel_array[2][3];
+ joinrel = (Rel *) lfirst(r);
+ id1 = (int) lfirst(joinrel->relids);
+ id2 = (int) lsecond(joinrel->relids);
+
+ if (id1 > id2)
+ {
+ tmprel_array[id2][id1] = *(Rel *) joinrel;
+ }
+ else
+ {
+ tmprel_array[id1][id2] = *(Rel *) joinrel; /* ever reached? */
+ }
}
- else
+
+ /* Trivial special cases handled first */
+ /* garel is global in "tsp.h" */
+
+ if (number_of_joins <= 2)
{
- garel[2] = tmprel_array[1][2];
+ i = 1;
+ foreach(r, join_rels)
+ {
+ garel[i] = *(Rel *) lfirst(r);
+ i++;
+ }
}
- }
- else
- {
- garel[1] = tmprel_array[1][2];
- if (rel13->cheapestpath->path_cost > rel23->cheapestpath->path_cost)
+
+
+ else if (number_of_joins == 3)
{
- garel[2] = tmprel_array[2][3];
+ Rel *rel12 = (Rel *) & tmprel_array[1][2];
+ Rel *rel13 = (Rel *) & tmprel_array[1][3];
+ Rel *rel23 = (Rel *) & tmprel_array[2][3];
+
+ if (rel12->cheapestpath->path_cost > rel13->cheapestpath->path_cost)
+ {
+ garel[1] = tmprel_array[1][3];
+ if (rel12->cheapestpath->path_cost > rel23->cheapestpath->path_cost)
+ {
+ garel[2] = tmprel_array[2][3];
+ }
+ else
+ {
+ garel[2] = tmprel_array[1][2];
+ }
+ }
+ else
+ {
+ garel[1] = tmprel_array[1][2];
+ if (rel13->cheapestpath->path_cost > rel23->cheapestpath->path_cost)
+ {
+ garel[2] = tmprel_array[2][3];
+ }
+ else
+ {
+ garel[2] = tmprel_array[1][3];
+ }
+ }
}
+
+
+ /* now the general case */
else
{
- garel[2] = tmprel_array[1][3];
- }
- }
- }
-
-
- /* now the general case */
- else
- {
- connectto = (int *) palloc((number_of_rels+1)*sizeof(int));
- disttoconnect = (Cost *) palloc((number_of_rels+1)*sizeof(Cost));
-
- nextn = 2;
- for (tempn = 2; tempn <= number_of_rels; tempn++ )
- {
- connectto[tempn] = 1;
- disttoconnect[tempn] = (Cost) MAXFLOAT;
- }
-
- joinrel = NULL;
- n = 1;
- i = 1;
- for (count = 2; count <= number_of_rels; count++ )
- {
- connectto[n] = 0;
- mindist = (Cost) MAXFLOAT;
- for (tempn = 2; tempn <= number_of_rels; tempn++ )
- {
- if (connectto[tempn] != 0)
- {
- if (n > tempn) {
- joinrel = (Rel *) &tmprel_array[tempn][n];
- }
- else {
- joinrel = (Rel *) &tmprel_array[n][tempn];
- }
- dist = joinrel->cheapestpath->path_cost;
-
- if (dist < disttoconnect[tempn])
- {
- disttoconnect[tempn] = dist;
- connectto[tempn] = n;
- }
- if (disttoconnect[tempn] < mindist)
- {
- mindist = disttoconnect[tempn];
- nextn = tempn;
+ connectto = (int *) palloc((number_of_rels + 1) * sizeof(int));
+ disttoconnect = (Cost *) palloc((number_of_rels + 1) * sizeof(Cost));
+
+ nextn = 2;
+ for (tempn = 2; tempn <= number_of_rels; tempn++)
+ {
+ connectto[tempn] = 1;
+ disttoconnect[tempn] = (Cost) MAXFLOAT;
+ }
+
+ joinrel = NULL;
+ n = 1;
+ i = 1;
+ for (count = 2; count <= number_of_rels; count++)
+ {
+ connectto[n] = 0;
+ mindist = (Cost) MAXFLOAT;
+ for (tempn = 2; tempn <= number_of_rels; tempn++)
+ {
+ if (connectto[tempn] != 0)
+ {
+ if (n > tempn)
+ {
+ joinrel = (Rel *) & tmprel_array[tempn][n];
+ }
+ else
+ {
+ joinrel = (Rel *) & tmprel_array[n][tempn];
+ }
+ dist = joinrel->cheapestpath->path_cost;
+
+ if (dist < disttoconnect[tempn])
+ {
+ disttoconnect[tempn] = dist;
+ connectto[tempn] = n;
+ }
+ if (disttoconnect[tempn] < mindist)
+ {
+ mindist = disttoconnect[tempn];
+ nextn = tempn;
+ }
+ }
+ }
+ n = nextn;
+ if (n > connectto[n])
+ {
+ garel[i] = tmprel_array[connectto[n]][n];
+ }
+ else
+ {
+ garel[i] = tmprel_array[n][connectto[n]];
+ }
+ i++;
+ }
+
+ pfree(connectto);
+ pfree(disttoconnect);
+
}
- }
- }
- n = nextn;
- if (n > connectto[n]) {
- garel[i] = tmprel_array[connectto[n]][n];
- }
- else {
- garel[i] = tmprel_array[n][connectto[n]];
- }
- i++;
- }
-
- pfree(connectto);
- pfree(disttoconnect);
-
- }
-
- for (i=0; i<=number_of_rels; i++) pfree(tmprel_array[i]);
- pfree(tmprel_array);
-}
+ for (i = 0; i <= number_of_rels; i++)
+ pfree(tmprel_array[i]);
+ pfree(tmprel_array);
+}
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d27b31cfbd7..7c4576d6f02 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* allpaths.c--
- * Routines to find possible search paths for processing a query
+ * Routines to find possible search paths for processing a query
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.10 1997/06/10 07:55:45 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.11 1997/09/07 04:43:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,226 +34,245 @@
#include "optimizer/geqo.h"
#ifdef GEQO
-bool _use_geqo_ = true;
+bool _use_geqo_ = true;
+
#else
-bool _use_geqo_ = false;
+bool _use_geqo_ = false;
+
#endif
-int32 _use_geqo_rels_ = GEQO_RELS;
+int32 _use_geqo_rels_ = GEQO_RELS;
-static void find_rel_paths(Query *root, List *rels);
-static List *find_join_paths(Query *root, List *outer_rels, int levels_left);
+static void find_rel_paths(Query * root, List * rels);
+static List *find_join_paths(Query * root, List * outer_rels, int levels_left);
-/*
+/*
* find-paths--
- * Finds all possible access paths for executing a query, returning the
- * top level list of relation entries.
- *
+ * Finds all possible access paths for executing a query, returning the
+ * top level list of relation entries.
+ *
* 'rels' is the list of single relation entries appearing in the query
*/
-List *
-find_paths(Query *root, List *rels)
+List *
+find_paths(Query * root, List * rels)
{
- int levels_left;
-
- /*
- * Set the number of join (not nesting) levels yet to be processed.
- */
- levels_left = length(rels);
-
- if (levels_left <= 0)
- return NIL;
-
- /*
- * Find the base relation paths.
- */
- find_rel_paths(root, rels);
-
- if (levels_left <= 1) {
+ int levels_left;
+
/*
- * Unsorted single relation, no more processing is required.
+ * Set the number of join (not nesting) levels yet to be processed.
*/
- return (rels);
- }else {
- /*
- * this means that joins or sorts are required.
- * set selectivities of clauses that have not been set
- * by an index.
+ levels_left = length(rels);
+
+ if (levels_left <= 0)
+ return NIL;
+
+ /*
+ * Find the base relation paths.
*/
- set_rest_relselec(root, rels);
+ find_rel_paths(root, rels);
+
+ if (levels_left <= 1)
+ {
- return(find_join_paths(root, rels, levels_left-1));
- }
+ /*
+ * Unsorted single relation, no more processing is required.
+ */
+ return (rels);
+ }
+ else
+ {
+
+ /*
+ * this means that joins or sorts are required. set selectivities
+ * of clauses that have not been set by an index.
+ */
+ set_rest_relselec(root, rels);
+
+ return (find_join_paths(root, rels, levels_left - 1));
+ }
}
-/*
+/*
* find-rel-paths--
- * Finds all paths available for scanning each relation entry in
- * 'rels'. Sequential scan and any available indices are considered
- * if possible(indices are not considered for lower nesting levels).
- * All unique paths are attached to the relation's 'pathlist' field.
- *
- * MODIFIES: rels
+ * Finds all paths available for scanning each relation entry in
+ * 'rels'. Sequential scan and any available indices are considered
+ * if possible(indices are not considered for lower nesting levels).
+ * All unique paths are attached to the relation's 'pathlist' field.
+ *
+ * MODIFIES: rels
*/
static void
-find_rel_paths(Query *root, List *rels)
+find_rel_paths(Query * root, List * rels)
{
- List *temp;
- Rel *rel;
- List *lastpath;
-
- foreach(temp, rels) {
- List *sequential_scan_list;
- List *rel_index_scan_list;
- List *or_index_scan_list;
-
- rel = (Rel *)lfirst(temp);
- sequential_scan_list = lcons(create_seqscan_path(rel),
- NIL);
-
- rel_index_scan_list =
- find_index_paths(root,
- rel,
- find_relation_indices(root,rel),
- rel->clauseinfo,
- rel->joininfo);
-
- or_index_scan_list =
- create_or_index_paths(root, rel, rel->clauseinfo);
-
- rel->pathlist = add_pathlist(rel,
- sequential_scan_list,
- append(rel_index_scan_list,
- or_index_scan_list));
-
- /* The unordered path is always the last in the list.
- * If it is not the cheapest path, prune it.
- */
- lastpath = rel->pathlist;
- while(lnext(lastpath)!=NIL)
- lastpath=lnext(lastpath);
- prune_rel_path(rel, (Path*)lfirst(lastpath));
- /*
- * if there is a qualification of sequential scan the selec.
- * value is not set -- so set it explicitly -- Sunita
- */
- set_rest_selec(root, rel->clauseinfo);
- rel->size = compute_rel_size(rel);
- rel->width = compute_rel_width(rel);
- }
- return;
+ List *temp;
+ Rel *rel;
+ List *lastpath;
+
+ foreach(temp, rels)
+ {
+ List *sequential_scan_list;
+ List *rel_index_scan_list;
+ List *or_index_scan_list;
+
+ rel = (Rel *) lfirst(temp);
+ sequential_scan_list = lcons(create_seqscan_path(rel),
+ NIL);
+
+ rel_index_scan_list =
+ find_index_paths(root,
+ rel,
+ find_relation_indices(root, rel),
+ rel->clauseinfo,
+ rel->joininfo);
+
+ or_index_scan_list =
+ create_or_index_paths(root, rel, rel->clauseinfo);
+
+ rel->pathlist = add_pathlist(rel,
+ sequential_scan_list,
+ append(rel_index_scan_list,
+ or_index_scan_list));
+
+ /*
+ * The unordered path is always the last in the list. If it is not
+ * the cheapest path, prune it.
+ */
+ lastpath = rel->pathlist;
+ while (lnext(lastpath) != NIL)
+ lastpath = lnext(lastpath);
+ prune_rel_path(rel, (Path *) lfirst(lastpath));
+
+ /*
+ * if there is a qualification of sequential scan the selec. value
+ * is not set -- so set it explicitly -- Sunita
+ */
+ set_rest_selec(root, rel->clauseinfo);
+ rel->size = compute_rel_size(rel);
+ rel->width = compute_rel_width(rel);
+ }
+ return;
}
-/*
+/*
* find-join-paths--
- * Find all possible joinpaths for a query by successively finding ways
- * to join single relations into join relations.
+ * Find all possible joinpaths for a query by successively finding ways
+ * to join single relations into join relations.
*
- * if BushyPlanFlag is set, bushy tree plans will be generated:
- * Find all possible joinpaths(bushy trees) for a query by systematically
- * finding ways to join relations(both original and derived) together.
- *
- * 'outer-rels' is the current list of relations for which join paths
- * are to be found, i.e., he current list of relations that
- * have already been derived.
+ * if BushyPlanFlag is set, bushy tree plans will be generated:
+ * Find all possible joinpaths(bushy trees) for a query by systematically
+ * finding ways to join relations(both original and derived) together.
+ *
+ * 'outer-rels' is the current list of relations for which join paths
+ * are to be found, i.e., he current list of relations that
+ * have already been derived.
* 'levels-left' is the current join level being processed, where '1' is
- * the "last" level
- *
+ * the "last" level
+ *
* Returns the final level of join relations, i.e., the relation that is
* the result of joining all the original relations togehter.
*/
-static List *
-find_join_paths(Query *root, List *outer_rels, int levels_left)
+static List *
+find_join_paths(Query * root, List * outer_rels, int levels_left)
{
- List *x;
- List *new_rels;
- Rel *rel;
-
- /*******************************************
- * genetic query optimizer entry point *
- *******************************************/
-
- if ( (_use_geqo_) && length(root->base_relation_list_) >= _use_geqo_rels_ )
- return lcons(geqo(root), NIL); /* returns *one* Rel, so lcons it */
-
- /*******************************************
- * rest will be deprecated in case of GEQO *
- *******************************************/
-
- /*
- * Determine all possible pairs of relations to be joined at this level.
- * Determine paths for joining these relation pairs and modify 'new-rels'
- * accordingly, then eliminate redundant join relations.
- */
- new_rels = find_join_rels(root, outer_rels);
-
- find_all_join_paths(root, new_rels);
-
- new_rels = prune_joinrels(new_rels);
-
-#if 0
- /*
- ** for each expensive predicate in each path in each distinct rel,
- ** consider doing pullup -- JMH
- */
- if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
- foreach(x, new_rels)
- xfunc_trypullup((Rel*)lfirst(x));
-#endif
+ List *x;
+ List *new_rels;
+ Rel *rel;
- prune_rel_paths(new_rels);
+ /*******************************************
+ * genetic query optimizer entry point *
+ *******************************************/
+
+ if ((_use_geqo_) && length(root->base_relation_list_) >= _use_geqo_rels_)
+ return lcons(geqo(root), NIL); /* returns *one* Rel, so lcons it */
+
+ /*******************************************
+ * rest will be deprecated in case of GEQO *
+ *******************************************/
- if(BushyPlanFlag) {
/*
- * In case of bushy trees
- * if there is still a join between a join relation and another
- * relation, add a new joininfo that involves the join relation
- * to the joininfo list of the other relation
+ * Determine all possible pairs of relations to be joined at this
+ * level. Determine paths for joining these relation pairs and modify
+ * 'new-rels' accordingly, then eliminate redundant join relations.
*/
- add_new_joininfos(root, new_rels,outer_rels);
- }
+ new_rels = find_join_rels(root, outer_rels);
+
+ find_all_join_paths(root, new_rels);
+
+ new_rels = prune_joinrels(new_rels);
- foreach(x, new_rels) {
- rel = (Rel*)lfirst(x);
- if ( rel->size <= 0 )
- rel->size = compute_rel_size(rel);
- rel->width = compute_rel_width(rel);
+#if 0
+
+ /*
+ * * for each expensive predicate in each path in each distinct rel, *
+ * consider doing pullup -- JMH
+ */
+ if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
+ foreach(x, new_rels)
+ xfunc_trypullup((Rel *) lfirst(x));
+#endif
+
+ prune_rel_paths(new_rels);
+
+ if (BushyPlanFlag)
+ {
+
+ /*
+ * In case of bushy trees if there is still a join between a join
+ * relation and another relation, add a new joininfo that involves
+ * the join relation to the joininfo list of the other relation
+ */
+ add_new_joininfos(root, new_rels, outer_rels);
+ }
+
+ foreach(x, new_rels)
+ {
+ rel = (Rel *) lfirst(x);
+ if (rel->size <= 0)
+ rel->size = compute_rel_size(rel);
+ rel->width = compute_rel_width(rel);
/*#define OPTIMIZER_DEBUG*/
#ifdef OPTIMIZER_DEBUG
- printf("levels left: %d\n", levels_left);
- debug_print_rel(root, rel);
-#endif
- }
-
- if(BushyPlanFlag) {
- /*
- * prune rels that have been completely incorporated into
- * new join rels
- */
- outer_rels = prune_oldrels(outer_rels);
- /*
- * merge join rels if then contain the same list of base rels
- */
- outer_rels = merge_joinrels(new_rels,outer_rels);
- root->join_relation_list_ = outer_rels;
- }
- else {
- root->join_relation_list_ = new_rels;
- }
-
- if(levels_left == 1) {
- if(BushyPlanFlag)
- return(final_join_rels(outer_rels));
+ printf("levels left: %d\n", levels_left);
+ debug_print_rel(root, rel);
+#endif
+ }
+
+ if (BushyPlanFlag)
+ {
+
+ /*
+ * prune rels that have been completely incorporated into new join
+ * rels
+ */
+ outer_rels = prune_oldrels(outer_rels);
+
+ /*
+ * merge join rels if then contain the same list of base rels
+ */
+ outer_rels = merge_joinrels(new_rels, outer_rels);
+ root->join_relation_list_ = outer_rels;
+ }
else
- return(new_rels);
- } else {
- if(BushyPlanFlag)
- return(find_join_paths(root, outer_rels, levels_left - 1));
+ {
+ root->join_relation_list_ = new_rels;
+ }
+
+ if (levels_left == 1)
+ {
+ if (BushyPlanFlag)
+ return (final_join_rels(outer_rels));
+ else
+ return (new_rels);
+ }
else
- return(find_join_paths(root, new_rels, levels_left - 1));
- }
+ {
+ if (BushyPlanFlag)
+ return (find_join_paths(root, outer_rels, levels_left - 1));
+ else
+ return (find_join_paths(root, new_rels, levels_left - 1));
+ }
}
/*****************************************************************************
@@ -262,115 +281,147 @@ find_join_paths(Query *root, List *outer_rels, int levels_left)
#ifdef OPTIMIZER_DEBUG
static void
-print_joinclauses(Query *root, List *clauses)
+print_joinclauses(Query * root, List * clauses)
{
- List *l;
- extern void print_expr(Node *expr, List *rtable); /* in print.c */
+ List *l;
+ extern void print_expr(Node * expr, List * rtable); /* in print.c */
- foreach(l, clauses) {
- CInfo *c = lfirst(l);
+ foreach(l, clauses)
+ {
+ CInfo *c = lfirst(l);
- print_expr((Node*)c->clause, root->rtable);
- if (lnext(l)) printf(" ");
- }
+ print_expr((Node *) c->clause, root->rtable);
+ if (lnext(l))
+ printf(" ");
+ }
}
static void
-print_path(Query *root, Path *path, int indent)
+print_path(Query * root, Path * path, int indent)
{
- char *ptype = NULL;
- JoinPath *jp;
- bool join = false;
- int i;
-
- for(i=0; i < indent; i++)
- printf("\t");
-
- switch(nodeTag(path)) {
- case T_Path:
- ptype = "SeqScan"; join=false; break;
- case T_IndexPath:
- ptype = "IdxScan"; join=false; break;
- case T_JoinPath:
- ptype = "Nestloop"; join=true; break;
- case T_MergePath:
- ptype = "MergeJoin"; join=true; break;
- case T_HashPath:
- ptype = "HashJoin"; join=true; break;
- default:
- break;
- }
- if (join) {
- int size = path->parent->size;
- jp = (JoinPath*)path;
- printf("%s size=%d cost=%f\n", ptype, size, path->path_cost);
- switch(nodeTag(path)) {
+ char *ptype = NULL;
+ JoinPath *jp;
+ bool join = false;
+ int i;
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+
+ switch (nodeTag(path))
+ {
+ case T_Path:
+ ptype = "SeqScan";
+ join = false;
+ break;
+ case T_IndexPath:
+ ptype = "IdxScan";
+ join = false;
+ break;
+ case T_JoinPath:
+ ptype = "Nestloop";
+ join = true;
+ break;
case T_MergePath:
+ ptype = "MergeJoin";
+ join = true;
+ break;
case T_HashPath:
- for(i=0; i < indent+1; i++)
- printf("\t");
- printf(" clauses=(");
- print_joinclauses(root,
- ((JoinPath*)path)->pathclauseinfo);
- printf(")\n");
-
- if (nodeTag(path)==T_MergePath) {
- MergePath *mp = (MergePath*)path;
- if (mp->outersortkeys || mp->innersortkeys) {
- for(i=0; i < indent+1; i++)
- printf("\t");
- printf(" sortouter=%d sortinner=%d\n",
- ((mp->outersortkeys)?1:0),
- ((mp->innersortkeys)?1:0));
- }
- }
- break;
+ ptype = "HashJoin";
+ join = true;
+ break;
default:
- break;
+ break;
}
- print_path(root, jp->outerjoinpath, indent+1);
- print_path(root, jp->innerjoinpath, indent+1);
- } else {
- int size = path->parent->size;
- int relid = lfirsti(path->parent->relids);
- printf("%s(%d) size=%d cost=%f",
- ptype, relid, size, path->path_cost);
-
- if (nodeTag(path)==T_IndexPath) {
- List *k, *l;
-
- printf(" keys=");
- foreach (k, path->keys) {
- printf("(");
- foreach (l, lfirst(k)) {
- Var *var = lfirst(l);
- printf("%d.%d", var->varnoold, var->varoattno);
- if (lnext(l)) printf(", ");
+ if (join)
+ {
+ int size = path->parent->size;
+
+ jp = (JoinPath *) path;
+ printf("%s size=%d cost=%f\n", ptype, size, path->path_cost);
+ switch (nodeTag(path))
+ {
+ case T_MergePath:
+ case T_HashPath:
+ for (i = 0; i < indent + 1; i++)
+ printf("\t");
+ printf(" clauses=(");
+ print_joinclauses(root,
+ ((JoinPath *) path)->pathclauseinfo);
+ printf(")\n");
+
+ if (nodeTag(path) == T_MergePath)
+ {
+ MergePath *mp = (MergePath *) path;
+
+ if (mp->outersortkeys || mp->innersortkeys)
+ {
+ for (i = 0; i < indent + 1; i++)
+ printf("\t");
+ printf(" sortouter=%d sortinner=%d\n",
+ ((mp->outersortkeys) ? 1 : 0),
+ ((mp->innersortkeys) ? 1 : 0));
+ }
+ }
+ break;
+ default:
+ break;
}
- printf(")");
- if (lnext(k)) printf(", ");
- }
+ print_path(root, jp->outerjoinpath, indent + 1);
+ print_path(root, jp->innerjoinpath, indent + 1);
+ }
+ else
+ {
+ int size = path->parent->size;
+ int relid = lfirsti(path->parent->relids);
+
+ printf("%s(%d) size=%d cost=%f",
+ ptype, relid, size, path->path_cost);
+
+ if (nodeTag(path) == T_IndexPath)
+ {
+ List *k,
+ *l;
+
+ printf(" keys=");
+ foreach(k, path->keys)
+ {
+ printf("(");
+ foreach(l, lfirst(k))
+ {
+ Var *var = lfirst(l);
+
+ printf("%d.%d", var->varnoold, var->varoattno);
+ if (lnext(l))
+ printf(", ");
+ }
+ printf(")");
+ if (lnext(k))
+ printf(", ");
+ }
+ }
+ printf("\n");
}
- printf("\n");
- }
}
-static void
-debug_print_rel(Query *root, Rel *rel)
+static void
+debug_print_rel(Query * root, Rel * rel)
{
- List *l;
-
- printf("(");
- foreach(l, rel->relids) {
- printf("%d ", lfirsti(l));
- }
- printf("): size=%d width=%d\n", rel->size, rel->width);
-
- printf("\tpath list:\n");
- foreach (l, rel->pathlist) {
- print_path(root, lfirst(l), 1);
- }
- printf("\tcheapest path:\n");
- print_path(root, rel->cheapestpath, 1);
+ List *l;
+
+ printf("(");
+ foreach(l, rel->relids)
+ {
+ printf("%d ", lfirsti(l));
+ }
+ printf("): size=%d width=%d\n", rel->size, rel->width);
+
+ printf("\tpath list:\n");
+ foreach(l, rel->pathlist)
+ {
+ print_path(root, lfirst(l), 1);
+ }
+ printf("\tcheapest path:\n");
+ print_path(root, rel->cheapestpath, 1);
}
-#endif /* OPTIMIZER_DEBUG */
+
+#endif /* OPTIMIZER_DEBUG */
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index 634e1130794..0ce580754e3 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* clausesel.c--
- * Routines to compute and set clause selectivities
+ * Routines to compute and set clause selectivities
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.2 1997/09/07 04:43:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,7 +23,7 @@
#include "optimizer/cost.h"
#include "optimizer/plancat.h"
-#include "parser/parsetree.h" /* for getrelid() */
+#include "parser/parsetree.h" /* for getrelid() */
#include "catalog/pg_proc.h"
#include "catalog/pg_operator.h"
@@ -31,301 +31,353 @@
#include "utils/elog.h"
#include "utils/lsyscache.h"
-static Cost compute_selec(Query *root, List *clauses, List *or_selectivities);
+static Cost compute_selec(Query * root, List * clauses, List * or_selectivities);
/****************************************************************************
- * ROUTINES TO SET CLAUSE SELECTIVITIES
+ * ROUTINES TO SET CLAUSE SELECTIVITIES
****************************************************************************/
-/*
+/*
* set_clause_selectivities -
- * Sets the selectivity field for each of clause in 'clauseinfo-list'
- * to 'new-selectivity'. If the selectivity has already been set, reset
- * it only if the new one is better.
- *
+ * Sets the selectivity field for each of clause in 'clauseinfo-list'
+ * to 'new-selectivity'. If the selectivity has already been set, reset
+ * it only if the new one is better.
+ *
* Returns nothing of interest.
*
*/
void
-set_clause_selectivities(List *clauseinfo_list, Cost new_selectivity)
+set_clause_selectivities(List * clauseinfo_list, Cost new_selectivity)
{
- List *temp;
- CInfo *clausenode;
- Cost cost_clause;
-
- foreach (temp,clauseinfo_list) {
- clausenode = (CInfo*)lfirst(temp);
- cost_clause = clausenode->selectivity;
- if ( FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause) {
- clausenode->selectivity = new_selectivity;
+ List *temp;
+ CInfo *clausenode;
+ Cost cost_clause;
+
+ foreach(temp, clauseinfo_list)
+ {
+ clausenode = (CInfo *) lfirst(temp);
+ cost_clause = clausenode->selectivity;
+ if (FLOAT_IS_ZERO(cost_clause) || new_selectivity < cost_clause)
+ {
+ clausenode->selectivity = new_selectivity;
+ }
}
- }
}
-/*
+/*
* product_selec -
- * Multiplies the selectivities of each clause in 'clauseinfo-list'.
- *
+ * Multiplies the selectivities of each clause in 'clauseinfo-list'.
+ *
* Returns a flonum corresponding to the selectivity of 'clauseinfo-list'.
*/
Cost
-product_selec(List *clauseinfo_list)
+product_selec(List * clauseinfo_list)
{
- Cost result = 1.0;
- if (clauseinfo_list!=NIL) {
- List *xclausenode = NIL;
- Cost temp;
-
- foreach(xclausenode,clauseinfo_list) {
- temp = ((CInfo *)lfirst(xclausenode))->selectivity;
- result = result * temp;
+ Cost result = 1.0;
+
+ if (clauseinfo_list != NIL)
+ {
+ List *xclausenode = NIL;
+ Cost temp;
+
+ foreach(xclausenode, clauseinfo_list)
+ {
+ temp = ((CInfo *) lfirst(xclausenode))->selectivity;
+ result = result * temp;
+ }
}
- }
- return(result);
+ return (result);
}
-/*
+/*
* set_rest_relselec -
- * Scans through clauses on each relation and assigns a selectivity to
- * those clauses that haven't been assigned a selectivity by an index.
- *
+ * Scans through clauses on each relation and assigns a selectivity to
+ * those clauses that haven't been assigned a selectivity by an index.
+ *
* Returns nothing of interest.
* MODIFIES: selectivities of the various rel's clauseinfo
- * slots.
+ * slots.
*/
void
-set_rest_relselec(Query *root, List *rel_list)
+set_rest_relselec(Query * root, List * rel_list)
{
- Rel *rel;
- List *x;
+ Rel *rel;
+ List *x;
- foreach (x,rel_list) {
- rel = (Rel*)lfirst(x);
- set_rest_selec(root, rel->clauseinfo);
- }
+ foreach(x, rel_list)
+ {
+ rel = (Rel *) lfirst(x);
+ set_rest_selec(root, rel->clauseinfo);
+ }
}
-/*
+/*
* set_rest_selec -
- * Sets the selectivity fields for those clauses within a single
- * relation's 'clauseinfo-list' that haven't already been set.
- *
+ * Sets the selectivity fields for those clauses within a single
+ * relation's 'clauseinfo-list' that haven't already been set.
+ *
* Returns nothing of interest.
- *
+ *
*/
void
-set_rest_selec(Query *root, List *clauseinfo_list)
+set_rest_selec(Query * root, List * clauseinfo_list)
{
- List *temp = NIL;
- CInfo *clausenode = (CInfo*)NULL;
- Cost cost_clause;
-
- foreach (temp,clauseinfo_list) {
- clausenode = (CInfo*)lfirst(temp);
- cost_clause = clausenode->selectivity;
+ List *temp = NIL;
+ CInfo *clausenode = (CInfo *) NULL;
+ Cost cost_clause;
- /*
- * Check to see if the selectivity of this clause or any 'or'
- * subclauses (if any) haven't been set yet.
- */
- if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause)) {
- clausenode->selectivity =
- compute_clause_selec(root,
- (Node*)clausenode->clause,
- lcons(makeFloat(cost_clause), NIL));
+ foreach(temp, clauseinfo_list)
+ {
+ clausenode = (CInfo *) lfirst(temp);
+ cost_clause = clausenode->selectivity;
+
+ /*
+ * Check to see if the selectivity of this clause or any 'or'
+ * subclauses (if any) haven't been set yet.
+ */
+ if (valid_or_clause(clausenode) || FLOAT_IS_ZERO(cost_clause))
+ {
+ clausenode->selectivity =
+ compute_clause_selec(root,
+ (Node *) clausenode->clause,
+ lcons(makeFloat(cost_clause), NIL));
+ }
}
- }
}
/****************************************************************************
- * ROUTINES TO COMPUTE SELECTIVITIES
+ * ROUTINES TO COMPUTE SELECTIVITIES
****************************************************************************/
-/*
+/*
* compute_clause_selec -
- * Given a clause, this routine will compute the selectivity of the
- * clause by calling 'compute_selec' with the appropriate parameters
- * and possibly use that return value to compute the real selectivity
- * of a clause.
- *
+ * Given a clause, this routine will compute the selectivity of the
+ * clause by calling 'compute_selec' with the appropriate parameters
+ * and possibly use that return value to compute the real selectivity
+ * of a clause.
+ *
* 'or-selectivities' are selectivities that have already been assigned
- * to subclauses of an 'or' clause.
- *
+ * to subclauses of an 'or' clause.
+ *
* Returns a flonum corresponding to the clause selectivity.
- *
+ *
*/
Cost
-compute_clause_selec(Query *root, Node *clause, List *or_selectivities)
+compute_clause_selec(Query * root, Node * clause, List * or_selectivities)
{
- if (!is_opclause (clause)) {
- /* if it's not an operator clause, then it is a boolean clause -jolly*/
- /*
- * Boolean variables get a selectivity of 1/2.
- */
- return(0.1);
- } else if (not_clause (clause)) {
- /*
- * 'not' gets "1.0 - selectivity-of-inner-clause".
- */
- return (1.000000 - compute_selec(root,
- lcons(get_notclausearg((Expr*)clause),
- NIL),
- or_selectivities));
- } else if (or_clause(clause)) {
- /*
- * Both 'or' and 'and' clauses are evaluated as described in
- * (compute_selec).
- */
- return (compute_selec(root,
- ((Expr*)clause)->args, or_selectivities));
- } else {
- return(compute_selec(root,
- lcons(clause,NIL),or_selectivities));
- }
+ if (!is_opclause(clause))
+ {
+
+ /*
+ * if it's not an operator clause, then it is a boolean clause
+ * -jolly
+ */
+
+ /*
+ * Boolean variables get a selectivity of 1/2.
+ */
+ return (0.1);
+ }
+ else if (not_clause(clause))
+ {
+
+ /*
+ * 'not' gets "1.0 - selectivity-of-inner-clause".
+ */
+ return (1.000000 - compute_selec(root,
+ lcons(get_notclausearg((Expr *) clause),
+ NIL),
+ or_selectivities));
+ }
+ else if (or_clause(clause))
+ {
+
+ /*
+ * Both 'or' and 'and' clauses are evaluated as described in
+ * (compute_selec).
+ */
+ return (compute_selec(root,
+ ((Expr *) clause)->args, or_selectivities));
+ }
+ else
+ {
+ return (compute_selec(root,
+ lcons(clause, NIL), or_selectivities));
+ }
}
-/*
- * compute_selec -
- * Computes the selectivity of a clause.
- *
- * If there is more than one clause in the argument 'clauses', then the
- * desired selectivity is that of an 'or' clause. Selectivities for an
- * 'or' clause such as (OR a b) are computed by finding the selectivity
- * of a (s1) and b (s2) and computing s1+s2 - s1*s2.
- *
- * In addition, if the clause is an 'or' clause, individual selectivities
- * may have already been assigned by indices to subclauses. These values
- * are contained in the list 'or-selectivities'.
- *
+/*
+ * compute_selec -
+ * Computes the selectivity of a clause.
+ *
+ * If there is more than one clause in the argument 'clauses', then the
+ * desired selectivity is that of an 'or' clause. Selectivities for an
+ * 'or' clause such as (OR a b) are computed by finding the selectivity
+ * of a (s1) and b (s2) and computing s1+s2 - s1*s2.
+ *
+ * In addition, if the clause is an 'or' clause, individual selectivities
+ * may have already been assigned by indices to subclauses. These values
+ * are contained in the list 'or-selectivities'.
+ *
* Returns the clause selectivity as a flonum.
- *
+ *
*/
-static Cost
-compute_selec(Query *root, List *clauses, List *or_selectivities)
+static Cost
+compute_selec(Query * root, List * clauses, List * or_selectivities)
{
- Cost s1 = 0;
- List *clause = lfirst(clauses);
-
- if (clauses==NULL) {
- s1 = 1.0;
- } else if (IsA(clause,Param)) {
- /* XXX How're we handling this before?? -ay */
- s1 = 1.0;
- } else if (IsA(clause,Const)) {
- s1 = ((bool) ((Const*) clause)->constvalue) ? 1.0 : 0.0;
- } else if (IsA(clause,Var)) {
- Oid relid = getrelid(((Var*)clause)->varno,
- root->rtable);
+ Cost s1 = 0;
+ List *clause = lfirst(clauses);
- /*
- * we have a bool Var. This is exactly equivalent to the clause:
- * reln.attribute = 't'
- * so we compute the selectivity as if that is what we have. The
- * magic #define constants are a hack. I didn't want to have to
- * do system cache look ups to find out all of that info.
- */
+ if (clauses == NULL)
+ {
+ s1 = 1.0;
+ }
+ else if (IsA(clause, Param))
+ {
+ /* XXX How're we handling this before?? -ay */
+ s1 = 1.0;
+ }
+ else if (IsA(clause, Const))
+ {
+ s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
+ }
+ else if (IsA(clause, Var))
+ {
+ Oid relid = getrelid(((Var *) clause)->varno,
+ root->rtable);
- s1 = restriction_selectivity(EqualSelectivityProcedure,
- BooleanEqualOperator,
- relid,
- ((Var*)clause)->varoattno,
- "t",
- _SELEC_CONSTANT_RIGHT_);
- } else if (or_selectivities) {
- /* If s1 has already been assigned by an index, use that value. */
- List *this_sel = lfirst(or_selectivities);
-
- s1 = floatVal(this_sel);
- } else if (is_funcclause((Node*)clause)) {
- /* this isn't an Oper, it's a Func!! */
- /*
- ** This is not an operator, so we guess at the selectivity.
- ** THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE
- ** ABLE TO HAVE SELECTIVITIES THEMSELVES.
- ** -- JMH 7/9/92
- */
- s1 = 0.1;
- } else if (NumRelids((Node*) clause) == 1) {
- /* ...otherwise, calculate s1 from 'clauses'.
- * The clause is not a join clause, since there is
- * only one relid in the clause. The clause
- * selectivity will be based on the operator
- * selectivity and operand values.
- */
- Oid opno = ((Oper*)((Expr*)clause)->oper)->opno;
- RegProcedure oprrest = get_oprrest(opno);
- Oid relid;
- int relidx;
- AttrNumber attno;
- Datum constval;
- int flag;
-
- get_relattval((Node*)clause, &relidx, &attno, &constval, &flag);
- relid = getrelid(relidx, root->rtable);
-
- /* if the oprrest procedure is missing for whatever reason,
- use a selectivity of 0.5*/
- if (!oprrest)
- s1 = (Cost) (0.5);
+ /*
+ * we have a bool Var. This is exactly equivalent to the clause:
+ * reln.attribute = 't' so we compute the selectivity as if that
+ * is what we have. The magic #define constants are a hack. I
+ * didn't want to have to do system cache look ups to find out all
+ * of that info.
+ */
+
+ s1 = restriction_selectivity(EqualSelectivityProcedure,
+ BooleanEqualOperator,
+ relid,
+ ((Var *) clause)->varoattno,
+ "t",
+ _SELEC_CONSTANT_RIGHT_);
+ }
+ else if (or_selectivities)
+ {
+ /* If s1 has already been assigned by an index, use that value. */
+ List *this_sel = lfirst(or_selectivities);
+
+ s1 = floatVal(this_sel);
+ }
+ else if (is_funcclause((Node *) clause))
+ {
+ /* this isn't an Oper, it's a Func!! */
+
+ /*
+ * * This is not an operator, so we guess at the selectivity. *
+ * THIS IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE * ABLE
+ * TO HAVE SELECTIVITIES THEMSELVES. * -- JMH 7/9/92
+ */
+ s1 = 0.1;
+ }
+ else if (NumRelids((Node *) clause) == 1)
+ {
+
+ /*
+ * ...otherwise, calculate s1 from 'clauses'. The clause is not a
+ * join clause, since there is only one relid in the clause. The
+ * clause selectivity will be based on the operator selectivity
+ * and operand values.
+ */
+ Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
+ RegProcedure oprrest = get_oprrest(opno);
+ Oid relid;
+ int relidx;
+ AttrNumber attno;
+ Datum constval;
+ int flag;
+
+ get_relattval((Node *) clause, &relidx, &attno, &constval, &flag);
+ relid = getrelid(relidx, root->rtable);
+
+ /*
+ * if the oprrest procedure is missing for whatever reason, use a
+ * selectivity of 0.5
+ */
+ if (!oprrest)
+ s1 = (Cost) (0.5);
+ else if (attno == InvalidAttrNumber)
+ {
+
+ /*
+ * attno can be Invalid if the clause had a function in it,
+ * i.e. WHERE myFunc(f) = 10
+ */
+ /* this should be FIXED somehow to use function selectivity */
+ s1 = (Cost) (0.5);
+ }
+ else
+ s1 = (Cost) restriction_selectivity(oprrest,
+ opno,
+ relid,
+ attno,
+ (char *) constval,
+ flag);
+
+ }
else
- if (attno == InvalidAttrNumber) {
- /* attno can be Invalid if the clause had a function in it,
- i.e. WHERE myFunc(f) = 10 */
- /* this should be FIXED somehow to use function selectivity */
- s1 = (Cost) (0.5);
- } else
- s1 = (Cost) restriction_selectivity(oprrest,
- opno,
- relid,
- attno,
- (char *)constval,
- flag);
-
- } else {
- /* The clause must be a join clause. The clause
- * selectivity will be based on the relations to be
- * scanned and the attributes they are to be joined
- * on.
+ {
+
+ /*
+ * The clause must be a join clause. The clause selectivity will
+ * be based on the relations to be scanned and the attributes they
+ * are to be joined on.
+ */
+ Oid opno = ((Oper *) ((Expr *) clause)->oper)->opno;
+ RegProcedure oprjoin = get_oprjoin(opno);
+ int relid1,
+ relid2;
+ AttrNumber attno1,
+ attno2;
+
+ get_rels_atts((Node *) clause, &relid1, &attno1, &relid2, &attno2);
+ relid1 = getrelid(relid1, root->rtable);
+ relid2 = getrelid(relid2, root->rtable);
+
+ /*
+ * if the oprjoin procedure is missing for whatever reason, use a
+ * selectivity of 0.5
+ */
+ if (!oprjoin)
+ s1 = (Cost) (0.5);
+ else
+ s1 = (Cost) join_selectivity(oprjoin,
+ opno,
+ relid1,
+ attno1,
+ relid2,
+ attno2);
+ }
+
+ /*
+ * A null clause list eliminates no tuples, so return a selectivity of
+ * 1.0. If there is only one clause, the selectivity is not that of
+ * an 'or' clause, but rather that of the single clause.
*/
- Oid opno = ((Oper*)((Expr*)clause)->oper)->opno;
- RegProcedure oprjoin = get_oprjoin (opno);
- int relid1, relid2;
- AttrNumber attno1, attno2;
-
- get_rels_atts((Node*)clause, &relid1, &attno1, &relid2, &attno2);
- relid1 = getrelid(relid1, root->rtable);
- relid2 = getrelid(relid2, root->rtable);
-
- /* if the oprjoin procedure is missing for whatever reason,
- use a selectivity of 0.5*/
- if (!oprjoin)
- s1 = (Cost) (0.5);
- else
- s1 = (Cost) join_selectivity(oprjoin,
- opno,
- relid1,
- attno1,
- relid2,
- attno2);
- }
-
- /* A null clause list eliminates no tuples, so return a selectivity
- * of 1.0. If there is only one clause, the selectivity is not
- * that of an 'or' clause, but rather that of the single clause.
- */
-
- if (length (clauses) < 2) {
- return(s1);
- } else {
- /* Compute selectivity of the 'or'ed subclauses. */
- /* Added check for taking lnext(NIL). -- JMH 3/9/92 */
- Cost s2;
-
- if (or_selectivities != NIL)
- s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
+
+ if (length(clauses) < 2)
+ {
+ return (s1);
+ }
else
- s2 = compute_selec(root, lnext(clauses), NIL);
- return(s1 + s2 - s1 * s2);
- }
-}
+ {
+ /* Compute selectivity of the 'or'ed subclauses. */
+ /* Added check for taking lnext(NIL). -- JMH 3/9/92 */
+ Cost s2;
+ if (or_selectivities != NIL)
+ s2 = compute_selec(root, lnext(clauses), lnext(or_selectivities));
+ else
+ s2 = compute_selec(root, lnext(clauses), NIL);
+ return (s1 + s2 - s1 * s2);
+ }
+}
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 35453fb3870..2873e62c48c 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* costsize.c--
- * Routines to compute (and set) relation sizes and path costs
+ * Routines to compute (and set) relation sizes and path costs
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.16 1997/08/19 21:31:48 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.17 1997/09/07 04:43:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,15 +17,15 @@
#include <math.h>
#ifdef HAVE_LIMITS_H
-# include <limits.h>
-# ifndef MAXINT
-# define MAXINT INT_MAX
-# endif
+#include <limits.h>
+#ifndef MAXINT
+#define MAXINT INT_MAX
+#endif
#else
-# ifdef HAVE_VALUES_H
-# include <values.h>
-# endif
-#endif
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+#endif
#include <utils/lsyscache.h>
#include "nodes/relation.h"
@@ -35,77 +35,81 @@
#include "optimizer/keys.h"
#include "optimizer/tlist.h"
-#include "storage/bufmgr.h" /* for BLCKSZ */
+#include "storage/bufmgr.h" /* for BLCKSZ */
-extern int NBuffers;
+extern int NBuffers;
-static int compute_attribute_width(TargetEntry *tlistentry);
-static double base_log(double x, double b);
-static int compute_targetlist_width(List *targetlist);
+static int compute_attribute_width(TargetEntry * tlistentry);
+static double base_log(double x, double b);
+static int compute_targetlist_width(List * targetlist);
-int _disable_cost_ = 30000000;
-
-bool _enable_seqscan_ = true;
-bool _enable_indexscan_ = true;
-bool _enable_sort_ = true;
-bool _enable_hash_ = true;
-bool _enable_nestloop_ = true;
-bool _enable_mergesort_ = true;
-bool _enable_hashjoin_ = true;
+int _disable_cost_ = 30000000;
-Cost _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
-Cost _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
+bool _enable_seqscan_ = true;
+bool _enable_indexscan_ = true;
+bool _enable_sort_ = true;
+bool _enable_hash_ = true;
+bool _enable_nestloop_ = true;
+bool _enable_mergesort_ = true;
+bool _enable_hashjoin_ = true;
-/*
+Cost _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
+Cost _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
+
+/*
* cost_seqscan--
- * Determines and returns the cost of scanning a relation sequentially.
- * If the relation is a temporary to be materialized from a query
- * embedded within a data field (determined by 'relid' containing an
- * attribute reference), then a predetermined constant is returned (we
- * have NO IDEA how big the result of a POSTQUEL procedure is going to
- * be).
- *
- * disk = p
- * cpu = *CPU-PAGE-WEIGHT* * t
- *
+ * Determines and returns the cost of scanning a relation sequentially.
+ * If the relation is a temporary to be materialized from a query
+ * embedded within a data field (determined by 'relid' containing an
+ * attribute reference), then a predetermined constant is returned (we
+ * have NO IDEA how big the result of a POSTQUEL procedure is going to
+ * be).
+ *
+ * disk = p
+ * cpu = *CPU-PAGE-WEIGHT* * t
+ *
* 'relid' is the relid of the relation to be scanned
* 'relpages' is the number of pages in the relation to be scanned
- * (as determined from the system catalogs)
+ * (as determined from the system catalogs)
* 'reltuples' is the number of tuples in the relation to be scanned
- *
+ *
* Returns a flonum.
- *
+ *
*/
Cost
cost_seqscan(int relid, int relpages, int reltuples)
{
- Cost temp = 0;
+ Cost temp = 0;
- if ( !_enable_seqscan_ )
- temp += _disable_cost_;
+ if (!_enable_seqscan_)
+ temp += _disable_cost_;
- if (relid < 0) {
- /*
- * cost of sequentially scanning a materialized temporary relation
- */
- temp += _TEMP_SCAN_COST_;
- } else {
- temp += relpages;
- temp += _cpu_page_wight_ * reltuples;
- }
- Assert(temp >= 0);
- return(temp);
+ if (relid < 0)
+ {
+
+ /*
+ * cost of sequentially scanning a materialized temporary relation
+ */
+ temp += _TEMP_SCAN_COST_;
+ }
+ else
+ {
+ temp += relpages;
+ temp += _cpu_page_wight_ * reltuples;
+ }
+ Assert(temp >= 0);
+ return (temp);
}
-/*
+/*
* cost_index--
- * Determines and returns the cost of scanning a relation using an index.
- *
- * disk = expected-index-pages + expected-data-pages
- * cpu = *CPU-PAGE-WEIGHT* *
- * (expected-index-tuples + expected-data-tuples)
- *
+ * Determines and returns the cost of scanning a relation using an index.
+ *
+ * disk = expected-index-pages + expected-data-pages
+ * cpu = *CPU-PAGE-WEIGHT* *
+ * (expected-index-tuples + expected-data-tuples)
+ *
* 'indexid' is the index OID
* 'expected-indexpages' is the number of index pages examined in the scan
* 'selec' is the selectivity of the index
@@ -113,100 +117,102 @@ cost_seqscan(int relid, int relpages, int reltuples)
* 'reltuples' is the number of tuples in the main relation
* 'indexpages' is the number of pages in the index relation
* 'indextuples' is the number of tuples in the index relation
- *
+ *
* Returns a flonum.
- *
+ *
*/
Cost
cost_index(Oid indexid,
- int expected_indexpages,
- Cost selec,
- int relpages,
- int reltuples,
- int indexpages,
- int indextuples,
- bool is_injoin)
+ int expected_indexpages,
+ Cost selec,
+ int relpages,
+ int reltuples,
+ int indexpages,
+ int indextuples,
+ bool is_injoin)
{
- Cost temp;
- double temp2;
+ Cost temp;
+ double temp2;
+
+ temp = (Cost) 0;
- temp = (Cost) 0;
+ if (!_enable_indexscan_ && !is_injoin)
+ temp += _disable_cost_;
- if (!_enable_indexscan_ && !is_injoin)
- temp += _disable_cost_;
+ /* expected index relation pages */
+ temp += expected_indexpages;
- /* expected index relation pages */
- temp += expected_indexpages;
+ /* expected base relation pages */
+ temp2 = (reltuples == 0) ? (double) 0 : (double) relpages / reltuples;
+ temp2 = temp2 * (double) selec *indextuples;
- /* expected base relation pages */
- temp2 = ( reltuples == 0 ) ? (double)0 : (double)relpages/reltuples;
- temp2 = temp2 * (double)selec * indextuples;
- temp += Min (relpages, (int)ceil (temp2));
+ temp += Min(relpages, (int) ceil(temp2));
- /* per index tuples */
- temp = temp + (_cpu_index_page_wight_ * selec * indextuples);
+ /* per index tuples */
+ temp = temp + (_cpu_index_page_wight_ * selec * indextuples);
- /* per heap tuples */
- temp = temp + (_cpu_page_wight_ * selec * reltuples);
+ /* per heap tuples */
+ temp = temp + (_cpu_page_wight_ * selec * reltuples);
- Assert(temp >= 0);
- return(temp);
+ Assert(temp >= 0);
+ return (temp);
}
-/*
+/*
* cost_sort--
- * Determines and returns the cost of sorting a relation by considering
- * 1. the cost of doing an external sort: XXX this is probably too low
- * disk = (p lg p)
- * cpu = *CPU-PAGE-WEIGHT* * (t lg t)
- * 2. the cost of reading the sort result into memory (another seqscan)
- * unless 'noread' is set
- *
+ * Determines and returns the cost of sorting a relation by considering
+ * 1. the cost of doing an external sort: XXX this is probably too low
+ * disk = (p lg p)
+ * cpu = *CPU-PAGE-WEIGHT* * (t lg t)
+ * 2. the cost of reading the sort result into memory (another seqscan)
+ * unless 'noread' is set
+ *
* 'keys' is a list of sort keys
* 'tuples' is the number of tuples in the relation
* 'width' is the average tuple width in bytes
* 'noread' is a flag indicating that the sort result can remain on disk
- * (i.e., the sort result is the result relation)
- *
+ * (i.e., the sort result is the result relation)
+ *
* Returns a flonum.
- *
+ *
*/
Cost
-cost_sort(List *keys, int tuples, int width, bool noread)
+cost_sort(List * keys, int tuples, int width, bool noread)
{
- Cost temp = 0;
- int npages = page_size (tuples,width);
- Cost pages = (Cost)npages;
- Cost numTuples = tuples;
-
- if ( !_enable_sort_ )
- temp += _disable_cost_ ;
- if (tuples == 0 || keys==NULL)
+ Cost temp = 0;
+ int npages = page_size(tuples, width);
+ Cost pages = (Cost) npages;
+ Cost numTuples = tuples;
+
+ if (!_enable_sort_)
+ temp += _disable_cost_;
+ if (tuples == 0 || keys == NULL)
{
- Assert(temp >= 0);
- return(temp);
+ Assert(temp >= 0);
+ return (temp);
}
- temp += pages * base_log((double)pages, (double)2.0);
+ temp += pages * base_log((double) pages, (double) 2.0);
- /*
- * could be base_log(pages, NBuffers), but we are only doing 2-way merges
- */
- temp += _cpu_page_wight_ *
- numTuples * base_log((double)pages,(double)2.0);
+ /*
+ * could be base_log(pages, NBuffers), but we are only doing 2-way
+ * merges
+ */
+ temp += _cpu_page_wight_ *
+ numTuples * base_log((double) pages, (double) 2.0);
- if( !noread )
- temp = temp + cost_seqscan(_TEMP_RELATION_ID_, npages, tuples);
- Assert(temp >= 0);
+ if (!noread)
+ temp = temp + cost_seqscan(_TEMP_RELATION_ID_, npages, tuples);
+ Assert(temp >= 0);
- return(temp);
+ return (temp);
}
-/*
+/*
* cost_result--
- * Determines and returns the cost of writing a relation of 'tuples'
- * tuples of 'width' bytes out to a result relation.
- *
+ * Determines and returns the cost of writing a relation of 'tuples'
+ * tuples of 'width' bytes out to a result relation.
+ *
* Returns a flonum.
*
*/
@@ -214,257 +220,273 @@ cost_sort(List *keys, int tuples, int width, bool noread)
Cost
cost_result(int tuples, int width)
{
- Cost temp =0;
- temp = temp + page_size(tuples,width);
- temp = temp + _cpu_page_wight_ * tuples;
- Assert(temp >= 0);
- return(temp);
+ Cost temp = 0;
+
+ temp = temp + page_size(tuples, width);
+ temp = temp + _cpu_page_wight_ * tuples;
+ Assert(temp >= 0);
+ return (temp);
}
+
#endif
-/*
+/*
* cost_nestloop--
- * Determines and returns the cost of joining two relations using the
- * nested loop algorithm.
- *
+ * Determines and returns the cost of joining two relations using the
+ * nested loop algorithm.
+ *
* 'outercost' is the (disk+cpu) cost of scanning the outer relation
* 'innercost' is the (disk+cpu) cost of scanning the inner relation
* 'outertuples' is the number of tuples in the outer relation
- *
+ *
* Returns a flonum.
*
*/
Cost
cost_nestloop(Cost outercost,
- Cost innercost,
- int outertuples,
- int innertuples,
- int outerpages,
- bool is_indexjoin)
+ Cost innercost,
+ int outertuples,
+ int innertuples,
+ int outerpages,
+ bool is_indexjoin)
{
- Cost temp =0;
+ Cost temp = 0;
- if ( !_enable_nestloop_ )
- temp += _disable_cost_;
- temp += outercost;
- temp += outertuples * innercost;
- Assert(temp >= 0);
+ if (!_enable_nestloop_)
+ temp += _disable_cost_;
+ temp += outercost;
+ temp += outertuples * innercost;
+ Assert(temp >= 0);
- return(temp);
+ return (temp);
}
-/*
+/*
* cost_mergesort--
- * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
- * outer and inner relations
- * 'outersortkeys' and 'innersortkeys' are lists of the keys to be used
- * to sort the outer and inner relations
- * 'outertuples' and 'innertuples' are the number of tuples in the outer
- * and inner relations
- * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
- * of the tuples of the outer and inner relations
- *
+ * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
+ * outer and inner relations
+ * 'outersortkeys' and 'innersortkeys' are lists of the keys to be used
+ * to sort the outer and inner relations
+ * 'outertuples' and 'innertuples' are the number of tuples in the outer
+ * and inner relations
+ * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
+ * of the tuples of the outer and inner relations
+ *
* Returns a flonum.
- *
+ *
*/
Cost
cost_mergesort(Cost outercost,
- Cost innercost,
- List *outersortkeys,
- List *innersortkeys,
- int outersize,
- int innersize,
- int outerwidth,
- int innerwidth)
+ Cost innercost,
+ List * outersortkeys,
+ List * innersortkeys,
+ int outersize,
+ int innersize,
+ int outerwidth,
+ int innerwidth)
{
- Cost temp = 0;
-
- if ( !_enable_mergesort_ )
- temp += _disable_cost_;
-
- temp += outercost;
- temp += innercost;
- temp += cost_sort(outersortkeys,outersize,outerwidth,false);
- temp += cost_sort(innersortkeys,innersize,innerwidth,false);
- temp += _cpu_page_wight_ * (outersize + innersize);
- Assert(temp >= 0);
-
- return(temp);
+ Cost temp = 0;
+
+ if (!_enable_mergesort_)
+ temp += _disable_cost_;
+
+ temp += outercost;
+ temp += innercost;
+ temp += cost_sort(outersortkeys, outersize, outerwidth, false);
+ temp += cost_sort(innersortkeys, innersize, innerwidth, false);
+ temp += _cpu_page_wight_ * (outersize + innersize);
+ Assert(temp >= 0);
+
+ return (temp);
}
-/*
- * cost_hashjoin-- XXX HASH
- * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
- * outer and inner relations
- * 'outerkeys' and 'innerkeys' are lists of the keys to be used
- * to hash the outer and inner relations
- * 'outersize' and 'innersize' are the number of tuples in the outer
- * and inner relations
- * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
- * of the tuples of the outer and inner relations
- *
+/*
+ * cost_hashjoin-- XXX HASH
+ * 'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
+ * outer and inner relations
+ * 'outerkeys' and 'innerkeys' are lists of the keys to be used
+ * to hash the outer and inner relations
+ * 'outersize' and 'innersize' are the number of tuples in the outer
+ * and inner relations
+ * 'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
+ * of the tuples of the outer and inner relations
+ *
* Returns a flonum.
*/
Cost
cost_hashjoin(Cost outercost,
- Cost innercost,
- List *outerkeys,
- List *innerkeys,
- int outersize,
- int innersize,
- int outerwidth,
- int innerwidth)
+ Cost innercost,
+ List * outerkeys,
+ List * innerkeys,
+ int outersize,
+ int innersize,
+ int outerwidth,
+ int innerwidth)
{
- Cost temp = 0;
- int outerpages = page_size (outersize,outerwidth);
- int innerpages = page_size (innersize,innerwidth);
- int nrun = ceil((double)outerpages/(double)NBuffers);
-
- if (outerpages < innerpages)
- return _disable_cost_;
- if ( !_enable_hashjoin_ )
- temp += _disable_cost_;
- /*
- temp += outercost + (nrun + 1) * innercost;
- *
- * the innercost shouldn't be used it. Instead the
- * cost of hashing the innerpath should be used
- *
- * ASSUME innercost is 1 for now -- a horrible hack
- * - jolly
- temp += outercost + (nrun + 1);
- *
- * But we must add innercost to result. - vadim 04/24/97
- */
- temp += outercost + innercost + (nrun + 1);
-
- temp += _cpu_page_wight_ * (outersize + nrun * innersize);
- Assert(temp >= 0);
-
- return(temp);
+ Cost temp = 0;
+ int outerpages = page_size(outersize, outerwidth);
+ int innerpages = page_size(innersize, innerwidth);
+ int nrun = ceil((double) outerpages / (double) NBuffers);
+
+ if (outerpages < innerpages)
+ return _disable_cost_;
+ if (!_enable_hashjoin_)
+ temp += _disable_cost_;
+
+ /*
+ * temp += outercost + (nrun + 1) * innercost;
+ *
+ * the innercost shouldn't be used it. Instead the cost of hashing the
+ * innerpath should be used
+ *
+ * ASSUME innercost is 1 for now -- a horrible hack - jolly temp +=
+ * outercost + (nrun + 1);
+ *
+ * But we must add innercost to result. - vadim 04/24/97
+ */
+ temp += outercost + innercost + (nrun + 1);
+
+ temp += _cpu_page_wight_ * (outersize + nrun * innersize);
+ Assert(temp >= 0);
+
+ return (temp);
}
-/*
+/*
* compute-rel-size--
- * Computes the size of each relation in 'rel-list' (after applying
- * restrictions), by multiplying the selectivity of each restriction
- * by the original size of the relation.
- *
- * Sets the 'size' field for each relation entry with this computed size.
- *
+ * Computes the size of each relation in 'rel-list' (after applying
+ * restrictions), by multiplying the selectivity of each restriction
+ * by the original size of the relation.
+ *
+ * Sets the 'size' field for each relation entry with this computed size.
+ *
* Returns the size.
*/
-int compute_rel_size(Rel *rel)
+int
+compute_rel_size(Rel * rel)
{
- Cost temp;
- int temp1;
-
- temp = rel->tuples * product_selec(rel->clauseinfo);
- Assert(temp >= 0);
- if (temp >= (MAXINT - 1)) {
- temp1 = MAXINT;
- } else {
- temp1 = ceil((double) temp);
- }
- Assert(temp1 >= 0);
- Assert(temp1 <= MAXINT);
- return(temp1);
+ Cost temp;
+ int temp1;
+
+ temp = rel->tuples * product_selec(rel->clauseinfo);
+ Assert(temp >= 0);
+ if (temp >= (MAXINT - 1))
+ {
+ temp1 = MAXINT;
+ }
+ else
+ {
+ temp1 = ceil((double) temp);
+ }
+ Assert(temp1 >= 0);
+ Assert(temp1 <= MAXINT);
+ return (temp1);
}
-/*
+/*
* compute-rel-width--
- * Computes the width in bytes of a tuple from 'rel'.
- *
+ * Computes the width in bytes of a tuple from 'rel'.
+ *
* Returns the width of the tuple as a fixnum.
*/
int
-compute_rel_width(Rel *rel)
+compute_rel_width(Rel * rel)
{
- return (compute_targetlist_width(get_actual_tlist(rel->targetlist)));
+ return (compute_targetlist_width(get_actual_tlist(rel->targetlist)));
}
-/*
+/*
* compute-targetlist-width--
- * Computes the width in bytes of a tuple made from 'targetlist'.
- *
+ * Computes the width in bytes of a tuple made from 'targetlist'.
+ *
* Returns the width of the tuple as a fixnum.
*/
static int
-compute_targetlist_width(List *targetlist)
+compute_targetlist_width(List * targetlist)
{
- List *temp_tl;
- int tuple_width = 0;
-
- foreach (temp_tl, targetlist) {
- tuple_width = tuple_width +
- compute_attribute_width(lfirst(temp_tl));
- }
- return(tuple_width);
+ List *temp_tl;
+ int tuple_width = 0;
+
+ foreach(temp_tl, targetlist)
+ {
+ tuple_width = tuple_width +
+ compute_attribute_width(lfirst(temp_tl));
+ }
+ return (tuple_width);
}
-/*
+/*
* compute-attribute-width--
- * Given a target list entry, find the size in bytes of the attribute.
- *
- * If a field is variable-length, it is assumed to be at least the size
- * of a TID field.
- *
+ * Given a target list entry, find the size in bytes of the attribute.
+ *
+ * If a field is variable-length, it is assumed to be at least the size
+ * of a TID field.
+ *
* Returns the width of the attribute as a fixnum.
*/
static int
-compute_attribute_width(TargetEntry *tlistentry)
+compute_attribute_width(TargetEntry * tlistentry)
{
- int width = get_typlen(tlistentry->resdom->restype);
- if (width < 0)
- return(_DEFAULT_ATTRIBUTE_WIDTH_);
- else
- return(width);
+ int width = get_typlen(tlistentry->resdom->restype);
+
+ if (width < 0)
+ return (_DEFAULT_ATTRIBUTE_WIDTH_);
+ else
+ return (width);
}
-/*
+/*
* compute-joinrel-size--
- * Computes the size of the join relation 'joinrel'.
- *
+ * Computes the size of the join relation 'joinrel'.
+ *
* Returns a fixnum.
*/
int
-compute_joinrel_size(JoinPath *joinpath)
+compute_joinrel_size(JoinPath * joinpath)
{
- Cost temp = 1.0;
- int temp1 = 0;
-
- temp *= ((Path*)joinpath->outerjoinpath)->parent->size;
- temp *= ((Path*)joinpath->innerjoinpath)->parent->size;
-
- temp = temp * product_selec(joinpath->pathclauseinfo);
- if (temp >= (MAXINT -1)) {
- temp1 = MAXINT;
- } else {
- /* should be ceil here, we don't want joinrel size's of one, do we? */
- temp1 = ceil((double)temp);
- }
- Assert(temp1 >= 0);
-
- return(temp1);
+ Cost temp = 1.0;
+ int temp1 = 0;
+
+ temp *= ((Path *) joinpath->outerjoinpath)->parent->size;
+ temp *= ((Path *) joinpath->innerjoinpath)->parent->size;
+
+ temp = temp * product_selec(joinpath->pathclauseinfo);
+ if (temp >= (MAXINT - 1))
+ {
+ temp1 = MAXINT;
+ }
+ else
+ {
+
+ /*
+ * should be ceil here, we don't want joinrel size's of one, do
+ * we?
+ */
+ temp1 = ceil((double) temp);
+ }
+ Assert(temp1 >= 0);
+
+ return (temp1);
}
-/*
+/*
* page-size--
- * Returns an estimate of the number of pages covered by a given
- * number of tuples of a given width (size in bytes).
+ * Returns an estimate of the number of pages covered by a given
+ * number of tuples of a given width (size in bytes).
*/
-int page_size(int tuples, int width)
+int
+page_size(int tuples, int width)
{
- int temp =0;
+ int temp = 0;
- temp = ceil((double)(tuples * (width + sizeof(HeapTupleData)))
- / BLCKSZ);
- Assert(temp >= 0);
- return(temp);
+ temp = ceil((double) (tuples * (width + sizeof(HeapTupleData)))
+ / BLCKSZ);
+ Assert(temp >= 0);
+ return (temp);
}
static double
base_log(double x, double b)
{
- return(log(x)/log(b));
+ return (log(x) / log(b));
}
diff --git a/src/backend/optimizer/path/hashutils.c b/src/backend/optimizer/path/hashutils.c
index cdbd9b6d901..5ec592ad1f9 100644
--- a/src/backend/optimizer/path/hashutils.c
+++ b/src/backend/optimizer/path/hashutils.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* hashutils.c--
- * Utilities for finding applicable merge clauses and pathkeys
+ * Utilities for finding applicable merge clauses and pathkeys
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/hashutils.c,v 1.1.1.1 1996/07/09 06:21:35 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/hashutils.c,v 1.2 1997/09/07 04:43:34 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,101 +20,109 @@
#include "optimizer/clauses.h"
-static HInfo *match_hashop_hashinfo(Oid hashop, List *hashinfo_list);
+static HInfo *match_hashop_hashinfo(Oid hashop, List * hashinfo_list);
-/*
+/*
* group-clauses-by-hashop--
- * If a join clause node in 'clauseinfo-list' is hashjoinable, store
- * it within a hashinfo node containing other clause nodes with the same
- * hash operator.
- *
+ * If a join clause node in 'clauseinfo-list' is hashjoinable, store
+ * it within a hashinfo node containing other clause nodes with the same
+ * hash operator.
+ *
* 'clauseinfo-list' is the list of clauseinfo nodes
* 'inner-relid' is the relid of the inner join relation
- *
+ *
* Returns the new list of hashinfo nodes.
- *
+ *
*/
-List *
-group_clauses_by_hashop(List *clauseinfo_list,
- int inner_relid)
+List *
+group_clauses_by_hashop(List * clauseinfo_list,
+ int inner_relid)
{
- List *hashinfo_list = NIL;
- CInfo *clauseinfo = (CInfo*)NULL;
- List *i = NIL;
- Oid hashjoinop = 0;
-
- foreach (i,clauseinfo_list) {
- clauseinfo = (CInfo*)lfirst(i);
- hashjoinop = clauseinfo->hashjoinoperator;
-
- /*
- * Create a new hashinfo node and add it to 'hashinfo-list' if one
- * does not yet exist for this hash operator.
- */
- if (hashjoinop ) {
- HInfo *xhashinfo = (HInfo*)NULL;
- Expr *clause = clauseinfo->clause;
- Var *leftop = get_leftop(clause);
- Var *rightop = get_rightop(clause);
- JoinKey *keys = (JoinKey*)NULL;
-
- xhashinfo =
- match_hashop_hashinfo(hashjoinop,hashinfo_list);
-
- if (inner_relid == leftop->varno){
- keys = makeNode(JoinKey);
- keys->outer = rightop;
- keys->inner = leftop;
- } else {
- keys = makeNode(JoinKey);
- keys->outer = leftop;
- keys->inner = rightop;
- }
-
- if (xhashinfo==NULL) {
- xhashinfo = makeNode(HInfo);
- xhashinfo->hashop = hashjoinop;
-
- xhashinfo->jmethod.jmkeys = NIL;
- xhashinfo->jmethod.clauses = NIL;
-
- /* XXX was push */
- hashinfo_list = lappend(hashinfo_list,xhashinfo);
- hashinfo_list = nreverse(hashinfo_list);
- }
-
- xhashinfo->jmethod.clauses =
- lcons(clause, xhashinfo->jmethod.clauses);
-
- xhashinfo->jmethod.jmkeys =
- lcons(keys, xhashinfo->jmethod.jmkeys);
+ List *hashinfo_list = NIL;
+ CInfo *clauseinfo = (CInfo *) NULL;
+ List *i = NIL;
+ Oid hashjoinop = 0;
+
+ foreach(i, clauseinfo_list)
+ {
+ clauseinfo = (CInfo *) lfirst(i);
+ hashjoinop = clauseinfo->hashjoinoperator;
+
+ /*
+ * Create a new hashinfo node and add it to 'hashinfo-list' if one
+ * does not yet exist for this hash operator.
+ */
+ if (hashjoinop)
+ {
+ HInfo *xhashinfo = (HInfo *) NULL;
+ Expr *clause = clauseinfo->clause;
+ Var *leftop = get_leftop(clause);
+ Var *rightop = get_rightop(clause);
+ JoinKey *keys = (JoinKey *) NULL;
+
+ xhashinfo =
+ match_hashop_hashinfo(hashjoinop, hashinfo_list);
+
+ if (inner_relid == leftop->varno)
+ {
+ keys = makeNode(JoinKey);
+ keys->outer = rightop;
+ keys->inner = leftop;
+ }
+ else
+ {
+ keys = makeNode(JoinKey);
+ keys->outer = leftop;
+ keys->inner = rightop;
+ }
+
+ if (xhashinfo == NULL)
+ {
+ xhashinfo = makeNode(HInfo);
+ xhashinfo->hashop = hashjoinop;
+
+ xhashinfo->jmethod.jmkeys = NIL;
+ xhashinfo->jmethod.clauses = NIL;
+
+ /* XXX was push */
+ hashinfo_list = lappend(hashinfo_list, xhashinfo);
+ hashinfo_list = nreverse(hashinfo_list);
+ }
+
+ xhashinfo->jmethod.clauses =
+ lcons(clause, xhashinfo->jmethod.clauses);
+
+ xhashinfo->jmethod.jmkeys =
+ lcons(keys, xhashinfo->jmethod.jmkeys);
+ }
}
- }
- return(hashinfo_list);
+ return (hashinfo_list);
}
-/*
+/*
* match-hashop-hashinfo--
- * Searches the list 'hashinfo-list' for a hashinfo node whose hash op
- * field equals 'hashop'.
- *
+ * Searches the list 'hashinfo-list' for a hashinfo node whose hash op
+ * field equals 'hashop'.
+ *
* Returns the node if it exists.
- *
+ *
*/
-static HInfo *
-match_hashop_hashinfo(Oid hashop, List *hashinfo_list)
+static HInfo *
+match_hashop_hashinfo(Oid hashop, List * hashinfo_list)
{
- Oid key = 0;
- HInfo *xhashinfo = (HInfo*)NULL;
- List *i = NIL;
-
- foreach( i, hashinfo_list) {
- xhashinfo = (HInfo*)lfirst(i);
- key = xhashinfo->hashop;
- if (hashop == key) { /* found */
- return(xhashinfo); /* should be a hashinfo node ! */
+ Oid key = 0;
+ HInfo *xhashinfo = (HInfo *) NULL;
+ List *i = NIL;
+
+ foreach(i, hashinfo_list)
+ {
+ xhashinfo = (HInfo *) lfirst(i);
+ key = xhashinfo->hashop;
+ if (hashop == key)
+ { /* found */
+ return (xhashinfo); /* should be a hashinfo node ! */
+ }
}
- }
- return((HInfo*)NIL);
+ return ((HInfo *) NIL);
}
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index f5b70e43a0f..bd9bc15ace0 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* indxpath.c--
- * Routines to determine which indices are usable for scanning a
- * given relation
+ * Routines to determine which indices are usable for scanning a
+ * given relation
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.8 1997/08/12 22:53:12 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.9 1997/09/07 04:43:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,308 +43,321 @@
#include "catalog/pg_proc.h"
#include "executor/executor.h"
-#include "parser/parsetree.h" /* for getrelid() */
-
-
-static void match_index_orclauses(Rel *rel, Rel *index, int indexkey,
- int xclass, List *clauseinfo_list);
-static bool match_index_to_operand(int indexkey, Expr *operand,
- Rel *rel, Rel *index);
-static List *match_index_orclause(Rel *rel, Rel *index, int indexkey,
- int xclass, List *or_clauses, List *other_matching_indices);
-static List *group_clauses_by_indexkey(Rel *rel, Rel *index,
- int *indexkeys, Oid *classes, List *clauseinfo_list);
-static List *group_clauses_by_ikey_for_joins(Rel *rel, Rel *index,
- int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list);
-static CInfo *match_clause_to_indexkey(Rel *rel, Rel *index, int indexkey,
- int xclass, CInfo *clauseInfo, bool join);
-static bool pred_test(List *predicate_list, List *clauseinfo_list,
- List *joininfo_list);
-static bool one_pred_test(Expr *predicate, List *clauseinfo_list);
-static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
-static bool one_pred_clause_test(Expr *predicate, Node *clause);
-static bool clause_pred_clause_test(Expr *predicate, Node *clause);
-static List *indexable_joinclauses (Rel *rel, Rel *index,
- List *joininfo_list, List *clauseinfo_list);
-static List *index_innerjoin(Query *root, Rel *rel,
- List *clausegroup_list, Rel *index);
-static List *create_index_paths(Query *root, Rel *rel, Rel *index,
- List *clausegroup_list, bool join);
-static List *add_index_paths(List *indexpaths, List *new_indexpaths);
-static bool function_index_operand(Expr *funcOpnd, Rel *rel, Rel *index);
-static bool SingleAttributeIndex(Rel *index);
+#include "parser/parsetree.h" /* for getrelid() */
+
+
+static void
+match_index_orclauses(Rel * rel, Rel * index, int indexkey,
+ int xclass, List * clauseinfo_list);
+static bool
+match_index_to_operand(int indexkey, Expr * operand,
+ Rel * rel, Rel * index);
+static List *
+match_index_orclause(Rel * rel, Rel * index, int indexkey,
+ int xclass, List * or_clauses, List * other_matching_indices);
+static List *
+group_clauses_by_indexkey(Rel * rel, Rel * index,
+ int *indexkeys, Oid * classes, List * clauseinfo_list);
+static List *
+group_clauses_by_ikey_for_joins(Rel * rel, Rel * index,
+ int *indexkeys, Oid * classes, List * join_cinfo_list, List * restr_cinfo_list);
+static CInfo *
+match_clause_to_indexkey(Rel * rel, Rel * index, int indexkey,
+ int xclass, CInfo * clauseInfo, bool join);
+static bool
+pred_test(List * predicate_list, List * clauseinfo_list,
+ List * joininfo_list);
+static bool one_pred_test(Expr * predicate, List * clauseinfo_list);
+static bool one_pred_clause_expr_test(Expr * predicate, Node * clause);
+static bool one_pred_clause_test(Expr * predicate, Node * clause);
+static bool clause_pred_clause_test(Expr * predicate, Node * clause);
+static List *
+indexable_joinclauses(Rel * rel, Rel * index,
+ List * joininfo_list, List * clauseinfo_list);
+static List *
+index_innerjoin(Query * root, Rel * rel,
+ List * clausegroup_list, Rel * index);
+static List *
+create_index_paths(Query * root, Rel * rel, Rel * index,
+ List * clausegroup_list, bool join);
+static List *add_index_paths(List * indexpaths, List * new_indexpaths);
+static bool function_index_operand(Expr * funcOpnd, Rel * rel, Rel * index);
+static bool SingleAttributeIndex(Rel * index);
/* If Spyros can use a constant PRS2_BOOL_TYPEID, I can use this */
#define BOOL_TYPEID ((Oid) 16)
-/*
+/*
* find-index-paths--
- * Finds all possible index paths by determining which indices in the
- * list 'indices' are usable.
- *
- * To be usable, an index must match against either a set of
- * restriction clauses or join clauses.
- *
- * Note that the current implementation requires that there exist
- * matching clauses for every key in the index (i.e., no partial
- * matches are allowed).
- *
- * If an index can't be used with restriction clauses, but its keys
- * match those of the result sort order (according to information stored
- * within 'sortkeys'), then the index is also considered.
+ * Finds all possible index paths by determining which indices in the
+ * list 'indices' are usable.
+ *
+ * To be usable, an index must match against either a set of
+ * restriction clauses or join clauses.
+ *
+ * Note that the current implementation requires that there exist
+ * matching clauses for every key in the index (i.e., no partial
+ * matches are allowed).
+ *
+ * If an index can't be used with restriction clauses, but its keys
+ * match those of the result sort order (according to information stored
+ * within 'sortkeys'), then the index is also considered.
*
* 'rel' is the relation entry to which these index paths correspond
* 'indices' is a list of possible index paths
* 'clauseinfo-list' is a list of restriction clauseinfo nodes for 'rel'
* 'joininfo-list' is a list of joininfo nodes for 'rel'
* 'sortkeys' is a node describing the result sort order (from
- * (find_sortkeys))
- *
+ * (find_sortkeys))
+ *
* Returns a list of index nodes.
- *
+ *
*/
-List *
-find_index_paths (Query *root,
- Rel *rel,
- List *indices,
- List *clauseinfo_list,
- List *joininfo_list)
+List *
+find_index_paths(Query * root,
+ Rel * rel,
+ List * indices,
+ List * clauseinfo_list,
+ List * joininfo_list)
{
- List *scanclausegroups = NIL;
- List *scanpaths = NIL;
- Rel *index = (Rel *)NULL;
- List *joinclausegroups = NIL;
- List *joinpaths = NIL;
- List *retval = NIL;
-
- if(indices == NIL)
- return(NULL);
-
- index = (Rel*)lfirst (indices);
-
- retval = find_index_paths(root,
- rel,
- lnext (indices),
- clauseinfo_list,
- joininfo_list);
-
- /* If this is a partial index, return if it fails the predicate test */
- if (index->indpred != NIL)
- if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
- return retval;
-
- /* 1. If this index has only one key, try matching it against
- * subclauses of an 'or' clause. The fields of the clauseinfo
- * nodes are marked with lists of the matching indices no path
- * are actually created.
- *
- * XXX NOTE: Currently btrees dos not support indices with
- * > 1 key, so the following test will always be true for
- * now but we have decided not to support index-scans
- * on disjunction . -- lp
- */
- if (SingleAttributeIndex(index))
- {
- match_index_orclauses (rel,
- index,
- index->indexkeys[0],
- index->classlist[0],
- clauseinfo_list);
- }
+ List *scanclausegroups = NIL;
+ List *scanpaths = NIL;
+ Rel *index = (Rel *) NULL;
+ List *joinclausegroups = NIL;
+ List *joinpaths = NIL;
+ List *retval = NIL;
+
+ if (indices == NIL)
+ return (NULL);
+
+ index = (Rel *) lfirst(indices);
+
+ retval = find_index_paths(root,
+ rel,
+ lnext(indices),
+ clauseinfo_list,
+ joininfo_list);
- /*
- * 2. If the keys of this index match any of the available
- * restriction clauses, then create pathnodes corresponding
- * to each group of usable clauses.
- */
- scanclausegroups = group_clauses_by_indexkey(rel,
- index,
- index->indexkeys,
- index->classlist,
- clauseinfo_list);
-
- scanpaths = NIL;
- if (scanclausegroups != NIL)
- scanpaths = create_index_paths (root,
- rel,
- index,
- scanclausegroups,
- false);
-
- /*
- * 3. If this index can be used with any join clause, then
- * create pathnodes for each group of usable clauses. An
- * index can be used with a join clause if its ordering is
- * useful for a mergejoin, or if the index can possibly be
- * used for scanning the inner relation of a nestloop join.
- */
- joinclausegroups = indexable_joinclauses(rel,index,joininfo_list, clauseinfo_list);
- joinpaths = NIL;
-
- if (joinclausegroups != NIL)
+ /* If this is a partial index, return if it fails the predicate test */
+ if (index->indpred != NIL)
+ if (!pred_test(index->indpred, clauseinfo_list, joininfo_list))
+ return retval;
+
+ /*
+ * 1. If this index has only one key, try matching it against
+ * subclauses of an 'or' clause. The fields of the clauseinfo nodes
+ * are marked with lists of the matching indices no path are actually
+ * created.
+ *
+ * XXX NOTE: Currently btrees dos not support indices with > 1 key, so
+ * the following test will always be true for now but we have decided
+ * not to support index-scans on disjunction . -- lp
+ */
+ if (SingleAttributeIndex(index))
{
- List *new_join_paths = create_index_paths(root, rel,
+ match_index_orclauses(rel,
index,
- joinclausegroups,
- true);
- List *innerjoin_paths = index_innerjoin(root, rel,joinclausegroups,index);
+ index->indexkeys[0],
+ index->classlist[0],
+ clauseinfo_list);
+ }
+
+ /*
+ * 2. If the keys of this index match any of the available restriction
+ * clauses, then create pathnodes corresponding to each group of
+ * usable clauses.
+ */
+ scanclausegroups = group_clauses_by_indexkey(rel,
+ index,
+ index->indexkeys,
+ index->classlist,
+ clauseinfo_list);
+
+ scanpaths = NIL;
+ if (scanclausegroups != NIL)
+ scanpaths = create_index_paths(root,
+ rel,
+ index,
+ scanclausegroups,
+ false);
+
+ /*
+ * 3. If this index can be used with any join clause, then create
+ * pathnodes for each group of usable clauses. An index can be used
+ * with a join clause if its ordering is useful for a mergejoin, or if
+ * the index can possibly be used for scanning the inner relation of a
+ * nestloop join.
+ */
+ joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list);
+ joinpaths = NIL;
- rel->innerjoin = nconc (rel->innerjoin, innerjoin_paths);
- joinpaths = new_join_paths;
+ if (joinclausegroups != NIL)
+ {
+ List *new_join_paths = create_index_paths(root, rel,
+ index,
+ joinclausegroups,
+ true);
+ List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index);
+
+ rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths);
+ joinpaths = new_join_paths;
}
-
- /*
- * Some sanity checks to make sure that
- * the indexpath is valid.
- */
- if (joinpaths!=NULL)
- retval = add_index_paths(joinpaths,retval);
- if (scanpaths!=NULL)
- retval = add_index_paths(scanpaths,retval);
-
- return retval;
+
+ /*
+ * Some sanity checks to make sure that the indexpath is valid.
+ */
+ if (joinpaths != NULL)
+ retval = add_index_paths(joinpaths, retval);
+ if (scanpaths != NULL)
+ retval = add_index_paths(scanpaths, retval);
+
+ return retval;
}
/****************************************************************************
- * ---- ROUTINES TO MATCH 'OR' CLAUSES ----
+ * ---- ROUTINES TO MATCH 'OR' CLAUSES ----
****************************************************************************/
-/*
+/*
* match-index-orclauses--
- * Attempt to match an index against subclauses within 'or' clauses.
- * If the index does match, then the clause is marked with information
- * about the index.
- *
- * Essentially, this adds 'index' to the list of indices in the
- * ClauseInfo field of each of the clauses which it matches.
- *
+ * Attempt to match an index against subclauses within 'or' clauses.
+ * If the index does match, then the clause is marked with information
+ * about the index.
+ *
+ * Essentially, this adds 'index' to the list of indices in the
+ * ClauseInfo field of each of the clauses which it matches.
+ *
* 'rel' is the node of the relation on which the index is defined.
* 'index' is the index node.
* 'indexkey' is the (single) key of the index
* 'class' is the class of the operator corresponding to 'indexkey'.
* 'clauseinfo-list' is the list of available restriction clauses.
- *
+ *
* Returns nothing.
- *
+ *
*/
static void
-match_index_orclauses(Rel *rel,
- Rel *index,
- int indexkey,
- int xclass,
- List *clauseinfo_list)
+match_index_orclauses(Rel * rel,
+ Rel * index,
+ int indexkey,
+ int xclass,
+ List * clauseinfo_list)
{
- CInfo *clauseinfo = (CInfo*)NULL;
- List *i = NIL;
-
- foreach (i, clauseinfo_list) {
- clauseinfo = (CInfo*)lfirst(i);
- if (valid_or_clause(clauseinfo)) {
-
- /* Mark the 'or' clause with a list of indices which
- * match each of its subclauses. The list is
- * generated by adding 'index' to the existing
- * list where appropriate.
- */
- clauseinfo->indexids =
- match_index_orclause (rel,index,indexkey,
- xclass,
- clauseinfo->clause->args,
- clauseinfo->indexids);
+ CInfo *clauseinfo = (CInfo *) NULL;
+ List *i = NIL;
+
+ foreach(i, clauseinfo_list)
+ {
+ clauseinfo = (CInfo *) lfirst(i);
+ if (valid_or_clause(clauseinfo))
+ {
+
+ /*
+ * Mark the 'or' clause with a list of indices which match
+ * each of its subclauses. The list is generated by adding
+ * 'index' to the existing list where appropriate.
+ */
+ clauseinfo->indexids =
+ match_index_orclause(rel, index, indexkey,
+ xclass,
+ clauseinfo->clause->args,
+ clauseinfo->indexids);
+ }
}
- }
}
/*
* match_index_operand--
- * Generalize test for a match between an existing index's key
- * and the operand on the rhs of a restriction clause. Now check
- * for functional indices as well.
+ * Generalize test for a match between an existing index's key
+ * and the operand on the rhs of a restriction clause. Now check
+ * for functional indices as well.
*/
-static bool
+static bool
match_index_to_operand(int indexkey,
- Expr *operand,
- Rel *rel,
- Rel *index)
+ Expr * operand,
+ Rel * rel,
+ Rel * index)
{
- /*
- * Normal index.
- */
- if (index->indproc == InvalidOid)
- return match_indexkey_operand(indexkey, (Var*)operand, rel);
-
- /*
- * functional index check
- */
- return (function_index_operand(operand, rel, index));
+
+ /*
+ * Normal index.
+ */
+ if (index->indproc == InvalidOid)
+ return match_indexkey_operand(indexkey, (Var *) operand, rel);
+
+ /*
+ * functional index check
+ */
+ return (function_index_operand(operand, rel, index));
}
-/*
+/*
* match-index-orclause--
- * Attempts to match an index against the subclauses of an 'or' clause.
- *
- * A match means that:
- * (1) the operator within the subclause can be used with one
- * of the index's operator classes, and
- * (2) there is a usable key that matches the variable within a
- * sargable clause.
- *
+ * Attempts to match an index against the subclauses of an 'or' clause.
+ *
+ * A match means that:
+ * (1) the operator within the subclause can be used with one
+ * of the index's operator classes, and
+ * (2) there is a usable key that matches the variable within a
+ * sargable clause.
+ *
* 'or-clauses' are the remaining subclauses within the 'or' clause
* 'other-matching-indices' is the list of information on other indices
- * that have already been matched to subclauses within this
- * particular 'or' clause (i.e., a list previously generated by
- * this routine)
- *
+ * that have already been matched to subclauses within this
+ * particular 'or' clause (i.e., a list previously generated by
+ * this routine)
+ *
* Returns a list of the form ((a b c) (d e f) nil (g h) ...) where
* a,b,c are nodes of indices that match the first subclause in
* 'or-clauses', d,e,f match the second subclause, no indices
* match the third, g,h match the fourth, etc.
*/
-static List *
-match_index_orclause(Rel *rel,
- Rel *index,
- int indexkey,
- int xclass,
- List *or_clauses,
- List *other_matching_indices)
+static List *
+match_index_orclause(Rel * rel,
+ Rel * index,
+ int indexkey,
+ int xclass,
+ List * or_clauses,
+ List * other_matching_indices)
{
- Node *clause = NULL;
- List *matched_indices = other_matching_indices;
- List *index_list = NIL;
- List *clist;
- List *ind;
-
- if (!matched_indices)
- matched_indices = lcons(NIL, NIL);
-
- for (clist = or_clauses, ind = matched_indices;
- clist;
- clist = lnext(clist), ind = lnext(ind))
+ Node *clause = NULL;
+ List *matched_indices = other_matching_indices;
+ List *index_list = NIL;
+ List *clist;
+ List *ind;
+
+ if (!matched_indices)
+ matched_indices = lcons(NIL, NIL);
+
+ for (clist = or_clauses, ind = matched_indices;
+ clist;
+ clist = lnext(clist), ind = lnext(ind))
{
- clause = lfirst(clist);
- if (is_opclause (clause) &&
- op_class(((Oper*)((Expr*)clause)->oper)->opno,
- xclass, index->relam) &&
- match_index_to_operand(indexkey,
- (Expr*)get_leftop((Expr*)clause),
- rel,
- index) &&
- IsA(get_rightop((Expr*)clause),Const)) {
-
- matched_indices = lcons(index, matched_indices);
- index_list = lappend(index_list,
- matched_indices);
- }
+ clause = lfirst(clist);
+ if (is_opclause(clause) &&
+ op_class(((Oper *) ((Expr *) clause)->oper)->opno,
+ xclass, index->relam) &&
+ match_index_to_operand(indexkey,
+ (Expr *) get_leftop((Expr *) clause),
+ rel,
+ index) &&
+ IsA(get_rightop((Expr *) clause), Const))
+ {
+
+ matched_indices = lcons(index, matched_indices);
+ index_list = lappend(index_list,
+ matched_indices);
+ }
}
- return(index_list);
-
+ return (index_list);
+
}
/****************************************************************************
- * ---- ROUTINES TO CHECK RESTRICTIONS ----
+ * ---- ROUTINES TO CHECK RESTRICTIONS ----
****************************************************************************/
@@ -358,176 +371,177 @@ match_index_orclause(Rel *rel,
* keys list represent the arguments to the function. -mer 3 Oct. 1991
*/
#define DoneMatchingIndexKeys(indexkeys, index) \
- (indexkeys[0] == 0 || \
- (index->indproc != InvalidOid))
+ (indexkeys[0] == 0 || \
+ (index->indproc != InvalidOid))
-/*
+/*
* group-clauses-by-indexkey--
- * Determines whether there are clauses which will match each and every
- * one of the remaining keys of an index.
- *
+ * Determines whether there are clauses which will match each and every
+ * one of the remaining keys of an index.
+ *
* 'rel' is the node of the relation corresponding to the index.
* 'indexkeys' are the remaining index keys to be matched.
* 'classes' are the classes of the index operators on those keys.
* 'clauses' is either:
- * (1) the list of available restriction clauses on a single
- * relation, or
- * (2) a list of join clauses between 'rel' and a fixed set of
- * relations,
- * depending on the value of 'join'.
+ * (1) the list of available restriction clauses on a single
+ * relation, or
+ * (2) a list of join clauses between 'rel' and a fixed set of
+ * relations,
+ * depending on the value of 'join'.
+ *
+ * NOTE: it works now for restriction clauses only. - vadim 03/18/97
*
- * NOTE: it works now for restriction clauses only. - vadim 03/18/97
- *
* Returns all possible groups of clauses that will match (given that
* one or more clauses can match any of the remaining keys).
- * E.g., if you have clauses A, B, and C, ((A B) (A C)) might be
+ * E.g., if you have clauses A, B, and C, ((A B) (A C)) might be
* returned for an index with 2 keys.
- *
+ *
*/
-static List *
-group_clauses_by_indexkey(Rel *rel,
- Rel *index,
- int *indexkeys,
- Oid *classes,
- List *clauseinfo_list)
+static List *
+group_clauses_by_indexkey(Rel * rel,
+ Rel * index,
+ int *indexkeys,
+ Oid * classes,
+ List * clauseinfo_list)
{
- List *curCinfo = NIL;
- CInfo *matched_clause = (CInfo*)NULL;
- List *clausegroup = NIL;
- int curIndxKey;
- Oid curClass;
+ List *curCinfo = NIL;
+ CInfo *matched_clause = (CInfo *) NULL;
+ List *clausegroup = NIL;
+ int curIndxKey;
+ Oid curClass;
- if (clauseinfo_list == NIL)
- return NIL;
+ if (clauseinfo_list == NIL)
+ return NIL;
- while ( !DoneMatchingIndexKeys(indexkeys, index) )
- {
- List *tempgroup = NIL;
-
- curIndxKey = indexkeys[0];
- curClass = classes[0];
-
- foreach (curCinfo,clauseinfo_list)
- {
- CInfo *temp = (CInfo*)lfirst(curCinfo);
-
- matched_clause = match_clause_to_indexkey (rel,
- index,
- curIndxKey,
- curClass,
- temp,
- false);
- if (!matched_clause)
- continue;
-
- tempgroup = lappend(tempgroup, matched_clause);
- }
- if ( tempgroup == NIL )
- break;
+ while (!DoneMatchingIndexKeys(indexkeys, index))
+ {
+ List *tempgroup = NIL;
+
+ curIndxKey = indexkeys[0];
+ curClass = classes[0];
+
+ foreach(curCinfo, clauseinfo_list)
+ {
+ CInfo *temp = (CInfo *) lfirst(curCinfo);
+
+ matched_clause = match_clause_to_indexkey(rel,
+ index,
+ curIndxKey,
+ curClass,
+ temp,
+ false);
+ if (!matched_clause)
+ continue;
- clausegroup = nconc (clausegroup, tempgroup);
-
- indexkeys++;
- classes++;
-
- }
+ tempgroup = lappend(tempgroup, matched_clause);
+ }
+ if (tempgroup == NIL)
+ break;
- /* clausegroup holds all matched clauses ordered by indexkeys */
+ clausegroup = nconc(clausegroup, tempgroup);
+
+ indexkeys++;
+ classes++;
+
+ }
- if (clausegroup != NIL)
- return(lcons(clausegroup, NIL));
- return NIL;
+ /* clausegroup holds all matched clauses ordered by indexkeys */
+
+ if (clausegroup != NIL)
+ return (lcons(clausegroup, NIL));
+ return NIL;
}
-/*
+/*
* group-clauses-by-ikey-for-joins--
- * special edition of group-clauses-by-indexkey - will
- * match join & restriction clauses. See comment in indexable_joinclauses.
- * - vadim 03/18/97
- *
+ * special edition of group-clauses-by-indexkey - will
+ * match join & restriction clauses. See comment in indexable_joinclauses.
+ * - vadim 03/18/97
+ *
*/
-static List *
-group_clauses_by_ikey_for_joins(Rel *rel,
- Rel *index,
- int *indexkeys,
- Oid *classes,
- List *join_cinfo_list,
- List *restr_cinfo_list)
+static List *
+group_clauses_by_ikey_for_joins(Rel * rel,
+ Rel * index,
+ int *indexkeys,
+ Oid * classes,
+ List * join_cinfo_list,
+ List * restr_cinfo_list)
{
- List *curCinfo = NIL;
- CInfo *matched_clause = (CInfo*)NULL;
- List *clausegroup = NIL;
- int curIndxKey;
- Oid curClass;
- bool jfound = false;
-
- if (join_cinfo_list == NIL)
- return NIL;
+ List *curCinfo = NIL;
+ CInfo *matched_clause = (CInfo *) NULL;
+ List *clausegroup = NIL;
+ int curIndxKey;
+ Oid curClass;
+ bool jfound = false;
+
+ if (join_cinfo_list == NIL)
+ return NIL;
+
+ while (!DoneMatchingIndexKeys(indexkeys, index))
+ {
+ List *tempgroup = NIL;
+
+ curIndxKey = indexkeys[0];
+ curClass = classes[0];
+
+ foreach(curCinfo, join_cinfo_list)
+ {
+ CInfo *temp = (CInfo *) lfirst(curCinfo);
+
+ matched_clause = match_clause_to_indexkey(rel,
+ index,
+ curIndxKey,
+ curClass,
+ temp,
+ true);
+ if (!matched_clause)
+ continue;
+
+ tempgroup = lappend(tempgroup, matched_clause);
+ jfound = true;
+ }
+ foreach(curCinfo, restr_cinfo_list)
+ {
+ CInfo *temp = (CInfo *) lfirst(curCinfo);
+
+ matched_clause = match_clause_to_indexkey(rel,
+ index,
+ curIndxKey,
+ curClass,
+ temp,
+ false);
+ if (!matched_clause)
+ continue;
+
+ tempgroup = lappend(tempgroup, matched_clause);
+ }
+ if (tempgroup == NIL)
+ break;
+
+ clausegroup = nconc(clausegroup, tempgroup);
+
+ indexkeys++;
+ classes++;
- while ( !DoneMatchingIndexKeys(indexkeys, index) )
- {
- List *tempgroup = NIL;
-
- curIndxKey = indexkeys[0];
- curClass = classes[0];
-
- foreach (curCinfo,join_cinfo_list)
- {
- CInfo *temp = (CInfo*)lfirst(curCinfo);
-
- matched_clause = match_clause_to_indexkey (rel,
- index,
- curIndxKey,
- curClass,
- temp,
- true);
- if (!matched_clause)
- continue;
-
- tempgroup = lappend(tempgroup, matched_clause);
- jfound = true;
}
- foreach (curCinfo,restr_cinfo_list)
- {
- CInfo *temp = (CInfo*)lfirst(curCinfo);
-
- matched_clause = match_clause_to_indexkey (rel,
- index,
- curIndxKey,
- curClass,
- temp,
- false);
- if (!matched_clause)
- continue;
-
- tempgroup = lappend(tempgroup, matched_clause);
+
+ /* clausegroup holds all matched clauses ordered by indexkeys */
+
+ if (clausegroup != NIL)
+ {
+
+ /*
+ * if no one join clause was matched then there ain't clauses for
+ * joins at all.
+ */
+ if (!jfound)
+ {
+ freeList(clausegroup);
+ return NIL;
+ }
+ return (lcons(clausegroup, NIL));
}
- if ( tempgroup == NIL )
- break;
-
- clausegroup = nconc (clausegroup, tempgroup);
-
- indexkeys++;
- classes++;
-
- }
-
- /* clausegroup holds all matched clauses ordered by indexkeys */
-
- if (clausegroup != NIL)
- {
- /*
- * if no one join clause was matched then there ain't clauses
- * for joins at all.
- */
- if ( !jfound )
- {
- freeList (clausegroup);
- return NIL;
- }
- return(lcons(clausegroup, NIL));
- }
- return NIL;
+ return NIL;
}
/*
@@ -537,798 +551,867 @@ group_clauses_by_ikey_for_joins(Rel *rel,
* Now we can match with functional indices.
*/
#define IndexScanableOperand(opnd, indkeys, rel, index) \
- ((index->indproc == InvalidOid) ? \
- match_indexkey_operand(indkeys, opnd, rel) : \
- function_index_operand((Expr*)opnd,rel,index))
+ ((index->indproc == InvalidOid) ? \
+ match_indexkey_operand(indkeys, opnd, rel) : \
+ function_index_operand((Expr*)opnd,rel,index))
/*
* There was
- * equal_indexkey_var(indkeys,opnd) : \
+ * equal_indexkey_var(indkeys,opnd) : \
* above, and now
- * match_indexkey_operand(indkeys, opnd, rel) : \
+ * match_indexkey_operand(indkeys, opnd, rel) : \
* - vadim 01/22/97
*/
-/*
+/*
* match_clause_to-indexkey--
- * Finds the first of a relation's available restriction clauses that
- * matches a key of an index.
- *
- * To match, the clause must:
- * (1) be in the form (op var const) if the clause is a single-
- * relation clause, and
- * (2) contain an operator which is in the same class as the index
- * operator for this key.
- *
- * If the clause being matched is a join clause, then 'join' is t.
- *
- * Returns a single clauseinfo node corresponding to the matching
+ * Finds the first of a relation's available restriction clauses that
+ * matches a key of an index.
+ *
+ * To match, the clause must:
+ * (1) be in the form (op var const) if the clause is a single-
+ * relation clause, and
+ * (2) contain an operator which is in the same class as the index
+ * operator for this key.
+ *
+ * If the clause being matched is a join clause, then 'join' is t.
+ *
+ * Returns a single clauseinfo node corresponding to the matching
* clause.
*
* NOTE: returns nil if clause is an or_clause.
- *
+ *
*/
-static CInfo *
-match_clause_to_indexkey(Rel *rel,
- Rel *index,
- int indexkey,
- int xclass,
- CInfo *clauseInfo,
- bool join)
+static CInfo *
+match_clause_to_indexkey(Rel * rel,
+ Rel * index,
+ int indexkey,
+ int xclass,
+ CInfo * clauseInfo,
+ bool join)
{
- Expr *clause = clauseInfo->clause;
- Var *leftop, *rightop;
- Oid join_op = InvalidOid;
- Oid restrict_op = InvalidOid;
- bool isIndexable = false;
-
- if (or_clause((Node*)clause) ||
- not_clause((Node*)clause) || single_node((Node*)clause))
- return ((CInfo*)NULL);
-
- leftop = get_leftop(clause);
- rightop = get_rightop(clause);
- /*
- * If this is not a join clause, check for clauses of the form:
- * (operator var/func constant) and (operator constant var/func)
- */
- if (!join)
- {
+ Expr *clause = clauseInfo->clause;
+ Var *leftop,
+ *rightop;
+ Oid join_op = InvalidOid;
+ Oid restrict_op = InvalidOid;
+ bool isIndexable = false;
+
+ if (or_clause((Node *) clause) ||
+ not_clause((Node *) clause) || single_node((Node *) clause))
+ return ((CInfo *) NULL);
+
+ leftop = get_leftop(clause);
+ rightop = get_rightop(clause);
+
/*
- * Check for standard s-argable clause
+ * If this is not a join clause, check for clauses of the form:
+ * (operator var/func constant) and (operator constant var/func)
*/
-#ifdef INDEXSCAN_PATCH
- /* Handle also function parameters. DZ - 27-8-1996 */
- if ((rightop && IsA(rightop,Const)) ||
- (rightop && IsA(rightop,Param)))
-#else
- if (rightop && IsA(rightop,Const))
-#endif
+ if (!join)
{
- restrict_op = ((Oper*)((Expr*)clause)->oper)->opno;
- isIndexable =
- ( op_class(restrict_op, xclass, index->relam) &&
- IndexScanableOperand(leftop,
- indexkey,
- rel,
- index) );
- }
- /*
- * Must try to commute the clause to standard s-arg format.
- */
+ /*
+ * Check for standard s-argable clause
+ */
#ifdef INDEXSCAN_PATCH
- /* ...And here... - vadim 01/22/97 */
- else if ((leftop && IsA(leftop,Const)) ||
- (leftop && IsA(leftop,Param)))
+ /* Handle also function parameters. DZ - 27-8-1996 */
+ if ((rightop && IsA(rightop, Const)) ||
+ (rightop && IsA(rightop, Param)))
#else
- else if (leftop && IsA(leftop,Const))
+ if (rightop && IsA(rightop, Const))
#endif
- {
- restrict_op =
- get_commutator(((Oper*)((Expr*)clause)->oper)->opno);
-
- if ( (restrict_op != InvalidOid) &&
- op_class(restrict_op, xclass, index->relam) &&
- IndexScanableOperand(rightop,
- indexkey,rel,index) )
- {
- isIndexable = true;
+ {
+ restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
+ isIndexable =
+ (op_class(restrict_op, xclass, index->relam) &&
+ IndexScanableOperand(leftop,
+ indexkey,
+ rel,
+ index));
+ }
+
/*
- * In place list modification.
- * (op const var/func) -> (op var/func const)
+ * Must try to commute the clause to standard s-arg format.
*/
- CommuteClause((Node*)clause);
- }
- }
- }
- /*
- * Check for an indexable scan on one of the join relations.
- * clause is of the form (operator var/func var/func)
- */
- else
- {
- if (rightop
- && match_index_to_operand(indexkey,(Expr*)rightop,rel,index))
- {
-
- join_op = get_commutator(((Oper*)((Expr*)clause)->oper)->opno);
-
- } else if (leftop
- && match_index_to_operand(indexkey,
- (Expr*)leftop,rel,index))
- {
- join_op = ((Oper*)((Expr*)clause)->oper)->opno;
+#ifdef INDEXSCAN_PATCH
+ /* ...And here... - vadim 01/22/97 */
+ else if ((leftop && IsA(leftop, Const)) ||
+ (leftop && IsA(leftop, Param)))
+#else
+ else if (leftop && IsA(leftop, Const))
+#endif
+ {
+ restrict_op =
+ get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
+
+ if ((restrict_op != InvalidOid) &&
+ op_class(restrict_op, xclass, index->relam) &&
+ IndexScanableOperand(rightop,
+ indexkey, rel, index))
+ {
+ isIndexable = true;
+
+ /*
+ * In place list modification. (op const var/func) -> (op
+ * var/func const)
+ */
+ CommuteClause((Node *) clause);
+ }
+ }
}
- if ( join_op && op_class(join_op,xclass,index->relam) &&
- join_clause_p((Node*)clause))
+ /*
+ * Check for an indexable scan on one of the join relations. clause is
+ * of the form (operator var/func var/func)
+ */
+ else
{
- isIndexable = true;
-
- /*
- * If we're using the operand's commutator we must
- * commute the clause.
- */
- if (join_op != ((Oper*)((Expr*)clause)->oper)->opno)
- CommuteClause((Node*)clause);
+ if (rightop
+ && match_index_to_operand(indexkey, (Expr *) rightop, rel, index))
+ {
+
+ join_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
+
+ }
+ else if (leftop
+ && match_index_to_operand(indexkey,
+ (Expr *) leftop, rel, index))
+ {
+ join_op = ((Oper *) ((Expr *) clause)->oper)->opno;
+ }
+
+ if (join_op && op_class(join_op, xclass, index->relam) &&
+ join_clause_p((Node *) clause))
+ {
+ isIndexable = true;
+
+ /*
+ * If we're using the operand's commutator we must commute the
+ * clause.
+ */
+ if (join_op != ((Oper *) ((Expr *) clause)->oper)->opno)
+ CommuteClause((Node *) clause);
+ }
}
- }
- if (isIndexable)
- return(clauseInfo);
+ if (isIndexable)
+ return (clauseInfo);
- return(NULL);
+ return (NULL);
}
/****************************************************************************
- * ---- ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS ----
+ * ---- ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS ----
****************************************************************************/
-/*
+/*
* pred_test--
- * Does the "predicate inclusion test" for partial indexes.
+ * Does the "predicate inclusion test" for partial indexes.
*
- * Recursively checks whether the clauses in clauseinfo_list imply
- * that the given predicate is true.
+ * Recursively checks whether the clauses in clauseinfo_list imply
+ * that the given predicate is true.
*
- * This routine (together with the routines it calls) iterates over
- * ANDs in the predicate first, then reduces the qualification
- * clauses down to their constituent terms, and iterates over ORs
- * in the predicate last. This order is important to make the test
- * succeed whenever possible (assuming the predicate has been
- * successfully cnfify()-ed). --Nels, Jan '93
+ * This routine (together with the routines it calls) iterates over
+ * ANDs in the predicate first, then reduces the qualification
+ * clauses down to their constituent terms, and iterates over ORs
+ * in the predicate last. This order is important to make the test
+ * succeed whenever possible (assuming the predicate has been
+ * successfully cnfify()-ed). --Nels, Jan '93
*/
-static bool
-pred_test(List *predicate_list, List *clauseinfo_list, List *joininfo_list)
+static bool
+pred_test(List * predicate_list, List * clauseinfo_list, List * joininfo_list)
{
- List *pred, *items, *item;
-
- /*
- * Note: if Postgres tried to optimize queries by forming equivalence
- * classes over equi-joined attributes (i.e., if it recognized that a
- * qualification such as "where a.b=c.d and a.b=5" could make use of
- * an index on c.d), then we could use that equivalence class info
- * here with joininfo_list to do more complete tests for the usability
- * of a partial index. For now, the test only uses restriction
- * clauses (those in clauseinfo_list). --Nels, Dec '92
- */
-
- if (predicate_list == NULL)
- return true; /* no predicate: the index is usable */
- if (clauseinfo_list == NULL)
- return false; /* no restriction clauses: the test must fail */
-
- foreach (pred, predicate_list) {
- /* if any clause is not implied, the whole predicate is not implied */
- if (and_clause(lfirst(pred))) {
- items = ((Expr*)lfirst(pred))->args;
- foreach (item, items) {
- if (!one_pred_test(lfirst(item), clauseinfo_list))
- return false;
- }
+ List *pred,
+ *items,
+ *item;
+
+ /*
+ * Note: if Postgres tried to optimize queries by forming equivalence
+ * classes over equi-joined attributes (i.e., if it recognized that a
+ * qualification such as "where a.b=c.d and a.b=5" could make use of
+ * an index on c.d), then we could use that equivalence class info
+ * here with joininfo_list to do more complete tests for the usability
+ * of a partial index. For now, the test only uses restriction
+ * clauses (those in clauseinfo_list). --Nels, Dec '92
+ */
+
+ if (predicate_list == NULL)
+ return true; /* no predicate: the index is usable */
+ if (clauseinfo_list == NULL)
+ return false; /* no restriction clauses: the test must
+ * fail */
+
+ foreach(pred, predicate_list)
+ {
+
+ /*
+ * if any clause is not implied, the whole predicate is not
+ * implied
+ */
+ if (and_clause(lfirst(pred)))
+ {
+ items = ((Expr *) lfirst(pred))->args;
+ foreach(item, items)
+ {
+ if (!one_pred_test(lfirst(item), clauseinfo_list))
+ return false;
+ }
+ }
+ else if (!one_pred_test(lfirst(pred), clauseinfo_list))
+ return false;
}
- else if (!one_pred_test(lfirst(pred), clauseinfo_list))
- return false;
- }
- return true;
+ return true;
}
-/*
+/*
* one_pred_test--
- * Does the "predicate inclusion test" for one conjunct of a predicate
- * expression.
+ * Does the "predicate inclusion test" for one conjunct of a predicate
+ * expression.
*/
-static bool
-one_pred_test(Expr *predicate, List *clauseinfo_list)
+static bool
+one_pred_test(Expr * predicate, List * clauseinfo_list)
{
- CInfo *clauseinfo;
- List *item;
-
- Assert(predicate != NULL);
- foreach (item, clauseinfo_list) {
- clauseinfo = (CInfo *)lfirst(item);
- /* if any clause implies the predicate, return true */
- if (one_pred_clause_expr_test(predicate, (Node*)clauseinfo->clause))
- return true;
- }
- return false;
+ CInfo *clauseinfo;
+ List *item;
+
+ Assert(predicate != NULL);
+ foreach(item, clauseinfo_list)
+ {
+ clauseinfo = (CInfo *) lfirst(item);
+ /* if any clause implies the predicate, return true */
+ if (one_pred_clause_expr_test(predicate, (Node *) clauseinfo->clause))
+ return true;
+ }
+ return false;
}
-/*
+/*
* one_pred_clause_expr_test--
- * Does the "predicate inclusion test" for a general restriction-clause
- * expression.
+ * Does the "predicate inclusion test" for a general restriction-clause
+ * expression.
*/
-static bool
-one_pred_clause_expr_test(Expr *predicate, Node *clause)
+static bool
+one_pred_clause_expr_test(Expr * predicate, Node * clause)
{
- List *items, *item;
-
- if (is_opclause(clause))
- return one_pred_clause_test(predicate, clause);
- else if (or_clause(clause)) {
- items = ((Expr*)clause)->args;
- foreach (item, items) {
- /* if any OR item doesn't imply the predicate, clause doesn't */
- if (!one_pred_clause_expr_test(predicate, lfirst(item)))
+ List *items,
+ *item;
+
+ if (is_opclause(clause))
+ return one_pred_clause_test(predicate, clause);
+ else if (or_clause(clause))
+ {
+ items = ((Expr *) clause)->args;
+ foreach(item, items)
+ {
+ /* if any OR item doesn't imply the predicate, clause doesn't */
+ if (!one_pred_clause_expr_test(predicate, lfirst(item)))
+ return false;
+ }
+ return true;
+ }
+ else if (and_clause(clause))
+ {
+ items = ((Expr *) clause)->args;
+ foreach(item, items)
+ {
+
+ /*
+ * if any AND item implies the predicate, the whole clause
+ * does
+ */
+ if (one_pred_clause_expr_test(predicate, lfirst(item)))
+ return true;
+ }
return false;
}
- return true;
- }else if (and_clause(clause)) {
- items = ((Expr*)clause)->args;
- foreach (item, items) {
- /* if any AND item implies the predicate, the whole clause does */
- if (one_pred_clause_expr_test(predicate, lfirst(item)))
- return true;
+ else
+ {
+ /* unknown clause type never implies the predicate */
+ return false;
}
- return false;
- }else {
- /* unknown clause type never implies the predicate */
- return false;
- }
}
-/*
+/*
* one_pred_clause_test--
- * Does the "predicate inclusion test" for one conjunct of a predicate
- * expression for a simple restriction clause.
+ * Does the "predicate inclusion test" for one conjunct of a predicate
+ * expression for a simple restriction clause.
*/
-static bool
-one_pred_clause_test(Expr *predicate, Node *clause)
+static bool
+one_pred_clause_test(Expr * predicate, Node * clause)
{
- List *items, *item;
-
- if (is_opclause((Node*)predicate))
- return clause_pred_clause_test(predicate, clause);
- else if (or_clause((Node*)predicate)) {
- items = predicate->args;
- foreach (item, items) {
- /* if any item is implied, the whole predicate is implied */
- if (one_pred_clause_test(lfirst(item), clause))
+ List *items,
+ *item;
+
+ if (is_opclause((Node *) predicate))
+ return clause_pred_clause_test(predicate, clause);
+ else if (or_clause((Node *) predicate))
+ {
+ items = predicate->args;
+ foreach(item, items)
+ {
+ /* if any item is implied, the whole predicate is implied */
+ if (one_pred_clause_test(lfirst(item), clause))
+ return true;
+ }
+ return false;
+ }
+ else if (and_clause((Node *) predicate))
+ {
+ items = predicate->args;
+ foreach(item, items)
+ {
+
+ /*
+ * if any item is not implied, the whole predicate is not
+ * implied
+ */
+ if (!one_pred_clause_test(lfirst(item), clause))
+ return false;
+ }
return true;
}
- return false;
- }else if (and_clause((Node*)predicate)) {
- items = predicate->args;
- foreach (item, items) {
- /*
- * if any item is not implied, the whole predicate is not
- * implied
- */
- if (!one_pred_clause_test(lfirst(item), clause))
+ else
+ {
+ elog(DEBUG, "Unsupported predicate type, index will not be used");
return false;
}
- return true;
- }
- else {
- elog(DEBUG, "Unsupported predicate type, index will not be used");
- return false;
- }
}
/*
* Define an "operator implication table" for btree operators ("strategies").
- * The "strategy numbers" are: (1) < (2) <= (3) = (4) >= (5) >
+ * The "strategy numbers" are: (1) < (2) <= (3) = (4) >= (5) >
*
* The interpretation of:
*
- * test_op = BT_implic_table[given_op-1][target_op-1]
+ * test_op = BT_implic_table[given_op-1][target_op-1]
*
* where test_op, given_op and target_op are strategy numbers (from 1 to 5)
* of btree operators, is as follows:
*
- * If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you
- * want to determine whether "ATTR target_op CONST2" must also be true, then
- * you can use "CONST1 test_op CONST2" as a test. If this test returns true,
- * then the target expression must be true; if the test returns false, then
- * the target expression may be false.
+ * If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you
+ * want to determine whether "ATTR target_op CONST2" must also be true, then
+ * you can use "CONST1 test_op CONST2" as a test. If this test returns true,
+ * then the target expression must be true; if the test returns false, then
+ * the target expression may be false.
*
* An entry where test_op==0 means the implication cannot be determined, i.e.,
* this test should always be considered false.
*/
-StrategyNumber BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
- {2, 2, 0, 0, 0},
- {1, 2, 0, 0, 0},
- {1, 2, 3, 4, 5},
- {0, 0, 0, 4, 5},
- {0, 0, 0, 4, 4}
+StrategyNumber BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
+ {2, 2, 0, 0, 0},
+ {1, 2, 0, 0, 0},
+ {1, 2, 3, 4, 5},
+ {0, 0, 0, 4, 5},
+ {0, 0, 0, 4, 4}
};
-/*
+/*
* clause_pred_clause_test--
- * Use operator class info to check whether clause implies predicate.
- *
- * Does the "predicate inclusion test" for a "simple clause" predicate
- * for a single "simple clause" restriction. Currently, this only handles
- * (binary boolean) operators that are in some btree operator class.
- * Eventually, rtree operators could also be handled by defining an
- * appropriate "RT_implic_table" array.
+ * Use operator class info to check whether clause implies predicate.
+ *
+ * Does the "predicate inclusion test" for a "simple clause" predicate
+ * for a single "simple clause" restriction. Currently, this only handles
+ * (binary boolean) operators that are in some btree operator class.
+ * Eventually, rtree operators could also be handled by defining an
+ * appropriate "RT_implic_table" array.
*/
-static bool
-clause_pred_clause_test(Expr *predicate, Node *clause)
+static bool
+clause_pred_clause_test(Expr * predicate, Node * clause)
{
- Var *pred_var, *clause_var;
- Const *pred_const, *clause_const;
- Oid pred_op, clause_op, test_op;
- Oid opclass_id;
- StrategyNumber pred_strategy, clause_strategy, test_strategy;
- Oper *test_oper;
- Expr *test_expr;
- bool test_result, isNull;
- Relation relation;
- HeapScanDesc scan;
- HeapTuple tuple;
- ScanKeyData entry[3];
- Form_pg_amop form;
-
- pred_var = (Var*)get_leftop(predicate);
- pred_const = (Const*)get_rightop(predicate);
- clause_var = (Var*)get_leftop((Expr*)clause);
- clause_const = (Const*)get_rightop((Expr*)clause);
-
- /* Check the basic form; for now, only allow the simplest case */
- if (!is_opclause(clause) ||
- !IsA(clause_var,Var) ||
- !IsA(clause_const,Const) ||
- !IsA(predicate->oper,Oper) ||
- !IsA(pred_var,Var) ||
- !IsA(pred_const,Const)) {
- return false;
- }
+ Var *pred_var,
+ *clause_var;
+ Const *pred_const,
+ *clause_const;
+ Oid pred_op,
+ clause_op,
+ test_op;
+ Oid opclass_id;
+ StrategyNumber pred_strategy,
+ clause_strategy,
+ test_strategy;
+ Oper *test_oper;
+ Expr *test_expr;
+ bool test_result,
+ isNull;
+ Relation relation;
+ HeapScanDesc scan;
+ HeapTuple tuple;
+ ScanKeyData entry[3];
+ Form_pg_amop form;
+
+ pred_var = (Var *) get_leftop(predicate);
+ pred_const = (Const *) get_rightop(predicate);
+ clause_var = (Var *) get_leftop((Expr *) clause);
+ clause_const = (Const *) get_rightop((Expr *) clause);
+
+ /* Check the basic form; for now, only allow the simplest case */
+ if (!is_opclause(clause) ||
+ !IsA(clause_var, Var) ||
+ !IsA(clause_const, Const) ||
+ !IsA(predicate->oper, Oper) ||
+ !IsA(pred_var, Var) ||
+ !IsA(pred_const, Const))
+ {
+ return false;
+ }
- /*
- * The implication can't be determined unless the predicate and the clause
- * refer to the same attribute.
- */
- if (clause_var->varattno != pred_var->varattno)
- return false;
+ /*
+ * The implication can't be determined unless the predicate and the
+ * clause refer to the same attribute.
+ */
+ if (clause_var->varattno != pred_var->varattno)
+ return false;
- /* Get the operators for the two clauses we're comparing */
- pred_op = ((Oper*)((Expr*)predicate)->oper)->opno;
- clause_op = ((Oper*)((Expr*)clause)->oper)->opno;
-
-
- /*
- * 1. Find a "btree" strategy number for the pred_op
- */
- /* XXX - hardcoded amopid value 403 to find "btree" operator classes */
- ScanKeyEntryInitialize(&entry[0], 0,
- Anum_pg_amop_amopid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(403));
-
- ScanKeyEntryInitialize(&entry[1], 0,
- Anum_pg_amop_amopopr,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(pred_op));
-
- relation = heap_openr(AccessMethodOperatorRelationName);
-
- /*
- * The following assumes that any given operator will only be in a single
- * btree operator class. This is true at least for all the pre-defined
- * operator classes. If it isn't true, then whichever operator class
- * happens to be returned first for the given operator will be used to
- * find the associated strategy numbers for the test. --Nels, Jan '93
- */
- scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
- tuple = heap_getnext(scan, false, (Buffer *)NULL);
- if (! HeapTupleIsValid(tuple)) {
- elog(DEBUG, "clause_pred_clause_test: unknown pred_op");
- return false;
- }
- form = (Form_pg_amop) GETSTRUCT(tuple);
+ /* Get the operators for the two clauses we're comparing */
+ pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno;
+ clause_op = ((Oper *) ((Expr *) clause)->oper)->opno;
- /* Get the predicate operator's strategy number (1 to 5) */
- pred_strategy = (StrategyNumber)form->amopstrategy;
- /* Remember which operator class this strategy number came from */
- opclass_id = form->amopclaid;
+ /*
+ * 1. Find a "btree" strategy number for the pred_op
+ */
+ /* XXX - hardcoded amopid value 403 to find "btree" operator classes */
+ ScanKeyEntryInitialize(&entry[0], 0,
+ Anum_pg_amop_amopid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(403));
- heap_endscan(scan);
+ ScanKeyEntryInitialize(&entry[1], 0,
+ Anum_pg_amop_amopopr,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(pred_op));
+ relation = heap_openr(AccessMethodOperatorRelationName);
- /*
- * 2. From the same opclass, find a strategy num for the clause_op
- */
- ScanKeyEntryInitialize(&entry[1], 0,
- Anum_pg_amop_amopclaid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(opclass_id));
+ /*
+ * The following assumes that any given operator will only be in a
+ * single btree operator class. This is true at least for all the
+ * pre-defined operator classes. If it isn't true, then whichever
+ * operator class happens to be returned first for the given operator
+ * will be used to find the associated strategy numbers for the test.
+ * --Nels, Jan '93
+ */
+ scan = heap_beginscan(relation, false, NowTimeQual, 2, entry);
+ tuple = heap_getnext(scan, false, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(DEBUG, "clause_pred_clause_test: unknown pred_op");
+ return false;
+ }
+ form = (Form_pg_amop) GETSTRUCT(tuple);
- ScanKeyEntryInitialize(&entry[2], 0,
- Anum_pg_amop_amopopr,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(clause_op));
+ /* Get the predicate operator's strategy number (1 to 5) */
+ pred_strategy = (StrategyNumber) form->amopstrategy;
- scan = heap_beginscan(relation, false, NowTimeQual, 3, entry);
- tuple = heap_getnext(scan, false, (Buffer *)NULL);
- if (! HeapTupleIsValid(tuple)) {
- elog(DEBUG, "clause_pred_clause_test: unknown clause_op");
- return false;
- }
- form = (Form_pg_amop) GETSTRUCT(tuple);
+ /* Remember which operator class this strategy number came from */
+ opclass_id = form->amopclaid;
- /* Get the restriction clause operator's strategy number (1 to 5) */
- clause_strategy = (StrategyNumber)form->amopstrategy;
- heap_endscan(scan);
+ heap_endscan(scan);
- /*
- * 3. Look up the "test" strategy number in the implication table
- */
+ /*
+ * 2. From the same opclass, find a strategy num for the clause_op
+ */
+ ScanKeyEntryInitialize(&entry[1], 0,
+ Anum_pg_amop_amopclaid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(opclass_id));
+
+ ScanKeyEntryInitialize(&entry[2], 0,
+ Anum_pg_amop_amopopr,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(clause_op));
+
+ scan = heap_beginscan(relation, false, NowTimeQual, 3, entry);
+ tuple = heap_getnext(scan, false, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(DEBUG, "clause_pred_clause_test: unknown clause_op");
+ return false;
+ }
+ form = (Form_pg_amop) GETSTRUCT(tuple);
- test_strategy = BT_implic_table[clause_strategy-1][pred_strategy-1];
- if (test_strategy == 0)
- return false; /* the implication cannot be determined */
+ /* Get the restriction clause operator's strategy number (1 to 5) */
+ clause_strategy = (StrategyNumber) form->amopstrategy;
+ heap_endscan(scan);
- /*
- * 4. From the same opclass, find the operator for the test strategy
- */
+ /*
+ * 3. Look up the "test" strategy number in the implication table
+ */
- ScanKeyEntryInitialize(&entry[2], 0,
- Anum_pg_amop_amopstrategy,
- Integer16EqualRegProcedure,
- Int16GetDatum(test_strategy));
+ test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
+ if (test_strategy == 0)
+ return false; /* the implication cannot be determined */
- scan = heap_beginscan(relation, false, NowTimeQual, 3, entry);
- tuple = heap_getnext(scan, false, (Buffer *)NULL);
- if (! HeapTupleIsValid(tuple)) {
- elog(DEBUG, "clause_pred_clause_test: unknown test_op");
- return false;
- }
- form = (Form_pg_amop) GETSTRUCT(tuple);
- /* Get the test operator */
- test_op = form->amopopr;
- heap_endscan(scan);
+ /*
+ * 4. From the same opclass, find the operator for the test strategy
+ */
+ ScanKeyEntryInitialize(&entry[2], 0,
+ Anum_pg_amop_amopstrategy,
+ Integer16EqualRegProcedure,
+ Int16GetDatum(test_strategy));
- /*
- * 5. Evaluate the test
- */
- test_oper = makeOper(test_op, /* opno */
- InvalidOid, /* opid */
- BOOL_TYPEID, /* opresulttype */
- 0, /* opsize */
- NULL); /* op_fcache */
- replace_opid(test_oper);
+ scan = heap_beginscan(relation, false, NowTimeQual, 3, entry);
+ tuple = heap_getnext(scan, false, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(DEBUG, "clause_pred_clause_test: unknown test_op");
+ return false;
+ }
+ form = (Form_pg_amop) GETSTRUCT(tuple);
+
+ /* Get the test operator */
+ test_op = form->amopopr;
+ heap_endscan(scan);
- test_expr = make_opclause(test_oper,
- copyObject(clause_const),
- copyObject(pred_const));
+
+ /*
+ * 5. Evaluate the test
+ */
+ test_oper = makeOper(test_op, /* opno */
+ InvalidOid, /* opid */
+ BOOL_TYPEID, /* opresulttype */
+ 0, /* opsize */
+ NULL); /* op_fcache */
+ replace_opid(test_oper);
+
+ test_expr = make_opclause(test_oper,
+ copyObject(clause_const),
+ copyObject(pred_const));
#ifndef OMIT_PARTIAL_INDEX
- test_result = ExecEvalExpr((Node*)test_expr, NULL, &isNull, NULL);
-#endif /* OMIT_PARTIAL_INDEX */
- if (isNull) {
- elog(DEBUG, "clause_pred_clause_test: null test result");
- return false;
- }
- return test_result;
+ test_result = ExecEvalExpr((Node *) test_expr, NULL, &isNull, NULL);
+#endif /* OMIT_PARTIAL_INDEX */
+ if (isNull)
+ {
+ elog(DEBUG, "clause_pred_clause_test: null test result");
+ return false;
+ }
+ return test_result;
}
/****************************************************************************
- * ---- ROUTINES TO CHECK JOIN CLAUSES ----
+ * ---- ROUTINES TO CHECK JOIN CLAUSES ----
****************************************************************************/
-/*
+/*
* indexable-joinclauses--
- * Finds all groups of join clauses from among 'joininfo-list' that can
- * be used in conjunction with 'index'.
- *
- * The first clause in the group is marked as having the other relation
- * in the join clause as its outer join relation.
- *
+ * Finds all groups of join clauses from among 'joininfo-list' that can
+ * be used in conjunction with 'index'.
+ *
+ * The first clause in the group is marked as having the other relation
+ * in the join clause as its outer join relation.
+ *
* Returns a list of these clause groups.
*
- * Added: clauseinfo_list - list of restriction CInfos. It's to
- * support multi-column indices in joins and for cases
- * when a key is in both join & restriction clauses. - vadim 03/18/97
- *
+ * Added: clauseinfo_list - list of restriction CInfos. It's to
+ * support multi-column indices in joins and for cases
+ * when a key is in both join & restriction clauses. - vadim 03/18/97
+ *
*/
-static List *
-indexable_joinclauses(Rel *rel, Rel *index,
- List *joininfo_list, List *clauseinfo_list)
+static List *
+indexable_joinclauses(Rel * rel, Rel * index,
+ List * joininfo_list, List * clauseinfo_list)
{
- JInfo *joininfo = (JInfo*)NULL;
- List *cg_list = NIL;
- List *i = NIL;
- List *clausegroups = NIL;
-
- foreach(i,joininfo_list) {
- joininfo = (JInfo*)lfirst(i);
-
- if ( joininfo->jinfoclauseinfo == NIL )
- continue;
- clausegroups =
- group_clauses_by_ikey_for_joins (rel,
- index,
- index->indexkeys,
- index->classlist,
- joininfo->jinfoclauseinfo,
- clauseinfo_list);
-
- if (clausegroups != NIL) {
- List *clauses = lfirst(clausegroups);
-
- ((CInfo*)lfirst(clauses))->cinfojoinid =
- joininfo->otherrels;
+ JInfo *joininfo = (JInfo *) NULL;
+ List *cg_list = NIL;
+ List *i = NIL;
+ List *clausegroups = NIL;
+
+ foreach(i, joininfo_list)
+ {
+ joininfo = (JInfo *) lfirst(i);
+
+ if (joininfo->jinfoclauseinfo == NIL)
+ continue;
+ clausegroups =
+ group_clauses_by_ikey_for_joins(rel,
+ index,
+ index->indexkeys,
+ index->classlist,
+ joininfo->jinfoclauseinfo,
+ clauseinfo_list);
+
+ if (clausegroups != NIL)
+ {
+ List *clauses = lfirst(clausegroups);
+
+ ((CInfo *) lfirst(clauses))->cinfojoinid =
+ joininfo->otherrels;
+ }
+ cg_list = nconc(cg_list, clausegroups);
}
- cg_list = nconc(cg_list,clausegroups);
- }
- return(cg_list);
+ return (cg_list);
}
/****************************************************************************
- * ---- PATH CREATION UTILITIES ----
+ * ---- PATH CREATION UTILITIES ----
****************************************************************************/
/*
* extract_restrict_clauses -
- * the list of clause info contains join clauses and restriction clauses.
- * This routine returns the restriction clauses only.
+ * the list of clause info contains join clauses and restriction clauses.
+ * This routine returns the restriction clauses only.
*/
#ifdef NOT_USED
-static List *
-extract_restrict_clauses(List *clausegroup)
+static List *
+extract_restrict_clauses(List * clausegroup)
{
- List *restrict_cls = NIL;
- List *l;
-
- foreach (l, clausegroup) {
- CInfo *cinfo = lfirst(l);
-
- if (!join_clause_p((Node*)cinfo->clause)) {
- restrict_cls = lappend(restrict_cls, cinfo);
+ List *restrict_cls = NIL;
+ List *l;
+
+ foreach(l, clausegroup)
+ {
+ CInfo *cinfo = lfirst(l);
+
+ if (!join_clause_p((Node *) cinfo->clause))
+ {
+ restrict_cls = lappend(restrict_cls, cinfo);
+ }
}
- }
- return restrict_cls;
+ return restrict_cls;
}
+
#endif
-/*
+/*
* index-innerjoin--
- * Creates index path nodes corresponding to paths to be used as inner
- * relations in nestloop joins.
+ * Creates index path nodes corresponding to paths to be used as inner
+ * relations in nestloop joins.
*
* 'clausegroup-list' is a list of list of clauseinfo nodes which can use
* 'index' on their inner relation.
- *
+ *
* Returns a list of index pathnodes.
- *
+ *
*/
-static List *
-index_innerjoin(Query *root, Rel *rel, List *clausegroup_list, Rel *index)
+static List *
+index_innerjoin(Query * root, Rel * rel, List * clausegroup_list, Rel * index)
{
- List *clausegroup = NIL;
- List *cg_list = NIL;
- List *i = NIL;
- IndexPath *pathnode = (IndexPath*)NULL;
- Cost temp_selec;
- float temp_pages;
-
- foreach(i,clausegroup_list) {
- List *attnos, *values, *flags;
-
- clausegroup = lfirst(i);
- pathnode = makeNode(IndexPath);
-
- get_joinvars(lfirsti(rel->relids),clausegroup,
- &attnos, &values, &flags);
- index_selectivity(lfirsti(index->relids),
- index->classlist,
- get_opnos(clausegroup),
- getrelid(lfirsti(rel->relids),
- root->rtable),
- attnos,
- values,
- flags,
- length(clausegroup),
- &temp_pages,
- &temp_selec);
- pathnode->path.pathtype = T_IndexScan;
- pathnode->path.parent = rel;
- pathnode->indexid = index->relids;
- pathnode->indexkeys = index->indexkeys;
- pathnode->indexqual = clausegroup;
-
- pathnode->path.joinid = ((CInfo*)lfirst(clausegroup))->cinfojoinid;
-
- pathnode->path.path_cost =
- cost_index((Oid)lfirsti(index->relids),
- (int)temp_pages,
- temp_selec,
- rel->pages,
- rel->tuples,
- index->pages,
- index->tuples,
- true);
-
- /* copy clauseinfo list into path for expensive function processing
- -- JMH, 7/7/92 */
- pathnode->path.locclauseinfo =
- set_difference(copyObject((Node*)rel->clauseinfo),
- clausegroup);
-
-#if 0 /* fix xfunc */
- /* add in cost for expensive functions! -- JMH, 7/7/92 */
- if (XfuncMode != XFUNC_OFF) {
- ((Path*)pathnode)->path_cost +=
- xfunc_get_path_cost((Path*)pathnode);
- }
+ List *clausegroup = NIL;
+ List *cg_list = NIL;
+ List *i = NIL;
+ IndexPath *pathnode = (IndexPath *) NULL;
+ Cost temp_selec;
+ float temp_pages;
+
+ foreach(i, clausegroup_list)
+ {
+ List *attnos,
+ *values,
+ *flags;
+
+ clausegroup = lfirst(i);
+ pathnode = makeNode(IndexPath);
+
+ get_joinvars(lfirsti(rel->relids), clausegroup,
+ &attnos, &values, &flags);
+ index_selectivity(lfirsti(index->relids),
+ index->classlist,
+ get_opnos(clausegroup),
+ getrelid(lfirsti(rel->relids),
+ root->rtable),
+ attnos,
+ values,
+ flags,
+ length(clausegroup),
+ &temp_pages,
+ &temp_selec);
+ pathnode->path.pathtype = T_IndexScan;
+ pathnode->path.parent = rel;
+ pathnode->indexid = index->relids;
+ pathnode->indexkeys = index->indexkeys;
+ pathnode->indexqual = clausegroup;
+
+ pathnode->path.joinid = ((CInfo *) lfirst(clausegroup))->cinfojoinid;
+
+ pathnode->path.path_cost =
+ cost_index((Oid) lfirsti(index->relids),
+ (int) temp_pages,
+ temp_selec,
+ rel->pages,
+ rel->tuples,
+ index->pages,
+ index->tuples,
+ true);
+
+ /*
+ * copy clauseinfo list into path for expensive function
+ * processing -- JMH, 7/7/92
+ */
+ pathnode->path.locclauseinfo =
+ set_difference(copyObject((Node *) rel->clauseinfo),
+ clausegroup);
+
+#if 0 /* fix xfunc */
+ /* add in cost for expensive functions! -- JMH, 7/7/92 */
+ if (XfuncMode != XFUNC_OFF)
+ {
+ ((Path *) pathnode)->path_cost +=
+ xfunc_get_path_cost((Path *) pathnode);
+ }
#endif
- cg_list = lappend(cg_list,pathnode);
- }
- return(cg_list);
+ cg_list = lappend(cg_list, pathnode);
+ }
+ return (cg_list);
}
-/*
+/*
* create-index-paths--
- * Creates a list of index path nodes for each group of clauses
- * (restriction or join) that can be used in conjunction with an index.
- *
+ * Creates a list of index path nodes for each group of clauses
+ * (restriction or join) that can be used in conjunction with an index.
+ *
* 'rel' is the relation for which 'index' is defined
- * 'clausegroup-list' is the list of clause groups (lists of clauseinfo
- * nodes) grouped by mergesortorder
+ * 'clausegroup-list' is the list of clause groups (lists of clauseinfo
+ * nodes) grouped by mergesortorder
* 'join' is a flag indicating whether or not the clauses are join
- * clauses
- *
+ * clauses
+ *
* Returns a list of new index path nodes.
- *
+ *
*/
-static List *
-create_index_paths(Query *root,
- Rel *rel,
- Rel *index,
- List *clausegroup_list,
- bool join)
+static List *
+create_index_paths(Query * root,
+ Rel * rel,
+ Rel * index,
+ List * clausegroup_list,
+ bool join)
{
- List *clausegroup = NIL;
- List *ip_list = NIL;
- List *i = NIL;
- List *j = NIL;
- IndexPath *temp_path;
-
- foreach(i, clausegroup_list) {
- CInfo *clauseinfo;
- List *temp_node = NIL;
- bool temp = true;
-
- clausegroup = lfirst(i);
-
- foreach (j,clausegroup) {
- clauseinfo = (CInfo*)lfirst(j);
- if (!(join_clause_p((Node*)clauseinfo->clause) &&
- equal_path_merge_ordering(index->ordering,
- clauseinfo->mergesortorder))) {
- temp = false;
- }
- }
+ List *clausegroup = NIL;
+ List *ip_list = NIL;
+ List *i = NIL;
+ List *j = NIL;
+ IndexPath *temp_path;
- if (!join || temp) { /* restriction, ordering scan */
- temp_path = create_index_path (root, rel,index,clausegroup,join);
- temp_node =
- lcons(temp_path, NIL);
- ip_list = nconc(ip_list,temp_node);
- }
- }
- return(ip_list);
+ foreach(i, clausegroup_list)
+ {
+ CInfo *clauseinfo;
+ List *temp_node = NIL;
+ bool temp = true;
+
+ clausegroup = lfirst(i);
+
+ foreach(j, clausegroup)
+ {
+ clauseinfo = (CInfo *) lfirst(j);
+ if (!(join_clause_p((Node *) clauseinfo->clause) &&
+ equal_path_merge_ordering(index->ordering,
+ clauseinfo->mergesortorder)))
+ {
+ temp = false;
+ }
+ }
+
+ if (!join || temp)
+ { /* restriction, ordering scan */
+ temp_path = create_index_path(root, rel, index, clausegroup, join);
+ temp_node =
+ lcons(temp_path, NIL);
+ ip_list = nconc(ip_list, temp_node);
+ }
+ }
+ return (ip_list);
}
-static List *
-add_index_paths(List *indexpaths, List *new_indexpaths)
+static List *
+add_index_paths(List * indexpaths, List * new_indexpaths)
{
- return append(indexpaths, new_indexpaths);
+ return append(indexpaths, new_indexpaths);
}
-static bool
-function_index_operand(Expr *funcOpnd, Rel *rel, Rel *index)
+static bool
+function_index_operand(Expr * funcOpnd, Rel * rel, Rel * index)
{
- Oid heapRelid = (Oid)lfirsti(rel->relids);
- Func *function;
- List *funcargs;
- int *indexKeys = index->indexkeys;
- List *arg;
- int i;
-
- /*
- * sanity check, make sure we know what we're dealing with here.
- */
- if (funcOpnd==NULL ||
- nodeTag(funcOpnd)!=T_Expr || funcOpnd->opType!=FUNC_EXPR ||
- funcOpnd->oper==NULL || indexKeys==NULL)
- return false;
+ Oid heapRelid = (Oid) lfirsti(rel->relids);
+ Func *function;
+ List *funcargs;
+ int *indexKeys = index->indexkeys;
+ List *arg;
+ int i;
- function = (Func*)funcOpnd->oper;
- funcargs = funcOpnd->args;
+ /*
+ * sanity check, make sure we know what we're dealing with here.
+ */
+ if (funcOpnd == NULL ||
+ nodeTag(funcOpnd) != T_Expr || funcOpnd->opType != FUNC_EXPR ||
+ funcOpnd->oper == NULL || indexKeys == NULL)
+ return false;
- if (function->funcid != index->indproc)
- return false;
+ function = (Func *) funcOpnd->oper;
+ funcargs = funcOpnd->args;
+
+ if (function->funcid != index->indproc)
+ return false;
+
+ /*
+ * Check that the arguments correspond to the same arguments used to
+ * create the functional index. To do this we must check that 1.
+ * refer to the right relatiion. 2. the args have the right attr.
+ * numbers in the right order.
+ *
+ *
+ * Check all args refer to the correct relation (i.e. the one with the
+ * functional index defined on it (rel). To do this we can simply
+ * compare range table entry numbers, they must be the same.
+ */
+ foreach(arg, funcargs)
+ {
+ if (heapRelid != ((Var *) lfirst(arg))->varno)
+ return false;
+ }
+
+ /*
+ * check attr numbers and order.
+ */
+ i = 0;
+ foreach(arg, funcargs)
+ {
+
+ if (indexKeys[i] == 0)
+ return (false);
- /*
- * Check that the arguments correspond to the same arguments used
- * to create the functional index. To do this we must check that
- * 1. refer to the right relatiion.
- * 2. the args have the right attr. numbers in the right order.
- *
- *
- * Check all args refer to the correct relation (i.e. the one with
- * the functional index defined on it (rel). To do this we can
- * simply compare range table entry numbers, they must be the same.
- */
- foreach (arg, funcargs) {
- if (heapRelid != ((Var*)lfirst(arg))->varno)
- return false;
- }
-
- /*
- * check attr numbers and order.
- */
- i = 0;
- foreach (arg, funcargs) {
-
- if (indexKeys[i]==0)
- return (false);
-
- if (((Var*)lfirst(arg))->varattno != indexKeys[i])
- return (false);
-
- i++;
- }
-
- return true;
+ if (((Var *) lfirst(arg))->varattno != indexKeys[i])
+ return (false);
+
+ i++;
+ }
+
+ return true;
}
-static bool
-SingleAttributeIndex(Rel *index)
+static bool
+SingleAttributeIndex(Rel * index)
{
- /*
- * return false for now as I don't know if we support index scans
- * on disjunction and the code doesn't work
- */
- return (false);
+
+ /*
+ * return false for now as I don't know if we support index scans on
+ * disjunction and the code doesn't work
+ */
+ return (false);
#if 0
- /*
- * Non-functional indices.
- */
- if (index->indproc == InvalidOid)
- return (index->indexkeys[0] != 0 &&
- index->indexkeys[1] == 0);
-
- /*
- * We have a functional index which is a single attr index
- */
- return true;
+
+ /*
+ * Non-functional indices.
+ */
+ if (index->indproc == InvalidOid)
+ return (index->indexkeys[0] != 0 &&
+ index->indexkeys[1] == 0);
+
+ /*
+ * We have a functional index which is a single attr index
+ */
+ return true;
#endif
}
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 87365278ffa..c20558cf42b 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* joinpath.c--
- * Routines to find all possible paths for processing a set of joins
+ * Routines to find all possible paths for processing a set of joins
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.2 1996/10/31 10:59:00 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.3 1997/09/07 04:43:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,269 +26,286 @@
#include "optimizer/paths.h"
#include "optimizer/pathnode.h"
#include "optimizer/keys.h"
-#include "optimizer/cost.h" /* for _enable_{hashjoin, _enable_mergesort} */
-
-static Path *best_innerjoin(List *join_paths, List *outer_relid);
-static List *sort_inner_and_outer(Rel *joinrel, Rel *outerrel, Rel *innerrel,
- List *mergeinfo_list);
-static List *match_unsorted_outer(Rel *joinrel, Rel *outerrel, Rel *innerrel,
- List *outerpath_list, Path *cheapest_inner, Path *best_innerjoin,
- List *mergeinfo_list);
-static List *match_unsorted_inner(Rel *joinrel, Rel *outerrel, Rel *innerrel,
- List *innerpath_list, List *mergeinfo_list);
-static bool EnoughMemoryForHashjoin(Rel *hashrel);
-static List *hash_inner_and_outer(Rel *joinrel, Rel *outerrel, Rel *innerrel,
- List *hashinfo_list);
-
-/*
+#include "optimizer/cost.h" /* for _enable_{hashjoin,
+ * _enable_mergesort} */
+
+static Path *best_innerjoin(List * join_paths, List * outer_relid);
+static List *
+sort_inner_and_outer(Rel * joinrel, Rel * outerrel, Rel * innerrel,
+ List * mergeinfo_list);
+static List *
+match_unsorted_outer(Rel * joinrel, Rel * outerrel, Rel * innerrel,
+ List * outerpath_list, Path * cheapest_inner, Path * best_innerjoin,
+ List * mergeinfo_list);
+static List *
+match_unsorted_inner(Rel * joinrel, Rel * outerrel, Rel * innerrel,
+ List * innerpath_list, List * mergeinfo_list);
+static bool EnoughMemoryForHashjoin(Rel * hashrel);
+static List *
+hash_inner_and_outer(Rel * joinrel, Rel * outerrel, Rel * innerrel,
+ List * hashinfo_list);
+
+/*
* find-all-join-paths--
- * Creates all possible ways to process joins for each of the join
- * relations in the list 'joinrels.' Each unique path will be included
- * in the join relation's 'pathlist' field.
- *
- * In postgres, n-way joins are handled left-only(permuting clauseless
- * joins doesn't usually win much).
- *
- * if BushyPlanFlag is true, bushy tree plans will be generated
+ * Creates all possible ways to process joins for each of the join
+ * relations in the list 'joinrels.' Each unique path will be included
+ * in the join relation's 'pathlist' field.
+ *
+ * In postgres, n-way joins are handled left-only(permuting clauseless
+ * joins doesn't usually win much).
+ *
+ * if BushyPlanFlag is true, bushy tree plans will be generated
*
* 'joinrels' is the list of relation entries to be joined
- *
+ *
* Modifies the pathlist field of the appropriate rel node to contain
* the unique join paths.
* If bushy trees are considered, may modify the relid field of the
* join rel nodes to flatten the lists.
- *
- * Returns nothing of interest. (?)
+ *
+ * Returns nothing of interest. (?)
* It does a destructive modification.
*/
void
-find_all_join_paths(Query *root, List *joinrels)
+find_all_join_paths(Query * root, List * joinrels)
{
- List *mergeinfo_list = NIL;
- List *hashinfo_list = NIL;
- List *temp_list = NIL;
- List *path = NIL;
-
- while (joinrels != NIL) {
- Rel *joinrel = (Rel *)lfirst(joinrels);
- List *innerrelids;
- List *outerrelids;
- Rel *innerrel;
- Rel *outerrel;
- Path *bestinnerjoin;
- List *pathlist = NIL;
-
- innerrelids = lsecond(joinrel->relids);
- outerrelids = lfirst(joinrel->relids);
-
- /*
- * base relation id is an integer and join relation relid is a
- * list of integers.
- */
- innerrel = (length(innerrelids)==1)?
- get_base_rel(root, lfirsti(innerrelids)) : get_join_rel(root,innerrelids);
- outerrel = (length(outerrelids)==1)?
- get_base_rel(root, lfirsti(outerrelids)) : get_join_rel(root, outerrelids);
-
- bestinnerjoin = best_innerjoin(innerrel->innerjoin,
- outerrel->relids);
- if( _enable_mergesort_ ) {
- mergeinfo_list =
- group_clauses_by_order(joinrel->clauseinfo,
- lfirsti(innerrel->relids));
- }
-
- if( _enable_hashjoin_ ) {
- hashinfo_list =
- group_clauses_by_hashop(joinrel->clauseinfo,
- lfirsti(innerrel->relids));
- }
-
- /* need to flatten the relids list */
- joinrel->relids = intAppend(outerrelids, innerrelids);
-
- /*
- * 1. Consider mergesort paths where both relations must be
- * explicitly sorted.
- */
- pathlist = sort_inner_and_outer(joinrel,outerrel,
- innerrel,mergeinfo_list);
-
- /*
- * 2. Consider paths where the outer relation need not be explicitly
- * sorted. This may include either nestloops and mergesorts where
- * the outer path is already ordered.
- */
- pathlist =
- add_pathlist(joinrel, pathlist,
- match_unsorted_outer(joinrel,
- outerrel,
- innerrel,
- outerrel->pathlist,
- (Path*)innerrel->cheapestpath,
- bestinnerjoin,
- mergeinfo_list));
-
- /*
- * 3. Consider paths where the inner relation need not be explicitly
- * sorted. This may include nestloops and mergesorts the actual
- * nestloop nodes were constructed in (match-unsorted-outer).
- */
- pathlist =
- add_pathlist(joinrel,pathlist,
- match_unsorted_inner(joinrel,outerrel,
- innerrel,
- innerrel->pathlist,
- mergeinfo_list));
-
- /*
- * 4. Consider paths where both outer and inner relations must be
- * hashed before being joined.
- */
-
- pathlist =
- add_pathlist(joinrel, pathlist,
- hash_inner_and_outer(joinrel,outerrel,
- innerrel,hashinfo_list));
-
- joinrel->pathlist = pathlist;
-
- /*
- * 'OuterJoinCost is only valid when calling (match-unsorted-inner)
- * with the same arguments as the previous invokation of
- * (match-unsorted-outer), so clear the field before going on.
- */
- temp_list = innerrel->pathlist;
- foreach(path, temp_list) {
-
- /*
- * XXX
- *
- * This gross hack is to get around an apparent optimizer bug on
- * Sparc (or maybe it is a bug of ours?) that causes really wierd
- * behavior.
- */
- if (IsA_JoinPath(path)) {
- ((Path*)lfirst(path))->outerjoincost = (Cost) 0;
- }
-
- /* do it iff it is a join path, which is not always
- true, esp since the base level */
+ List *mergeinfo_list = NIL;
+ List *hashinfo_list = NIL;
+ List *temp_list = NIL;
+ List *path = NIL;
+
+ while (joinrels != NIL)
+ {
+ Rel *joinrel = (Rel *) lfirst(joinrels);
+ List *innerrelids;
+ List *outerrelids;
+ Rel *innerrel;
+ Rel *outerrel;
+ Path *bestinnerjoin;
+ List *pathlist = NIL;
+
+ innerrelids = lsecond(joinrel->relids);
+ outerrelids = lfirst(joinrel->relids);
+
+ /*
+ * base relation id is an integer and join relation relid is a
+ * list of integers.
+ */
+ innerrel = (length(innerrelids) == 1) ?
+ get_base_rel(root, lfirsti(innerrelids)) : get_join_rel(root, innerrelids);
+ outerrel = (length(outerrelids) == 1) ?
+ get_base_rel(root, lfirsti(outerrelids)) : get_join_rel(root, outerrelids);
+
+ bestinnerjoin = best_innerjoin(innerrel->innerjoin,
+ outerrel->relids);
+ if (_enable_mergesort_)
+ {
+ mergeinfo_list =
+ group_clauses_by_order(joinrel->clauseinfo,
+ lfirsti(innerrel->relids));
+ }
+
+ if (_enable_hashjoin_)
+ {
+ hashinfo_list =
+ group_clauses_by_hashop(joinrel->clauseinfo,
+ lfirsti(innerrel->relids));
+ }
+
+ /* need to flatten the relids list */
+ joinrel->relids = intAppend(outerrelids, innerrelids);
+
+ /*
+ * 1. Consider mergesort paths where both relations must be
+ * explicitly sorted.
+ */
+ pathlist = sort_inner_and_outer(joinrel, outerrel,
+ innerrel, mergeinfo_list);
+
+ /*
+ * 2. Consider paths where the outer relation need not be
+ * explicitly sorted. This may include either nestloops and
+ * mergesorts where the outer path is already ordered.
+ */
+ pathlist =
+ add_pathlist(joinrel, pathlist,
+ match_unsorted_outer(joinrel,
+ outerrel,
+ innerrel,
+ outerrel->pathlist,
+ (Path *) innerrel->cheapestpath,
+ bestinnerjoin,
+ mergeinfo_list));
+
+ /*
+ * 3. Consider paths where the inner relation need not be
+ * explicitly sorted. This may include nestloops and mergesorts
+ * the actual nestloop nodes were constructed in
+ * (match-unsorted-outer).
+ */
+ pathlist =
+ add_pathlist(joinrel, pathlist,
+ match_unsorted_inner(joinrel, outerrel,
+ innerrel,
+ innerrel->pathlist,
+ mergeinfo_list));
+
+ /*
+ * 4. Consider paths where both outer and inner relations must be
+ * hashed before being joined.
+ */
+
+ pathlist =
+ add_pathlist(joinrel, pathlist,
+ hash_inner_and_outer(joinrel, outerrel,
+ innerrel, hashinfo_list));
+
+ joinrel->pathlist = pathlist;
+
+ /*
+ * 'OuterJoinCost is only valid when calling
+ * (match-unsorted-inner) with the same arguments as the previous
+ * invokation of (match-unsorted-outer), so clear the field before
+ * going on.
+ */
+ temp_list = innerrel->pathlist;
+ foreach(path, temp_list)
+ {
+
+ /*
+ * XXX
+ *
+ * This gross hack is to get around an apparent optimizer bug on
+ * Sparc (or maybe it is a bug of ours?) that causes really
+ * wierd behavior.
+ */
+ if (IsA_JoinPath(path))
+ {
+ ((Path *) lfirst(path))->outerjoincost = (Cost) 0;
+ }
+
+ /*
+ * do it iff it is a join path, which is not always true, esp
+ * since the base level
+ */
+ }
+
+ joinrels = lnext(joinrels);
}
-
- joinrels = lnext(joinrels);
- }
}
-/*
+/*
* best-innerjoin--
- * Find the cheapest index path that has already been identified by
- * (indexable_joinclauses) as being a possible inner path for the given
- * outer relation in a nestloop join.
- *
+ * Find the cheapest index path that has already been identified by
+ * (indexable_joinclauses) as being a possible inner path for the given
+ * outer relation in a nestloop join.
+ *
* 'join-paths' is a list of join nodes
* 'outer-relid' is the relid of the outer join relation
- *
+ *
* Returns the pathnode of the selected path.
*/
-static Path *
-best_innerjoin(List *join_paths, List *outer_relids)
+static Path *
+best_innerjoin(List * join_paths, List * outer_relids)
{
- Path *cheapest = (Path*)NULL;
- List *join_path;
-
- foreach(join_path, join_paths) {
- Path *path = (Path *)lfirst(join_path);
+ Path *cheapest = (Path *) NULL;
+ List *join_path;
+
+ foreach(join_path, join_paths)
+ {
+ Path *path = (Path *) lfirst(join_path);
- if (intMember(lfirsti(path->joinid), outer_relids)
- && ((cheapest==NULL ||
- path_is_cheaper((Path*)lfirst(join_path),cheapest)))) {
+ if (intMember(lfirsti(path->joinid), outer_relids)
+ && ((cheapest == NULL ||
+ path_is_cheaper((Path *) lfirst(join_path), cheapest))))
+ {
- cheapest = (Path*)lfirst(join_path);
+ cheapest = (Path *) lfirst(join_path);
+ }
}
- }
- return(cheapest);
+ return (cheapest);
}
-/*
+/*
* sort-inner-and-outer--
- * Create mergesort join paths by explicitly sorting both the outer and
- * inner join relations on each available merge ordering.
- *
+ * Create mergesort join paths by explicitly sorting both the outer and
+ * inner join relations on each available merge ordering.
+ *
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
* 'mergeinfo-list' is a list of nodes containing info on(mergesortable)
- * clauses for joining the relations
- *
+ * clauses for joining the relations
+ *
* Returns a list of mergesort paths.
*/
-static List *
-sort_inner_and_outer(Rel *joinrel,
- Rel *outerrel,
- Rel *innerrel,
- List *mergeinfo_list)
+static List *
+sort_inner_and_outer(Rel * joinrel,
+ Rel * outerrel,
+ Rel * innerrel,
+ List * mergeinfo_list)
{
- List *ms_list = NIL;
- MInfo *xmergeinfo = (MInfo*)NULL;
- MergePath *temp_node = (MergePath*)NULL;
- List *i;
- List *outerkeys = NIL;
- List *innerkeys = NIL;
- List *merge_pathkeys = NIL;
-
- foreach(i, mergeinfo_list) {
- xmergeinfo = (MInfo *)lfirst(i);
-
- outerkeys =
- extract_path_keys(xmergeinfo->jmethod.jmkeys,
- outerrel->targetlist,
- OUTER);
-
- innerkeys =
- extract_path_keys(xmergeinfo->jmethod.jmkeys,
- innerrel->targetlist,
- INNER);
-
- merge_pathkeys =
- new_join_pathkeys(outerkeys, joinrel->targetlist,
- xmergeinfo->jmethod.clauses);
-
- temp_node =
- create_mergesort_path(joinrel,
- outerrel->size,
- innerrel->size,
- outerrel->width,
- innerrel->width,
- (Path*)outerrel->cheapestpath,
- (Path*)innerrel->cheapestpath,
- merge_pathkeys,
- xmergeinfo->m_ordering,
- xmergeinfo->jmethod.clauses,
- outerkeys,
- innerkeys);
-
- ms_list = lappend(ms_list, temp_node);
- }
- return(ms_list);
+ List *ms_list = NIL;
+ MInfo *xmergeinfo = (MInfo *) NULL;
+ MergePath *temp_node = (MergePath *) NULL;
+ List *i;
+ List *outerkeys = NIL;
+ List *innerkeys = NIL;
+ List *merge_pathkeys = NIL;
+
+ foreach(i, mergeinfo_list)
+ {
+ xmergeinfo = (MInfo *) lfirst(i);
+
+ outerkeys =
+ extract_path_keys(xmergeinfo->jmethod.jmkeys,
+ outerrel->targetlist,
+ OUTER);
+
+ innerkeys =
+ extract_path_keys(xmergeinfo->jmethod.jmkeys,
+ innerrel->targetlist,
+ INNER);
+
+ merge_pathkeys =
+ new_join_pathkeys(outerkeys, joinrel->targetlist,
+ xmergeinfo->jmethod.clauses);
+
+ temp_node =
+ create_mergesort_path(joinrel,
+ outerrel->size,
+ innerrel->size,
+ outerrel->width,
+ innerrel->width,
+ (Path *) outerrel->cheapestpath,
+ (Path *) innerrel->cheapestpath,
+ merge_pathkeys,
+ xmergeinfo->m_ordering,
+ xmergeinfo->jmethod.clauses,
+ outerkeys,
+ innerkeys);
+
+ ms_list = lappend(ms_list, temp_node);
+ }
+ return (ms_list);
}
-/*
+/*
* match-unsorted-outer--
- * Creates possible join paths for processing a single join relation
- * 'joinrel' by employing either iterative substitution or
- * mergesorting on each of its possible outer paths(assuming that the
- * outer relation need not be explicitly sorted).
- *
- * 1. The inner path is the cheapest available inner path.
- * 2. Mergesort wherever possible. Mergesorts are considered if there
- * are mergesortable join clauses between the outer and inner join
- * relations such that the outer path is keyed on the variables
- * appearing in the clauses. The corresponding inner merge path is
- * either a path whose keys match those of the outer path(if such a
- * path is available) or an explicit sort on the appropriate inner
- * join keys, whichever is cheaper.
- *
+ * Creates possible join paths for processing a single join relation
+ * 'joinrel' by employing either iterative substitution or
+ * mergesorting on each of its possible outer paths(assuming that the
+ * outer relation need not be explicitly sorted).
+ *
+ * 1. The inner path is the cheapest available inner path.
+ * 2. Mergesort wherever possible. Mergesorts are considered if there
+ * are mergesortable join clauses between the outer and inner join
+ * relations such that the outer path is keyed on the variables
+ * appearing in the clauses. The corresponding inner merge path is
+ * either a path whose keys match those of the outer path(if such a
+ * path is available) or an explicit sort on the appropriate inner
+ * join keys, whichever is cheaper.
+ *
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
@@ -296,331 +313,355 @@ sort_inner_and_outer(Rel *joinrel,
* 'cheapest-inner' is the cheapest inner path
* 'best-innerjoin' is the best inner index path(if any)
* 'mergeinfo-list' is a list of nodes containing info on mergesortable
- * clauses
- *
+ * clauses
+ *
* Returns a list of possible join path nodes.
*/
-static List *
-match_unsorted_outer(Rel *joinrel,
- Rel *outerrel,
- Rel *innerrel,
- List *outerpath_list,
- Path *cheapest_inner,
- Path *best_innerjoin,
- List *mergeinfo_list)
+static List *
+match_unsorted_outer(Rel * joinrel,
+ Rel * outerrel,
+ Rel * innerrel,
+ List * outerpath_list,
+ Path * cheapest_inner,
+ Path * best_innerjoin,
+ List * mergeinfo_list)
{
- Path *outerpath = (Path*)NULL;
- List *jp_list = NIL;
- List *temp_node = NIL;
- List *merge_pathkeys = NIL;
- Path *nestinnerpath =(Path*)NULL;
- List *paths = NIL;
- List *i = NIL;
- PathOrder *outerpath_ordering = NULL;
-
- foreach(i,outerpath_list) {
- List *clauses = NIL;
- List *matchedJoinKeys = NIL;
- List *matchedJoinClauses = NIL;
- MInfo *xmergeinfo = (MInfo*)NULL;
-
- outerpath = (Path*)lfirst(i);
-
- outerpath_ordering = &outerpath->p_ordering;
-
- if (outerpath_ordering) {
- xmergeinfo =
- match_order_mergeinfo(outerpath_ordering,
- mergeinfo_list);
- }
-
- if (xmergeinfo) {
- clauses = xmergeinfo->jmethod.clauses;
- }
-
- if (clauses) {
- List *keys = xmergeinfo->jmethod.jmkeys;
- List *clauses = xmergeinfo->jmethod.clauses;
-
- matchedJoinKeys =
- match_pathkeys_joinkeys(outerpath->keys,
- keys,
- clauses,
- OUTER,
- &matchedJoinClauses);
- merge_pathkeys =
- new_join_pathkeys(outerpath->keys,
- joinrel->targetlist, clauses);
- } else {
- merge_pathkeys = outerpath->keys;
- }
-
- if(best_innerjoin &&
- path_is_cheaper(best_innerjoin, cheapest_inner)) {
- nestinnerpath = best_innerjoin;
- } else {
- nestinnerpath = cheapest_inner;
- }
-
- paths = lcons(create_nestloop_path(joinrel,
- outerrel,
- outerpath,
- nestinnerpath,
- merge_pathkeys),
- NIL);
-
- if (clauses && matchedJoinKeys) {
- bool path_is_cheaper_than_sort;
- List *varkeys = NIL;
- Path *mergeinnerpath =
- match_paths_joinkeys(matchedJoinKeys,
- outerpath_ordering,
- innerrel->pathlist,
- INNER);
-
- path_is_cheaper_than_sort =
- (bool) (mergeinnerpath &&
- (mergeinnerpath->path_cost <
- (cheapest_inner->path_cost +
- cost_sort(matchedJoinKeys,
- innerrel->size,
- innerrel->width,
- false))));
- if(!path_is_cheaper_than_sort) {
- varkeys =
- extract_path_keys(matchedJoinKeys,
- innerrel->targetlist,
- INNER);
- }
-
-
- /*
- * Keep track of the cost of the outer path used with
- * this ordered inner path for later processing in
- * (match-unsorted-inner), since it isn't a sort and
- * thus wouldn't otherwise be considered.
- */
- if (path_is_cheaper_than_sort) {
- mergeinnerpath->outerjoincost = outerpath->path_cost;
- } else {
- mergeinnerpath = cheapest_inner;
- }
-
- temp_node =
- lcons(create_mergesort_path(joinrel,
- outerrel->size,
- innerrel->size,
- outerrel->width,
- innerrel->width,
- outerpath,
- mergeinnerpath,
- merge_pathkeys,
- xmergeinfo->m_ordering,
- matchedJoinClauses,
- NIL,
- varkeys),
- paths);
- } else {
- temp_node = paths;
- }
- jp_list = nconc(jp_list, temp_node);
- }
- return(jp_list);
+ Path *outerpath = (Path *) NULL;
+ List *jp_list = NIL;
+ List *temp_node = NIL;
+ List *merge_pathkeys = NIL;
+ Path *nestinnerpath = (Path *) NULL;
+ List *paths = NIL;
+ List *i = NIL;
+ PathOrder *outerpath_ordering = NULL;
+
+ foreach(i, outerpath_list)
+ {
+ List *clauses = NIL;
+ List *matchedJoinKeys = NIL;
+ List *matchedJoinClauses = NIL;
+ MInfo *xmergeinfo = (MInfo *) NULL;
+
+ outerpath = (Path *) lfirst(i);
+
+ outerpath_ordering = &outerpath->p_ordering;
+
+ if (outerpath_ordering)
+ {
+ xmergeinfo =
+ match_order_mergeinfo(outerpath_ordering,
+ mergeinfo_list);
+ }
+
+ if (xmergeinfo)
+ {
+ clauses = xmergeinfo->jmethod.clauses;
+ }
+
+ if (clauses)
+ {
+ List *keys = xmergeinfo->jmethod.jmkeys;
+ List *clauses = xmergeinfo->jmethod.clauses;
+
+ matchedJoinKeys =
+ match_pathkeys_joinkeys(outerpath->keys,
+ keys,
+ clauses,
+ OUTER,
+ &matchedJoinClauses);
+ merge_pathkeys =
+ new_join_pathkeys(outerpath->keys,
+ joinrel->targetlist, clauses);
+ }
+ else
+ {
+ merge_pathkeys = outerpath->keys;
+ }
+
+ if (best_innerjoin &&
+ path_is_cheaper(best_innerjoin, cheapest_inner))
+ {
+ nestinnerpath = best_innerjoin;
+ }
+ else
+ {
+ nestinnerpath = cheapest_inner;
+ }
+
+ paths = lcons(create_nestloop_path(joinrel,
+ outerrel,
+ outerpath,
+ nestinnerpath,
+ merge_pathkeys),
+ NIL);
+
+ if (clauses && matchedJoinKeys)
+ {
+ bool path_is_cheaper_than_sort;
+ List *varkeys = NIL;
+ Path *mergeinnerpath =
+ match_paths_joinkeys(matchedJoinKeys,
+ outerpath_ordering,
+ innerrel->pathlist,
+ INNER);
+
+ path_is_cheaper_than_sort =
+ (bool) (mergeinnerpath &&
+ (mergeinnerpath->path_cost <
+ (cheapest_inner->path_cost +
+ cost_sort(matchedJoinKeys,
+ innerrel->size,
+ innerrel->width,
+ false))));
+ if (!path_is_cheaper_than_sort)
+ {
+ varkeys =
+ extract_path_keys(matchedJoinKeys,
+ innerrel->targetlist,
+ INNER);
+ }
+
+
+ /*
+ * Keep track of the cost of the outer path used with this
+ * ordered inner path for later processing in
+ * (match-unsorted-inner), since it isn't a sort and thus
+ * wouldn't otherwise be considered.
+ */
+ if (path_is_cheaper_than_sort)
+ {
+ mergeinnerpath->outerjoincost = outerpath->path_cost;
+ }
+ else
+ {
+ mergeinnerpath = cheapest_inner;
+ }
+
+ temp_node =
+ lcons(create_mergesort_path(joinrel,
+ outerrel->size,
+ innerrel->size,
+ outerrel->width,
+ innerrel->width,
+ outerpath,
+ mergeinnerpath,
+ merge_pathkeys,
+ xmergeinfo->m_ordering,
+ matchedJoinClauses,
+ NIL,
+ varkeys),
+ paths);
+ }
+ else
+ {
+ temp_node = paths;
+ }
+ jp_list = nconc(jp_list, temp_node);
+ }
+ return (jp_list);
}
-/*
+/*
* match-unsorted-inner --
- * Find the cheapest ordered join path for a given(ordered, unsorted)
- * inner join path.
- *
- * Scans through each path available on an inner join relation and tries
- * matching its ordering keys against those of mergejoin clauses.
- * If 1. an appropriately-ordered inner path and matching mergeclause are
- * found, and
- * 2. sorting the cheapest outer path is cheaper than using an ordered
- * but unsorted outer path(as was considered in
- * (match-unsorted-outer)),
- * then this merge path is considered.
- *
+ * Find the cheapest ordered join path for a given(ordered, unsorted)
+ * inner join path.
+ *
+ * Scans through each path available on an inner join relation and tries
+ * matching its ordering keys against those of mergejoin clauses.
+ * If 1. an appropriately-ordered inner path and matching mergeclause are
+ * found, and
+ * 2. sorting the cheapest outer path is cheaper than using an ordered
+ * but unsorted outer path(as was considered in
+ * (match-unsorted-outer)),
+ * then this merge path is considered.
+ *
* 'joinrel' is the join result relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
* 'innerpath-list' is the list of possible inner join paths
* 'mergeinfo-list' is a list of nodes containing info on mergesortable
- * clauses
- *
+ * clauses
+ *
* Returns a list of possible merge paths.
*/
-static List *
-match_unsorted_inner(Rel *joinrel,
- Rel *outerrel,
- Rel *innerrel,
- List *innerpath_list,
- List *mergeinfo_list)
+static List *
+match_unsorted_inner(Rel * joinrel,
+ Rel * outerrel,
+ Rel * innerrel,
+ List * innerpath_list,
+ List * mergeinfo_list)
{
- Path *innerpath = (Path*)NULL;
- List *mp_list = NIL;
- List *temp_node = NIL;
- PathOrder *innerpath_ordering = NULL;
- Cost temp1 = 0.0;
- bool temp2 = false;
- List *i = NIL;
-
- foreach (i, innerpath_list) {
- MInfo *xmergeinfo = (MInfo*)NULL;
- List *clauses = NIL;
- List *matchedJoinKeys = NIL;
- List *matchedJoinClauses = NIL;
-
- innerpath = (Path*)lfirst(i);
-
- innerpath_ordering = &innerpath->p_ordering;
-
- if (innerpath_ordering) {
- xmergeinfo =
- match_order_mergeinfo(innerpath_ordering,
- mergeinfo_list);
- }
-
- if (xmergeinfo) {
- clauses = ((JoinMethod*)xmergeinfo)->clauses;
- }
-
- if (clauses) {
- List *keys = xmergeinfo->jmethod.jmkeys;
- List *cls = xmergeinfo->jmethod.clauses;
-
- matchedJoinKeys =
- match_pathkeys_joinkeys(innerpath->keys,
- keys,
- cls,
- INNER,
- &matchedJoinClauses);
- }
-
- /*
- * (match-unsorted-outer) if it is applicable.
- * 'OuterJoinCost was set above in
- */
- if (clauses && matchedJoinKeys) {
- temp1 = outerrel->cheapestpath->path_cost +
- cost_sort(matchedJoinKeys, outerrel->size, outerrel->width,
- false);
-
- temp2 = (bool) (FLOAT_IS_ZERO(innerpath->outerjoincost)
- || (innerpath->outerjoincost > temp1));
-
- if(temp2) {
- List *outerkeys =
- extract_path_keys(matchedJoinKeys,
- outerrel->targetlist,
- OUTER);
- List *merge_pathkeys =
- new_join_pathkeys(outerkeys,
- joinrel->targetlist,
- clauses);
-
- temp_node =
- lcons(create_mergesort_path(joinrel,
- outerrel->size,
- innerrel->size,
- outerrel->width,
- innerrel->width,
- (Path*)outerrel->cheapestpath,
- innerpath,
- merge_pathkeys,
- xmergeinfo->m_ordering,
- matchedJoinClauses,
- outerkeys,
- NIL),
- NIL);
-
- mp_list = nconc(mp_list,temp_node);
- }
+ Path *innerpath = (Path *) NULL;
+ List *mp_list = NIL;
+ List *temp_node = NIL;
+ PathOrder *innerpath_ordering = NULL;
+ Cost temp1 = 0.0;
+ bool temp2 = false;
+ List *i = NIL;
+
+ foreach(i, innerpath_list)
+ {
+ MInfo *xmergeinfo = (MInfo *) NULL;
+ List *clauses = NIL;
+ List *matchedJoinKeys = NIL;
+ List *matchedJoinClauses = NIL;
+
+ innerpath = (Path *) lfirst(i);
+
+ innerpath_ordering = &innerpath->p_ordering;
+
+ if (innerpath_ordering)
+ {
+ xmergeinfo =
+ match_order_mergeinfo(innerpath_ordering,
+ mergeinfo_list);
+ }
+
+ if (xmergeinfo)
+ {
+ clauses = ((JoinMethod *) xmergeinfo)->clauses;
+ }
+
+ if (clauses)
+ {
+ List *keys = xmergeinfo->jmethod.jmkeys;
+ List *cls = xmergeinfo->jmethod.clauses;
+
+ matchedJoinKeys =
+ match_pathkeys_joinkeys(innerpath->keys,
+ keys,
+ cls,
+ INNER,
+ &matchedJoinClauses);
+ }
+
+ /*
+ * (match-unsorted-outer) if it is applicable. 'OuterJoinCost was
+ * set above in
+ */
+ if (clauses && matchedJoinKeys)
+ {
+ temp1 = outerrel->cheapestpath->path_cost +
+ cost_sort(matchedJoinKeys, outerrel->size, outerrel->width,
+ false);
+
+ temp2 = (bool) (FLOAT_IS_ZERO(innerpath->outerjoincost)
+ || (innerpath->outerjoincost > temp1));
+
+ if (temp2)
+ {
+ List *outerkeys =
+ extract_path_keys(matchedJoinKeys,
+ outerrel->targetlist,
+ OUTER);
+ List *merge_pathkeys =
+ new_join_pathkeys(outerkeys,
+ joinrel->targetlist,
+ clauses);
+
+ temp_node =
+ lcons(create_mergesort_path(joinrel,
+ outerrel->size,
+ innerrel->size,
+ outerrel->width,
+ innerrel->width,
+ (Path *) outerrel->cheapestpath,
+ innerpath,
+ merge_pathkeys,
+ xmergeinfo->m_ordering,
+ matchedJoinClauses,
+ outerkeys,
+ NIL),
+ NIL);
+
+ mp_list = nconc(mp_list, temp_node);
+ }
+ }
}
- }
- return(mp_list);
-
+ return (mp_list);
+
}
-static bool
-EnoughMemoryForHashjoin(Rel *hashrel)
+static bool
+EnoughMemoryForHashjoin(Rel * hashrel)
{
- int ntuples;
- int tupsize;
- int pages;
-
- ntuples = hashrel->size;
- if (ntuples == 0) ntuples = 1000;
- tupsize = hashrel->width + sizeof(HeapTupleData);
- pages = page_size(ntuples, tupsize);
- /*
- * if amount of buffer space below hashjoin threshold,
- * return false
- */
- if (ceil(sqrt((double)pages)) > NBuffers)
- return false;
- return true;
+ int ntuples;
+ int tupsize;
+ int pages;
+
+ ntuples = hashrel->size;
+ if (ntuples == 0)
+ ntuples = 1000;
+ tupsize = hashrel->width + sizeof(HeapTupleData);
+ pages = page_size(ntuples, tupsize);
+
+ /*
+ * if amount of buffer space below hashjoin threshold, return false
+ */
+ if (ceil(sqrt((double) pages)) > NBuffers)
+ return false;
+ return true;
}
-/*
- * hash-inner-and-outer-- XXX HASH
- * Create hashjoin join paths by explicitly hashing both the outer and
- * inner join relations on each available hash op.
- *
+/*
+ * hash-inner-and-outer-- XXX HASH
+ * Create hashjoin join paths by explicitly hashing both the outer and
+ * inner join relations on each available hash op.
+ *
* 'joinrel' is the join relation
* 'outerrel' is the outer join relation
* 'innerrel' is the inner join relation
* 'hashinfo-list' is a list of nodes containing info on(hashjoinable)
- * clauses for joining the relations
- *
+ * clauses for joining the relations
+ *
* Returns a list of hashjoin paths.
*/
-static List *
-hash_inner_and_outer(Rel *joinrel,
- Rel *outerrel,
- Rel *innerrel,
- List *hashinfo_list)
+static List *
+hash_inner_and_outer(Rel * joinrel,
+ Rel * outerrel,
+ Rel * innerrel,
+ List * hashinfo_list)
{
- HInfo *xhashinfo = (HInfo*)NULL;
- List *hjoin_list = NIL;
- HashPath *temp_node = (HashPath*)NULL;
- List *i = NIL;
- List *outerkeys = NIL;
- List *innerkeys = NIL;
- List *hash_pathkeys = NIL;
-
- foreach (i, hashinfo_list) {
- xhashinfo = (HInfo*)lfirst(i);
- outerkeys =
- extract_path_keys(((JoinMethod*)xhashinfo)->jmkeys,
- outerrel->targetlist,
- OUTER);
- innerkeys =
- extract_path_keys(((JoinMethod*)xhashinfo)->jmkeys,
- innerrel->targetlist,
- INNER);
- hash_pathkeys =
- new_join_pathkeys(outerkeys,
- joinrel->targetlist,
- ((JoinMethod*)xhashinfo)->clauses);
-
- if (EnoughMemoryForHashjoin(innerrel)) {
- temp_node = create_hashjoin_path(joinrel,
- outerrel->size,
- innerrel->size,
- outerrel->width,
- innerrel->width,
- (Path*)outerrel->cheapestpath,
- (Path*)innerrel->cheapestpath,
- hash_pathkeys,
- xhashinfo->hashop,
- ((JoinMethod*)xhashinfo)->clauses,
- outerkeys,
- innerkeys);
- hjoin_list = lappend(hjoin_list, temp_node);
+ HInfo *xhashinfo = (HInfo *) NULL;
+ List *hjoin_list = NIL;
+ HashPath *temp_node = (HashPath *) NULL;
+ List *i = NIL;
+ List *outerkeys = NIL;
+ List *innerkeys = NIL;
+ List *hash_pathkeys = NIL;
+
+ foreach(i, hashinfo_list)
+ {
+ xhashinfo = (HInfo *) lfirst(i);
+ outerkeys =
+ extract_path_keys(((JoinMethod *) xhashinfo)->jmkeys,
+ outerrel->targetlist,
+ OUTER);
+ innerkeys =
+ extract_path_keys(((JoinMethod *) xhashinfo)->jmkeys,
+ innerrel->targetlist,
+ INNER);
+ hash_pathkeys =
+ new_join_pathkeys(outerkeys,
+ joinrel->targetlist,
+ ((JoinMethod *) xhashinfo)->clauses);
+
+ if (EnoughMemoryForHashjoin(innerrel))
+ {
+ temp_node = create_hashjoin_path(joinrel,
+ outerrel->size,
+ innerrel->size,
+ outerrel->width,
+ innerrel->width,
+ (Path *) outerrel->cheapestpath,
+ (Path *) innerrel->cheapestpath,
+ hash_pathkeys,
+ xhashinfo->hashop,
+ ((JoinMethod *) xhashinfo)->clauses,
+ outerkeys,
+ innerkeys);
+ hjoin_list = lappend(hjoin_list, temp_node);
+ }
}
- }
- return(hjoin_list);
+ return (hjoin_list);
}
-
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 00f8a04a050..98762f9800c 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* joinrels.c--
- * Routines to determine which relations should be joined
+ * Routines to determine which relations should be joined
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.4 1997/06/05 09:33:52 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.5 1997/09/07 04:43:40 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,467 +24,508 @@
#include "optimizer/pathnode.h"
#ifdef USE_RIGHT_SIDED_PLANS
-bool _use_right_sided_plans_ = true;
+bool _use_right_sided_plans_ = true;
+
#else
-bool _use_right_sided_plans_ = false;
+bool _use_right_sided_plans_ = false;
+
#endif
-static List *find_clause_joins(Query *root, Rel *outer_rel, List *joininfo_list);
-static List *find_clauseless_joins(Rel *outer_rel, List *inner_rels);
-static Rel *init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo);
-static List *new_join_tlist(List *tlist, List *other_relids,
- int first_resdomno);
-static List *new_joininfo_list(List *joininfo_list, List *join_relids);
-static void add_superrels(Rel *rel, Rel *super_rel);
-static bool nonoverlap_rels(Rel *rel1, Rel *rel2);
-static bool nonoverlap_sets(List *s1, List *s2);
-static void set_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel,
- JInfo *jinfo);
-
-/*
+static List *find_clause_joins(Query * root, Rel * outer_rel, List * joininfo_list);
+static List *find_clauseless_joins(Rel * outer_rel, List * inner_rels);
+static Rel *init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo);
+static List *
+new_join_tlist(List * tlist, List * other_relids,
+ int first_resdomno);
+static List *new_joininfo_list(List * joininfo_list, List * join_relids);
+static void add_superrels(Rel * rel, Rel * super_rel);
+static bool nonoverlap_rels(Rel * rel1, Rel * rel2);
+static bool nonoverlap_sets(List * s1, List * s2);
+static void
+set_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel,
+ JInfo * jinfo);
+
+/*
* find-join-rels--
- * Find all possible joins for each of the outer join relations in
- * 'outer-rels'. A rel node is created for each possible join relation,
- * and the resulting list of nodes is returned. If at all possible, only
- * those relations for which join clauses exist are considered. If none
- * of these exist for a given relation, all remaining possibilities are
- * considered.
- *
+ * Find all possible joins for each of the outer join relations in
+ * 'outer-rels'. A rel node is created for each possible join relation,
+ * and the resulting list of nodes is returned. If at all possible, only
+ * those relations for which join clauses exist are considered. If none
+ * of these exist for a given relation, all remaining possibilities are
+ * considered.
+ *
* 'outer-rels' is the list of rel nodes
- *
+ *
* Returns a list of rel nodes corresponding to the new join relations.
*/
-List *
-find_join_rels(Query *root, List *outer_rels)
+List *
+find_join_rels(Query * root, List * outer_rels)
{
- List *joins = NIL;
- List *join_list = NIL;
- List *r = NIL;
-
- foreach(r, outer_rels) {
- Rel *outer_rel = (Rel *)lfirst(r);
-
- if(!(joins = find_clause_joins(root, outer_rel,outer_rel->joininfo)))
- if (BushyPlanFlag)
- joins = find_clauseless_joins(outer_rel,outer_rels);
- else
- joins = find_clauseless_joins(outer_rel,root->base_relation_list_);
-
- join_list = nconc(join_list, joins);
- }
-
- return(join_list);
+ List *joins = NIL;
+ List *join_list = NIL;
+ List *r = NIL;
+
+ foreach(r, outer_rels)
+ {
+ Rel *outer_rel = (Rel *) lfirst(r);
+
+ if (!(joins = find_clause_joins(root, outer_rel, outer_rel->joininfo)))
+ if (BushyPlanFlag)
+ joins = find_clauseless_joins(outer_rel, outer_rels);
+ else
+ joins = find_clauseless_joins(outer_rel, root->base_relation_list_);
+
+ join_list = nconc(join_list, joins);
+ }
+
+ return (join_list);
}
-/*
+/*
* find-clause-joins--
- * Determines whether joins can be performed between an outer relation
- * 'outer-rel' and those relations within 'outer-rel's joininfo nodes
- * (i.e., relations that participate in join clauses that 'outer-rel'
- * participates in). This is possible if all but one of the relations
- * contained within the join clauses of the joininfo node are already
- * contained within 'outer-rel'.
+ * Determines whether joins can be performed between an outer relation
+ * 'outer-rel' and those relations within 'outer-rel's joininfo nodes
+ * (i.e., relations that participate in join clauses that 'outer-rel'
+ * participates in). This is possible if all but one of the relations
+ * contained within the join clauses of the joininfo node are already
+ * contained within 'outer-rel'.
*
* 'outer-rel' is the relation entry for the outer relation
- * 'joininfo-list' is a list of join clauses which 'outer-rel'
- * participates in
- *
+ * 'joininfo-list' is a list of join clauses which 'outer-rel'
+ * participates in
+ *
* Returns a list of new join relations.
*/
-static List *
-find_clause_joins(Query *root, Rel *outer_rel, List *joininfo_list)
+static List *
+find_clause_joins(Query * root, Rel * outer_rel, List * joininfo_list)
{
- List *join_list = NIL;
- List *i = NIL;
-
- foreach (i, joininfo_list) {
- JInfo *joininfo = (JInfo*)lfirst(i);
- Rel *rel;
-
- if(!joininfo->inactive) {
- List *other_rels = joininfo->otherrels;
-
- if(other_rels != NIL) {
- if(length(other_rels) == 1) {
- rel = init_join_rel(outer_rel,
- get_base_rel(root, lfirsti(other_rels)),
- joininfo);
- /* how about right-sided plan ? */
- if ( _use_right_sided_plans_ &&
- length (outer_rel->relids) > 1 )
- {
- if (rel != NULL)
- join_list = lappend(join_list, rel);
- rel = init_join_rel(get_base_rel(root, lfirsti(other_rels)),
- outer_rel,
- joininfo);
- }
- } else if (BushyPlanFlag) {
- rel = init_join_rel(outer_rel,
- get_join_rel(root, other_rels),
- joininfo);
- } else {
- rel = NULL;
- }
+ List *join_list = NIL;
+ List *i = NIL;
- if (rel != NULL)
- join_list = lappend(join_list, rel);
- }
+ foreach(i, joininfo_list)
+ {
+ JInfo *joininfo = (JInfo *) lfirst(i);
+ Rel *rel;
+
+ if (!joininfo->inactive)
+ {
+ List *other_rels = joininfo->otherrels;
+
+ if (other_rels != NIL)
+ {
+ if (length(other_rels) == 1)
+ {
+ rel = init_join_rel(outer_rel,
+ get_base_rel(root, lfirsti(other_rels)),
+ joininfo);
+ /* how about right-sided plan ? */
+ if (_use_right_sided_plans_ &&
+ length(outer_rel->relids) > 1)
+ {
+ if (rel != NULL)
+ join_list = lappend(join_list, rel);
+ rel = init_join_rel(get_base_rel(root, lfirsti(other_rels)),
+ outer_rel,
+ joininfo);
+ }
+ }
+ else if (BushyPlanFlag)
+ {
+ rel = init_join_rel(outer_rel,
+ get_join_rel(root, other_rels),
+ joininfo);
+ }
+ else
+ {
+ rel = NULL;
+ }
+
+ if (rel != NULL)
+ join_list = lappend(join_list, rel);
+ }
+ }
}
- }
- return(join_list);
+ return (join_list);
}
-/*
+/*
* find-clauseless-joins--
- * Given an outer relation 'outer-rel' and a list of inner relations
- * 'inner-rels', create a join relation between 'outer-rel' and each
- * member of 'inner-rels' that isn't already included in 'outer-rel'.
- *
+ * Given an outer relation 'outer-rel' and a list of inner relations
+ * 'inner-rels', create a join relation between 'outer-rel' and each
+ * member of 'inner-rels' that isn't already included in 'outer-rel'.
+ *
* Returns a list of new join relations.
*/
-static List *
-find_clauseless_joins(Rel *outer_rel, List *inner_rels)
+static List *
+find_clauseless_joins(Rel * outer_rel, List * inner_rels)
{
- Rel *inner_rel;
- List *t_list = NIL;
- List *temp_node = NIL;
- List *i = NIL;
-
- foreach (i, inner_rels) {
- inner_rel = (Rel *)lfirst(i);
- if(nonoverlap_rels(inner_rel, outer_rel)) {
- temp_node = lcons(init_join_rel(outer_rel,
- inner_rel,
- (JInfo*)NULL),
- NIL);
- t_list = nconc(t_list,temp_node);
- }
- }
-
- return(t_list);
+ Rel *inner_rel;
+ List *t_list = NIL;
+ List *temp_node = NIL;
+ List *i = NIL;
+
+ foreach(i, inner_rels)
+ {
+ inner_rel = (Rel *) lfirst(i);
+ if (nonoverlap_rels(inner_rel, outer_rel))
+ {
+ temp_node = lcons(init_join_rel(outer_rel,
+ inner_rel,
+ (JInfo *) NULL),
+ NIL);
+ t_list = nconc(t_list, temp_node);
+ }
+ }
+
+ return (t_list);
}
-/*
+/*
* init-join-rel--
- * Creates and initializes a new join relation.
- *
+ * Creates and initializes a new join relation.
+ *
* 'outer-rel' and 'inner-rel' are relation nodes for the relations to be
- * joined
+ * joined
* 'joininfo' is the joininfo node(join clause) containing both
- * 'outer-rel' and 'inner-rel', if any exists
- *
+ * 'outer-rel' and 'inner-rel', if any exists
+ *
* Returns the new join relation node.
*/
-static Rel *
-init_join_rel(Rel *outer_rel, Rel *inner_rel, JInfo *joininfo)
+static Rel *
+init_join_rel(Rel * outer_rel, Rel * inner_rel, JInfo * joininfo)
{
- Rel *joinrel = makeNode(Rel);
- List *joinrel_joininfo_list = NIL;
- List *new_outer_tlist;
- List *new_inner_tlist;
-
- /*
- * Create a new tlist by removing irrelevant elements from both
- * tlists of the outer and inner join relations and then merging
- * the results together.
- */
- new_outer_tlist =
- new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */
- inner_rel->relids, 1);
- new_inner_tlist =
- new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */
- outer_rel->relids,
- length(new_outer_tlist) + 1);
-
- joinrel->relids = NIL;
- joinrel->indexed = false;
- joinrel->pages = 0;
- joinrel->tuples = 0;
- joinrel->width = 0;
-/* joinrel->targetlist = NIL;*/
- joinrel->pathlist = NIL;
- joinrel->unorderedpath = (Path *)NULL;
- joinrel->cheapestpath = (Path *)NULL;
- joinrel->pruneable = true;
- joinrel->classlist = NULL;
- joinrel->relam = InvalidOid;
- joinrel->ordering = NULL;
- joinrel->clauseinfo = NIL;
- joinrel->joininfo = NULL;
- joinrel->innerjoin = NIL;
- joinrel->superrels = NIL;
-
- joinrel->relids = lcons(outer_rel->relids, /* ??? aren't they lists? -ay */
- lcons(inner_rel->relids, NIL));
-
- new_outer_tlist = nconc(new_outer_tlist,new_inner_tlist);
- joinrel->targetlist = new_outer_tlist;
-
- if (joininfo) {
- joinrel->clauseinfo = joininfo->jinfoclauseinfo;
- if (BushyPlanFlag)
- joininfo->inactive = true;
- }
-
- joinrel_joininfo_list =
- new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo),
- intAppend(outer_rel->relids, inner_rel->relids));
-
- joinrel->joininfo = joinrel_joininfo_list;
-
- set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo);
-
- return(joinrel);
+ Rel *joinrel = makeNode(Rel);
+ List *joinrel_joininfo_list = NIL;
+ List *new_outer_tlist;
+ List *new_inner_tlist;
+
+ /*
+ * Create a new tlist by removing irrelevant elements from both tlists
+ * of the outer and inner join relations and then merging the results
+ * together.
+ */
+ new_outer_tlist =
+ new_join_tlist(outer_rel->targetlist, /* XXX 1-based attnos */
+ inner_rel->relids, 1);
+ new_inner_tlist =
+ new_join_tlist(inner_rel->targetlist, /* XXX 1-based attnos */
+ outer_rel->relids,
+ length(new_outer_tlist) + 1);
+
+ joinrel->relids = NIL;
+ joinrel->indexed = false;
+ joinrel->pages = 0;
+ joinrel->tuples = 0;
+ joinrel->width = 0;
+/* joinrel->targetlist = NIL;*/
+ joinrel->pathlist = NIL;
+ joinrel->unorderedpath = (Path *) NULL;
+ joinrel->cheapestpath = (Path *) NULL;
+ joinrel->pruneable = true;
+ joinrel->classlist = NULL;
+ joinrel->relam = InvalidOid;
+ joinrel->ordering = NULL;
+ joinrel->clauseinfo = NIL;
+ joinrel->joininfo = NULL;
+ joinrel->innerjoin = NIL;
+ joinrel->superrels = NIL;
+
+ joinrel->relids = lcons(outer_rel->relids, /* ??? aren't they lists?
+ * -ay */
+ lcons(inner_rel->relids, NIL));
+
+ new_outer_tlist = nconc(new_outer_tlist, new_inner_tlist);
+ joinrel->targetlist = new_outer_tlist;
+
+ if (joininfo)
+ {
+ joinrel->clauseinfo = joininfo->jinfoclauseinfo;
+ if (BushyPlanFlag)
+ joininfo->inactive = true;
+ }
+
+ joinrel_joininfo_list =
+ new_joininfo_list(append(outer_rel->joininfo, inner_rel->joininfo),
+ intAppend(outer_rel->relids, inner_rel->relids));
+
+ joinrel->joininfo = joinrel_joininfo_list;
+
+ set_joinrel_size(joinrel, outer_rel, inner_rel, joininfo);
+
+ return (joinrel);
}
-/*
+/*
* new-join-tlist--
- * Builds a join relations's target list by keeping those elements that
- * will be in the final target list and any other elements that are still
- * needed for future joins. For a target list entry to still be needed
- * for future joins, its 'joinlist' field must not be empty after removal
- * of all relids in 'other-relids'.
- *
+ * Builds a join relations's target list by keeping those elements that
+ * will be in the final target list and any other elements that are still
+ * needed for future joins. For a target list entry to still be needed
+ * for future joins, its 'joinlist' field must not be empty after removal
+ * of all relids in 'other-relids'.
+ *
* 'tlist' is the target list of one of the join relations
* 'other-relids' is a list of relids contained within the other
- * join relation
+ * join relation
* 'first-resdomno' is the resdom number to use for the first created
- * target list entry
- *
+ * target list entry
+ *
* Returns the new target list.
*/
-static List *
-new_join_tlist(List *tlist,
- List *other_relids,
- int first_resdomno)
+static List *
+new_join_tlist(List * tlist,
+ List * other_relids,
+ int first_resdomno)
{
- int resdomno = first_resdomno - 1;
- TargetEntry *xtl = NULL;
- List *temp_node = NIL;
- List *t_list = NIL;
- List *i = NIL;
- List *join_list = NIL;
- bool in_final_tlist =false;
-
-
- foreach(i,tlist) {
- xtl= lfirst(i);
- in_final_tlist = (join_list==NIL);
- if( in_final_tlist) {
- resdomno += 1;
- temp_node =
- lcons(create_tl_element(get_expr(xtl),
- resdomno),
- NIL);
- t_list = nconc(t_list,temp_node);
- }
- }
-
- return(t_list);
+ int resdomno = first_resdomno - 1;
+ TargetEntry *xtl = NULL;
+ List *temp_node = NIL;
+ List *t_list = NIL;
+ List *i = NIL;
+ List *join_list = NIL;
+ bool in_final_tlist = false;
+
+
+ foreach(i, tlist)
+ {
+ xtl = lfirst(i);
+ in_final_tlist = (join_list == NIL);
+ if (in_final_tlist)
+ {
+ resdomno += 1;
+ temp_node =
+ lcons(create_tl_element(get_expr(xtl),
+ resdomno),
+ NIL);
+ t_list = nconc(t_list, temp_node);
+ }
+ }
+
+ return (t_list);
}
-/*
+/*
* new-joininfo-list--
- * Builds a join relation's joininfo list by checking for join clauses
- * which still need to used in future joins involving this relation. A
- * join clause is still needed if there are still relations in the clause
- * not contained in the list of relations comprising this join relation.
- * New joininfo nodes are only created and added to
- * 'current-joininfo-list' if a node for a particular join hasn't already
- * been created.
+ * Builds a join relation's joininfo list by checking for join clauses
+ * which still need to used in future joins involving this relation. A
+ * join clause is still needed if there are still relations in the clause
+ * not contained in the list of relations comprising this join relation.
+ * New joininfo nodes are only created and added to
+ * 'current-joininfo-list' if a node for a particular join hasn't already
+ * been created.
*
- * 'current-joininfo-list' contains a list of those joininfo nodes that
- * have already been built
+ * 'current-joininfo-list' contains a list of those joininfo nodes that
+ * have already been built
* 'joininfo-list' is the list of join clauses involving this relation
- * 'join-relids' is a list of relids corresponding to the relations
- * currently being joined
- *
+ * 'join-relids' is a list of relids corresponding to the relations
+ * currently being joined
+ *
* Returns a list of joininfo nodes, new and old.
*/
-static List *
-new_joininfo_list(List *joininfo_list, List *join_relids)
+static List *
+new_joininfo_list(List * joininfo_list, List * join_relids)
{
- List *current_joininfo_list = NIL;
- List *new_otherrels = NIL;
- JInfo *other_joininfo = (JInfo*)NULL;
- List *xjoininfo = NIL;
-
- foreach (xjoininfo, joininfo_list) {
- List *or;
- JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
-
- new_otherrels = joininfo->otherrels;
- foreach (or, new_otherrels)
- {
- if ( intMember (lfirsti(or), join_relids) )
- new_otherrels = lremove ((void*)lfirst(or), new_otherrels);
- }
- joininfo->otherrels = new_otherrels;
- if ( new_otherrels != NIL )
+ List *current_joininfo_list = NIL;
+ List *new_otherrels = NIL;
+ JInfo *other_joininfo = (JInfo *) NULL;
+ List *xjoininfo = NIL;
+
+ foreach(xjoininfo, joininfo_list)
{
- other_joininfo = joininfo_member(new_otherrels,
- current_joininfo_list);
- if(other_joininfo) {
- other_joininfo->jinfoclauseinfo =
- (List*)LispUnion(joininfo->jinfoclauseinfo,
- other_joininfo->jinfoclauseinfo);
- }else {
- other_joininfo = makeNode(JInfo);
-
- other_joininfo->otherrels =
- joininfo->otherrels;
- other_joininfo->jinfoclauseinfo =
- joininfo->jinfoclauseinfo;
- other_joininfo->mergesortable =
- joininfo->mergesortable;
- other_joininfo->hashjoinable =
- joininfo->hashjoinable;
- other_joininfo->inactive = false;
-
- current_joininfo_list = lcons(other_joininfo,
- current_joininfo_list);
- }
+ List *or;
+ JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
+
+ new_otherrels = joininfo->otherrels;
+ foreach(or, new_otherrels)
+ {
+ if (intMember(lfirsti(or), join_relids))
+ new_otherrels = lremove((void *) lfirst(or), new_otherrels);
+ }
+ joininfo->otherrels = new_otherrels;
+ if (new_otherrels != NIL)
+ {
+ other_joininfo = joininfo_member(new_otherrels,
+ current_joininfo_list);
+ if (other_joininfo)
+ {
+ other_joininfo->jinfoclauseinfo =
+ (List *) LispUnion(joininfo->jinfoclauseinfo,
+ other_joininfo->jinfoclauseinfo);
+ }
+ else
+ {
+ other_joininfo = makeNode(JInfo);
+
+ other_joininfo->otherrels =
+ joininfo->otherrels;
+ other_joininfo->jinfoclauseinfo =
+ joininfo->jinfoclauseinfo;
+ other_joininfo->mergesortable =
+ joininfo->mergesortable;
+ other_joininfo->hashjoinable =
+ joininfo->hashjoinable;
+ other_joininfo->inactive = false;
+
+ current_joininfo_list = lcons(other_joininfo,
+ current_joininfo_list);
+ }
+ }
}
- }
- return(current_joininfo_list);
+ return (current_joininfo_list);
}
/*
* add-new-joininfos--
- * For each new join relation, create new joininfos that
- * use the join relation as inner relation, and add
- * the new joininfos to those rel nodes that still
- * have joins with the join relation.
+ * For each new join relation, create new joininfos that
+ * use the join relation as inner relation, and add
+ * the new joininfos to those rel nodes that still
+ * have joins with the join relation.
*
* 'joinrels' is a list of join relations.
*
* Modifies the joininfo field of appropriate rel nodes.
*/
void
-add_new_joininfos(Query *root, List *joinrels, List *outerrels)
+add_new_joininfos(Query * root, List * joinrels, List * outerrels)
{
- List *xjoinrel = NIL;
- List *xrelid = NIL;
- List *xrel = NIL;
- List *xjoininfo = NIL;
-
- foreach(xjoinrel, joinrels) {
- Rel *joinrel = (Rel *)lfirst(xjoinrel);
- foreach(xrelid, joinrel->relids) {
- Relid relid = (Relid)lfirst(xrelid);
- Rel *rel = get_join_rel(root, relid);
- add_superrels(rel,joinrel);
+ List *xjoinrel = NIL;
+ List *xrelid = NIL;
+ List *xrel = NIL;
+ List *xjoininfo = NIL;
+
+ foreach(xjoinrel, joinrels)
+ {
+ Rel *joinrel = (Rel *) lfirst(xjoinrel);
+
+ foreach(xrelid, joinrel->relids)
+ {
+ Relid relid = (Relid) lfirst(xrelid);
+ Rel *rel = get_join_rel(root, relid);
+
+ add_superrels(rel, joinrel);
+ }
}
- }
- foreach(xjoinrel, joinrels) {
- Rel *joinrel = (Rel *)lfirst(xjoinrel);
-
- foreach(xjoininfo, joinrel->joininfo) {
- JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
- List *other_rels = joininfo->otherrels;
- List *clause_info = joininfo->jinfoclauseinfo;
- bool mergesortable = joininfo->mergesortable;
- bool hashjoinable = joininfo->hashjoinable;
-
- foreach(xrelid, other_rels) {
- Relid relid = (Relid)lfirst(xrelid);
- Rel *rel = get_join_rel(root, relid);
- List *super_rels = rel->superrels;
- List *xsuper_rel = NIL;
- JInfo *new_joininfo = makeNode(JInfo);
-
- new_joininfo->otherrels = joinrel->relids;
- new_joininfo->jinfoclauseinfo = clause_info;
- new_joininfo->mergesortable = mergesortable;
- new_joininfo->hashjoinable = hashjoinable;
- new_joininfo->inactive = false;
- rel->joininfo =
- lappend(rel->joininfo, new_joininfo);
-
- foreach(xsuper_rel, super_rels) {
- Rel *super_rel = (Rel *)lfirst(xsuper_rel);
-
- if( nonoverlap_rels(super_rel,joinrel) ) {
- List *new_relids = super_rel->relids;
- JInfo *other_joininfo =
- joininfo_member(new_relids,
- joinrel->joininfo);
-
- if (other_joininfo) {
- other_joininfo->jinfoclauseinfo =
- (List*)LispUnion(clause_info,
- other_joininfo->jinfoclauseinfo);
- } else {
- JInfo *new_joininfo = makeNode(JInfo);
-
- new_joininfo->otherrels = new_relids;
- new_joininfo->jinfoclauseinfo = clause_info;
- new_joininfo->mergesortable = mergesortable;
- new_joininfo->hashjoinable = hashjoinable;
- new_joininfo->inactive = false;
- joinrel->joininfo =
- lappend(joinrel->joininfo,
- new_joininfo);
+ foreach(xjoinrel, joinrels)
+ {
+ Rel *joinrel = (Rel *) lfirst(xjoinrel);
+
+ foreach(xjoininfo, joinrel->joininfo)
+ {
+ JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
+ List *other_rels = joininfo->otherrels;
+ List *clause_info = joininfo->jinfoclauseinfo;
+ bool mergesortable = joininfo->mergesortable;
+ bool hashjoinable = joininfo->hashjoinable;
+
+ foreach(xrelid, other_rels)
+ {
+ Relid relid = (Relid) lfirst(xrelid);
+ Rel *rel = get_join_rel(root, relid);
+ List *super_rels = rel->superrels;
+ List *xsuper_rel = NIL;
+ JInfo *new_joininfo = makeNode(JInfo);
+
+ new_joininfo->otherrels = joinrel->relids;
+ new_joininfo->jinfoclauseinfo = clause_info;
+ new_joininfo->mergesortable = mergesortable;
+ new_joininfo->hashjoinable = hashjoinable;
+ new_joininfo->inactive = false;
+ rel->joininfo =
+ lappend(rel->joininfo, new_joininfo);
+
+ foreach(xsuper_rel, super_rels)
+ {
+ Rel *super_rel = (Rel *) lfirst(xsuper_rel);
+
+ if (nonoverlap_rels(super_rel, joinrel))
+ {
+ List *new_relids = super_rel->relids;
+ JInfo *other_joininfo =
+ joininfo_member(new_relids,
+ joinrel->joininfo);
+
+ if (other_joininfo)
+ {
+ other_joininfo->jinfoclauseinfo =
+ (List *) LispUnion(clause_info,
+ other_joininfo->jinfoclauseinfo);
+ }
+ else
+ {
+ JInfo *new_joininfo = makeNode(JInfo);
+
+ new_joininfo->otherrels = new_relids;
+ new_joininfo->jinfoclauseinfo = clause_info;
+ new_joininfo->mergesortable = mergesortable;
+ new_joininfo->hashjoinable = hashjoinable;
+ new_joininfo->inactive = false;
+ joinrel->joininfo =
+ lappend(joinrel->joininfo,
+ new_joininfo);
+ }
+ }
+ }
}
- }
}
- }
}
- }
- foreach(xrel, outerrels) {
- Rel *rel = (Rel *)lfirst(xrel);
- rel->superrels = NIL;
- }
+ foreach(xrel, outerrels)
+ {
+ Rel *rel = (Rel *) lfirst(xrel);
+
+ rel->superrels = NIL;
+ }
}
/*
* final-join-rels--
- * Find the join relation that includes all the original
- * relations, i.e. the final join result.
+ * Find the join relation that includes all the original
+ * relations, i.e. the final join result.
*
* 'join-rel-list' is a list of join relations.
*
* Returns the list of final join relations.
*/
-List *
-final_join_rels(List *join_rel_list)
+List *
+final_join_rels(List * join_rel_list)
{
- List *xrel = NIL;
- List *temp = NIL;
- List *t_list = NIL;
-
- /*
- * find the relations that has no further joins,
- * i.e., its joininfos all have otherrels nil.
- */
- foreach(xrel,join_rel_list) {
- Rel *rel = (Rel *)lfirst(xrel);
- List *xjoininfo = NIL;
- bool final = true;
-
- foreach (xjoininfo, rel->joininfo) {
- JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
-
- if (joininfo->otherrels != NIL) {
- final = false;
- break;
- }
- }
- if (final) {
- temp = lcons(rel, NIL);
- t_list = nconc(t_list, temp);
+ List *xrel = NIL;
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ /*
+ * find the relations that has no further joins, i.e., its joininfos
+ * all have otherrels nil.
+ */
+ foreach(xrel, join_rel_list)
+ {
+ Rel *rel = (Rel *) lfirst(xrel);
+ List *xjoininfo = NIL;
+ bool final = true;
+
+ foreach(xjoininfo, rel->joininfo)
+ {
+ JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
+
+ if (joininfo->otherrels != NIL)
+ {
+ final = false;
+ break;
+ }
+ }
+ if (final)
+ {
+ temp = lcons(rel, NIL);
+ t_list = nconc(t_list, temp);
+ }
}
- }
- return(t_list);
+ return (t_list);
}
/*
* add_superrels--
- * add rel to the temporary property list superrels.
+ * add rel to the temporary property list superrels.
*
* 'rel' a rel node
* 'super-rel' rel node of a join relation that includes rel
@@ -492,60 +533,69 @@ final_join_rels(List *join_rel_list)
* Modifies the superrels field of rel
*/
static void
-add_superrels(Rel *rel, Rel *super_rel)
+add_superrels(Rel * rel, Rel * super_rel)
{
- rel->superrels = lappend(rel->superrels, super_rel);
+ rel->superrels = lappend(rel->superrels, super_rel);
}
/*
* nonoverlap-rels--
- * test if two join relations overlap, i.e., includes the same
- * relation.
+ * test if two join relations overlap, i.e., includes the same
+ * relation.
*
* 'rel1' and 'rel2' are two join relations
*
* Returns non-nil if rel1 and rel2 do not overlap.
*/
-static bool
-nonoverlap_rels(Rel *rel1, Rel *rel2)
+static bool
+nonoverlap_rels(Rel * rel1, Rel * rel2)
{
- return(nonoverlap_sets(rel1->relids, rel2->relids));
+ return (nonoverlap_sets(rel1->relids, rel2->relids));
}
-static bool
-nonoverlap_sets(List *s1, List *s2)
+static bool
+nonoverlap_sets(List * s1, List * s2)
{
- List *x = NIL;
-
- foreach(x,s1) {
- int e = lfirsti(x);
- if(intMember(e,s2))
- return(false);
- }
- return(true);
+ List *x = NIL;
+
+ foreach(x, s1)
+ {
+ int e = lfirsti(x);
+
+ if (intMember(e, s2))
+ return (false);
+ }
+ return (true);
}
static void
-set_joinrel_size(Rel *joinrel, Rel *outer_rel, Rel *inner_rel, JInfo *jinfo)
+set_joinrel_size(Rel * joinrel, Rel * outer_rel, Rel * inner_rel, JInfo * jinfo)
{
- int ntuples;
- float selec;
-
- /* voodoo magic. but better than a size of 0. I have no idea why
- we didn't set the size before. -ay 2/95 */
- if (jinfo==NULL) {
- /* worst case: the cartesian product */
- ntuples = outer_rel->tuples * inner_rel->tuples;
- } else {
- selec = product_selec(jinfo->jinfoclauseinfo);
-/* ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */
- ntuples = outer_rel->tuples * inner_rel->tuples * selec;
- }
-
- /* I bet sizes less than 1 will screw up optimization so
- make the best case 1 instead of 0 - jolly*/
- if (ntuples < 1)
- ntuples = 1;
-
- joinrel->tuples = ntuples;
+ int ntuples;
+ float selec;
+
+ /*
+ * voodoo magic. but better than a size of 0. I have no idea why we
+ * didn't set the size before. -ay 2/95
+ */
+ if (jinfo == NULL)
+ {
+ /* worst case: the cartesian product */
+ ntuples = outer_rel->tuples * inner_rel->tuples;
+ }
+ else
+ {
+ selec = product_selec(jinfo->jinfoclauseinfo);
+/* ntuples = Min(outer_rel->tuples,inner_rel->tuples) * selec; */
+ ntuples = outer_rel->tuples * inner_rel->tuples * selec;
+ }
+
+ /*
+ * I bet sizes less than 1 will screw up optimization so make the best
+ * case 1 instead of 0 - jolly
+ */
+ if (ntuples < 1)
+ ntuples = 1;
+
+ joinrel->tuples = ntuples;
}
diff --git a/src/backend/optimizer/path/joinutils.c b/src/backend/optimizer/path/joinutils.c
index 1be5a57f2ec..c88d3cf19e8 100644
--- a/src/backend/optimizer/path/joinutils.c
+++ b/src/backend/optimizer/path/joinutils.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* joinutils.c--
- * Utilities for matching and building join and path keys
+ * Utilities for matching and building join and path keys
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/joinutils.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/joinutils.c,v 1.2 1997/09/07 04:43:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,407 +26,440 @@
#include "optimizer/ordering.h"
-static int match_pathkey_joinkeys(List *pathkey, List *joinkeys,
- int which_subkey);
-static bool every_func(List *joinkeys, List *pathkey,
- int which_subkey);
-static List *new_join_pathkey(List *subkeys,
- List *considered_subkeys, List *join_rel_tlist,
- List *joinclauses);
-static List *new_matching_subkeys(Var *subkey, List *considered_subkeys,
- List *join_rel_tlist, List *joinclauses);
+static int
+match_pathkey_joinkeys(List * pathkey, List * joinkeys,
+ int which_subkey);
+static bool
+every_func(List * joinkeys, List * pathkey,
+ int which_subkey);
+static List *
+new_join_pathkey(List * subkeys,
+ List * considered_subkeys, List * join_rel_tlist,
+ List * joinclauses);
+static List *
+new_matching_subkeys(Var * subkey, List * considered_subkeys,
+ List * join_rel_tlist, List * joinclauses);
/****************************************************************************
- * KEY COMPARISONS
+ * KEY COMPARISONS
****************************************************************************/
-/*
+/*
* match-pathkeys-joinkeys--
- * Attempts to match the keys of a path against the keys of join clauses.
- * This is done by looking for a matching join key in 'joinkeys' for
- * every path key in the list 'pathkeys'. If there is a matching join key
- * (not necessarily unique) for every path key, then the list of
- * corresponding join keys and join clauses are returned in the order in
- * which the keys matched the path keys.
- *
+ * Attempts to match the keys of a path against the keys of join clauses.
+ * This is done by looking for a matching join key in 'joinkeys' for
+ * every path key in the list 'pathkeys'. If there is a matching join key
+ * (not necessarily unique) for every path key, then the list of
+ * corresponding join keys and join clauses are returned in the order in
+ * which the keys matched the path keys.
+ *
* 'pathkeys' is a list of path keys:
- * ( ( (var) (var) ... ) ( (var) ... ) )
+ * ( ( (var) (var) ... ) ( (var) ... ) )
* 'joinkeys' is a list of join keys:
- * ( (outer inner) (outer inner) ... )
+ * ( (outer inner) (outer inner) ... )
* 'joinclauses' is a list of clauses corresponding to the join keys in
- * 'joinkeys'
+ * 'joinkeys'
* 'which-subkey' is a flag that selects the desired subkey of a join key
- * in 'joinkeys'
- *
+ * in 'joinkeys'
+ *
* Returns the join keys and corresponding join clauses in a list if all
* of the path keys were matched:
- * (
- * ( (outerkey0 innerkey0) ... (outerkeyN innerkeyN) )
- * ( clause0 ... clauseN )
- * )
+ * (
+ * ( (outerkey0 innerkey0) ... (outerkeyN innerkeyN) )
+ * ( clause0 ... clauseN )
+ * )
* and nil otherwise.
- *
+ *
* Returns a list of matched join keys and a list of matched join clauses
* in matchedJoinClausesPtr. - ay 11/94
*/
-List *
-match_pathkeys_joinkeys(List *pathkeys,
- List *joinkeys,
- List *joinclauses,
- int which_subkey,
- List **matchedJoinClausesPtr)
+List *
+match_pathkeys_joinkeys(List * pathkeys,
+ List * joinkeys,
+ List * joinclauses,
+ int which_subkey,
+ List ** matchedJoinClausesPtr)
{
- List *matched_joinkeys = NIL;
- List *matched_joinclauses = NIL;
- List *pathkey = NIL;
- List *i = NIL;
- int matched_joinkey_index = -1;
-
- foreach(i, pathkeys) {
- pathkey = lfirst(i);
- matched_joinkey_index =
- match_pathkey_joinkeys(pathkey, joinkeys, which_subkey);
-
- if (matched_joinkey_index != -1 ) {
- List *xjoinkey = nth(matched_joinkey_index,joinkeys);
- List *joinclause = nth(matched_joinkey_index,joinclauses);
-
- /* XXX was "push" function */
- matched_joinkeys = lappend(matched_joinkeys,xjoinkey);
- matched_joinkeys = nreverse(matched_joinkeys);
-
- matched_joinclauses = lappend(matched_joinclauses,joinclause);
- matched_joinclauses = nreverse(matched_joinclauses);
- joinkeys = LispRemove(xjoinkey,joinkeys);
- } else {
- return(NIL);
- }
-
- }
- if(matched_joinkeys==NULL ||
- length(matched_joinkeys) != length(pathkeys)) {
- return NIL;
- }
-
- *matchedJoinClausesPtr = nreverse(matched_joinclauses);
- return (nreverse(matched_joinkeys));
+ List *matched_joinkeys = NIL;
+ List *matched_joinclauses = NIL;
+ List *pathkey = NIL;
+ List *i = NIL;
+ int matched_joinkey_index = -1;
+
+ foreach(i, pathkeys)
+ {
+ pathkey = lfirst(i);
+ matched_joinkey_index =
+ match_pathkey_joinkeys(pathkey, joinkeys, which_subkey);
+
+ if (matched_joinkey_index != -1)
+ {
+ List *xjoinkey = nth(matched_joinkey_index, joinkeys);
+ List *joinclause = nth(matched_joinkey_index, joinclauses);
+
+ /* XXX was "push" function */
+ matched_joinkeys = lappend(matched_joinkeys, xjoinkey);
+ matched_joinkeys = nreverse(matched_joinkeys);
+
+ matched_joinclauses = lappend(matched_joinclauses, joinclause);
+ matched_joinclauses = nreverse(matched_joinclauses);
+ joinkeys = LispRemove(xjoinkey, joinkeys);
+ }
+ else
+ {
+ return (NIL);
+ }
+
+ }
+ if (matched_joinkeys == NULL ||
+ length(matched_joinkeys) != length(pathkeys))
+ {
+ return NIL;
+ }
+
+ *matchedJoinClausesPtr = nreverse(matched_joinclauses);
+ return (nreverse(matched_joinkeys));
}
-/*
+/*
* match-pathkey-joinkeys--
- * Returns the 0-based index into 'joinkeys' of the first joinkey whose
- * outer or inner subkey matches any subkey of 'pathkey'.
+ * Returns the 0-based index into 'joinkeys' of the first joinkey whose
+ * outer or inner subkey matches any subkey of 'pathkey'.
*/
static int
-match_pathkey_joinkeys(List *pathkey,
- List *joinkeys,
- int which_subkey)
+match_pathkey_joinkeys(List * pathkey,
+ List * joinkeys,
+ int which_subkey)
{
- Var *path_subkey;
- int pos;
- List *i = NIL;
- List *x = NIL;
- JoinKey *jk;
-
- foreach(i, pathkey) {
- path_subkey = (Var *)lfirst(i);
- pos = 0;
- foreach(x, joinkeys) {
- jk = (JoinKey*)lfirst(x);
- if(var_equal(path_subkey,
- extract_subkey(jk, which_subkey)))
- return(pos);
- pos++;
+ Var *path_subkey;
+ int pos;
+ List *i = NIL;
+ List *x = NIL;
+ JoinKey *jk;
+
+ foreach(i, pathkey)
+ {
+ path_subkey = (Var *) lfirst(i);
+ pos = 0;
+ foreach(x, joinkeys)
+ {
+ jk = (JoinKey *) lfirst(x);
+ if (var_equal(path_subkey,
+ extract_subkey(jk, which_subkey)))
+ return (pos);
+ pos++;
+ }
}
- }
- return(-1); /* no index found */
+ return (-1); /* no index found */
}
-/*
+/*
* match-paths-joinkeys--
- * Attempts to find a path in 'paths' whose keys match a set of join
- * keys 'joinkeys'. To match,
- * 1. the path node ordering must equal 'ordering'.
- * 2. each subkey of a given path must match(i.e., be(var_equal) to) the
- * appropriate subkey of the corresponding join key in 'joinkeys',
- * i.e., the Nth path key must match its subkeys against the subkey of
- * the Nth join key in 'joinkeys'.
- *
- * 'joinkeys' is the list of key pairs to which the path keys must be
- * matched
+ * Attempts to find a path in 'paths' whose keys match a set of join
+ * keys 'joinkeys'. To match,
+ * 1. the path node ordering must equal 'ordering'.
+ * 2. each subkey of a given path must match(i.e., be(var_equal) to) the
+ * appropriate subkey of the corresponding join key in 'joinkeys',
+ * i.e., the Nth path key must match its subkeys against the subkey of
+ * the Nth join key in 'joinkeys'.
+ *
+ * 'joinkeys' is the list of key pairs to which the path keys must be
+ * matched
* 'ordering' is the ordering of the(outer) path to which 'joinkeys'
- * must correspond
+ * must correspond
* 'paths' is a list of(inner) paths which are to be matched against
- * each join key in 'joinkeys'
+ * each join key in 'joinkeys'
* 'which-subkey' is a flag that selects the desired subkey of a join key
- * in 'joinkeys'
- *
+ * in 'joinkeys'
+ *
* Returns the matching path node if one exists, nil otherwise.
*/
-static bool
-every_func(List *joinkeys, List *pathkey, int which_subkey)
+static bool
+every_func(List * joinkeys, List * pathkey, int which_subkey)
{
- JoinKey *xjoinkey;
- Var *temp;
- Var *tempkey = NULL;
- bool found = false;
- List *i = NIL;
- List *j = NIL;
-
- foreach(i,joinkeys) {
- xjoinkey = (JoinKey*)lfirst(i);
- found = false;
- foreach(j,pathkey) {
- temp = (Var*)lfirst((List*)lfirst(j));
- if(temp == NULL) continue;
- tempkey = extract_subkey(xjoinkey,which_subkey);
- if(var_equal(tempkey, temp)) {
- found = true;
- break;
- }
+ JoinKey *xjoinkey;
+ Var *temp;
+ Var *tempkey = NULL;
+ bool found = false;
+ List *i = NIL;
+ List *j = NIL;
+
+ foreach(i, joinkeys)
+ {
+ xjoinkey = (JoinKey *) lfirst(i);
+ found = false;
+ foreach(j, pathkey)
+ {
+ temp = (Var *) lfirst((List *) lfirst(j));
+ if (temp == NULL)
+ continue;
+ tempkey = extract_subkey(xjoinkey, which_subkey);
+ if (var_equal(tempkey, temp))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found == false)
+ return (false);
}
- if(found == false)
- return(false);
- }
- return(found);
+ return (found);
}
/*
* match_paths_joinkeys -
- * find the cheapest path that matches the join keys
+ * find the cheapest path that matches the join keys
*/
-Path *
-match_paths_joinkeys(List *joinkeys,
- PathOrder *ordering,
- List *paths,
- int which_subkey)
+Path *
+match_paths_joinkeys(List * joinkeys,
+ PathOrder * ordering,
+ List * paths,
+ int which_subkey)
{
- Path *matched_path = NULL ;
- bool key_match = false;
- List *i = NIL;
-
- foreach(i,paths) {
- Path *path = (Path*)lfirst(i);
-
- key_match = every_func(joinkeys, path->keys, which_subkey);
-
- if (equal_path_path_ordering(ordering,
- &path->p_ordering) &&
- length(joinkeys) == length(path->keys) &&
- key_match) {
-
- if (matched_path) {
- if (path->path_cost < matched_path->path_cost)
- matched_path = path;
- } else {
- matched_path = path;
- }
+ Path *matched_path = NULL;
+ bool key_match = false;
+ List *i = NIL;
+
+ foreach(i, paths)
+ {
+ Path *path = (Path *) lfirst(i);
+
+ key_match = every_func(joinkeys, path->keys, which_subkey);
+
+ if (equal_path_path_ordering(ordering,
+ &path->p_ordering) &&
+ length(joinkeys) == length(path->keys) &&
+ key_match)
+ {
+
+ if (matched_path)
+ {
+ if (path->path_cost < matched_path->path_cost)
+ matched_path = path;
+ }
+ else
+ {
+ matched_path = path;
+ }
+ }
}
- }
- return matched_path;
+ return matched_path;
}
-/*
+/*
* extract-path-keys--
- * Builds a subkey list for a path by pulling one of the subkeys from
- * a list of join keys 'joinkeys' and then finding the var node in the
- * target list 'tlist' that corresponds to that subkey.
- *
+ * Builds a subkey list for a path by pulling one of the subkeys from
+ * a list of join keys 'joinkeys' and then finding the var node in the
+ * target list 'tlist' that corresponds to that subkey.
+ *
* 'joinkeys' is a list of join key pairs
* 'tlist' is a relation target list
* 'which-subkey' is a flag that selects the desired subkey of a join key
- * in 'joinkeys'
- *
+ * in 'joinkeys'
+ *
* Returns a list of pathkeys: ((tlvar1)(tlvar2)...(tlvarN)).
* [I've no idea why they have to be list of lists. Should be fixed. -ay 12/94]
*/
-List *
-extract_path_keys(List *joinkeys,
- List *tlist,
- int which_subkey)
+List *
+extract_path_keys(List * joinkeys,
+ List * tlist,
+ int which_subkey)
{
- List *pathkeys = NIL;
- List *jk;
-
- foreach(jk, joinkeys) {
- JoinKey *jkey = (JoinKey*)lfirst(jk);
- Var *var, *key;
- List *p;
-
- /*
- * find the right Var in the target list for this key
- */
- var = (Var*)extract_subkey(jkey, which_subkey);
- key = (Var*)matching_tlvar(var, tlist);
-
- /*
- * include it in the pathkeys list if we haven't already done so
- */
- foreach(p, pathkeys) {
- Var *pkey = lfirst((List*)lfirst(p)); /* XXX fix me */
- if (key == pkey)
- break;
- }
- if (p!=NIL)
- continue; /* key already in pathkeys */
+ List *pathkeys = NIL;
+ List *jk;
+
+ foreach(jk, joinkeys)
+ {
+ JoinKey *jkey = (JoinKey *) lfirst(jk);
+ Var *var,
+ *key;
+ List *p;
- pathkeys =
- lappend(pathkeys, lcons(key,NIL));
- }
- return(pathkeys);
+ /*
+ * find the right Var in the target list for this key
+ */
+ var = (Var *) extract_subkey(jkey, which_subkey);
+ key = (Var *) matching_tlvar(var, tlist);
+
+ /*
+ * include it in the pathkeys list if we haven't already done so
+ */
+ foreach(p, pathkeys)
+ {
+ Var *pkey = lfirst((List *) lfirst(p)); /* XXX fix me */
+
+ if (key == pkey)
+ break;
+ }
+ if (p != NIL)
+ continue; /* key already in pathkeys */
+
+ pathkeys =
+ lappend(pathkeys, lcons(key, NIL));
+ }
+ return (pathkeys);
}
/****************************************************************************
- * NEW PATHKEY FORMATION
+ * NEW PATHKEY FORMATION
****************************************************************************/
-/*
+/*
* new-join-pathkeys--
- * Find the path keys for a join relation by finding all vars in the list
- * of join clauses 'joinclauses' such that:
- * (1) the var corresponding to the outer join relation is a
- * key on the outer path
- * (2) the var appears in the target list of the join relation
- * In other words, add to each outer path key the inner path keys that
- * are required for qualification.
- *
+ * Find the path keys for a join relation by finding all vars in the list
+ * of join clauses 'joinclauses' such that:
+ * (1) the var corresponding to the outer join relation is a
+ * key on the outer path
+ * (2) the var appears in the target list of the join relation
+ * In other words, add to each outer path key the inner path keys that
+ * are required for qualification.
+ *
* 'outer-pathkeys' is the list of the outer path's path keys
* 'join-rel-tlist' is the target list of the join relation
* 'joinclauses' is the list of restricting join clauses
- *
- * Returns the list of new path keys.
- *
+ *
+ * Returns the list of new path keys.
+ *
*/
-List *
-new_join_pathkeys(List *outer_pathkeys,
- List *join_rel_tlist,
- List *joinclauses)
-{
- List *outer_pathkey = NIL;
- List *t_list = NIL;
- List *x;
- List *i = NIL;
-
- foreach(i, outer_pathkeys) {
- outer_pathkey = lfirst(i);
- x = new_join_pathkey(outer_pathkey, NIL,
- join_rel_tlist,joinclauses);
- if (x!=NIL) {
- t_list = lappend(t_list, x);
+List *
+new_join_pathkeys(List * outer_pathkeys,
+ List * join_rel_tlist,
+ List * joinclauses)
+{
+ List *outer_pathkey = NIL;
+ List *t_list = NIL;
+ List *x;
+ List *i = NIL;
+
+ foreach(i, outer_pathkeys)
+ {
+ outer_pathkey = lfirst(i);
+ x = new_join_pathkey(outer_pathkey, NIL,
+ join_rel_tlist, joinclauses);
+ if (x != NIL)
+ {
+ t_list = lappend(t_list, x);
+ }
}
- }
- return(t_list);
+ return (t_list);
}
-/*
+/*
* new-join-pathkey--
- * Finds new vars that become subkeys due to qualification clauses that
- * contain any previously considered subkeys. These new subkeys plus the
- * subkeys from 'subkeys' form a new pathkey for the join relation.
- *
- * Note that each returned subkey is the var node found in
- * 'join-rel-tlist' rather than the joinclause var node.
- *
+ * Finds new vars that become subkeys due to qualification clauses that
+ * contain any previously considered subkeys. These new subkeys plus the
+ * subkeys from 'subkeys' form a new pathkey for the join relation.
+ *
+ * Note that each returned subkey is the var node found in
+ * 'join-rel-tlist' rather than the joinclause var node.
+ *
* 'subkeys' is a list of subkeys for which matching subkeys are to be
- * found
+ * found
* 'considered-subkeys' is the current list of all subkeys corresponding
- * to a given pathkey
- *
+ * to a given pathkey
+ *
* Returns a new pathkey(list of subkeys).
- *
+ *
*/
-static List *
-new_join_pathkey(List *subkeys,
- List *considered_subkeys,
- List *join_rel_tlist,
- List *joinclauses)
+static List *
+new_join_pathkey(List * subkeys,
+ List * considered_subkeys,
+ List * join_rel_tlist,
+ List * joinclauses)
{
- List *t_list = NIL;
- Var *subkey;
- List *i = NIL;
- List *matched_subkeys = NIL;
- Expr *tlist_key = (Expr*)NULL;
- List *newly_considered_subkeys = NIL;
-
- foreach (i, subkeys) {
- subkey = (Var *)lfirst(i);
- if(subkey == NULL)
- break; /* XXX something is wrong */
- matched_subkeys =
- new_matching_subkeys(subkey,considered_subkeys,
- join_rel_tlist,joinclauses);
- tlist_key = matching_tlvar(subkey,join_rel_tlist);
- newly_considered_subkeys = NIL;
-
- if (tlist_key) {
- if(!member(tlist_key, matched_subkeys))
- newly_considered_subkeys = lcons(tlist_key,
- matched_subkeys);
- }
- else {
- newly_considered_subkeys = matched_subkeys;
- }
-
- considered_subkeys =
- append(considered_subkeys, newly_considered_subkeys);
-
- t_list = nconc(t_list,newly_considered_subkeys);
- }
- return(t_list);
+ List *t_list = NIL;
+ Var *subkey;
+ List *i = NIL;
+ List *matched_subkeys = NIL;
+ Expr *tlist_key = (Expr *) NULL;
+ List *newly_considered_subkeys = NIL;
+
+ foreach(i, subkeys)
+ {
+ subkey = (Var *) lfirst(i);
+ if (subkey == NULL)
+ break; /* XXX something is wrong */
+ matched_subkeys =
+ new_matching_subkeys(subkey, considered_subkeys,
+ join_rel_tlist, joinclauses);
+ tlist_key = matching_tlvar(subkey, join_rel_tlist);
+ newly_considered_subkeys = NIL;
+
+ if (tlist_key)
+ {
+ if (!member(tlist_key, matched_subkeys))
+ newly_considered_subkeys = lcons(tlist_key,
+ matched_subkeys);
+ }
+ else
+ {
+ newly_considered_subkeys = matched_subkeys;
+ }
+
+ considered_subkeys =
+ append(considered_subkeys, newly_considered_subkeys);
+
+ t_list = nconc(t_list, newly_considered_subkeys);
+ }
+ return (t_list);
}
-/*
+/*
* new-matching-subkeys--
- * Returns a list of new subkeys:
- * (1) which are not listed in 'considered-subkeys'
- * (2) for which the "other" variable in some clause in 'joinclauses' is
- * 'subkey'
- * (3) which are mentioned in 'join-rel-tlist'
- *
- * Note that each returned subkey is the var node found in
- * 'join-rel-tlist' rather than the joinclause var node.
- *
+ * Returns a list of new subkeys:
+ * (1) which are not listed in 'considered-subkeys'
+ * (2) for which the "other" variable in some clause in 'joinclauses' is
+ * 'subkey'
+ * (3) which are mentioned in 'join-rel-tlist'
+ *
+ * Note that each returned subkey is the var node found in
+ * 'join-rel-tlist' rather than the joinclause var node.
+ *
* 'subkey' is the var node for which we are trying to find matching
- * clauses
- *
+ * clauses
+ *
* Returns a list of new subkeys.
*
*/
-static List *
-new_matching_subkeys(Var *subkey,
- List *considered_subkeys,
- List *join_rel_tlist,
- List *joinclauses)
+static List *
+new_matching_subkeys(Var * subkey,
+ List * considered_subkeys,
+ List * join_rel_tlist,
+ List * joinclauses)
{
- Expr *joinclause = NULL;
- List *t_list = NIL;
- List *temp = NIL;
- List *i = NIL;
- Expr *tlist_other_var = (Expr *)NULL;
-
- foreach(i,joinclauses) {
- joinclause = lfirst(i);
- tlist_other_var =
- matching_tlvar(other_join_clause_var(subkey,joinclause),
- join_rel_tlist);
-
- if(tlist_other_var &&
- !(member(tlist_other_var,considered_subkeys))) {
-
- /* XXX was "push" function */
- considered_subkeys = lappend(considered_subkeys,
- tlist_other_var);
-
- /* considered_subkeys = nreverse(considered_subkeys);
- XXX -- I am not sure of this. */
-
- temp = lcons(tlist_other_var, NIL);
- t_list = nconc(t_list,temp);
- }
- }
- return(t_list);
+ Expr *joinclause = NULL;
+ List *t_list = NIL;
+ List *temp = NIL;
+ List *i = NIL;
+ Expr *tlist_other_var = (Expr *) NULL;
+
+ foreach(i, joinclauses)
+ {
+ joinclause = lfirst(i);
+ tlist_other_var =
+ matching_tlvar(other_join_clause_var(subkey, joinclause),
+ join_rel_tlist);
+
+ if (tlist_other_var &&
+ !(member(tlist_other_var, considered_subkeys)))
+ {
+
+ /* XXX was "push" function */
+ considered_subkeys = lappend(considered_subkeys,
+ tlist_other_var);
+
+ /*
+ * considered_subkeys = nreverse(considered_subkeys); XXX -- I
+ * am not sure of this.
+ */
+
+ temp = lcons(tlist_other_var, NIL);
+ t_list = nconc(t_list, temp);
+ }
+ }
+ return (t_list);
}
diff --git a/src/backend/optimizer/path/mergeutils.c b/src/backend/optimizer/path/mergeutils.c
index d5f0fdcb65b..93004a6741e 100644
--- a/src/backend/optimizer/path/mergeutils.c
+++ b/src/backend/optimizer/path/mergeutils.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* mergeutils.c--
- * Utilities for finding applicable merge clauses and pathkeys
+ * Utilities for finding applicable merge clauses and pathkeys
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/mergeutils.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/mergeutils.c,v 1.2 1997/09/07 04:43:45 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,102 +21,110 @@
#include "optimizer/clauses.h"
#include "optimizer/ordering.h"
-/*
+/*
* group-clauses-by-order--
- * If a join clause node in 'clauseinfo-list' is mergesortable, store
- * it within a mergeinfo node containing other clause nodes with the same
- * mergesort ordering.
- *
+ * If a join clause node in 'clauseinfo-list' is mergesortable, store
+ * it within a mergeinfo node containing other clause nodes with the same
+ * mergesort ordering.
+ *
* 'clauseinfo-list' is the list of clauseinfo nodes
* 'inner-relid' is the relid of the inner join relation
- *
+ *
* Returns the new list of mergeinfo nodes.
- *
+ *
*/
-List *
-group_clauses_by_order(List *clauseinfo_list,
- int inner_relid)
+List *
+group_clauses_by_order(List * clauseinfo_list,
+ int inner_relid)
{
- List *mergeinfo_list = NIL;
- List *xclauseinfo = NIL;
-
- foreach (xclauseinfo, clauseinfo_list) {
- CInfo *clauseinfo = (CInfo *)lfirst(xclauseinfo);
- MergeOrder *merge_ordering = clauseinfo->mergesortorder;
-
- if (merge_ordering) {
- /*
- * Create a new mergeinfo node and add it to
- * 'mergeinfo-list' if one does not yet exist for this
- * merge ordering.
- */
- PathOrder p_ordering;
- MInfo *xmergeinfo;
- Expr *clause = clauseinfo->clause;
- Var *leftop = get_leftop (clause);
- Var *rightop = get_rightop (clause);
- JoinKey *keys;
-
- p_ordering.ordtype = MERGE_ORDER;
- p_ordering.ord.merge = merge_ordering;
- xmergeinfo =
- match_order_mergeinfo(&p_ordering, mergeinfo_list);
- if (inner_relid == leftop->varno) {
- keys = makeNode(JoinKey);
- keys->outer = rightop;
- keys->inner = leftop;
- } else {
- keys = makeNode(JoinKey);
- keys->outer = leftop;
- keys->inner = rightop;
- }
-
- if (xmergeinfo==NULL) {
- xmergeinfo = makeNode(MInfo);
-
- xmergeinfo->m_ordering = merge_ordering;
- mergeinfo_list = lcons(xmergeinfo,
- mergeinfo_list);
- }
-
- ((JoinMethod *)xmergeinfo)->clauses =
- lcons(clause,
- ((JoinMethod *)xmergeinfo)->clauses);
- ((JoinMethod *)xmergeinfo)->jmkeys =
- lcons(keys,
- ((JoinMethod *)xmergeinfo)->jmkeys);
+ List *mergeinfo_list = NIL;
+ List *xclauseinfo = NIL;
+
+ foreach(xclauseinfo, clauseinfo_list)
+ {
+ CInfo *clauseinfo = (CInfo *) lfirst(xclauseinfo);
+ MergeOrder *merge_ordering = clauseinfo->mergesortorder;
+
+ if (merge_ordering)
+ {
+
+ /*
+ * Create a new mergeinfo node and add it to 'mergeinfo-list'
+ * if one does not yet exist for this merge ordering.
+ */
+ PathOrder p_ordering;
+ MInfo *xmergeinfo;
+ Expr *clause = clauseinfo->clause;
+ Var *leftop = get_leftop(clause);
+ Var *rightop = get_rightop(clause);
+ JoinKey *keys;
+
+ p_ordering.ordtype = MERGE_ORDER;
+ p_ordering.ord.merge = merge_ordering;
+ xmergeinfo =
+ match_order_mergeinfo(&p_ordering, mergeinfo_list);
+ if (inner_relid == leftop->varno)
+ {
+ keys = makeNode(JoinKey);
+ keys->outer = rightop;
+ keys->inner = leftop;
+ }
+ else
+ {
+ keys = makeNode(JoinKey);
+ keys->outer = leftop;
+ keys->inner = rightop;
+ }
+
+ if (xmergeinfo == NULL)
+ {
+ xmergeinfo = makeNode(MInfo);
+
+ xmergeinfo->m_ordering = merge_ordering;
+ mergeinfo_list = lcons(xmergeinfo,
+ mergeinfo_list);
+ }
+
+ ((JoinMethod *) xmergeinfo)->clauses =
+ lcons(clause,
+ ((JoinMethod *) xmergeinfo)->clauses);
+ ((JoinMethod *) xmergeinfo)->jmkeys =
+ lcons(keys,
+ ((JoinMethod *) xmergeinfo)->jmkeys);
+ }
}
- }
- return(mergeinfo_list);
+ return (mergeinfo_list);
}
-/*
+/*
* match-order-mergeinfo--
- * Searches the list 'mergeinfo-list' for a mergeinfo node whose order
- * field equals 'ordering'.
- *
+ * Searches the list 'mergeinfo-list' for a mergeinfo node whose order
+ * field equals 'ordering'.
+ *
* Returns the node if it exists.
- *
+ *
*/
-MInfo *
-match_order_mergeinfo(PathOrder *ordering, List *mergeinfo_list)
+MInfo *
+match_order_mergeinfo(PathOrder * ordering, List * mergeinfo_list)
{
- MergeOrder *xmergeorder;
- List *xmergeinfo = NIL;
+ MergeOrder *xmergeorder;
+ List *xmergeinfo = NIL;
- foreach(xmergeinfo, mergeinfo_list) {
- MInfo *mergeinfo = (MInfo*)lfirst(xmergeinfo);
+ foreach(xmergeinfo, mergeinfo_list)
+ {
+ MInfo *mergeinfo = (MInfo *) lfirst(xmergeinfo);
- xmergeorder = mergeinfo->m_ordering;
+ xmergeorder = mergeinfo->m_ordering;
- if ((ordering->ordtype==MERGE_ORDER &&
- equal_merge_merge_ordering(ordering->ord.merge, xmergeorder)) ||
- (ordering->ordtype==SORTOP_ORDER &&
- equal_path_merge_ordering(ordering->ord.sortop, xmergeorder))) {
+ if ((ordering->ordtype == MERGE_ORDER &&
+ equal_merge_merge_ordering(ordering->ord.merge, xmergeorder)) ||
+ (ordering->ordtype == SORTOP_ORDER &&
+ equal_path_merge_ordering(ordering->ord.sortop, xmergeorder)))
+ {
- return (mergeinfo);
+ return (mergeinfo);
+ }
}
- }
- return((MInfo*) NIL);
+ return ((MInfo *) NIL);
}
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index e040675e6ec..96408b78905 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* orindxpath.c--
- * Routines to find index paths that match a set of 'or' clauses
+ * Routines to find index paths that match a set of 'or' clauses
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.1.1.1 1996/07/09 06:21:36 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.2 1997/09/07 04:43:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,241 +31,267 @@
#include "parser/parsetree.h"
-static void best_or_subclause_indices(Query *root, Rel *rel, List *subclauses,
- List *indices, List *examined_indexids, Cost subcost, List *selectivities,
- List **indexids, Cost *cost, List **selecs);
-static void best_or_subclause_index(Query *root, Rel *rel, Expr *subclause,
- List *indices, int *indexid, Cost *cost, Cost *selec);
+static void
+best_or_subclause_indices(Query * root, Rel * rel, List * subclauses,
+ List * indices, List * examined_indexids, Cost subcost, List * selectivities,
+ List ** indexids, Cost * cost, List ** selecs);
+static void
+best_or_subclause_index(Query * root, Rel * rel, Expr * subclause,
+ List * indices, int *indexid, Cost * cost, Cost * selec);
-/*
+/*
* create-or-index-paths--
- * Creates index paths for indices that match 'or' clauses.
- *
+ * Creates index paths for indices that match 'or' clauses.
+ *
* 'rel' is the relation entry for which the paths are to be defined on
* 'clauses' is the list of available restriction clause nodes
- *
+ *
* Returns a list of these index path nodes.
- *
+ *
*/
-List *
-create_or_index_paths(Query *root,
- Rel *rel, List *clauses)
+List *
+create_or_index_paths(Query * root,
+ Rel * rel, List * clauses)
{
- List *t_list = NIL;
-
- if (clauses != NIL) {
- CInfo *clausenode = (CInfo *) (lfirst (clauses));
-
- /* Check to see if this clause is an 'or' clause, and, if so,
- * whether or not each of the subclauses within the 'or' clause has
- * been matched by an index (the 'Index field was set in
- * (match_or) if no index matches a given subclause, one of the
- * lists of index nodes returned by (get_index) will be 'nil').
- */
- if (valid_or_clause(clausenode) &&
- clausenode->indexids) {
- List *temp = NIL;
- List *index_list = NIL;
- bool index_flag = true;
-
- index_list = clausenode->indexids;
- foreach(temp,index_list) {
- if (!temp)
- index_flag = false;
- }
- if (index_flag) { /* used to be a lisp every function */
- IndexPath *pathnode = makeNode(IndexPath);
- List *indexids;
- Cost cost;
- List *selecs;
+ List *t_list = NIL;
+
+ if (clauses != NIL)
+ {
+ CInfo *clausenode = (CInfo *) (lfirst(clauses));
+
+ /*
+ * Check to see if this clause is an 'or' clause, and, if so,
+ * whether or not each of the subclauses within the 'or' clause
+ * has been matched by an index (the 'Index field was set in
+ * (match_or) if no index matches a given subclause, one of the
+ * lists of index nodes returned by (get_index) will be 'nil').
+ */
+ if (valid_or_clause(clausenode) &&
+ clausenode->indexids)
+ {
+ List *temp = NIL;
+ List *index_list = NIL;
+ bool index_flag = true;
+
+ index_list = clausenode->indexids;
+ foreach(temp, index_list)
+ {
+ if (!temp)
+ index_flag = false;
+ }
+ if (index_flag)
+ { /* used to be a lisp every function */
+ IndexPath *pathnode = makeNode(IndexPath);
+ List *indexids;
+ Cost cost;
+ List *selecs;
- best_or_subclause_indices(root,
- rel,
- clausenode->clause->args,
- clausenode->indexids,
- NIL,
- (Cost)0,
- NIL,
- &indexids,
- &cost,
- &selecs);
-
- pathnode->path.pathtype = T_IndexScan;
- pathnode->path.parent = rel;
- pathnode->indexqual =
- lcons(clausenode,NIL);
- pathnode->indexid = indexids;
- pathnode->path.path_cost = cost;
-
- /* copy clauseinfo list into path for expensive
- function processing -- JMH, 7/7/92 */
- pathnode->path.locclauseinfo =
- set_difference(clauses,
- copyObject((Node*)
- rel->clauseinfo));
-
-#if 0 /* fix xfunc */
- /* add in cost for expensive functions! -- JMH, 7/7/92 */
- if (XfuncMode != XFUNC_OFF) {
- ((Path*)pathnode)->path_cost +=
- xfunc_get_path_cost((Path)pathnode);
+ best_or_subclause_indices(root,
+ rel,
+ clausenode->clause->args,
+ clausenode->indexids,
+ NIL,
+ (Cost) 0,
+ NIL,
+ &indexids,
+ &cost,
+ &selecs);
+
+ pathnode->path.pathtype = T_IndexScan;
+ pathnode->path.parent = rel;
+ pathnode->indexqual =
+ lcons(clausenode, NIL);
+ pathnode->indexid = indexids;
+ pathnode->path.path_cost = cost;
+
+ /*
+ * copy clauseinfo list into path for expensive function
+ * processing -- JMH, 7/7/92
+ */
+ pathnode->path.locclauseinfo =
+ set_difference(clauses,
+ copyObject((Node *)
+ rel->clauseinfo));
+
+#if 0 /* fix xfunc */
+ /* add in cost for expensive functions! -- JMH, 7/7/92 */
+ if (XfuncMode != XFUNC_OFF)
+ {
+ ((Path *) pathnode)->path_cost +=
+ xfunc_get_path_cost((Path) pathnode);
+ }
+#endif
+ clausenode->selectivity = (Cost) floatVal(selecs);
+ t_list =
+ lcons(pathnode,
+ create_or_index_paths(root, rel, lnext(clauses)));
+ }
+ else
+ {
+ t_list = create_or_index_paths(root, rel, lnext(clauses));
+ }
}
-#endif
- clausenode->selectivity = (Cost)floatVal(selecs);
- t_list =
- lcons(pathnode,
- create_or_index_paths(root, rel,lnext(clauses)));
- } else {
- t_list = create_or_index_paths(root, rel,lnext(clauses));
- }
}
- }
- return(t_list);
+ return (t_list);
}
-/*
+/*
* best-or-subclause-indices--
- * Determines the best index to be used in conjunction with each subclause
- * of an 'or' clause and the cost of scanning a relation using these
- * indices. The cost is the sum of the individual index costs.
- *
+ * Determines the best index to be used in conjunction with each subclause
+ * of an 'or' clause and the cost of scanning a relation using these
+ * indices. The cost is the sum of the individual index costs.
+ *
* 'rel' is the node of the relation on which the index is defined
* 'subclauses' are the subclauses of the 'or' clause
* 'indices' are those index nodes that matched subclauses of the 'or'
- * clause
- * 'examined-indexids' is a list of those index ids to be used with
- * subclauses that have already been examined
+ * clause
+ * 'examined-indexids' is a list of those index ids to be used with
+ * subclauses that have already been examined
* 'subcost' is the cost of using the indices in 'examined-indexids'
* 'selectivities' is a list of the selectivities of subclauses that
- * have already been examined
- *
+ * have already been examined
+ *
* Returns a list of the indexids, cost, and selectivities of each
* subclause, e.g., ((i1 i2 i3) cost (s1 s2 s3)), where 'i' is an OID,
* 'cost' is a flonum, and 's' is a flonum.
*/
static void
-best_or_subclause_indices(Query *root,
- Rel *rel,
- List *subclauses,
- List *indices,
- List *examined_indexids,
- Cost subcost,
- List *selectivities,
- List **indexids, /* return value */
- Cost *cost, /* return value */
- List **selecs) /* return value */
+best_or_subclause_indices(Query * root,
+ Rel * rel,
+ List * subclauses,
+ List * indices,
+ List * examined_indexids,
+ Cost subcost,
+ List * selectivities,
+ List ** indexids, /* return value */
+ Cost * cost, /* return value */
+ List ** selecs) /* return value */
{
- if (subclauses==NIL) {
- *indexids = nreverse(examined_indexids);
- *cost = subcost;
- *selecs = nreverse(selectivities);
- } else {
- int best_indexid;
- Cost best_cost;
- Cost best_selec;
-
- best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices),
- &best_indexid, &best_cost, &best_selec);
-
- best_or_subclause_indices(root,
- rel,
- lnext(subclauses),
- lnext(indices),
- lconsi(best_indexid, examined_indexids),
- subcost + best_cost,
- lcons(makeFloat(best_selec), selectivities),
- indexids,
- cost,
- selecs);
- }
- return;
-}
+ if (subclauses == NIL)
+ {
+ *indexids = nreverse(examined_indexids);
+ *cost = subcost;
+ *selecs = nreverse(selectivities);
+ }
+ else
+ {
+ int best_indexid;
+ Cost best_cost;
+ Cost best_selec;
+
+ best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices),
+ &best_indexid, &best_cost, &best_selec);
-/*
+ best_or_subclause_indices(root,
+ rel,
+ lnext(subclauses),
+ lnext(indices),
+ lconsi(best_indexid, examined_indexids),
+ subcost + best_cost,
+ lcons(makeFloat(best_selec), selectivities),
+ indexids,
+ cost,
+ selecs);
+ }
+ return;
+}
+
+/*
* best-or-subclause-index--
- * Determines which is the best index to be used with a subclause of
- * an 'or' clause by estimating the cost of using each index and selecting
- * the least expensive.
- *
+ * Determines which is the best index to be used with a subclause of
+ * an 'or' clause by estimating the cost of using each index and selecting
+ * the least expensive.
+ *
* 'rel' is the node of the relation on which the index is defined
* 'subclause' is the subclause
* 'indices' is a list of index nodes that match the subclause
- *
+ *
* Returns a list (index-id index-subcost index-selectivity)
* (a fixnum, a fixnum, and a flonum respectively).
- *
+ *
*/
static void
-best_or_subclause_index(Query *root,
- Rel *rel,
- Expr *subclause,
- List *indices,
- int *retIndexid, /* return value */
- Cost *retCost, /* return value */
- Cost *retSelec) /* return value */
+best_or_subclause_index(Query * root,
+ Rel * rel,
+ Expr * subclause,
+ List * indices,
+ int *retIndexid, /* return value */
+ Cost * retCost, /* return value */
+ Cost * retSelec) /* return value */
{
- if (indices != NIL) {
- Datum value;
- int flag = 0;
- Cost subcost;
- Rel *index = (Rel *)lfirst (indices);
- AttrNumber attno = (get_leftop (subclause))->varattno ;
- Oid opno = ((Oper*)subclause->oper)->opno;
- bool constant_on_right = non_null((Expr*)get_rightop(subclause));
- float npages, selec;
- int subclause_indexid;
- Cost subclause_cost;
- Cost subclause_selec;
-
- if(constant_on_right) {
- value = ((Const*)get_rightop (subclause))->constvalue;
- } else {
- value = NameGetDatum("");
- }
- if(constant_on_right) {
- flag = (_SELEC_IS_CONSTANT_ ||_SELEC_CONSTANT_RIGHT_);
- } else {
- flag = _SELEC_CONSTANT_RIGHT_;
- }
- index_selectivity(lfirsti(index->relids),
- index->classlist,
- lconsi(opno,NIL),
- getrelid(lfirsti(rel->relids),
- root->rtable),
- lconsi(attno,NIL),
- lconsi(value,NIL),
- lconsi(flag,NIL),
- 1,
- &npages,
- &selec);
-
- subcost = cost_index((Oid) lfirsti(index->relids),
- (int)npages,
- (Cost)selec,
- rel->pages,
- rel->tuples,
- index->pages,
- index->tuples,
- false);
- best_or_subclause_index(root,
- rel,
- subclause,
- lnext(indices),
- &subclause_indexid,
- &subclause_cost,
- &subclause_selec);
+ if (indices != NIL)
+ {
+ Datum value;
+ int flag = 0;
+ Cost subcost;
+ Rel *index = (Rel *) lfirst(indices);
+ AttrNumber attno = (get_leftop(subclause))->varattno;
+ Oid opno = ((Oper *) subclause->oper)->opno;
+ bool constant_on_right = non_null((Expr *) get_rightop(subclause));
+ float npages,
+ selec;
+ int subclause_indexid;
+ Cost subclause_cost;
+ Cost subclause_selec;
- if (subclause_indexid==0 || subcost < subclause_cost) {
- *retIndexid = lfirsti(index->relids);
- *retCost = subcost;
- *retSelec = selec;
- } else {
- *retIndexid = 0;
- *retCost = 0.0;
- *retSelec = 0.0;
- }
- }
- return;
+ if (constant_on_right)
+ {
+ value = ((Const *) get_rightop(subclause))->constvalue;
+ }
+ else
+ {
+ value = NameGetDatum("");
+ }
+ if (constant_on_right)
+ {
+ flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_);
+ }
+ else
+ {
+ flag = _SELEC_CONSTANT_RIGHT_;
+ }
+ index_selectivity(lfirsti(index->relids),
+ index->classlist,
+ lconsi(opno, NIL),
+ getrelid(lfirsti(rel->relids),
+ root->rtable),
+ lconsi(attno, NIL),
+ lconsi(value, NIL),
+ lconsi(flag, NIL),
+ 1,
+ &npages,
+ &selec);
+
+ subcost = cost_index((Oid) lfirsti(index->relids),
+ (int) npages,
+ (Cost) selec,
+ rel->pages,
+ rel->tuples,
+ index->pages,
+ index->tuples,
+ false);
+ best_or_subclause_index(root,
+ rel,
+ subclause,
+ lnext(indices),
+ &subclause_indexid,
+ &subclause_cost,
+ &subclause_selec);
+
+ if (subclause_indexid == 0 || subcost < subclause_cost)
+ {
+ *retIndexid = lfirsti(index->relids);
+ *retCost = subcost;
+ *retSelec = selec;
+ }
+ else
+ {
+ *retIndexid = 0;
+ *retCost = 0.0;
+ *retSelec = 0.0;
+ }
+ }
+ return;
}
diff --git a/src/backend/optimizer/path/predmig.c b/src/backend/optimizer/path/predmig.c
index 241ab4a12d7..c302af3b581 100644
--- a/src/backend/optimizer/path/predmig.c
+++ b/src/backend/optimizer/path/predmig.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* predmig.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/predmig.c,v 1.2 1996/10/23 07:14:41 bryanh Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/predmig.c,v 1.3 1997/09/07 04:43:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,23 +16,23 @@
** Main Routines to handle Predicate Migration (i.e. correct optimization
** of queries with expensive functions.)
**
-** The reasoning behind some of these algorithms is rather detailed.
-** Have a look at Sequoia Tech Report 92/13 for more info. Also
+** The reasoning behind some of these algorithms is rather detailed.
+** Have a look at Sequoia Tech Report 92/13 for more info. Also
** see Monma and Sidney's paper "Sequencing with Series-Parallel
** Precedence Constraints", in "Mathematics of Operations Research",
** volume 4 (1979), pp. 215-224.
**
-** The main thing that this code does that wasn't handled in xfunc.c is
+** The main thing that this code does that wasn't handled in xfunc.c is
** it considers the possibility that two joins in a stream may not
** be ordered by ascending rank -- in such a scenario, it may be optimal
** to pullup more restrictions than we did via xfunc_try_pullup.
**
-** This code in some sense generalizes xfunc_try_pullup; if you
+** This code in some sense generalizes xfunc_try_pullup; if you
** run postgres -x noprune, you'll turn off xfunc_try_pullup, and this
** code will do everything that xfunc_try_pullup would have, and maybe
-** more. However, this results in no pruning, which may slow down the
+** more. However, this results in no pruning, which may slow down the
** optimizer and/or cause the system to run out of memory.
-** -- JMH, 11/13/92
+** -- JMH, 11/13/92
*/
#include "nodes/pg_list.h"
@@ -49,331 +49,350 @@
#include "optimizer/tlist.h"
#include "lib/qsort.h"
-#define is_clause(node) (get_cinfo(node)) /* a stream node represents a
- clause (not a join) iff it
- has a non-NULL cinfo field */
-
-static void xfunc_predmig(JoinPath pathnode, Stream streamroot,
- Stream laststream, bool *progressp);
-static bool xfunc_series_llel(Stream stream);
-static bool xfunc_llel_chains(Stream root, Stream bottom);
-static Stream xfunc_complete_stream(Stream stream);
-static bool xfunc_prdmig_pullup(Stream origstream, Stream pullme,
- JoinPath joinpath);
-static void xfunc_form_groups(Stream root, Stream bottom);
-static void xfunc_free_stream(Stream root);
-static Stream xfunc_add_clauses(Stream current);
-static void xfunc_setup_group(Stream node, Stream bottom);
-static Stream xfunc_streaminsert(CInfo clauseinfo, Stream current,
- int clausetype);
-static int xfunc_num_relids(Stream node);
+#define is_clause(node) (get_cinfo(node)) /* a stream node
+ * represents a clause
+ * (not a join) iff it has
+ * a non-NULL cinfo field */
+
+static void
+xfunc_predmig(JoinPath pathnode, Stream streamroot,
+ Stream laststream, bool * progressp);
+static bool xfunc_series_llel(Stream stream);
+static bool xfunc_llel_chains(Stream root, Stream bottom);
+static Stream xfunc_complete_stream(Stream stream);
+static bool
+xfunc_prdmig_pullup(Stream origstream, Stream pullme,
+ JoinPath joinpath);
+static void xfunc_form_groups(Stream root, Stream bottom);
+static void xfunc_free_stream(Stream root);
+static Stream xfunc_add_clauses(Stream current);
+static void xfunc_setup_group(Stream node, Stream bottom);
+static Stream
+xfunc_streaminsert(CInfo clauseinfo, Stream current,
+ int clausetype);
+static int xfunc_num_relids(Stream node);
static StreamPtr xfunc_get_downjoin(Stream node);
static StreamPtr xfunc_get_upjoin(Stream node);
-static Stream xfunc_stream_qsort(Stream root, Stream bottom);
-static int xfunc_stream_compare(void *arg1, void *arg2);
-static bool xfunc_check_stream(Stream node);
-static bool xfunc_in_stream(Stream node, Stream stream);
+static Stream xfunc_stream_qsort(Stream root, Stream bottom);
+static int xfunc_stream_compare(void *arg1, void *arg2);
+static bool xfunc_check_stream(Stream node);
+static bool xfunc_in_stream(Stream node, Stream stream);
-/* ----------------- MAIN FUNCTIONS ------------------------ */
+/* ----------------- MAIN FUNCTIONS ------------------------ */
/*
** xfunc_do_predmig
-** wrapper for Predicate Migration. It calls xfunc_predmig until no
+** wrapper for Predicate Migration. It calls xfunc_predmig until no
** more progress is made.
-** return value says if any changes were ever made.
+** return value says if any changes were ever made.
*/
-bool xfunc_do_predmig(Path root)
+bool
+xfunc_do_predmig(Path root)
{
- bool progress, changed = false;
-
- if (is_join(root))
- do
- {
- progress = false;
- Assert(IsA(root,JoinPath));
- xfunc_predmig((JoinPath)root, (Stream)NULL, (Stream)NULL,
- &progress);
- if (changed && progress)
- elog(DEBUG, "Needed to do a second round of predmig!\n");
- if (progress) changed = true;
- } while (progress);
- return(changed);
+ bool progress,
+ changed = false;
+
+ if (is_join(root))
+ do
+ {
+ progress = false;
+ Assert(IsA(root, JoinPath));
+ xfunc_predmig((JoinPath) root, (Stream) NULL, (Stream) NULL,
+ &progress);
+ if (changed && progress)
+ elog(DEBUG, "Needed to do a second round of predmig!\n");
+ if (progress)
+ changed = true;
+ } while (progress);
+ return (changed);
}
/*
** xfunc_predmig
- ** The main routine for Predicate Migration. It traverses a join tree,
- ** and for each root-to-leaf path in the plan tree it constructs a
+ ** The main routine for Predicate Migration. It traverses a join tree,
+ ** and for each root-to-leaf path in the plan tree it constructs a
** "Stream", which it passes to xfunc_series_llel for optimization.
** Destructively modifies the join tree (via predicate pullup).
*/
static void
-xfunc_predmig(JoinPath pathnode, /* root of the join tree */
- Stream streamroot,
- Stream laststream, /* for recursive calls -- these are
- the root of the stream under
- construction, and the lowest node
- created so far */
- bool *progressp)
+xfunc_predmig(JoinPath pathnode,/* root of the join tree */
+ Stream streamroot,
+ Stream laststream,/* for recursive calls -- these are the
+ * root of the stream under construction,
+ * and the lowest node created so far */
+ bool * progressp)
{
- Stream newstream;
-
- /*
- ** traverse the join tree dfs-style, constructing a stream as you go.
- ** When you hit a scan node, pass the stream off to xfunc_series_llel.
- */
-
- /* sanity check */
- if ((!streamroot && laststream) ||
- (streamroot && !laststream))
- elog(WARN, "called xfunc_predmig with bad inputs");
- if (streamroot) Assert(xfunc_check_stream(streamroot));
-
- /* add path node to stream */
- newstream = RMakeStream();
- if (!streamroot)
- streamroot = newstream;
- set_upstream(newstream, (StreamPtr)laststream);
- if (laststream)
- set_downstream(laststream, (StreamPtr)newstream);
- set_downstream(newstream, (StreamPtr)NULL);
- set_pathptr(newstream, (pathPtr)pathnode);
- set_cinfo(newstream, (CInfo)NULL);
- set_clausetype(newstream, XFUNC_UNKNOWN);
-
- /* base case: we're at a leaf, call xfunc_series_llel */
- if (!is_join(pathnode))
+ Stream newstream;
+
+ /*
+ * * traverse the join tree dfs-style, constructing a stream as you
+ * go. * When you hit a scan node, pass the stream off to
+ * xfunc_series_llel.
+ */
+
+ /* sanity check */
+ if ((!streamroot && laststream) ||
+ (streamroot && !laststream))
+ elog(WARN, "called xfunc_predmig with bad inputs");
+ if (streamroot)
+ Assert(xfunc_check_stream(streamroot));
+
+ /* add path node to stream */
+ newstream = RMakeStream();
+ if (!streamroot)
+ streamroot = newstream;
+ set_upstream(newstream, (StreamPtr) laststream);
+ if (laststream)
+ set_downstream(laststream, (StreamPtr) newstream);
+ set_downstream(newstream, (StreamPtr) NULL);
+ set_pathptr(newstream, (pathPtr) pathnode);
+ set_cinfo(newstream, (CInfo) NULL);
+ set_clausetype(newstream, XFUNC_UNKNOWN);
+
+ /* base case: we're at a leaf, call xfunc_series_llel */
+ if (!is_join(pathnode))
{
- /* form a fleshed-out copy of the stream */
- Stream fullstream = xfunc_complete_stream(streamroot);
-
- /* sort it via series-llel */
- if (xfunc_series_llel(fullstream))
- *progressp = true;
-
- /* free up the copy */
- xfunc_free_stream(fullstream);
+ /* form a fleshed-out copy of the stream */
+ Stream fullstream = xfunc_complete_stream(streamroot);
+
+ /* sort it via series-llel */
+ if (xfunc_series_llel(fullstream))
+ *progressp = true;
+
+ /* free up the copy */
+ xfunc_free_stream(fullstream);
}
- else
+ else
{
- /* visit left child */
- xfunc_predmig((JoinPath)get_outerjoinpath(pathnode),
- streamroot, newstream, progressp);
-
- /* visit right child */
- xfunc_predmig((JoinPath)get_innerjoinpath(pathnode),
- streamroot, newstream, progressp);
+ /* visit left child */
+ xfunc_predmig((JoinPath) get_outerjoinpath(pathnode),
+ streamroot, newstream, progressp);
+
+ /* visit right child */
+ xfunc_predmig((JoinPath) get_innerjoinpath(pathnode),
+ streamroot, newstream, progressp);
}
-
- /* remove this node */
- if (get_upstream(newstream))
- set_downstream((Stream)get_upstream(newstream), (StreamPtr)NULL);
- pfree(newstream);
+
+ /* remove this node */
+ if (get_upstream(newstream))
+ set_downstream((Stream) get_upstream(newstream), (StreamPtr) NULL);
+ pfree(newstream);
}
/*
** xfunc_series_llel
** A flavor of Monma and Sidney's Series-Parallel algorithm.
- ** Traverse stream downwards. When you find a node with restrictions on it,
+ ** Traverse stream downwards. When you find a node with restrictions on it,
** call xfunc_llel_chains on the substream from root to that node.
*/
-static bool xfunc_series_llel(Stream stream)
+static bool
+xfunc_series_llel(Stream stream)
{
- Stream temp, next;
- bool progress = false;
-
- for (temp = stream; temp != (Stream)NULL; temp = next)
+ Stream temp,
+ next;
+ bool progress = false;
+
+ for (temp = stream; temp != (Stream) NULL; temp = next)
{
- next = (Stream)xfunc_get_downjoin(temp);
- /*
- ** if there are restrictions/secondary join clauses above this
- ** node, call xfunc_llel_chains
- */
- if (get_upstream(temp) && is_clause((Stream)get_upstream(temp)))
- if (xfunc_llel_chains(stream, temp))
- progress = true;
+ next = (Stream) xfunc_get_downjoin(temp);
+
+ /*
+ * * if there are restrictions/secondary join clauses above this *
+ * node, call xfunc_llel_chains
+ */
+ if (get_upstream(temp) && is_clause((Stream) get_upstream(temp)))
+ if (xfunc_llel_chains(stream, temp))
+ progress = true;
}
- return(progress);
+ return (progress);
}
/*
** xfunc_llel_chains
** A flavor of Monma and Sidney's Parallel Chains algorithm.
** Given a stream which has been well-ordered except for its lowermost
- ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate.
+ ** restrictions/2-ary joins, pull up the restrictions/2-arys as appropriate.
** What that means here is to form groups in the chain above the lowest
- ** join node above bottom inclusive, and then take all the restrictions
+ ** join node above bottom inclusive, and then take all the restrictions
** following bottom, and try to pull them up as far as possible.
*/
-static bool xfunc_llel_chains(Stream root, Stream bottom)
+static bool
+xfunc_llel_chains(Stream root, Stream bottom)
{
- bool progress = false;
- Stream origstream;
- Stream tmpstream, pathstream;
- Stream rootcopy = root;
-
- Assert(xfunc_check_stream(root));
-
- /* xfunc_prdmig_pullup will need an unmodified copy of the stream */
- origstream = (Stream)copyObject((Node)root);
-
- /* form groups among ill-ordered nodes */
- xfunc_form_groups(root, bottom);
-
- /* sort chain by rank */
- Assert(xfunc_in_stream(bottom, root));
- rootcopy = xfunc_stream_qsort(root, bottom);
-
- /*
- ** traverse sorted stream -- if any restriction has moved above a join,
- ** we must pull it up in the plan. That is, make plan tree
- ** reflect order of sorted stream.
- */
- for (tmpstream = rootcopy,
- pathstream = (Stream)xfunc_get_downjoin(rootcopy);
- tmpstream != (Stream)NULL && pathstream != (Stream)NULL;
- tmpstream = (Stream)get_downstream(tmpstream))
+ bool progress = false;
+ Stream origstream;
+ Stream tmpstream,
+ pathstream;
+ Stream rootcopy = root;
+
+ Assert(xfunc_check_stream(root));
+
+ /* xfunc_prdmig_pullup will need an unmodified copy of the stream */
+ origstream = (Stream) copyObject((Node) root);
+
+ /* form groups among ill-ordered nodes */
+ xfunc_form_groups(root, bottom);
+
+ /* sort chain by rank */
+ Assert(xfunc_in_stream(bottom, root));
+ rootcopy = xfunc_stream_qsort(root, bottom);
+
+ /*
+ * * traverse sorted stream -- if any restriction has moved above a
+ * join, * we must pull it up in the plan. That is, make plan tree *
+ * reflect order of sorted stream.
+ */
+ for (tmpstream = rootcopy,
+ pathstream = (Stream) xfunc_get_downjoin(rootcopy);
+ tmpstream != (Stream) NULL && pathstream != (Stream) NULL;
+ tmpstream = (Stream) get_downstream(tmpstream))
{
- if (is_clause(tmpstream)
- && get_pathptr(pathstream) != get_pathptr(tmpstream))
+ if (is_clause(tmpstream)
+ && get_pathptr(pathstream) != get_pathptr(tmpstream))
{
- /*
- ** If restriction moved above a Join after sort, we pull it
- ** up in the join plan.
- ** If restriction moved down, we ignore it.
- ** This is because Joey's Sequoia paper proves that
- ** restrictions should never move down. If this
- ** one were moved down, it would violate "semantic correctness",
- ** i.e. it would be lower than the attributes it references.
- */
- Assert(xfunc_num_relids(pathstream)>xfunc_num_relids(tmpstream));
- progress =
- xfunc_prdmig_pullup(origstream, tmpstream,
- (JoinPath)get_pathptr(pathstream));
+
+ /*
+ * * If restriction moved above a Join after sort, we pull it *
+ * up in the join plan. * If restriction moved down, we
+ * ignore it. * This is because Joey's Sequoia paper proves
+ * that * restrictions should never move down. If this * one
+ * were moved down, it would violate "semantic correctness", *
+ * i.e. it would be lower than the attributes it references.
+ */
+ Assert(xfunc_num_relids(pathstream) > xfunc_num_relids(tmpstream));
+ progress =
+ xfunc_prdmig_pullup(origstream, tmpstream,
+ (JoinPath) get_pathptr(pathstream));
}
- if (get_downstream(tmpstream))
- pathstream =
- (Stream)xfunc_get_downjoin((Stream)get_downstream(tmpstream));
+ if (get_downstream(tmpstream))
+ pathstream =
+ (Stream) xfunc_get_downjoin((Stream) get_downstream(tmpstream));
}
-
- /* free up origstream */
- xfunc_free_stream(origstream);
- return(progress);
+
+ /* free up origstream */
+ xfunc_free_stream(origstream);
+ return (progress);
}
/*
** xfunc_complete_stream --
** Given a stream composed of join nodes only, make a copy containing the
- ** join nodes along with the associated restriction nodes.
+ ** join nodes along with the associated restriction nodes.
*/
-static Stream xfunc_complete_stream(Stream stream)
+static Stream
+xfunc_complete_stream(Stream stream)
{
- Stream tmpstream, copystream, curstream = (Stream)NULL;
-
- copystream = (Stream)copyObject((Node)stream);
- Assert(xfunc_check_stream(copystream));
-
- curstream = copystream;
- Assert(!is_clause(curstream));
-
- /* curstream = (Stream)xfunc_get_downjoin(curstream); */
-
- while(curstream != (Stream)NULL)
+ Stream tmpstream,
+ copystream,
+ curstream = (Stream) NULL;
+
+ copystream = (Stream) copyObject((Node) stream);
+ Assert(xfunc_check_stream(copystream));
+
+ curstream = copystream;
+ Assert(!is_clause(curstream));
+
+ /* curstream = (Stream)xfunc_get_downjoin(curstream); */
+
+ while (curstream != (Stream) NULL)
{
- xfunc_add_clauses(curstream);
- curstream = (Stream)xfunc_get_downjoin(curstream);
+ xfunc_add_clauses(curstream);
+ curstream = (Stream) xfunc_get_downjoin(curstream);
}
-
- /* find top of stream and return it */
- for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr)NULL;
- tmpstream = (Stream)get_upstream(tmpstream))
- /* no body in for loop */;
-
- return(tmpstream);
+
+ /* find top of stream and return it */
+ for (tmpstream = copystream; get_upstream(tmpstream) != (StreamPtr) NULL;
+ tmpstream = (Stream) get_upstream(tmpstream))
+ /* no body in for loop */ ;
+
+ return (tmpstream);
}
/*
** xfunc_prdmig_pullup
** pullup a clause in a path above joinpath. Since the JoinPath tree
- ** doesn't have upward pointers, it's difficult to deal with. Thus we
+ ** doesn't have upward pointers, it's difficult to deal with. Thus we
** require the original stream, which maintains pointers to all the path
- ** nodes. We use the original stream to find out what joins are
+ ** nodes. We use the original stream to find out what joins are
** above the clause.
*/
-static bool
+static bool
xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath)
{
- CInfo clauseinfo = get_cinfo(pullme);
- bool progress = false;
- Stream upjoin, orignode, temp;
- int whichchild;
-
- /* find node in origstream that contains clause */
- for (orignode = origstream;
- orignode != (Stream) NULL
- && get_cinfo(orignode) != clauseinfo;
- orignode = (Stream)get_downstream(orignode))
- /* empty body in for loop */ ;
- if (!orignode)
- elog(WARN, "Didn't find matching node in original stream");
-
-
- /* pull up this node as far as it should go */
- for (upjoin = (Stream)xfunc_get_upjoin(orignode);
- upjoin != (Stream)NULL
- && (JoinPath)get_pathptr((Stream)xfunc_get_downjoin(upjoin))
- != joinpath;
- upjoin = (Stream)xfunc_get_upjoin(upjoin))
+ CInfo clauseinfo = get_cinfo(pullme);
+ bool progress = false;
+ Stream upjoin,
+ orignode,
+ temp;
+ int whichchild;
+
+ /* find node in origstream that contains clause */
+ for (orignode = origstream;
+ orignode != (Stream) NULL
+ && get_cinfo(orignode) != clauseinfo;
+ orignode = (Stream) get_downstream(orignode))
+ /* empty body in for loop */ ;
+ if (!orignode)
+ elog(WARN, "Didn't find matching node in original stream");
+
+
+ /* pull up this node as far as it should go */
+ for (upjoin = (Stream) xfunc_get_upjoin(orignode);
+ upjoin != (Stream) NULL
+ && (JoinPath) get_pathptr((Stream) xfunc_get_downjoin(upjoin))
+ != joinpath;
+ upjoin = (Stream) xfunc_get_upjoin(upjoin))
{
-#ifdef DEBUG
- elog(DEBUG, "pulling up in xfunc_predmig_pullup!");
+#ifdef DEBUG
+ elog(DEBUG, "pulling up in xfunc_predmig_pullup!");
#endif
- /* move clause up in path */
- if (get_pathptr((Stream)get_downstream(upjoin))
- == (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(upjoin)))
- whichchild = OUTER;
- else whichchild = INNER;
- clauseinfo = xfunc_pullup((Path)get_pathptr((Stream)get_downstream(upjoin)),
- (JoinPath)get_pathptr(upjoin),
- clauseinfo,
- whichchild,
- get_clausetype(orignode));
- set_pathptr(pullme, get_pathptr(upjoin));
- /* pullme has been moved into locclauseinfo */
- set_clausetype(pullme, XFUNC_LOCPRD);
-
- /*
- ** xfunc_pullup makes new path nodes for children of
- ** get_pathptr(current). We must modify the stream nodes to point
- ** to these path nodes
- */
- if (whichchild == OUTER)
+ /* move clause up in path */
+ if (get_pathptr((Stream) get_downstream(upjoin))
+ == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)))
+ whichchild = OUTER;
+ else
+ whichchild = INNER;
+ clauseinfo = xfunc_pullup((Path) get_pathptr((Stream) get_downstream(upjoin)),
+ (JoinPath) get_pathptr(upjoin),
+ clauseinfo,
+ whichchild,
+ get_clausetype(orignode));
+ set_pathptr(pullme, get_pathptr(upjoin));
+ /* pullme has been moved into locclauseinfo */
+ set_clausetype(pullme, XFUNC_LOCPRD);
+
+ /*
+ * * xfunc_pullup makes new path nodes for children of *
+ * get_pathptr(current). We must modify the stream nodes to point *
+ * to these path nodes
+ */
+ if (whichchild == OUTER)
{
- for(temp = (Stream)get_downstream(upjoin); is_clause(temp);
- temp = (Stream)get_downstream(temp))
+ for (temp = (Stream) get_downstream(upjoin); is_clause(temp);
+ temp = (Stream) get_downstream(temp))
+ set_pathptr
+ (temp, (pathPtr)
+ get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
set_pathptr
- (temp, (pathPtr)
- get_outerjoinpath((JoinPath)get_pathptr(upjoin)));
- set_pathptr
- (temp,
- (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(upjoin)));
+ (temp,
+ (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(upjoin)));
}
- else
+ else
{
- for(temp = (Stream)get_downstream(upjoin); is_clause(temp);
- temp = (Stream)get_downstream(temp))
+ for (temp = (Stream) get_downstream(upjoin); is_clause(temp);
+ temp = (Stream) get_downstream(temp))
+ set_pathptr
+ (temp, (pathPtr)
+ get_innerjoinpath((JoinPath) get_pathptr(upjoin)));
set_pathptr
- (temp, (pathPtr)
- get_innerjoinpath((JoinPath)get_pathptr(upjoin)));
- set_pathptr
- (temp, (pathPtr)
- get_innerjoinpath((JoinPath)get_pathptr(upjoin)));
+ (temp, (pathPtr)
+ get_innerjoinpath((JoinPath) get_pathptr(upjoin)));
}
- progress = true;
+ progress = true;
}
- if (!progress)
- elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup");
- return(progress);
+ if (!progress)
+ elog(DEBUG, "didn't succeed in pulling up in xfunc_prdmig_pullup");
+ return (progress);
}
/*
@@ -386,143 +405,151 @@ xfunc_prdmig_pullup(Stream origstream, Stream pullme, JoinPath joinpath)
** equal to the cost of the first plus the selectivity of the first times the
** cost of the second. We define each node to be in a group by itself,
** and then repeatedly find adjacent groups which are ordered by descending
- ** rank, and make larger groups. You know that two adjacent nodes are in a
- ** group together if the lower has groupup set to true. They will both have
+ ** rank, and make larger groups. You know that two adjacent nodes are in a
+ ** group together if the lower has groupup set to true. They will both have
** the same groupcost and groupsel (since they're in the same group!)
*/
-static void xfunc_form_groups(Query* queryInfo, Stream root, Stream bottom)
+static void
+xfunc_form_groups(Query * queryInfo, Stream root, Stream bottom)
{
- Stream temp, parent;
- int lowest = xfunc_num_relids((Stream)xfunc_get_upjoin(bottom));
- bool progress;
- LispValue primjoin;
- int whichchild;
-
- if (!lowest) return; /* no joins in stream, so no groups */
-
- /* initialize groups to be single nodes */
- for (temp = root;
- temp != (Stream)NULL && temp != bottom;
- temp = (Stream)get_downstream(temp))
+ Stream temp,
+ parent;
+ int lowest = xfunc_num_relids((Stream) xfunc_get_upjoin(bottom));
+ bool progress;
+ LispValue primjoin;
+ int whichchild;
+
+ if (!lowest)
+ return; /* no joins in stream, so no groups */
+
+ /* initialize groups to be single nodes */
+ for (temp = root;
+ temp != (Stream) NULL && temp != bottom;
+ temp = (Stream) get_downstream(temp))
{
- /* if a Join node */
- if (!is_clause(temp))
+ /* if a Join node */
+ if (!is_clause(temp))
{
- if (get_pathptr((Stream)get_downstream(temp))
- == (pathPtr)get_outerjoinpath((JoinPath)get_pathptr(temp)))
- whichchild = OUTER;
- else whichchild = INNER;
- set_groupcost(temp,
- xfunc_join_expense((JoinPath)get_pathptr(temp),
- whichchild));
- if (primjoin = xfunc_primary_join((JoinPath)get_pathptr(temp)))
+ if (get_pathptr((Stream) get_downstream(temp))
+ == (pathPtr) get_outerjoinpath((JoinPath) get_pathptr(temp)))
+ whichchild = OUTER;
+ else
+ whichchild = INNER;
+ set_groupcost(temp,
+ xfunc_join_expense((JoinPath) get_pathptr(temp),
+ whichchild));
+ if (primjoin = xfunc_primary_join((JoinPath) get_pathptr(temp)))
{
- set_groupsel(temp,
- compute_clause_selec(queryInfo,
- primjoin, NIL));
+ set_groupsel(temp,
+ compute_clause_selec(queryInfo,
+ primjoin, NIL));
}
- else
+ else
{
- set_groupsel(temp,1.0);
+ set_groupsel(temp, 1.0);
}
}
- else /* a restriction, or 2-ary join pred */
+ else
+/* a restriction, or 2-ary join pred */
{
- set_groupcost(temp,
- xfunc_expense(queryInfo,
- get_clause(get_cinfo(temp))));
- set_groupsel(temp,
- compute_clause_selec(queryInfo,
- get_clause(get_cinfo(temp)),
- NIL));
+ set_groupcost(temp,
+ xfunc_expense(queryInfo,
+ get_clause(get_cinfo(temp))));
+ set_groupsel(temp,
+ compute_clause_selec(queryInfo,
+ get_clause(get_cinfo(temp)),
+ NIL));
}
- set_groupup(temp,false);
+ set_groupup(temp, false);
}
-
- /* make passes upwards, forming groups */
- do
+
+ /* make passes upwards, forming groups */
+ do
{
- progress = false;
- for (temp = (Stream)get_upstream(bottom);
- temp != (Stream)NULL;
- temp = (Stream)get_upstream(temp))
+ progress = false;
+ for (temp = (Stream) get_upstream(bottom);
+ temp != (Stream) NULL;
+ temp = (Stream) get_upstream(temp))
{
- /* check for grouping with node upstream */
- if (!get_groupup(temp) && /* not already grouped */
- (parent = (Stream)get_upstream(temp)) != (Stream)NULL &&
+ /* check for grouping with node upstream */
+ if (!get_groupup(temp) && /* not already grouped */
+ (parent = (Stream) get_upstream(temp)) != (Stream) NULL &&
/* temp is a join or temp is the top of a group */
- (is_join((Path)get_pathptr(temp)) ||
- get_downstream(temp) &&
- get_groupup((Stream)get_downstream(temp))) &&
- get_grouprank(parent) < get_grouprank(temp))
+ (is_join((Path) get_pathptr(temp)) ||
+ get_downstream(temp) &&
+ get_groupup((Stream) get_downstream(temp))) &&
+ get_grouprank(parent) < get_grouprank(temp))
{
- progress = true; /* we formed a new group */
- set_groupup(temp,true);
- set_groupcost(temp,
- get_groupcost(temp) +
- get_groupsel(temp) * get_groupcost(parent));
- set_groupsel(temp,get_groupsel(temp) * get_groupsel(parent));
-
- /* fix costs and sels of all members of group */
- xfunc_setup_group(temp, bottom);
+ progress = true;/* we formed a new group */
+ set_groupup(temp, true);
+ set_groupcost(temp,
+ get_groupcost(temp) +
+ get_groupsel(temp) * get_groupcost(parent));
+ set_groupsel(temp, get_groupsel(temp) * get_groupsel(parent));
+
+ /* fix costs and sels of all members of group */
+ xfunc_setup_group(temp, bottom);
}
}
- } while(progress);
+ } while (progress);
}
-/* ------------------- UTILITY FUNCTIONS ------------------------- */
+/* ------------------- UTILITY FUNCTIONS ------------------------- */
/*
** xfunc_free_stream --
** walk down a stream and pfree it
*/
-static void xfunc_free_stream(Stream root)
+static void
+xfunc_free_stream(Stream root)
{
- Stream cur, next;
-
- Assert(xfunc_check_stream(root));
-
- if (root != (Stream)NULL)
- for (cur = root; cur != (Stream)NULL; cur = next)
- {
- next = (Stream)get_downstream(cur);
- pfree(cur);
- }
+ Stream cur,
+ next;
+
+ Assert(xfunc_check_stream(root));
+
+ if (root != (Stream) NULL)
+ for (cur = root; cur != (Stream) NULL; cur = next)
+ {
+ next = (Stream) get_downstream(cur);
+ pfree(cur);
+ }
}
/*
** xfunc_add<_clauses
- ** find any clauses above current, and insert them into stream as
+ ** find any clauses above current, and insert them into stream as
** appropriate. Return uppermost clause inserted, or current if none.
*/
-static Stream xfunc_add_clauses(Stream current)
+static Stream
+xfunc_add_clauses(Stream current)
{
- Stream topnode = current;
- LispValue temp;
- LispValue primjoin;
-
- /* first add in the local clauses */
- foreach(temp, get_locclauseinfo((Path)get_pathptr(current)))
+ Stream topnode = current;
+ LispValue temp;
+ LispValue primjoin;
+
+ /* first add in the local clauses */
+ foreach(temp, get_locclauseinfo((Path) get_pathptr(current)))
{
- topnode =
- xfunc_streaminsert((CInfo)lfirst(temp), topnode,
- XFUNC_LOCPRD);
+ topnode =
+ xfunc_streaminsert((CInfo) lfirst(temp), topnode,
+ XFUNC_LOCPRD);
}
-
- /* and add in the join clauses */
- if (IsA(get_pathptr(current),JoinPath))
+
+ /* and add in the join clauses */
+ if (IsA(get_pathptr(current), JoinPath))
{
- primjoin = xfunc_primary_join((JoinPath)get_pathptr(current));
- foreach(temp, get_pathclauseinfo((JoinPath)get_pathptr(current)))
+ primjoin = xfunc_primary_join((JoinPath) get_pathptr(current));
+ foreach(temp, get_pathclauseinfo((JoinPath) get_pathptr(current)))
{
- if (!equal(get_clause((CInfo)lfirst(temp)), primjoin))
- topnode =
- xfunc_streaminsert((CInfo)lfirst(temp), topnode,
- XFUNC_JOINPRD);
+ if (!equal(get_clause((CInfo) lfirst(temp)), primjoin))
+ topnode =
+ xfunc_streaminsert((CInfo) lfirst(temp), topnode,
+ XFUNC_JOINPRD);
}
}
- return(topnode);
+ return (topnode);
}
@@ -531,33 +558,36 @@ static Stream xfunc_add_clauses(Stream current)
** find all elements of stream that are grouped with node and are above
** bottom, and set their groupcost and groupsel to be the same as node's.
*/
-static void xfunc_setup_group(Stream node, Stream bottom)
+static void
+xfunc_setup_group(Stream node, Stream bottom)
{
- Stream temp;
-
- if (node != bottom)
- /* traverse downwards */
- for (temp = (Stream)get_downstream(node);
- temp != (Stream)NULL && temp != bottom;
- temp = (Stream)get_downstream(temp))
- {
- if (!get_groupup(temp)) break;
- else
- {
- set_groupcost(temp, get_groupcost(node));
- set_groupsel(temp, get_groupsel(node));
- }
- }
-
- /* traverse upwards */
- for (temp = (Stream)get_upstream(node); temp != (Stream)NULL;
- temp = (Stream)get_upstream(temp))
+ Stream temp;
+
+ if (node != bottom)
+ /* traverse downwards */
+ for (temp = (Stream) get_downstream(node);
+ temp != (Stream) NULL && temp != bottom;
+ temp = (Stream) get_downstream(temp))
+ {
+ if (!get_groupup(temp))
+ break;
+ else
+ {
+ set_groupcost(temp, get_groupcost(node));
+ set_groupsel(temp, get_groupsel(node));
+ }
+ }
+
+ /* traverse upwards */
+ for (temp = (Stream) get_upstream(node); temp != (Stream) NULL;
+ temp = (Stream) get_upstream(temp))
{
- if (!get_groupup((Stream)get_downstream(temp))) break;
- else
+ if (!get_groupup((Stream) get_downstream(temp)))
+ break;
+ else
{
- set_groupcost(temp, get_groupcost(node));
- set_groupsel(temp, get_groupsel(node));
+ set_groupcost(temp, get_groupcost(node));
+ set_groupsel(temp, get_groupsel(node));
}
}
}
@@ -568,70 +598,75 @@ static void xfunc_setup_group(Stream node, Stream bottom)
** Make a new Stream node to hold clause, and insert it above current.
** Return new node.
*/
-static Stream
+static Stream
xfunc_streaminsert(CInfo clauseinfo,
- Stream current,
- int clausetype) /* XFUNC_LOCPRD or XFUNC_JOINPRD */
+ Stream current,
+ int clausetype) /* XFUNC_LOCPRD or XFUNC_JOINPRD */
{
- Stream newstream = RMakeStream();
- set_upstream(newstream, get_upstream(current));
- if (get_upstream(current))
- set_downstream((Stream)(get_upstream(current)), (StreamPtr)newstream);
- set_upstream(current, (StreamPtr)newstream);
- set_downstream(newstream, (StreamPtr)current);
- set_pathptr(newstream, get_pathptr(current));
- set_cinfo(newstream, clauseinfo);
- set_clausetype(newstream, clausetype);
- return(newstream);
+ Stream newstream = RMakeStream();
+
+ set_upstream(newstream, get_upstream(current));
+ if (get_upstream(current))
+ set_downstream((Stream) (get_upstream(current)), (StreamPtr) newstream);
+ set_upstream(current, (StreamPtr) newstream);
+ set_downstream(newstream, (StreamPtr) current);
+ set_pathptr(newstream, get_pathptr(current));
+ set_cinfo(newstream, clauseinfo);
+ set_clausetype(newstream, clausetype);
+ return (newstream);
}
/*
** Given a Stream node, find the number of relids referenced in the pathnode
** associated with the stream node. The number of relids gives a unique
- ** ordering on the joins in a stream, which we use to compare the height of
+ ** ordering on the joins in a stream, which we use to compare the height of
** join nodes.
*/
-static int xfunc_num_relids(Stream node)
+static int
+xfunc_num_relids(Stream node)
{
- if (!node || !IsA(get_pathptr(node),JoinPath))
- return(0);
- else return(length
- (get_relids(get_parent((JoinPath)get_pathptr(node)))));
+ if (!node || !IsA(get_pathptr(node), JoinPath))
+ return (0);
+ else
+ return (length
+ (get_relids(get_parent((JoinPath) get_pathptr(node)))));
}
-/*
+/*
** xfunc_get_downjoin --
** Given a stream node, find the next lowest node which points to a
** join predicate or a scan node.
*/
-static StreamPtr xfunc_get_downjoin(Stream node)
+static StreamPtr
+xfunc_get_downjoin(Stream node)
{
- Stream temp;
-
- if (!is_clause(node)) /* if this is a join */
- node = (Stream)get_downstream(node);
- for (temp = node; temp && is_clause(temp);
- temp = (Stream)get_downstream(temp))
- /* empty body in for loop */ ;
-
- return((StreamPtr)temp);
+ Stream temp;
+
+ if (!is_clause(node)) /* if this is a join */
+ node = (Stream) get_downstream(node);
+ for (temp = node; temp && is_clause(temp);
+ temp = (Stream) get_downstream(temp))
+ /* empty body in for loop */ ;
+
+ return ((StreamPtr) temp);
}
/*
** xfunc_get_upjoin --
** same as above, but upwards.
*/
-static StreamPtr xfunc_get_upjoin(Stream node)
+static StreamPtr
+xfunc_get_upjoin(Stream node)
{
- Stream temp;
-
- if (!is_clause(node)) /* if this is a join */
- node = (Stream)get_upstream(node);
- for (temp = node; temp && is_clause(temp);
- temp = (Stream)get_upstream(temp))
- /* empty body in for loop */ ;
-
- return((StreamPtr)temp);
+ Stream temp;
+
+ if (!is_clause(node)) /* if this is a join */
+ node = (Stream) get_upstream(node);
+ for (temp = node; temp && is_clause(temp);
+ temp = (Stream) get_upstream(temp))
+ /* empty body in for loop */ ;
+
+ return ((StreamPtr) temp);
}
/*
@@ -639,43 +674,46 @@ static StreamPtr xfunc_get_upjoin(Stream node)
** Given a stream, sort by group rank the elements in the stream from the
** node "bottom" up. DESTRUCTIVELY MODIFIES STREAM! Returns new root.
*/
-static Stream xfunc_stream_qsort(Stream root, Stream bottom)
+static Stream
+xfunc_stream_qsort(Stream root, Stream bottom)
{
- int i;
- size_t num;
- Stream *nodearray, output;
- Stream tmp;
-
- /* find size of list */
- for (num = 0, tmp = root; tmp != bottom;
- tmp = (Stream)get_downstream(tmp))
- num ++;
- if (num <= 1) return (root);
-
- /* copy elements of the list into an array */
- nodearray = (Stream *) palloc(num * sizeof(Stream));
-
- for (tmp = root, i = 0; tmp != bottom;
- tmp = (Stream)get_downstream(tmp), i++)
- nodearray[i] = tmp;
-
- /* sort the array */
- pg_qsort(nodearray, num, sizeof(LispValue), xfunc_stream_compare);
-
- /* paste together the array elements */
- output = nodearray[num - 1];
- set_upstream(output, (StreamPtr)NULL);
- for (i = num - 2; i >= 0; i--)
+ int i;
+ size_t num;
+ Stream *nodearray,
+ output;
+ Stream tmp;
+
+ /* find size of list */
+ for (num = 0, tmp = root; tmp != bottom;
+ tmp = (Stream) get_downstream(tmp))
+ num++;
+ if (num <= 1)
+ return (root);
+
+ /* copy elements of the list into an array */
+ nodearray = (Stream *) palloc(num * sizeof(Stream));
+
+ for (tmp = root, i = 0; tmp != bottom;
+ tmp = (Stream) get_downstream(tmp), i++)
+ nodearray[i] = tmp;
+
+ /* sort the array */
+ pg_qsort(nodearray, num, sizeof(LispValue), xfunc_stream_compare);
+
+ /* paste together the array elements */
+ output = nodearray[num - 1];
+ set_upstream(output, (StreamPtr) NULL);
+ for (i = num - 2; i >= 0; i--)
{
- set_downstream(nodearray[i+1], (StreamPtr)nodearray[i]);
- set_upstream(nodearray[i], (StreamPtr)nodearray[i+1]);
+ set_downstream(nodearray[i + 1], (StreamPtr) nodearray[i]);
+ set_upstream(nodearray[i], (StreamPtr) nodearray[i + 1]);
}
- set_downstream(nodearray[0], (StreamPtr)bottom);
- if (bottom)
- set_upstream(bottom, (StreamPtr)nodearray[0]);
-
- Assert(xfunc_check_stream(output));
- return(output);
+ set_downstream(nodearray[0], (StreamPtr) bottom);
+ if (bottom)
+ set_upstream(bottom, (StreamPtr) nodearray[0]);
+
+ Assert(xfunc_check_stream(output));
+ return (output);
}
/*
@@ -684,90 +722,102 @@ static Stream xfunc_stream_qsort(Stream root, Stream bottom)
** Compare nodes by group rank. If group ranks are equal, ensure that
** join nodes appear in same order as in plan tree.
*/
-static int xfunc_stream_compare(void *arg1, void *arg2)
+static int
+xfunc_stream_compare(void *arg1, void *arg2)
{
- Stream stream1 = *(Stream *) arg1;
- Stream stream2 = *(Stream *) arg2;
- Cost rank1, rank2;
-
- rank1 = get_grouprank(stream1);
- rank2 = get_grouprank(stream2);
-
- if (rank1 > rank2) return(1);
- else if (rank1 < rank2) return(-1);
- else
+ Stream stream1 = *(Stream *) arg1;
+ Stream stream2 = *(Stream *) arg2;
+ Cost rank1,
+ rank2;
+
+ rank1 = get_grouprank(stream1);
+ rank2 = get_grouprank(stream2);
+
+ if (rank1 > rank2)
+ return (1);
+ else if (rank1 < rank2)
+ return (-1);
+ else
{
- if (is_clause(stream1) && is_clause(stream2))
- return(0); /* doesn't matter what order if both are restrictions */
- else if (!is_clause(stream1) && !is_clause(stream2))
+ if (is_clause(stream1) && is_clause(stream2))
+ return (0); /* doesn't matter what order if both are
+ * restrictions */
+ else if (!is_clause(stream1) && !is_clause(stream2))
{
- if (xfunc_num_relids(stream1) < xfunc_num_relids(stream2))
- return(-1);
- else return(1);
+ if (xfunc_num_relids(stream1) < xfunc_num_relids(stream2))
+ return (-1);
+ else
+ return (1);
}
- else if (is_clause(stream1) && !is_clause(stream2))
+ else if (is_clause(stream1) && !is_clause(stream2))
{
- if (xfunc_num_relids(stream1) == xfunc_num_relids(stream2))
- /* stream1 is a restriction over stream2 */
- return(1);
- else return(-1);
+ if (xfunc_num_relids(stream1) == xfunc_num_relids(stream2))
+ /* stream1 is a restriction over stream2 */
+ return (1);
+ else
+ return (-1);
}
- else if (!is_clause(stream1) && is_clause(stream2))
+ else if (!is_clause(stream1) && is_clause(stream2))
{
- /* stream2 is a restriction over stream1: never push down */
- return(-1);
+ /* stream2 is a restriction over stream1: never push down */
+ return (-1);
}
}
}
-/* ------------------ DEBUGGING ROUTINES ---------------------------- */
+/* ------------------ DEBUGGING ROUTINES ---------------------------- */
/*
** Make sure all pointers in stream make sense. Make sure no joins are
** out of order.
*/
-static bool xfunc_check_stream(Stream node)
+static bool
+xfunc_check_stream(Stream node)
{
- Stream temp;
- int numrelids, tmp;
-
- /* set numrelids higher than max */
- if (!is_clause(node))
- numrelids = xfunc_num_relids(node) + 1;
- else if (xfunc_get_downjoin(node))
- numrelids = xfunc_num_relids((Stream)xfunc_get_downjoin(node)) + 1;
- else numrelids = 1;
-
- for (temp = node; get_downstream(temp); temp = (Stream)get_downstream(temp))
+ Stream temp;
+ int numrelids,
+ tmp;
+
+ /* set numrelids higher than max */
+ if (!is_clause(node))
+ numrelids = xfunc_num_relids(node) + 1;
+ else if (xfunc_get_downjoin(node))
+ numrelids = xfunc_num_relids((Stream) xfunc_get_downjoin(node)) + 1;
+ else
+ numrelids = 1;
+
+ for (temp = node; get_downstream(temp); temp = (Stream) get_downstream(temp))
{
- if ((Stream)get_upstream((Stream)get_downstream(temp)) != temp)
+ if ((Stream) get_upstream((Stream) get_downstream(temp)) != temp)
{
- elog(WARN, "bad pointers in stream");
- return(false);
+ elog(WARN, "bad pointers in stream");
+ return (false);
}
- if (!is_clause(temp))
+ if (!is_clause(temp))
{
- if ((tmp = xfunc_num_relids(temp)) >= numrelids)
+ if ((tmp = xfunc_num_relids(temp)) >= numrelids)
{
- elog(WARN, "Joins got reordered!");
- return(false);
+ elog(WARN, "Joins got reordered!");
+ return (false);
}
- numrelids = tmp;
+ numrelids = tmp;
}
}
-
- return(true);
+
+ return (true);
}
/*
** xfunc_in_stream
** check if node is in stream
*/
-static bool xfunc_in_stream(Stream node, Stream stream)
+static bool
+xfunc_in_stream(Stream node, Stream stream)
{
- Stream temp;
-
- for (temp = stream; temp; temp = (Stream)get_downstream(temp))
- if (temp == node) return(1);
- return(0);
+ Stream temp;
+
+ for (temp = stream; temp; temp = (Stream) get_downstream(temp))
+ if (temp == node)
+ return (1);
+ return (0);
}
diff --git a/src/backend/optimizer/path/prune.c b/src/backend/optimizer/path/prune.c
index 0b154e108fa..4f3ae2d15de 100644
--- a/src/backend/optimizer/path/prune.c
+++ b/src/backend/optimizer/path/prune.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* prune.c--
- * Routines to prune redundant paths and relations
+ * Routines to prune redundant paths and relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.3 1997/06/10 07:55:47 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.4 1997/09/07 04:43:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,181 +24,199 @@
#include "utils/elog.h"
-static List *prune_joinrel(Rel *rel, List *other_rels);
+static List *prune_joinrel(Rel * rel, List * other_rels);
-/*
+/*
* prune-joinrels--
- * Removes any redundant relation entries from a list of rel nodes
- * 'rel-list'.
- *
- * Returns the resulting list.
- *
+ * Removes any redundant relation entries from a list of rel nodes
+ * 'rel-list'.
+ *
+ * Returns the resulting list.
+ *
*/
-List *prune_joinrels(List *rel_list)
+List *
+prune_joinrels(List * rel_list)
{
- List *temp_list = NIL;
-
- if (rel_list != NIL) {
- temp_list = lcons(lfirst(rel_list),
- prune_joinrels(prune_joinrel((Rel*)lfirst(rel_list),
- lnext(rel_list))));
- }
- return(temp_list);
+ List *temp_list = NIL;
+
+ if (rel_list != NIL)
+ {
+ temp_list = lcons(lfirst(rel_list),
+ prune_joinrels(prune_joinrel((Rel *) lfirst(rel_list),
+ lnext(rel_list))));
+ }
+ return (temp_list);
}
-/*
+/*
* prune-joinrel--
- * Prunes those relations from 'other-rels' that are redundant with
- * 'rel'. A relation is redundant if it is built up of the same
- * relations as 'rel'. Paths for the redundant relation are merged into
- * the pathlist of 'rel'.
- *
+ * Prunes those relations from 'other-rels' that are redundant with
+ * 'rel'. A relation is redundant if it is built up of the same
+ * relations as 'rel'. Paths for the redundant relation are merged into
+ * the pathlist of 'rel'.
+ *
* Returns a list of non-redundant relations, and sets the pathlist field
* of 'rel' appropriately.
- *
+ *
*/
-static List *
-prune_joinrel(Rel *rel, List *other_rels)
+static List *
+prune_joinrel(Rel * rel, List * other_rels)
{
- List *i = NIL;
- List *t_list = NIL;
- List *temp_node = NIL;
- Rel *other_rel = (Rel *)NULL;
-
- foreach(i, other_rels) {
- other_rel = (Rel*)lfirst(i);
- if(same(rel->relids, other_rel->relids)) {
- rel->pathlist = add_pathlist(rel,
- rel->pathlist,
- other_rel->pathlist);
- t_list = nconc(t_list, NIL); /* XXX is this right ? */
- } else {
- temp_node = lcons(other_rel, NIL);
- t_list = nconc(t_list,temp_node);
- }
- }
- return(t_list);
+ List *i = NIL;
+ List *t_list = NIL;
+ List *temp_node = NIL;
+ Rel *other_rel = (Rel *) NULL;
+
+ foreach(i, other_rels)
+ {
+ other_rel = (Rel *) lfirst(i);
+ if (same(rel->relids, other_rel->relids))
+ {
+ rel->pathlist = add_pathlist(rel,
+ rel->pathlist,
+ other_rel->pathlist);
+ t_list = nconc(t_list, NIL); /* XXX is this right ? */
+ }
+ else
+ {
+ temp_node = lcons(other_rel, NIL);
+ t_list = nconc(t_list, temp_node);
+ }
+ }
+ return (t_list);
}
-/*
+/*
* prune-rel-paths--
- * For each relation entry in 'rel-list' (which corresponds to a join
- * relation), set pointers to the unordered path and cheapest paths
- * (if the unordered path isn't the cheapest, it is pruned), and
- * reset the relation's size field to reflect the join.
- *
+ * For each relation entry in 'rel-list' (which corresponds to a join
+ * relation), set pointers to the unordered path and cheapest paths
+ * (if the unordered path isn't the cheapest, it is pruned), and
+ * reset the relation's size field to reflect the join.
+ *
* Returns nothing of interest.
- *
+ *
*/
void
-prune_rel_paths(List *rel_list)
+prune_rel_paths(List * rel_list)
{
- List *x = NIL;
- List *y = NIL;
- Path *path = NULL;
- Rel *rel = (Rel*)NULL;
- JoinPath *cheapest = (JoinPath*)NULL;
-
- foreach(x, rel_list) {
- rel = (Rel*)lfirst(x);
- rel->size = 0;
- foreach(y, rel->pathlist) {
- path = (Path*)lfirst(y);
-
- if(!path->p_ordering.ord.sortop) {
- break;
- }
+ List *x = NIL;
+ List *y = NIL;
+ Path *path = NULL;
+ Rel *rel = (Rel *) NULL;
+ JoinPath *cheapest = (JoinPath *) NULL;
+
+ foreach(x, rel_list)
+ {
+ rel = (Rel *) lfirst(x);
+ rel->size = 0;
+ foreach(y, rel->pathlist)
+ {
+ path = (Path *) lfirst(y);
+
+ if (!path->p_ordering.ord.sortop)
+ {
+ break;
+ }
+ }
+ cheapest = (JoinPath *) prune_rel_path(rel, path);
+ if (IsA_JoinPath(cheapest))
+ {
+ rel->size = compute_joinrel_size(cheapest);
+ }
+ else
+ elog(WARN, "non JoinPath called");
}
- cheapest = (JoinPath*)prune_rel_path(rel, path);
- if (IsA_JoinPath(cheapest))
- {
- rel->size = compute_joinrel_size(cheapest);
- }
- else
- elog(WARN, "non JoinPath called");
- }
}
-/*
+/*
* prune-rel-path--
- * Compares the unordered path for a relation with the cheapest path. If
- * the unordered path is not cheapest, it is pruned.
- *
- * Resets the pointers in 'rel' for unordered and cheapest paths.
- *
+ * Compares the unordered path for a relation with the cheapest path. If
+ * the unordered path is not cheapest, it is pruned.
+ *
+ * Resets the pointers in 'rel' for unordered and cheapest paths.
+ *
* Returns the cheapest path.
- *
+ *
*/
-Path *
-prune_rel_path(Rel *rel, Path *unorderedpath)
+Path *
+prune_rel_path(Rel * rel, Path * unorderedpath)
{
- Path *cheapest = set_cheapest(rel, rel->pathlist);
-
- /* don't prune if not pruneable -- JMH, 11/23/92 */
- if(unorderedpath != cheapest
- && rel->pruneable) {
-
- rel->unorderedpath = (Path *)NULL;
- rel->pathlist = lremove(unorderedpath, rel->pathlist);
- } else {
- rel->unorderedpath = (Path *)unorderedpath;
- }
-
- return(cheapest);
+ Path *cheapest = set_cheapest(rel, rel->pathlist);
+
+ /* don't prune if not pruneable -- JMH, 11/23/92 */
+ if (unorderedpath != cheapest
+ && rel->pruneable)
+ {
+
+ rel->unorderedpath = (Path *) NULL;
+ rel->pathlist = lremove(unorderedpath, rel->pathlist);
+ }
+ else
+ {
+ rel->unorderedpath = (Path *) unorderedpath;
+ }
+
+ return (cheapest);
}
/*
* merge-joinrels--
- * Given two lists of rel nodes that are already
- * pruned, merge them into one pruned rel node list
+ * Given two lists of rel nodes that are already
+ * pruned, merge them into one pruned rel node list
*
* 'rel-list1' and
* 'rel-list2' are the rel node lists
*
* Returns one pruned rel node list
*/
-List *
-merge_joinrels(List *rel_list1, List *rel_list2)
+List *
+merge_joinrels(List * rel_list1, List * rel_list2)
{
- List *xrel = NIL;
-
- foreach(xrel,rel_list1) {
- Rel *rel = (Rel*)lfirst(xrel);
- rel_list2 = prune_joinrel(rel,rel_list2);
- }
- return(append(rel_list1, rel_list2));
+ List *xrel = NIL;
+
+ foreach(xrel, rel_list1)
+ {
+ Rel *rel = (Rel *) lfirst(xrel);
+
+ rel_list2 = prune_joinrel(rel, rel_list2);
+ }
+ return (append(rel_list1, rel_list2));
}
/*
* prune_oldrels--
- * If all the joininfo's in a rel node are inactive,
- * that means that this node has been joined into
- * other nodes in all possible ways, therefore
- * this node can be discarded. If not, it will cause
- * extra complexity of the optimizer.
+ * If all the joininfo's in a rel node are inactive,
+ * that means that this node has been joined into
+ * other nodes in all possible ways, therefore
+ * this node can be discarded. If not, it will cause
+ * extra complexity of the optimizer.
*
* old_rels is a list of rel nodes
- *
+ *
* Returns a new list of rel nodes
*/
-List *prune_oldrels(List *old_rels)
+List *
+prune_oldrels(List * old_rels)
{
- Rel *rel;
- List *joininfo_list, *xjoininfo;
-
- if(old_rels == NIL)
- return(NIL);
-
- rel = (Rel*)lfirst(old_rels);
- joininfo_list = rel->joininfo;
- if(joininfo_list == NIL)
- return (lcons(rel, prune_oldrels(lnext(old_rels))));
-
- foreach(xjoininfo, joininfo_list) {
- JInfo *joininfo = (JInfo*)lfirst(xjoininfo);
- if(!joininfo->inactive)
- return (lcons(rel, prune_oldrels(lnext(old_rels))));
- }
- return(prune_oldrels(lnext(old_rels)));
+ Rel *rel;
+ List *joininfo_list,
+ *xjoininfo;
+
+ if (old_rels == NIL)
+ return (NIL);
+
+ rel = (Rel *) lfirst(old_rels);
+ joininfo_list = rel->joininfo;
+ if (joininfo_list == NIL)
+ return (lcons(rel, prune_oldrels(lnext(old_rels))));
+
+ foreach(xjoininfo, joininfo_list)
+ {
+ JInfo *joininfo = (JInfo *) lfirst(xjoininfo);
+
+ if (!joininfo->inactive)
+ return (lcons(rel, prune_oldrels(lnext(old_rels))));
+ }
+ return (prune_oldrels(lnext(old_rels)));
}
diff --git a/src/backend/optimizer/path/xfunc.c b/src/backend/optimizer/path/xfunc.c
index 3e3ee650f94..36135d4a823 100644
--- a/src/backend/optimizer/path/xfunc.c
+++ b/src/backend/optimizer/path/xfunc.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* xfunc.c--
- * Utility routines to handle expensive function optimization.
- * Includes xfunc_trypullup(), which attempts early pullup of predicates
- * to allow for maximal pruning.
- *
+ * Utility routines to handle expensive function optimization.
+ * Includes xfunc_trypullup(), which attempts early pullup of predicates
+ * to allow for maximal pruning.
+ *
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.3 1997/02/14 04:15:39 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/xfunc.c,v 1.4 1997/09/07 04:43:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <math.h> /* for MAXFLOAT on most systems */
+#include <math.h> /* for MAXFLOAT on most systems */
-#include <values.h> /* for MAXFLOAT on SunOS */
+#include <values.h> /* for MAXFLOAT on SunOS */
#include <string.h>
#include "postgres.h"
@@ -40,82 +40,96 @@
#include "lib/lispsort.h"
#include "access/heapam.h"
#include "tcop/dest.h"
-#include "storage/buf_internals.h" /* for NBuffers */
-#include "optimizer/tlist.h" /* for get_expr */
+#include "storage/buf_internals.h" /* for NBuffers */
+#include "optimizer/tlist.h" /* for get_expr */
#define ever ; 1 ;
/* local funcs */
-static int xfunc_card_unreferenced(Query *queryInfo,
- Expr *clause, Relid referenced); */
+static int
+xfunc_card_unreferenced(Query * queryInfo,
+ Expr * clause, Relid referenced);
+
+*/
/*
** xfunc_trypullup --
-** Preliminary pullup of predicates, to allow for maximal pruning.
+** Preliminary pullup of predicates, to allow for maximal pruning.
** Given a relation, check each of its paths and see if you can
** pullup clauses from its inner and outer.
*/
-void xfunc_trypullup(Rel rel)
+void
+xfunc_trypullup(Rel rel)
{
- LispValue y; /* list ptr */
- CInfo maxcinfo; /* The CInfo to pull up, as calculated by
- xfunc_shouldpull() */
- JoinPath curpath; /* current path in list */
- int progress; /* has progress been made this time through? */
- int clausetype;
-
- do {
- progress = false; /* no progress yet in this iteration */
- foreach(y, get_pathlist(rel)) {
- curpath = (JoinPath)lfirst(y);
-
- /*
- ** for each operand, attempt to pullup predicates until first
- ** failure.
- */
- for(ever) {
- /* No, the following should NOT be '==' !! */
- if (clausetype =
- xfunc_shouldpull((Path)get_innerjoinpath(curpath),
- curpath, INNER, &maxcinfo)) {
-
- xfunc_pullup((Path)get_innerjoinpath(curpath),
- curpath, maxcinfo, INNER, clausetype);
- progress = true;
- }else
- break;
- }
- for(ever) {
-
- /* No, the following should NOT be '==' !! */
- if (clausetype =
- xfunc_shouldpull((Path)get_outerjoinpath(curpath),
- curpath, OUTER, &maxcinfo)) {
-
- xfunc_pullup((Path)get_outerjoinpath(curpath),
- curpath, maxcinfo, OUTER, clausetype);
- progress = true;
- }else
- break;
- }
-
- /*
- ** make sure the unpruneable flag bubbles up, i.e.
- ** if anywhere below us in the path pruneable is false,
- ** then pruneable should be false here
- */
- if (get_pruneable(get_parent(curpath)) &&
- (!get_pruneable(get_parent
- ((Path)get_innerjoinpath(curpath))) ||
- !get_pruneable(get_parent((Path)
- get_outerjoinpath(curpath))))) {
-
- set_pruneable(get_parent(curpath),false);
- progress = true;
- }
- }
- } while(progress);
+ LispValue y; /* list ptr */
+ CInfo maxcinfo; /* The CInfo to pull up, as calculated by
+ * xfunc_shouldpull() */
+ JoinPath curpath; /* current path in list */
+ int progress; /* has progress been made this time
+ * through? */
+ int clausetype;
+
+ do
+ {
+ progress = false; /* no progress yet in this iteration */
+ foreach(y, get_pathlist(rel))
+ {
+ curpath = (JoinPath) lfirst(y);
+
+ /*
+ * * for each operand, attempt to pullup predicates until
+ * first * failure.
+ */
+ for (ever)
+ {
+ /* No, the following should NOT be '==' !! */
+ if (clausetype =
+ xfunc_shouldpull((Path) get_innerjoinpath(curpath),
+ curpath, INNER, &maxcinfo))
+ {
+
+ xfunc_pullup((Path) get_innerjoinpath(curpath),
+ curpath, maxcinfo, INNER, clausetype);
+ progress = true;
+ }
+ else
+ break;
+ }
+ for (ever)
+ {
+
+ /* No, the following should NOT be '==' !! */
+ if (clausetype =
+ xfunc_shouldpull((Path) get_outerjoinpath(curpath),
+ curpath, OUTER, &maxcinfo))
+ {
+
+ xfunc_pullup((Path) get_outerjoinpath(curpath),
+ curpath, maxcinfo, OUTER, clausetype);
+ progress = true;
+ }
+ else
+ break;
+ }
+
+ /*
+ * * make sure the unpruneable flag bubbles up, i.e. * if
+ * anywhere below us in the path pruneable is false, * then
+ * pruneable should be false here
+ */
+ if (get_pruneable(get_parent(curpath)) &&
+ (!get_pruneable(get_parent
+ ((Path) get_innerjoinpath(curpath))) ||
+ !get_pruneable(get_parent((Path)
+ get_outerjoinpath(curpath)))))
+ {
+
+ set_pruneable(get_parent(curpath), false);
+ progress = true;
+ }
+ }
+ } while (progress);
}
/*
@@ -128,108 +142,123 @@ void xfunc_trypullup(Rel rel)
** we'd better set the unpruneable flag. -- JMH, 11/11/92
**
** Returns: 0 if nothing left to pullup
- ** XFUNC_LOCPRD if a local predicate is to be pulled up
- ** XFUNC_JOINPRD if a secondary join predicate is to be pulled up
+ ** XFUNC_LOCPRD if a local predicate is to be pulled up
+ ** XFUNC_JOINPRD if a secondary join predicate is to be pulled up
*/
-int xfunc_shouldpull(Query* queryInfo,
- Path childpath,
- JoinPath parentpath,
- int whichchild,
- CInfo *maxcinfopt) /* Out: pointer to clause to pullup */
+int
+xfunc_shouldpull(Query * queryInfo,
+ Path childpath,
+ JoinPath parentpath,
+ int whichchild,
+ CInfo * maxcinfopt) /* Out: pointer to clause to
+ * pullup */
{
- LispValue clauselist, tmplist; /* lists of clauses */
- CInfo maxcinfo; /* clause to pullup */
- LispValue primjoinclause /* primary join clause */
+ LispValue clauselist,
+ tmplist; /* lists of clauses */
+ CInfo maxcinfo; /* clause to pullup */
+ LispValue primjoinclause /* primary join clause */
= xfunc_primary_join(parentpath);
- Cost tmprank, maxrank = (-1 * MAXFLOAT); /* ranks of clauses */
- Cost joinselec = 0; /* selectivity of the join predicate */
- Cost joincost = 0; /* join cost + primjoinclause cost */
- int retval = XFUNC_LOCPRD;
-
- clauselist = get_locclauseinfo(childpath);
-
- if (clauselist != LispNil) {
- /* find local predicate with maximum rank */
- for (tmplist = clauselist,
- maxcinfo = (CInfo) lfirst(tmplist),
- maxrank = xfunc_rank(get_clause(maxcinfo));
- tmplist != LispNil;
- tmplist = lnext(tmplist)) {
-
- if ((tmprank = xfunc_rank(get_clause((CInfo)lfirst(tmplist))))
- > maxrank) {
- maxcinfo = (CInfo) lfirst(tmplist);
- maxrank = tmprank;
- }
+ Cost tmprank,
+ maxrank = (-1 * MAXFLOAT); /* ranks of clauses */
+ Cost joinselec = 0; /* selectivity of the join
+ * predicate */
+ Cost joincost = 0; /* join cost + primjoinclause cost */
+ int retval = XFUNC_LOCPRD;
+
+ clauselist = get_locclauseinfo(childpath);
+
+ if (clauselist != LispNil)
+ {
+ /* find local predicate with maximum rank */
+ for (tmplist = clauselist,
+ maxcinfo = (CInfo) lfirst(tmplist),
+ maxrank = xfunc_rank(get_clause(maxcinfo));
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ {
+
+ if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
+ > maxrank)
+ {
+ maxcinfo = (CInfo) lfirst(tmplist);
+ maxrank = tmprank;
+ }
+ }
}
- }
-
- /*
- ** If child is a join path, and there are multiple join clauses,
- ** see if any join clause has even higher rank than the highest
- ** local predicate
- */
- if (is_join(childpath) && xfunc_num_join_clauses((JoinPath)childpath) > 1)
- for (tmplist = get_pathclauseinfo((JoinPath)childpath);
- tmplist != LispNil;
- tmplist = lnext(tmplist)) {
-
- if (tmplist != LispNil &&
- (tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
- > maxrank) {
- maxcinfo = (CInfo) lfirst(tmplist);
- maxrank = tmprank;
- retval = XFUNC_JOINPRD;
- }
- }
- if (maxrank == (-1 * MAXFLOAT)) /* no expensive clauses */
- return(0);
-
- /*
- ** Pullup over join if clause is higher rank than join, or if
- ** join is nested loop and current path is inner child (note that
- ** restrictions on the inner of a nested loop don't buy you anything --
- ** you still have to scan the entire inner relation each time).
- ** Note that the cost of a secondary join clause is only what's
- ** calculated by xfunc_expense(), since the actual joining
- ** (i.e. the usual path_cost) is paid for by the primary join clause.
- */
- if (primjoinclause != LispNil) {
- joinselec = compute_clause_selec(queryInfo, primjoinclause, LispNil);
- joincost = xfunc_join_expense(parentpath, whichchild);
-
- if (XfuncMode == XFUNC_PULLALL ||
- (XfuncMode != XFUNC_WAIT &&
- ((joincost != 0 &&
- (maxrank = xfunc_rank(get_clause(maxcinfo))) >
- ((joinselec - 1.0) / joincost))
- || (joincost == 0 && joinselec < 1)
- || (!is_join(childpath)
- && (whichchild == INNER)
- && IsA(parentpath,JoinPath)
- && !IsA(parentpath,HashPath)
- && !IsA(parentpath,MergePath))))) {
-
- *maxcinfopt = maxcinfo;
- return(retval);
-
- }else if (maxrank != -(MAXFLOAT)) {
- /*
- ** we've left an expensive restriction below a join. Since
- ** we may pullup this restriction in predmig.c, we'd best
- ** set the Rel of this join to be unpruneable
- */
- set_pruneable(get_parent(parentpath), false);
- /* and fall through */
+
+ /*
+ * * If child is a join path, and there are multiple join clauses, *
+ * see if any join clause has even higher rank than the highest *
+ * local predicate
+ */
+ if (is_join(childpath) && xfunc_num_join_clauses((JoinPath) childpath) > 1)
+ for (tmplist = get_pathclauseinfo((JoinPath) childpath);
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ {
+
+ if (tmplist != LispNil &&
+ (tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
+ > maxrank)
+ {
+ maxcinfo = (CInfo) lfirst(tmplist);
+ maxrank = tmprank;
+ retval = XFUNC_JOINPRD;
+ }
+ }
+ if (maxrank == (-1 * MAXFLOAT)) /* no expensive clauses */
+ return (0);
+
+ /*
+ * * Pullup over join if clause is higher rank than join, or if * join
+ * is nested loop and current path is inner child (note that *
+ * restrictions on the inner of a nested loop don't buy you anything
+ * -- * you still have to scan the entire inner relation each time). *
+ * Note that the cost of a secondary join clause is only what's *
+ * calculated by xfunc_expense(), since the actual joining * (i.e. the
+ * usual path_cost) is paid for by the primary join clause.
+ */
+ if (primjoinclause != LispNil)
+ {
+ joinselec = compute_clause_selec(queryInfo, primjoinclause, LispNil);
+ joincost = xfunc_join_expense(parentpath, whichchild);
+
+ if (XfuncMode == XFUNC_PULLALL ||
+ (XfuncMode != XFUNC_WAIT &&
+ ((joincost != 0 &&
+ (maxrank = xfunc_rank(get_clause(maxcinfo))) >
+ ((joinselec - 1.0) / joincost))
+ || (joincost == 0 && joinselec < 1)
+ || (!is_join(childpath)
+ && (whichchild == INNER)
+ && IsA(parentpath, JoinPath)
+ && !IsA(parentpath, HashPath)
+ && !IsA(parentpath, MergePath)))))
+ {
+
+ *maxcinfopt = maxcinfo;
+ return (retval);
+
+ }
+ else if (maxrank != -(MAXFLOAT))
+ {
+
+ /*
+ * * we've left an expensive restriction below a join. Since *
+ * we may pullup this restriction in predmig.c, we'd best *
+ * set the Rel of this join to be unpruneable
+ */
+ set_pruneable(get_parent(parentpath), false);
+ /* and fall through */
+ }
}
- }
- return(0);
+ return (0);
}
/*
** xfunc_pullup --
- ** move clause from child pathnode to parent pathnode. This operation
+ ** move clause from child pathnode to parent pathnode. This operation
** makes the child pathnode produce a larger relation than it used to.
** This means that we must construct a new Rel just for the childpath,
** although this Rel will not be added to the list of Rels to be joined up
@@ -238,101 +267,111 @@ int xfunc_shouldpull(Query* queryInfo,
**
** Now returns a pointer to the new pulled-up CInfo. -- JMH, 11/18/92
*/
-CInfo xfunc_pullup(Query* queryInfo,
- Path childpath,
- JoinPath parentpath,
- CInfo cinfo, /* clause to pull up */
- int whichchild,/* whether child is INNER or OUTER of join */
- int clausetype)/* whether clause to pull is join or local */
+CInfo
+xfunc_pullup(Query * queryInfo,
+ Path childpath,
+ JoinPath parentpath,
+ CInfo cinfo, /* clause to pull up */
+ int whichchild, /* whether child is INNER or OUTER of join */
+ int clausetype) /* whether clause to pull is join or local */
{
- Path newkid;
- Rel newrel;
- Cost pulled_selec;
- Cost cost;
- CInfo newinfo;
-
- /* remove clause from childpath */
- newkid = (Path)copyObject((Node)childpath);
- if (clausetype == XFUNC_LOCPRD) {
- set_locclauseinfo(newkid,
- xfunc_LispRemove((LispValue)cinfo,
- (List)get_locclauseinfo(newkid)));
- }else {
- set_pathclauseinfo
- ((JoinPath)newkid,
- xfunc_LispRemove((LispValue)cinfo,
- (List)get_pathclauseinfo((JoinPath)newkid)));
- }
-
- /*
- ** give the new child path its own Rel node that reflects the
- ** lack of the pulled-up predicate
- */
- pulled_selec = compute_clause_selec(queryInfo,
- get_clause(cinfo), LispNil);
- xfunc_copyrel(get_parent(newkid), &newrel);
- set_parent(newkid, newrel);
- set_pathlist(newrel, lcons(newkid, NIL));
- set_unorderedpath(newrel, (PathPtr)newkid);
- set_cheapestpath(newrel, (PathPtr)newkid);
- set_size(newrel,
- (Count)((Cost)get_size(get_parent(childpath)) / pulled_selec));
-
- /*
- ** fix up path cost of newkid. To do this we subtract away all the
- ** xfunc_costs of childpath, then recompute the xfunc_costs of newkid
- */
- cost = get_path_cost(newkid) - xfunc_get_path_cost(childpath);
- Assert(cost >= 0);
- set_path_cost(newkid, cost);
- cost = get_path_cost(newkid) + xfunc_get_path_cost(newkid);
- set_path_cost(newkid, cost);
-
- /*
- ** We copy the cinfo, since it may appear in other plans, and we're going
- ** to munge it. -- JMH, 7/22/92
- */
- newinfo = (CInfo)copyObject((Node)cinfo);
-
- /*
- ** Fix all vars in the clause
- ** to point to the right varno and varattno in parentpath
- */
- xfunc_fixvars(get_clause(newinfo), newrel, whichchild);
-
- /* add clause to parentpath, and fix up its cost. */
- set_locclauseinfo(parentpath,
- lispCons((LispValue)newinfo,
- (LispValue)get_locclauseinfo(parentpath)));
- /* put new childpath into the path tree */
- if (whichchild == INNER) {
- set_innerjoinpath(parentpath, (pathPtr)newkid);
- }else {
- set_outerjoinpath(parentpath, (pathPtr)newkid);
- }
-
- /*
- ** recompute parentpath cost from scratch -- the cost
- ** of the join method has changed
- */
- cost = xfunc_total_path_cost(parentpath);
- set_path_cost(parentpath, cost);
-
- return(newinfo);
+ Path newkid;
+ Rel newrel;
+ Cost pulled_selec;
+ Cost cost;
+ CInfo newinfo;
+
+ /* remove clause from childpath */
+ newkid = (Path) copyObject((Node) childpath);
+ if (clausetype == XFUNC_LOCPRD)
+ {
+ set_locclauseinfo(newkid,
+ xfunc_LispRemove((LispValue) cinfo,
+ (List) get_locclauseinfo(newkid)));
+ }
+ else
+ {
+ set_pathclauseinfo
+ ((JoinPath) newkid,
+ xfunc_LispRemove((LispValue) cinfo,
+ (List) get_pathclauseinfo((JoinPath) newkid)));
+ }
+
+ /*
+ * * give the new child path its own Rel node that reflects the * lack
+ * of the pulled-up predicate
+ */
+ pulled_selec = compute_clause_selec(queryInfo,
+ get_clause(cinfo), LispNil);
+ xfunc_copyrel(get_parent(newkid), &newrel);
+ set_parent(newkid, newrel);
+ set_pathlist(newrel, lcons(newkid, NIL));
+ set_unorderedpath(newrel, (PathPtr) newkid);
+ set_cheapestpath(newrel, (PathPtr) newkid);
+ set_size(newrel,
+ (Count) ((Cost) get_size(get_parent(childpath)) / pulled_selec));
+
+ /*
+ * * fix up path cost of newkid. To do this we subtract away all the *
+ * xfunc_costs of childpath, then recompute the xfunc_costs of newkid
+ */
+ cost = get_path_cost(newkid) - xfunc_get_path_cost(childpath);
+ Assert(cost >= 0);
+ set_path_cost(newkid, cost);
+ cost = get_path_cost(newkid) + xfunc_get_path_cost(newkid);
+ set_path_cost(newkid, cost);
+
+ /*
+ * * We copy the cinfo, since it may appear in other plans, and we're
+ * going * to munge it. -- JMH, 7/22/92
+ */
+ newinfo = (CInfo) copyObject((Node) cinfo);
+
+ /*
+ * * Fix all vars in the clause * to point to the right varno and
+ * varattno in parentpath
+ */
+ xfunc_fixvars(get_clause(newinfo), newrel, whichchild);
+
+ /* add clause to parentpath, and fix up its cost. */
+ set_locclauseinfo(parentpath,
+ lispCons((LispValue) newinfo,
+ (LispValue) get_locclauseinfo(parentpath)));
+ /* put new childpath into the path tree */
+ if (whichchild == INNER)
+ {
+ set_innerjoinpath(parentpath, (pathPtr) newkid);
+ }
+ else
+ {
+ set_outerjoinpath(parentpath, (pathPtr) newkid);
+ }
+
+ /*
+ * * recompute parentpath cost from scratch -- the cost * of the join
+ * method has changed
+ */
+ cost = xfunc_total_path_cost(parentpath);
+ set_path_cost(parentpath, cost);
+
+ return (newinfo);
}
/*
- ** calculate (selectivity-1)/cost.
+ ** calculate (selectivity-1)/cost.
*/
-Cost xfunc_rank(Query *queryInfo,LispValue clause)
+Cost
+xfunc_rank(Query * queryInfo, LispValue clause)
{
- Cost selec = compute_clause_selec(queryInfo, clause, LispNil);
- Cost cost = xfunc_expense(queryInfo,clause);
-
- if (cost == 0)
- if (selec > 1) return(MAXFLOAT);
- else return(-(MAXFLOAT));
- return((selec - 1)/cost);
+ Cost selec = compute_clause_selec(queryInfo, clause, LispNil);
+ Cost cost = xfunc_expense(queryInfo, clause);
+
+ if (cost == 0)
+ if (selec > 1)
+ return (MAXFLOAT);
+ else
+ return (-(MAXFLOAT));
+ return ((selec - 1) / cost);
}
/*
@@ -340,91 +379,99 @@ Cost xfunc_rank(Query *queryInfo,LispValue clause)
** by the cardinalities of all the base relations of the query that are *not*
** referenced in the clause.
*/
-Cost xfunc_expense(Query* queryInfo, clause)
- LispValue clause;
+Cost
+xfunc_expense(Query * queryInfo, clause)
+LispValue clause;
{
- Cost cost = xfunc_local_expense(clause);
-
- if (cost)
+ Cost cost = xfunc_local_expense(clause);
+
+ if (cost)
{
- Count card = xfunc_card_unreferenced(queryInfo, clause, LispNil);
- if (card)
- cost /= card;
+ Count card = xfunc_card_unreferenced(queryInfo, clause, LispNil);
+
+ if (card)
+ cost /= card;
}
-
- return(cost);
+
+ return (cost);
}
/*
** xfunc_join_expense --
** Find global expense of a join clause
*/
-Cost xfunc_join_expense(Query *queryInfo, JoinPath path, int whichchild)
+Cost
+xfunc_join_expense(Query * queryInfo, JoinPath path, int whichchild)
{
- LispValue primjoinclause = xfunc_primary_join(path);
-
- /*
- ** the second argument to xfunc_card_unreferenced reflects all the
- ** relations involved in the join clause, i.e. all the relids in the Rel
- ** of the join clause
- */
- Count card = 0;
- Cost cost = xfunc_expense_per_tuple(path, whichchild);
-
- card = xfunc_card_unreferenced(queryInfo,
- primjoinclause,
- get_relids(get_parent(path)));
- if (primjoinclause)
- cost += xfunc_local_expense(primjoinclause);
-
- if (card) cost /= card;
-
- return(cost);
+ LispValue primjoinclause = xfunc_primary_join(path);
+
+ /*
+ * * the second argument to xfunc_card_unreferenced reflects all the *
+ * relations involved in the join clause, i.e. all the relids in the
+ * Rel * of the join clause
+ */
+ Count card = 0;
+ Cost cost = xfunc_expense_per_tuple(path, whichchild);
+
+ card = xfunc_card_unreferenced(queryInfo,
+ primjoinclause,
+ get_relids(get_parent(path)));
+ if (primjoinclause)
+ cost += xfunc_local_expense(primjoinclause);
+
+ if (card)
+ cost /= card;
+
+ return (cost);
}
/*
** Recursively find the per-tuple expense of a clause. See
** xfunc_func_expense for more discussion.
*/
-Cost xfunc_local_expense(LispValue clause)
+Cost
+xfunc_local_expense(LispValue clause)
{
- Cost cost = 0; /* running expense */
- LispValue tmpclause;
-
- /* First handle the base case */
- if (IsA(clause,Const) || IsA(clause,Var) || IsA(clause,Param))
- return(0);
- /* now other stuff */
- else if (IsA(clause,Iter))
- /* Too low. Should multiply by the expected number of iterations. */
- return(xfunc_local_expense(get_iterexpr((Iter)clause)));
- else if (IsA(clause,ArrayRef))
- return(xfunc_local_expense(get_refexpr((ArrayRef)clause)));
- else if (fast_is_clause(clause))
- return(xfunc_func_expense((LispValue)get_op(clause),
- (LispValue)get_opargs(clause)));
- else if (fast_is_funcclause(clause))
- return(xfunc_func_expense((LispValue)get_function(clause),
- (LispValue)get_funcargs(clause)));
- else if (fast_not_clause(clause))
- return(xfunc_local_expense(lsecond(clause)));
- else if (fast_or_clause(clause)) {
- /* find cost of evaluating each disjunct */
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- cost += xfunc_local_expense(lfirst(tmpclause));
- return(cost);
- }else {
- elog(WARN, "Clause node of undetermined type");
- return(-1);
- }
+ Cost cost = 0; /* running expense */
+ LispValue tmpclause;
+
+ /* First handle the base case */
+ if (IsA(clause, Const) || IsA(clause, Var) || IsA(clause, Param))
+ return (0);
+ /* now other stuff */
+ else if (IsA(clause, Iter))
+ /* Too low. Should multiply by the expected number of iterations. */
+ return (xfunc_local_expense(get_iterexpr((Iter) clause)));
+ else if (IsA(clause, ArrayRef))
+ return (xfunc_local_expense(get_refexpr((ArrayRef) clause)));
+ else if (fast_is_clause(clause))
+ return (xfunc_func_expense((LispValue) get_op(clause),
+ (LispValue) get_opargs(clause)));
+ else if (fast_is_funcclause(clause))
+ return (xfunc_func_expense((LispValue) get_function(clause),
+ (LispValue) get_funcargs(clause)));
+ else if (fast_not_clause(clause))
+ return (xfunc_local_expense(lsecond(clause)));
+ else if (fast_or_clause(clause))
+ {
+ /* find cost of evaluating each disjunct */
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ cost += xfunc_local_expense(lfirst(tmpclause));
+ return (cost);
+ }
+ else
+ {
+ elog(WARN, "Clause node of undetermined type");
+ return (-1);
+ }
}
/*
** xfunc_func_expense --
** given a Func or Oper and its args, find its expense.
** Note: in Stonebraker's SIGMOD '91 paper, he uses a more complicated metric
- ** than the one here. We can ignore the expected number of tuples for
+ ** than the one here. We can ignore the expected number of tuples for
** our calculations; we just need the per-tuple expense. But he also
** proposes components to take into account the costs of accessing disk and
** archive. We didn't adopt that scheme here; eventually the vacuum
@@ -434,268 +481,323 @@ Cost xfunc_local_expense(LispValue clause)
** accessing secondary or tertiary storage, since we don't have sufficient
** stats to do it right.
*/
-Cost xfunc_func_expense(LispValue node, LispValue args)
+Cost
+xfunc_func_expense(LispValue node, LispValue args)
{
- HeapTuple tupl; /* the pg_proc tuple for each function */
- Form_pg_proc proc; /* a data structure to hold the pg_proc tuple */
- int width = 0; /* byte width of the field referenced by each clause */
- RegProcedure funcid; /* ID of function associate with node */
- Cost cost = 0; /* running expense */
- LispValue tmpclause;
- LispValue operand; /* one operand of an operator */
-
- if (IsA(node,Oper)) {
- /* don't trust the opid in the Oper node. Use the opno. */
- if (!(funcid = get_opcode(get_opno((Oper)node))))
- elog(WARN, "Oper's function is undefined");
- }else {
- funcid = get_funcid((Func)node);
- }
-
- /* look up tuple in cache */
- tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for procedure %d", funcid);
- proc = (Form_pg_proc) GETSTRUCT(tupl);
-
- /*
- ** if it's a Postquel function, its cost is stored in the
- ** associated plan.
- */
- if (proc->prolang == SQLlanguageId) {
- LispValue tmpplan;
- List planlist;
-
- if (IsA(node,Oper) || get_func_planlist((Func)node) == LispNil) {
- Oid *argOidVect; /* vector of argtypes */
- char *pq_src; /* text of PQ function */
- int nargs; /* num args to PQ function */
- QueryTreeList *queryTree_list; /* dummy variable */
-
- /*
- ** plan the function, storing it in the Func node for later
- ** use by the executor.
- */
- pq_src = (char *) textout(&(proc->prosrc));
- nargs = proc->pronargs;
- if (nargs > 0)
- argOidVect = proc->proargtypes;
- planlist = (List)pg_plan(pq_src, argOidVect, nargs,
- &parseTree_list, None);
- if (IsA(node,Func))
- set_func_planlist((Func)node, planlist);
-
- }else {/* plan has been cached inside the Func node already */
- planlist = get_func_planlist((Func)node);
+ HeapTuple tupl; /* the pg_proc tuple for each function */
+ Form_pg_proc proc; /* a data structure to hold the pg_proc
+ * tuple */
+ int width = 0; /* byte width of the field referenced by
+ * each clause */
+ RegProcedure funcid; /* ID of function associate with node */
+ Cost cost = 0; /* running expense */
+ LispValue tmpclause;
+ LispValue operand; /* one operand of an operator */
+
+ if (IsA(node, Oper))
+ {
+ /* don't trust the opid in the Oper node. Use the opno. */
+ if (!(funcid = get_opcode(get_opno((Oper) node))))
+ elog(WARN, "Oper's function is undefined");
}
-
- /*
- ** Return the sum of the costs of the plans (the PQ function
- ** may have many queries in its body).
- */
- foreach(tmpplan, planlist)
- cost += get_cost((Plan)lfirst(tmpplan));
- return(cost);
- }else { /* it's a C function */
+ else
+ {
+ funcid = get_funcid((Func) node);
+ }
+
+ /* look up tuple in cache */
+ tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for procedure %d", funcid);
+ proc = (Form_pg_proc) GETSTRUCT(tupl);
+
/*
- ** find the cost of evaluating the function's arguments
- ** and the width of the operands
+ * * if it's a Postquel function, its cost is stored in the *
+ * associated plan.
*/
- for (tmpclause = args; tmpclause != LispNil;
- tmpclause = lnext(tmpclause)) {
-
- if ((operand = lfirst(tmpclause)) != LispNil) {
- cost += xfunc_local_expense(operand);
- width += xfunc_width(operand);
- }
+ if (proc->prolang == SQLlanguageId)
+ {
+ LispValue tmpplan;
+ List planlist;
+
+ if (IsA(node, Oper) || get_func_planlist((Func) node) == LispNil)
+ {
+ Oid *argOidVect; /* vector of argtypes */
+ char *pq_src; /* text of PQ function */
+ int nargs; /* num args to PQ function */
+ QueryTreeList *queryTree_list; /* dummy variable */
+
+ /*
+ * * plan the function, storing it in the Func node for later *
+ * use by the executor.
+ */
+ pq_src = (char *) textout(&(proc->prosrc));
+ nargs = proc->pronargs;
+ if (nargs > 0)
+ argOidVect = proc->proargtypes;
+ planlist = (List) pg_plan(pq_src, argOidVect, nargs,
+ &parseTree_list, None);
+ if (IsA(node, Func))
+ set_func_planlist((Func) node, planlist);
+
+ }
+ else
+ { /* plan has been cached inside the Func
+ * node already */
+ planlist = get_func_planlist((Func) node);
+ }
+
+ /*
+ * * Return the sum of the costs of the plans (the PQ function *
+ * may have many queries in its body).
+ */
+ foreach(tmpplan, planlist)
+ cost += get_cost((Plan) lfirst(tmpplan));
+ return (cost);
+ }
+ else
+ { /* it's a C function */
+
+ /*
+ * * find the cost of evaluating the function's arguments * and
+ * the width of the operands
+ */
+ for (tmpclause = args; tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ {
+
+ if ((operand = lfirst(tmpclause)) != LispNil)
+ {
+ cost += xfunc_local_expense(operand);
+ width += xfunc_width(operand);
+ }
+ }
+
+ /*
+ * * when stats become available, add in cost of accessing
+ * secondary * and tertiary storage here.
+ */
+ return (cost +
+ (Cost) proc->propercall_cpu +
+ (Cost) proc->properbyte_cpu * (Cost) proc->probyte_pct / 100.00 *
+ (Cost) width
+
+ /*
+ * Pct_of_obj_in_mem DISK_COST * proc->probyte_pct/100.00 * width
+ * Pct_of_obj_on_disk + ARCH_COST * proc->probyte_pct/100.00 *
+ * width Pct_of_obj_on_arch
+ */
+ );
}
-
- /*
- ** when stats become available, add in cost of accessing secondary
- ** and tertiary storage here.
- */
- return(cost +
- (Cost)proc->propercall_cpu +
- (Cost)proc->properbyte_cpu * (Cost)proc->probyte_pct/100.00 *
- (Cost)width
- /*
- * Pct_of_obj_in_mem
- DISK_COST * proc->probyte_pct/100.00 * width
- * Pct_of_obj_on_disk +
- ARCH_COST * proc->probyte_pct/100.00 * width
- * Pct_of_obj_on_arch
- */
- );
- }
}
-/*
+/*
** xfunc_width --
** recursively find the width of a expression
*/
-int xfunc_width(LispValue clause)
+int
+xfunc_width(LispValue clause)
{
- Relation rd; /* Relation Descriptor */
- HeapTuple tupl; /* structure to hold a cached tuple */
- TypeTupleForm type; /* structure to hold a type tuple */
- int retval = 0;
-
- if (IsA(clause,Const)) {
- /* base case: width is the width of this constant */
- retval = get_constlen((Const) clause);
- goto exit;
- }else if (IsA(clause,ArrayRef)) {
- /* base case: width is width of the refelem within the array */
- retval = get_refelemlength((ArrayRef)clause);
- goto exit;
- }else if (IsA(clause,Var)) {
- /* base case: width is width of this attribute */
- tupl = SearchSysCacheTuple(TYPOID,
- PointerGetDatum(get_vartype((Var)clause)),
- 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for type %d",
- get_vartype((Var)clause));
- type = (TypeTupleForm) GETSTRUCT(tupl);
- if (get_varattno((Var)clause) == 0) {
- /* clause is a tuple. Get its width */
- rd = heap_open(type->typrelid);
- retval = xfunc_tuple_width(rd);
- heap_close(rd);
- }else {
- /* attribute is a base type */
- retval = type->typlen;
+ Relation rd; /* Relation Descriptor */
+ HeapTuple tupl; /* structure to hold a cached tuple */
+ TypeTupleForm type; /* structure to hold a type tuple */
+ int retval = 0;
+
+ if (IsA(clause, Const))
+ {
+ /* base case: width is the width of this constant */
+ retval = get_constlen((Const) clause);
+ goto exit;
}
- goto exit;
- }else if (IsA(clause,Param)) {
- if (typeid_get_relid(get_paramtype((Param)clause))) {
- /* Param node returns a tuple. Find its width */
- rd = heap_open(typeid_get_relid(get_paramtype((Param)clause)));
- retval = xfunc_tuple_width(rd);
- heap_close(rd);
- }else if (get_param_tlist((Param)clause) != LispNil) {
- /* Param node projects a complex type */
- Assert(length(get_param_tlist((Param)clause)) == 1); /* sanity */
- retval =
- xfunc_width((LispValue)
- get_expr(lfirst(get_param_tlist((Param)clause))));
- }else {
- /* Param node returns a base type */
- retval = tlen(get_id_type(get_paramtype((Param)clause)));
+ else if (IsA(clause, ArrayRef))
+ {
+ /* base case: width is width of the refelem within the array */
+ retval = get_refelemlength((ArrayRef) clause);
+ goto exit;
}
- goto exit;
- }else if (IsA(clause,Iter)) {
- /*
- ** An Iter returns a setof things, so return the width of a single
- ** thing.
- ** Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET FIXED,
- ** SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!!
- ** This whole Iter business is bogus, anyway.
- */
- retval = xfunc_width(get_iterexpr((Iter)clause));
- goto exit;
- }else if (fast_is_clause(clause)) {
- /*
- ** get function associated with this Oper, and treat this as
- ** a Func
- */
- tupl = SearchSysCacheTuple(OPROID,
- ObjectIdGetDatum(get_opno((Oper)get_op(clause))),
- 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for procedure %d",
- get_opno((Oper)get_op(clause)));
- return(xfunc_func_width
- ((RegProcedure)(((OperatorTupleForm)(GETSTRUCT(tupl)))->oprcode),
- (LispValue)get_opargs(clause)));
- }else if (fast_is_funcclause(clause)) {
- Func func = (Func)get_function(clause);
- if (get_func_tlist(func) != LispNil) {
- /* this function has a projection on it. Get the length
- of the projected attribute */
- Assert(length(get_func_tlist(func)) == 1); /* sanity */
- retval =
- xfunc_width((LispValue)
- get_expr(lfirst(get_func_tlist(func))));
- goto exit;
- }else {
- return(xfunc_func_width((RegProcedure)get_funcid(func),
- (LispValue)get_funcargs(clause)));
+ else if (IsA(clause, Var))
+ {
+ /* base case: width is width of this attribute */
+ tupl = SearchSysCacheTuple(TYPOID,
+ PointerGetDatum(get_vartype((Var) clause)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for type %d",
+ get_vartype((Var) clause));
+ type = (TypeTupleForm) GETSTRUCT(tupl);
+ if (get_varattno((Var) clause) == 0)
+ {
+ /* clause is a tuple. Get its width */
+ rd = heap_open(type->typrelid);
+ retval = xfunc_tuple_width(rd);
+ heap_close(rd);
+ }
+ else
+ {
+ /* attribute is a base type */
+ retval = type->typlen;
+ }
+ goto exit;
+ }
+ else if (IsA(clause, Param))
+ {
+ if (typeid_get_relid(get_paramtype((Param) clause)))
+ {
+ /* Param node returns a tuple. Find its width */
+ rd = heap_open(typeid_get_relid(get_paramtype((Param) clause)));
+ retval = xfunc_tuple_width(rd);
+ heap_close(rd);
+ }
+ else if (get_param_tlist((Param) clause) != LispNil)
+ {
+ /* Param node projects a complex type */
+ Assert(length(get_param_tlist((Param) clause)) == 1); /* sanity */
+ retval =
+ xfunc_width((LispValue)
+ get_expr(lfirst(get_param_tlist((Param) clause))));
+ }
+ else
+ {
+ /* Param node returns a base type */
+ retval = tlen(get_id_type(get_paramtype((Param) clause)));
+ }
+ goto exit;
+ }
+ else if (IsA(clause, Iter))
+ {
+
+ /*
+ * * An Iter returns a setof things, so return the width of a
+ * single * thing. * Note: THIS MAY NOT WORK RIGHT WHEN AGGS GET
+ * FIXED, * SINCE AGG FUNCTIONS CHEW ON THE WHOLE SETOF THINGS!!!! *
+ * This whole Iter business is bogus, anyway.
+ */
+ retval = xfunc_width(get_iterexpr((Iter) clause));
+ goto exit;
+ }
+ else if (fast_is_clause(clause))
+ {
+
+ /*
+ * * get function associated with this Oper, and treat this as * a
+ * Func
+ */
+ tupl = SearchSysCacheTuple(OPROID,
+ ObjectIdGetDatum(get_opno((Oper) get_op(clause))),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for procedure %d",
+ get_opno((Oper) get_op(clause)));
+ return (xfunc_func_width
+ ((RegProcedure) (((OperatorTupleForm) (GETSTRUCT(tupl)))->oprcode),
+ (LispValue) get_opargs(clause)));
+ }
+ else if (fast_is_funcclause(clause))
+ {
+ Func func = (Func) get_function(clause);
+
+ if (get_func_tlist(func) != LispNil)
+ {
+
+ /*
+ * this function has a projection on it. Get the length of
+ * the projected attribute
+ */
+ Assert(length(get_func_tlist(func)) == 1); /* sanity */
+ retval =
+ xfunc_width((LispValue)
+ get_expr(lfirst(get_func_tlist(func))));
+ goto exit;
+ }
+ else
+ {
+ return (xfunc_func_width((RegProcedure) get_funcid(func),
+ (LispValue) get_funcargs(clause)));
+ }
+ }
+ else
+ {
+ elog(WARN, "Clause node of undetermined type");
+ return (-1);
}
- }else {
- elog(WARN, "Clause node of undetermined type");
- return(-1);
- }
-
- exit:
- if (retval == -1)
- retval = VARLEN_DEFAULT;
- return(retval);
+
+exit:
+ if (retval == -1)
+ retval = VARLEN_DEFAULT;
+ return (retval);
}
/*
** xfunc_card_unreferenced:
- ** find all relations not referenced in clause, and multiply their
- ** cardinalities. Ignore relation of cardinality 0.
+ ** find all relations not referenced in clause, and multiply their
+ ** cardinalities. Ignore relation of cardinality 0.
** User may pass in referenced list, if they know it (useful
** for joins).
*/
-static Count
-xfunc_card_unreferenced(Query *queryInfo,
- LispValue clause, Relid referenced)
+static Count
+xfunc_card_unreferenced(Query * queryInfo,
+ LispValue clause, Relid referenced)
{
- Relid unreferenced, allrelids = LispNil;
- LispValue temp;
-
- /* find all relids of base relations referenced in query */
- foreach (temp,queryInfo->base_relation_list_)
+ Relid unreferenced,
+ allrelids = LispNil;
+ LispValue temp;
+
+ /* find all relids of base relations referenced in query */
+ foreach(temp, queryInfo->base_relation_list_)
{
- Assert(lnext(get_relids((Rel)lfirst(temp))) == LispNil);
- allrelids = lappend(allrelids,
- lfirst(get_relids((Rel)lfirst(temp))));
+ Assert(lnext(get_relids((Rel) lfirst(temp))) == LispNil);
+ allrelids = lappend(allrelids,
+ lfirst(get_relids((Rel) lfirst(temp))));
}
-
- /* find all relids referenced in query but not in clause */
- if (!referenced)
- referenced = xfunc_find_references(clause);
- unreferenced = set_difference(allrelids, referenced);
-
- return(xfunc_card_product(unreferenced));
+
+ /* find all relids referenced in query but not in clause */
+ if (!referenced)
+ referenced = xfunc_find_references(clause);
+ unreferenced = set_difference(allrelids, referenced);
+
+ return (xfunc_card_product(unreferenced));
}
/*
- ** xfunc_card_product
+ ** xfunc_card_product
** multiple together cardinalities of a list relations.
*/
-Count xfunc_card_product(Query *queryInfo, Relid relids)
+Count
+xfunc_card_product(Query * queryInfo, Relid relids)
{
- LispValue cinfonode;
- LispValue temp;
- Rel currel;
- Cost tuples;
- Count retval = 0;
-
- foreach(temp,relids) {
- currel = get_rel(lfirst(temp));
- tuples = get_tuples(currel);
-
- if (tuples) { /* not of cardinality 0 */
- /* factor in the selectivity of all zero-cost clauses */
- foreach (cinfonode, get_clauseinfo(currel)) {
- if (!xfunc_expense(queryInfo,get_clause((CInfo)lfirst(cinfonode))))
- tuples *=
- compute_clause_selec(queryInfo,
- get_clause((CInfo)lfirst(cinfonode)),
- LispNil);
- }
-
- if (retval == 0) retval = tuples;
- else retval *= tuples;
+ LispValue cinfonode;
+ LispValue temp;
+ Rel currel;
+ Cost tuples;
+ Count retval = 0;
+
+ foreach(temp, relids)
+ {
+ currel = get_rel(lfirst(temp));
+ tuples = get_tuples(currel);
+
+ if (tuples)
+ { /* not of cardinality 0 */
+ /* factor in the selectivity of all zero-cost clauses */
+ foreach(cinfonode, get_clauseinfo(currel))
+ {
+ if (!xfunc_expense(queryInfo, get_clause((CInfo) lfirst(cinfonode))))
+ tuples *=
+ compute_clause_selec(queryInfo,
+ get_clause((CInfo) lfirst(cinfonode)),
+ LispNil);
+ }
+
+ if (retval == 0)
+ retval = tuples;
+ else
+ retval *= tuples;
+ }
}
- }
- if (retval == 0) retval = 1; /* saves caller from dividing by zero */
- return(retval);
+ if (retval == 0)
+ retval = 1; /* saves caller from dividing by zero */
+ return (retval);
}
@@ -703,48 +805,60 @@ Count xfunc_card_product(Query *queryInfo, Relid relids)
** xfunc_find_references:
** Traverse a clause and find all relids referenced in the clause.
*/
-List xfunc_find_references(LispValue clause)
+List
+xfunc_find_references(LispValue clause)
{
- List retval = (List)LispNil;
- LispValue tmpclause;
-
- /* Base cases */
- if (IsA(clause,Var))
- return(lispCons(lfirst(get_varid((Var)clause)), LispNil));
- else if (IsA(clause,Const) || IsA(clause,Param))
- return((List)LispNil);
-
- /* recursion */
- else if (IsA(clause,Iter))
- /* Too low. Should multiply by the expected number of iterations. maybe */
- return(xfunc_find_references(get_iterexpr((Iter)clause)));
- else if (IsA(clause,ArrayRef))
- return(xfunc_find_references(get_refexpr((ArrayRef)clause)));
- else if (fast_is_clause(clause)) {
- /* string together result of all operands of Oper */
- for (tmpclause = (LispValue)get_opargs(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
- return(retval);
- }else if (fast_is_funcclause(clause)) {
- /* string together result of all args of Func */
- for (tmpclause = (LispValue)get_funcargs(clause);
- tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
- return(retval);
- }else if (fast_not_clause(clause))
- return(xfunc_find_references(lsecond(clause)));
- else if (fast_or_clause(clause)) {
- /* string together result of all operands of OR */
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
- return(retval);
- }else {
- elog(WARN, "Clause node of undetermined type");
- return((List)LispNil);
- }
+ List retval = (List) LispNil;
+ LispValue tmpclause;
+
+ /* Base cases */
+ if (IsA(clause, Var))
+ return (lispCons(lfirst(get_varid((Var) clause)), LispNil));
+ else if (IsA(clause, Const) || IsA(clause, Param))
+ return ((List) LispNil);
+
+ /* recursion */
+ else if (IsA(clause, Iter))
+
+ /*
+ * Too low. Should multiply by the expected number of iterations.
+ * maybe
+ */
+ return (xfunc_find_references(get_iterexpr((Iter) clause)));
+ else if (IsA(clause, ArrayRef))
+ return (xfunc_find_references(get_refexpr((ArrayRef) clause)));
+ else if (fast_is_clause(clause))
+ {
+ /* string together result of all operands of Oper */
+ for (tmpclause = (LispValue) get_opargs(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
+ return (retval);
+ }
+ else if (fast_is_funcclause(clause))
+ {
+ /* string together result of all args of Func */
+ for (tmpclause = (LispValue) get_funcargs(clause);
+ tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
+ return (retval);
+ }
+ else if (fast_not_clause(clause))
+ return (xfunc_find_references(lsecond(clause)));
+ else if (fast_or_clause(clause))
+ {
+ /* string together result of all operands of OR */
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval = nconc(retval, xfunc_find_references(lfirst(tmpclause)));
+ return (retval);
+ }
+ else
+ {
+ elog(WARN, "Clause node of undetermined type");
+ return ((List) LispNil);
+ }
}
/*
@@ -753,212 +867,219 @@ List xfunc_find_references(LispValue clause)
** min rank Hash or Merge clause, while for Nested Loop it's the
** min rank pathclause
*/
-LispValue xfunc_primary_join(JoinPath pathnode)
+LispValue
+xfunc_primary_join(JoinPath pathnode)
{
- LispValue joinclauselist = get_pathclauseinfo(pathnode);
- CInfo mincinfo;
- LispValue tmplist;
- LispValue minclause = LispNil;
- Cost minrank, tmprank;
-
- if (IsA(pathnode,MergePath))
+ LispValue joinclauselist = get_pathclauseinfo(pathnode);
+ CInfo mincinfo;
+ LispValue tmplist;
+ LispValue minclause = LispNil;
+ Cost minrank,
+ tmprank;
+
+ if (IsA(pathnode, MergePath))
{
- for(tmplist = get_path_mergeclauses((MergePath)pathnode),
- minclause = lfirst(tmplist),
- minrank = xfunc_rank(minclause);
- tmplist != LispNil;
- tmplist = lnext(tmplist))
- if ((tmprank = xfunc_rank(lfirst(tmplist)))
- < minrank)
- {
- minrank = tmprank;
- minclause = lfirst(tmplist);
- }
- return(minclause);
+ for (tmplist = get_path_mergeclauses((MergePath) pathnode),
+ minclause = lfirst(tmplist),
+ minrank = xfunc_rank(minclause);
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ if ((tmprank = xfunc_rank(lfirst(tmplist)))
+ < minrank)
+ {
+ minrank = tmprank;
+ minclause = lfirst(tmplist);
+ }
+ return (minclause);
}
- else if (IsA(pathnode,HashPath))
+ else if (IsA(pathnode, HashPath))
{
- for(tmplist = get_path_hashclauses((HashPath)pathnode),
- minclause = lfirst(tmplist),
- minrank = xfunc_rank(minclause);
- tmplist != LispNil;
- tmplist = lnext(tmplist))
- if ((tmprank = xfunc_rank(lfirst(tmplist)))
- < minrank)
- {
- minrank = tmprank;
- minclause = lfirst(tmplist);
- }
- return(minclause);
+ for (tmplist = get_path_hashclauses((HashPath) pathnode),
+ minclause = lfirst(tmplist),
+ minrank = xfunc_rank(minclause);
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ if ((tmprank = xfunc_rank(lfirst(tmplist)))
+ < minrank)
+ {
+ minrank = tmprank;
+ minclause = lfirst(tmplist);
+ }
+ return (minclause);
}
-
- /* if we drop through, it's nested loop join */
- if (joinclauselist == LispNil)
- return(LispNil);
-
- for(tmplist = joinclauselist, mincinfo = (CInfo) lfirst(joinclauselist),
- minrank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)));
- tmplist != LispNil;
- tmplist = lnext(tmplist))
- if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
- < minrank)
- {
- minrank = tmprank;
- mincinfo = (CInfo) lfirst(tmplist);
- }
- return((LispValue)get_clause(mincinfo));
+
+ /* if we drop through, it's nested loop join */
+ if (joinclauselist == LispNil)
+ return (LispNil);
+
+ for (tmplist = joinclauselist, mincinfo = (CInfo) lfirst(joinclauselist),
+ minrank = xfunc_rank(get_clause((CInfo) lfirst(tmplist)));
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
+ if ((tmprank = xfunc_rank(get_clause((CInfo) lfirst(tmplist))))
+ < minrank)
+ {
+ minrank = tmprank;
+ mincinfo = (CInfo) lfirst(tmplist);
+ }
+ return ((LispValue) get_clause(mincinfo));
}
/*
** xfunc_get_path_cost
** get the expensive function costs of the path
*/
-Cost xfunc_get_path_cost(Query *queryInfo, Path pathnode)
+Cost
+xfunc_get_path_cost(Query * queryInfo, Path pathnode)
{
- Cost cost = 0;
- LispValue tmplist;
- Cost selec = 1.0;
-
- /*
- ** first add in the expensive local function costs.
- ** We ensure that the clauses are sorted by rank, so that we
- ** know (via selectivities) the number of tuples that will be checked
- ** by each function. If we're not doing any optimization of expensive
- ** functions, we don't sort.
- */
- if (XfuncMode != XFUNC_OFF)
- set_locclauseinfo(pathnode, lisp_qsort(get_locclauseinfo(pathnode),
- xfunc_cinfo_compare));
- for(tmplist = get_locclauseinfo(pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ Cost cost = 0;
+ LispValue tmplist;
+ Cost selec = 1.0;
+
+ /*
+ * * first add in the expensive local function costs. * We ensure that
+ * the clauses are sorted by rank, so that we * know (via
+ * selectivities) the number of tuples that will be checked * by each
+ * function. If we're not doing any optimization of expensive *
+ * functions, we don't sort.
+ */
+ if (XfuncMode != XFUNC_OFF)
+ set_locclauseinfo(pathnode, lisp_qsort(get_locclauseinfo(pathnode),
+ xfunc_cinfo_compare));
+ for (tmplist = get_locclauseinfo(pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(get_clause((CInfo)lfirst(tmplist)))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- get_clause((CInfo)lfirst(tmplist)),
- LispNil);
+ cost += (Cost) (xfunc_local_expense(get_clause((CInfo) lfirst(tmplist)))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ get_clause((CInfo) lfirst(tmplist)),
+ LispNil);
}
-
- /*
- ** Now add in any node-specific expensive function costs.
- ** Again, we must ensure that the clauses are sorted by rank.
- */
- if (IsA(pathnode,JoinPath))
+
+ /*
+ * * Now add in any node-specific expensive function costs. * Again,
+ * we must ensure that the clauses are sorted by rank.
+ */
+ if (IsA(pathnode, JoinPath))
{
- if (XfuncMode != XFUNC_OFF)
- set_pathclauseinfo((JoinPath)pathnode, lisp_qsort
- (get_pathclauseinfo((JoinPath)pathnode),
- xfunc_cinfo_compare));
- for(tmplist = get_pathclauseinfo((JoinPath)pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ if (XfuncMode != XFUNC_OFF)
+ set_pathclauseinfo((JoinPath) pathnode, lisp_qsort
+ (get_pathclauseinfo((JoinPath) pathnode),
+ xfunc_cinfo_compare));
+ for (tmplist = get_pathclauseinfo((JoinPath) pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(get_clause((CInfo)lfirst(tmplist)))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- get_clause((CInfo)lfirst(tmplist)),
- LispNil);
+ cost += (Cost) (xfunc_local_expense(get_clause((CInfo) lfirst(tmplist)))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ get_clause((CInfo) lfirst(tmplist)),
+ LispNil);
}
}
- if (IsA(pathnode,HashPath))
+ if (IsA(pathnode, HashPath))
{
- if (XfuncMode != XFUNC_OFF)
- set_path_hashclauses
- ((HashPath)pathnode,
- lisp_qsort(get_path_hashclauses((HashPath)pathnode),
- xfunc_clause_compare));
- for(tmplist = get_path_hashclauses((HashPath)pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ if (XfuncMode != XFUNC_OFF)
+ set_path_hashclauses
+ ((HashPath) pathnode,
+ lisp_qsort(get_path_hashclauses((HashPath) pathnode),
+ xfunc_clause_compare));
+ for (tmplist = get_path_hashclauses((HashPath) pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(lfirst(tmplist))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- lfirst(tmplist), LispNil);
+ cost += (Cost) (xfunc_local_expense(lfirst(tmplist))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ lfirst(tmplist), LispNil);
}
}
- if (IsA(pathnode,MergePath))
+ if (IsA(pathnode, MergePath))
{
- if (XfuncMode != XFUNC_OFF)
- set_path_mergeclauses
- ((MergePath)pathnode,
- lisp_qsort(get_path_mergeclauses((MergePath)pathnode),
- xfunc_clause_compare));
- for(tmplist = get_path_mergeclauses((MergePath)pathnode), selec = 1.0;
- tmplist != LispNil;
- tmplist = lnext(tmplist))
+ if (XfuncMode != XFUNC_OFF)
+ set_path_mergeclauses
+ ((MergePath) pathnode,
+ lisp_qsort(get_path_mergeclauses((MergePath) pathnode),
+ xfunc_clause_compare));
+ for (tmplist = get_path_mergeclauses((MergePath) pathnode), selec = 1.0;
+ tmplist != LispNil;
+ tmplist = lnext(tmplist))
{
- cost += (Cost)(xfunc_local_expense(lfirst(tmplist))
- * (Cost)get_tuples(get_parent(pathnode)) * selec);
- selec *= compute_clause_selec(queryInfo,
- lfirst(tmplist), LispNil);
+ cost += (Cost) (xfunc_local_expense(lfirst(tmplist))
+ * (Cost) get_tuples(get_parent(pathnode)) * selec);
+ selec *= compute_clause_selec(queryInfo,
+ lfirst(tmplist), LispNil);
}
}
- Assert(cost >= 0);
- return(cost);
+ Assert(cost >= 0);
+ return (cost);
}
/*
- ** Recalculate the cost of a path node. This includes the basic cost of the
+ ** Recalculate the cost of a path node. This includes the basic cost of the
** node, as well as the cost of its expensive functions.
** We need to do this to the parent after pulling a clause from a child into a
** parent. Thus we should only be calling this function on JoinPaths.
*/
-Cost xfunc_total_path_cost(JoinPath pathnode)
+Cost
+xfunc_total_path_cost(JoinPath pathnode)
{
- Cost cost = xfunc_get_path_cost((Path)pathnode);
-
- Assert(IsA(pathnode,JoinPath));
- if (IsA(pathnode,MergePath))
+ Cost cost = xfunc_get_path_cost((Path) pathnode);
+
+ Assert(IsA(pathnode, JoinPath));
+ if (IsA(pathnode, MergePath))
{
- MergePath mrgnode = (MergePath)pathnode;
- cost += cost_mergesort(get_path_cost((Path)get_outerjoinpath(mrgnode)),
- get_path_cost((Path)get_innerjoinpath(mrgnode)),
- get_outersortkeys(mrgnode),
- get_innersortkeys(mrgnode),
- get_tuples(get_parent((Path)get_outerjoinpath
- (mrgnode))),
- get_tuples(get_parent((Path)get_innerjoinpath
- (mrgnode))),
- get_width(get_parent((Path)get_outerjoinpath
- (mrgnode))),
- get_width(get_parent((Path)get_innerjoinpath
- (mrgnode))));
- Assert(cost >= 0);
- return(cost);
+ MergePath mrgnode = (MergePath) pathnode;
+
+ cost += cost_mergesort(get_path_cost((Path) get_outerjoinpath(mrgnode)),
+ get_path_cost((Path) get_innerjoinpath(mrgnode)),
+ get_outersortkeys(mrgnode),
+ get_innersortkeys(mrgnode),
+ get_tuples(get_parent((Path) get_outerjoinpath
+ (mrgnode))),
+ get_tuples(get_parent((Path) get_innerjoinpath
+ (mrgnode))),
+ get_width(get_parent((Path) get_outerjoinpath
+ (mrgnode))),
+ get_width(get_parent((Path) get_innerjoinpath
+ (mrgnode))));
+ Assert(cost >= 0);
+ return (cost);
}
- else if (IsA(pathnode,HashPath))
+ else if (IsA(pathnode, HashPath))
{
- HashPath hashnode = (HashPath)pathnode;
- cost += cost_hashjoin(get_path_cost((Path)get_outerjoinpath(hashnode)),
- get_path_cost((Path)get_innerjoinpath(hashnode)),
- get_outerhashkeys(hashnode),
- get_innerhashkeys(hashnode),
- get_tuples(get_parent((Path)get_outerjoinpath
- (hashnode))),
- get_tuples(get_parent((Path)get_innerjoinpath
- (hashnode))),
- get_width(get_parent((Path)get_outerjoinpath
- (hashnode))),
- get_width(get_parent((Path)get_innerjoinpath
- (hashnode))));
- Assert (cost >= 0);
- return(cost);
+ HashPath hashnode = (HashPath) pathnode;
+
+ cost += cost_hashjoin(get_path_cost((Path) get_outerjoinpath(hashnode)),
+ get_path_cost((Path) get_innerjoinpath(hashnode)),
+ get_outerhashkeys(hashnode),
+ get_innerhashkeys(hashnode),
+ get_tuples(get_parent((Path) get_outerjoinpath
+ (hashnode))),
+ get_tuples(get_parent((Path) get_innerjoinpath
+ (hashnode))),
+ get_width(get_parent((Path) get_outerjoinpath
+ (hashnode))),
+ get_width(get_parent((Path) get_innerjoinpath
+ (hashnode))));
+ Assert(cost >= 0);
+ return (cost);
}
- else /* Nested Loop Join */
+ else
+/* Nested Loop Join */
{
- cost += cost_nestloop(get_path_cost((Path)get_outerjoinpath(pathnode)),
- get_path_cost((Path)get_innerjoinpath(pathnode)),
- get_tuples(get_parent((Path)get_outerjoinpath
- (pathnode))),
- get_tuples(get_parent((Path)get_innerjoinpath
- (pathnode))),
- get_pages(get_parent((Path)get_outerjoinpath
- (pathnode))),
- IsA(get_innerjoinpath(pathnode),IndexPath));
- Assert(cost >= 0);
- return(cost);
+ cost += cost_nestloop(get_path_cost((Path) get_outerjoinpath(pathnode)),
+ get_path_cost((Path) get_innerjoinpath(pathnode)),
+ get_tuples(get_parent((Path) get_outerjoinpath
+ (pathnode))),
+ get_tuples(get_parent((Path) get_innerjoinpath
+ (pathnode))),
+ get_pages(get_parent((Path) get_outerjoinpath
+ (pathnode))),
+ IsA(get_innerjoinpath(pathnode), IndexPath));
+ Assert(cost >= 0);
+ return (cost);
}
}
@@ -967,7 +1088,7 @@ Cost xfunc_total_path_cost(JoinPath pathnode)
** xfunc_expense_per_tuple --
** return the expense of the join *per-tuple* of the input relation.
** The cost model here is that a join costs
- ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n
+ ** k*card(outer)*card(inner) + l*card(outer) + m*card(inner) + n
**
** We treat the l and m terms by considering them to be like restrictions
** constrained to be right under the join. Thus the cost per inner and
@@ -975,138 +1096,146 @@ Cost xfunc_total_path_cost(JoinPath pathnode)
**
** The cost per tuple of outer is k + l/referenced(inner). Cost per tuple
** of inner is k + m/referenced(outer).
- ** The constants k, l, m and n depend on the join method. Measures here are
+ ** The constants k, l, m and n depend on the join method. Measures here are
** based on the costs in costsize.c, with fudging for HashJoin and Sorts to
** make it fit our model (the 'q' in HashJoin results in a
** card(outer)/card(inner) term, and sorting results in a log term.
-
+
*/
-Cost xfunc_expense_per_tuple(JoinPath joinnode, int whichchild)
+Cost
+xfunc_expense_per_tuple(JoinPath joinnode, int whichchild)
{
- Rel outerrel = get_parent((Path)get_outerjoinpath(joinnode));
- Rel innerrel = get_parent((Path)get_innerjoinpath(joinnode));
- Count outerwidth = get_width(outerrel);
- Count outers_per_page = ceil(BLCKSZ/(outerwidth + sizeof(HeapTupleData)));
-
- if (IsA(joinnode,HashPath))
+ Rel outerrel = get_parent((Path) get_outerjoinpath(joinnode));
+ Rel innerrel = get_parent((Path) get_innerjoinpath(joinnode));
+ Count outerwidth = get_width(outerrel);
+ Count outers_per_page = ceil(BLCKSZ / (outerwidth + sizeof(HeapTupleData)));
+
+ if (IsA(joinnode, HashPath))
{
- if (whichchild == INNER)
- return((1 + _CPU_PAGE_WEIGHT_)*outers_per_page/NBuffers);
- else
- return(((1 + _CPU_PAGE_WEIGHT_)*outers_per_page/NBuffers)
- + _CPU_PAGE_WEIGHT_
- / xfunc_card_product(get_relids(innerrel)));
+ if (whichchild == INNER)
+ return ((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers);
+ else
+ return (((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers)
+ + _CPU_PAGE_WEIGHT_
+ / xfunc_card_product(get_relids(innerrel)));
}
- else if (IsA(joinnode,MergePath))
+ else if (IsA(joinnode, MergePath))
{
- /* assumes sort exists, and costs one (I/O + CPU) per tuple */
- if (whichchild == INNER)
- return((2*_CPU_PAGE_WEIGHT_ + 1)
- / xfunc_card_product(get_relids(outerrel)));
- else
- return((2*_CPU_PAGE_WEIGHT_ + 1)
- / xfunc_card_product(get_relids(innerrel)));
+ /* assumes sort exists, and costs one (I/O + CPU) per tuple */
+ if (whichchild == INNER)
+ return ((2 * _CPU_PAGE_WEIGHT_ + 1)
+ / xfunc_card_product(get_relids(outerrel)));
+ else
+ return ((2 * _CPU_PAGE_WEIGHT_ + 1)
+ / xfunc_card_product(get_relids(innerrel)));
}
- else /* nestloop */
+ else
+/* nestloop */
{
- Assert(IsA(joinnode,JoinPath));
- return(_CPU_PAGE_WEIGHT_);
+ Assert(IsA(joinnode, JoinPath));
+ return (_CPU_PAGE_WEIGHT_);
}
}
/*
** xfunc_fixvars --
- ** After pulling up a clause, we must walk its expression tree, fixing Var
+ ** After pulling up a clause, we must walk its expression tree, fixing Var
** nodes to point to the correct varno (either INNER or OUTER, depending
- ** on which child the clause was pulled from), and the right varattno in the
+ ** on which child the clause was pulled from), and the right varattno in the
** target list of the child's former relation. If the target list of the
** child Rel does not contain the attribute we need, we add it.
*/
-void xfunc_fixvars(LispValue clause, /* clause being pulled up */
- Rel rel, /* rel it's being pulled from */
- int varno) /* whether rel is INNER or OUTER of join */
+void
+xfunc_fixvars(LispValue clause, /* clause being pulled up */
+ Rel rel, /* rel it's being pulled from */
+ int varno) /* whether rel is INNER or OUTER of join */
{
- LispValue tmpclause; /* temporary variable */
- TargetEntry *tle; /* tlist member corresponding to var */
-
-
- if (IsA(clause,Const) || IsA(clause,Param)) return;
- else if (IsA(clause,Var))
+ LispValue tmpclause; /* temporary variable */
+ TargetEntry *tle; /* tlist member corresponding to var */
+
+
+ if (IsA(clause, Const) || IsA(clause, Param))
+ return;
+ else if (IsA(clause, Var))
{
- /* here's the meat */
- tle = tlistentry_member((Var)clause, get_targetlist(rel));
- if (tle == LispNil)
+ /* here's the meat */
+ tle = tlistentry_member((Var) clause, get_targetlist(rel));
+ if (tle == LispNil)
{
- /*
- ** The attribute we need is not in the target list,
- ** so we have to add it.
- **
- */
- add_tl_element(rel, (Var)clause);
- tle = tlistentry_member((Var)clause, get_targetlist(rel));
+
+ /*
+ * * The attribute we need is not in the target list, * so we
+ * have to add it. *
+ *
+ */
+ add_tl_element(rel, (Var) clause);
+ tle = tlistentry_member((Var) clause, get_targetlist(rel));
}
- set_varno(((Var)clause), varno);
- set_varattno(((Var)clause), get_resno(get_resdom(get_entry(tle))));
+ set_varno(((Var) clause), varno);
+ set_varattno(((Var) clause), get_resno(get_resdom(get_entry(tle))));
}
- else if (IsA(clause,Iter))
- xfunc_fixvars(get_iterexpr((Iter)clause), rel, varno);
- else if (fast_is_clause(clause))
+ else if (IsA(clause, Iter))
+ xfunc_fixvars(get_iterexpr((Iter) clause), rel, varno);
+ else if (fast_is_clause(clause))
{
- xfunc_fixvars(lfirst(lnext(clause)), rel, varno);
- xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno);
+ xfunc_fixvars(lfirst(lnext(clause)), rel, varno);
+ xfunc_fixvars(lfirst(lnext(lnext(clause))), rel, varno);
}
- else if (fast_is_funcclause(clause))
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- xfunc_fixvars(lfirst(tmpclause), rel, varno);
- else if (fast_not_clause(clause))
- xfunc_fixvars(lsecond(clause), rel, varno);
- else if (fast_or_clause(clause))
- for (tmpclause = lnext(clause); tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- xfunc_fixvars(lfirst(tmpclause), rel, varno);
- else
+ else if (fast_is_funcclause(clause))
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ xfunc_fixvars(lfirst(tmpclause), rel, varno);
+ else if (fast_not_clause(clause))
+ xfunc_fixvars(lsecond(clause), rel, varno);
+ else if (fast_or_clause(clause))
+ for (tmpclause = lnext(clause); tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ xfunc_fixvars(lfirst(tmpclause), rel, varno);
+ else
{
- elog(WARN, "Clause node of undetermined type");
+ elog(WARN, "Clause node of undetermined type");
}
}
/*
** Comparison function for lisp_qsort() on a list of CInfo's.
- ** arg1 and arg2 should really be of type (CInfo *).
+ ** arg1 and arg2 should really be of type (CInfo *).
*/
-int xfunc_cinfo_compare(void *arg1, void *arg2)
+int
+xfunc_cinfo_compare(void *arg1, void *arg2)
{
- CInfo info1 = *(CInfo *) arg1;
- CInfo info2 = *(CInfo *) arg2;
-
- LispValue clause1 = (LispValue) get_clause(info1),
- clause2 = (LispValue) get_clause(info2);
-
- return(xfunc_clause_compare((void *) &clause1, (void *) &clause2));
+ CInfo info1 = *(CInfo *) arg1;
+ CInfo info2 = *(CInfo *) arg2;
+
+ LispValue clause1 = (LispValue) get_clause(info1),
+ clause2 = (LispValue) get_clause(info2);
+
+ return (xfunc_clause_compare((void *) &clause1, (void *) &clause2));
}
/*
- ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two
+ ** xfunc_clause_compare: comparison function for lisp_qsort() that compares two
** clauses based on expense/(1 - selectivity)
** arg1 and arg2 are really pointers to clauses.
*/
-int xfunc_clause_compare(void *arg1, void *arg2)
+int
+xfunc_clause_compare(void *arg1, void *arg2)
{
- LispValue clause1 = *(LispValue *) arg1;
- LispValue clause2 = *(LispValue *) arg2;
- Cost rank1, /* total xfunc rank of clause1 */
- rank2; /* total xfunc rank of clause2 */
-
- rank1 = xfunc_rank(clause1);
- rank2 = xfunc_rank(clause2);
-
- if ( rank1 < rank2)
- return(-1);
- else if (rank1 == rank2)
- return(0);
- else return(1);
+ LispValue clause1 = *(LispValue *) arg1;
+ LispValue clause2 = *(LispValue *) arg2;
+ Cost rank1, /* total xfunc rank of clause1 */
+ rank2; /* total xfunc rank of clause2 */
+
+ rank1 = xfunc_rank(clause1);
+ rank2 = xfunc_rank(clause2);
+
+ if (rank1 < rank2)
+ return (-1);
+ else if (rank1 == rank2)
+ return (0);
+ else
+ return (1);
}
/*
@@ -1115,58 +1244,62 @@ int xfunc_clause_compare(void *arg1, void *arg2)
** (this assumes the predicates have been converted to Conjunctive NF)
** Modifies the clause list!
*/
-void xfunc_disjunct_sort(LispValue clause_list)
+void
+xfunc_disjunct_sort(LispValue clause_list)
{
- LispValue temp;
-
- foreach(temp, clause_list)
- if(or_clause(lfirst(temp)))
- lnext(lfirst(temp)) =
- lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare);
+ LispValue temp;
+
+ foreach(temp, clause_list)
+ if (or_clause(lfirst(temp)))
+ lnext(lfirst(temp)) =
+ lisp_qsort(lnext(lfirst(temp)), xfunc_disjunct_compare);
}
/*
- ** xfunc_disjunct_compare: comparison function for qsort() that compares two
+ ** xfunc_disjunct_compare: comparison function for qsort() that compares two
** disjuncts based on cost/selec.
** arg1 and arg2 are really pointers to disjuncts
*/
-int xfunc_disjunct_compare(Query* queryInfo, void *arg1, void *arg2)
+int
+xfunc_disjunct_compare(Query * queryInfo, void *arg1, void *arg2)
{
- LispValue disjunct1 = *(LispValue *) arg1;
- LispValue disjunct2 = *(LispValue *) arg2;
- Cost cost1, /* total cost of disjunct1 */
- cost2, /* total cost of disjunct2 */
- selec1,
- selec2;
- Cost rank1, rank2;
-
- cost1 = xfunc_expense(queryInfo, disjunct1);
- cost2 = xfunc_expense(queryInfo, disjunct2);
- selec1 = compute_clause_selec(queryInfo,
- disjunct1, LispNil);
- selec2 = compute_clause_selec(queryInfo,
- disjunct2, LispNil);
-
- if (selec1 == 0)
- rank1 = MAXFLOAT;
- else if (cost1 == 0)
- rank1 = 0;
- else
- rank1 = cost1/selec1;
-
- if (selec2 == 0)
- rank2 = MAXFLOAT;
- else if (cost2 == 0)
- rank2 = 0;
- else
- rank2 = cost2/selec2;
-
- if ( rank1 < rank2)
- return(-1);
- else if (rank1 == rank2)
- return(0);
- else return(1);
+ LispValue disjunct1 = *(LispValue *) arg1;
+ LispValue disjunct2 = *(LispValue *) arg2;
+ Cost cost1, /* total cost of disjunct1 */
+ cost2, /* total cost of disjunct2 */
+ selec1,
+ selec2;
+ Cost rank1,
+ rank2;
+
+ cost1 = xfunc_expense(queryInfo, disjunct1);
+ cost2 = xfunc_expense(queryInfo, disjunct2);
+ selec1 = compute_clause_selec(queryInfo,
+ disjunct1, LispNil);
+ selec2 = compute_clause_selec(queryInfo,
+ disjunct2, LispNil);
+
+ if (selec1 == 0)
+ rank1 = MAXFLOAT;
+ else if (cost1 == 0)
+ rank1 = 0;
+ else
+ rank1 = cost1 / selec1;
+
+ if (selec2 == 0)
+ rank2 = MAXFLOAT;
+ else if (cost2 == 0)
+ rank2 = 0;
+ else
+ rank2 = cost2 / selec2;
+
+ if (rank1 < rank2)
+ return (-1);
+ else if (rank1 == rank2)
+ return (0);
+ else
+ return (1);
}
/* ------------------------ UTILITY FUNCTIONS ------------------------------- */
@@ -1174,182 +1307,197 @@ int xfunc_disjunct_compare(Query* queryInfo, void *arg1, void *arg2)
** xfunc_func_width --
** Given a function OID and operands, find the width of the return value.
*/
-int xfunc_func_width(RegProcedure funcid, LispValue args)
+int
+xfunc_func_width(RegProcedure funcid, LispValue args)
{
- Relation rd; /* Relation Descriptor */
- HeapTuple tupl; /* structure to hold a cached tuple */
- Form_pg_proc proc; /* structure to hold the pg_proc tuple */
- TypeTupleForm type; /* structure to hold the pg_type tuple */
- LispValue tmpclause;
- int retval;
-
- /* lookup function and find its return type */
- Assert(RegProcedureIsValid(funcid));
- tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for procedure %d", funcid);
- proc = (Form_pg_proc) GETSTRUCT(tupl);
-
- /* if function returns a tuple, get the width of that */
- if (typeid_get_relid(proc->prorettype))
+ Relation rd; /* Relation Descriptor */
+ HeapTuple tupl; /* structure to hold a cached tuple */
+ Form_pg_proc proc; /* structure to hold the pg_proc tuple */
+ TypeTupleForm type; /* structure to hold the pg_type tuple */
+ LispValue tmpclause;
+ int retval;
+
+ /* lookup function and find its return type */
+ Assert(RegProcedureIsValid(funcid));
+ tupl = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for procedure %d", funcid);
+ proc = (Form_pg_proc) GETSTRUCT(tupl);
+
+ /* if function returns a tuple, get the width of that */
+ if (typeid_get_relid(proc->prorettype))
{
- rd = heap_open(typeid_get_relid(proc->prorettype));
- retval = xfunc_tuple_width(rd);
- heap_close(rd);
- goto exit;
+ rd = heap_open(typeid_get_relid(proc->prorettype));
+ retval = xfunc_tuple_width(rd);
+ heap_close(rd);
+ goto exit;
}
- else /* function returns a base type */
+ else
+/* function returns a base type */
{
- tupl = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(proc->prorettype),
- 0,0,0);
- if (!HeapTupleIsValid(tupl))
- elog(WARN, "Cache lookup failed for type %d", proc->prorettype);
- type = (TypeTupleForm) GETSTRUCT(tupl);
- /* if the type length is known, return that */
- if (type->typlen != -1)
+ tupl = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(proc->prorettype),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tupl))
+ elog(WARN, "Cache lookup failed for type %d", proc->prorettype);
+ type = (TypeTupleForm) GETSTRUCT(tupl);
+ /* if the type length is known, return that */
+ if (type->typlen != -1)
{
- retval = type->typlen;
- goto exit;
+ retval = type->typlen;
+ goto exit;
}
- else /* estimate the return size */
+ else
+/* estimate the return size */
{
- /* find width of the function's arguments */
- for (tmpclause = args; tmpclause != LispNil;
- tmpclause = lnext(tmpclause))
- retval += xfunc_width(lfirst(tmpclause));
- /* multiply by outin_ratio */
- retval = (int)(proc->prooutin_ratio/100.0 * retval);
- goto exit;
+ /* find width of the function's arguments */
+ for (tmpclause = args; tmpclause != LispNil;
+ tmpclause = lnext(tmpclause))
+ retval += xfunc_width(lfirst(tmpclause));
+ /* multiply by outin_ratio */
+ retval = (int) (proc->prooutin_ratio / 100.0 * retval);
+ goto exit;
}
}
- exit:
- return(retval);
+exit:
+ return (retval);
}
/*
** xfunc_tuple_width --
- ** Return the sum of the lengths of all the attributes of a given relation
+ ** Return the sum of the lengths of all the attributes of a given relation
*/
-int xfunc_tuple_width(Relation rd)
+int
+xfunc_tuple_width(Relation rd)
{
- int i;
- int retval = 0;
- TupleDesc tdesc = RelationGetTupleDescriptor(rd);
-
- for (i = 0; i < tdesc->natts; i++)
+ int i;
+ int retval = 0;
+ TupleDesc tdesc = RelationGetTupleDescriptor(rd);
+
+ for (i = 0; i < tdesc->natts; i++)
{
- if (tdesc->attrs[i]->attlen != -1)
- retval += tdesc->attrs[i]->attlen;
- else retval += VARLEN_DEFAULT;
+ if (tdesc->attrs[i]->attlen != -1)
+ retval += tdesc->attrs[i]->attlen;
+ else
+ retval += VARLEN_DEFAULT;
}
-
- return(retval);
+
+ return (retval);
}
/*
** xfunc_num_join_clauses --
** Find the number of join clauses associated with this join path
*/
-int xfunc_num_join_clauses(JoinPath path)
+int
+xfunc_num_join_clauses(JoinPath path)
{
- int num = length(get_pathclauseinfo(path));
- if (IsA(path,MergePath))
- return(num + length(get_path_mergeclauses((MergePath)path)));
- else if (IsA(path,HashPath))
- return(num + length(get_path_hashclauses((HashPath)path)));
- else return(num);
+ int num = length(get_pathclauseinfo(path));
+
+ if (IsA(path, MergePath))
+ return (num + length(get_path_mergeclauses((MergePath) path)));
+ else if (IsA(path, HashPath))
+ return (num + length(get_path_hashclauses((HashPath) path)));
+ else
+ return (num);
}
/*
** xfunc_LispRemove --
** Just like LispRemove, but it whines if the item to be removed ain't there
*/
-LispValue xfunc_LispRemove(LispValue foo, List bar)
+LispValue
+xfunc_LispRemove(LispValue foo, List bar)
{
- LispValue temp = LispNil;
- LispValue result = LispNil;
- int sanity = false;
-
- for (temp = bar; !null(temp); temp = lnext(temp))
- if (! equal((Node)(foo),(Node)(lfirst(temp))) )
- {
- result = lappend(result,lfirst(temp));
- }
- else sanity = true; /* found a matching item to remove! */
-
- if (!sanity)
- elog(WARN, "xfunc_LispRemove: didn't find a match!");
-
- return(result);
+ LispValue temp = LispNil;
+ LispValue result = LispNil;
+ int sanity = false;
+
+ for (temp = bar; !null(temp); temp = lnext(temp))
+ if (!equal((Node) (foo), (Node) (lfirst(temp))))
+ {
+ result = lappend(result, lfirst(temp));
+ }
+ else
+ sanity = true; /* found a matching item to remove! */
+
+ if (!sanity)
+ elog(WARN, "xfunc_LispRemove: didn't find a match!");
+
+ return (result);
}
#define Node_Copy(a, b, c, d) \
- if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) { \
- return false; \
- }
+ if (NodeCopy((Node)((a)->d), (Node*)&((b)->d), c) != true) { \
+ return false; \
+ }
/*
** xfunc_copyrel --
** Just like _copyRel, but doesn't copy the paths
*/
-bool xfunc_copyrel(Rel from, Rel *to)
+bool
+xfunc_copyrel(Rel from, Rel * to)
{
- Rel newnode;
- Pointer (*alloc)() = palloc;
-
- /* COPY_CHECKARGS() */
- if (to == NULL)
- {
- return false;
- }
-
- /* COPY_CHECKNULL() */
- if (from == NULL)
+ Rel newnode;
+
+ Pointer(*alloc) () = palloc;
+
+ /* COPY_CHECKARGS() */
+ if (to == NULL)
+ {
+ return false;
+ }
+
+ /* COPY_CHECKNULL() */
+ if (from == NULL)
{
- (*to) = NULL;
- return true;
- }
-
- /* COPY_NEW(c) */
- newnode = (Rel)(*alloc)(classSize(Rel));
- if (newnode == NULL)
- {
- return false;
- }
-
- /* ----------------
- * copy node superclass fields
- * ----------------
- */
- CopyNodeFields((Node)from, (Node)newnode, alloc);
-
- /* ----------------
- * copy remainder of node
- * ----------------
- */
- Node_Copy(from, newnode, alloc, relids);
-
- newnode->indexed = from->indexed;
- newnode->pages = from->pages;
- newnode->tuples = from->tuples;
- newnode->size = from->size;
- newnode->width = from->width;
-
- Node_Copy(from, newnode, alloc, targetlist);
- /* No!!!! Node_Copy(from, newnode, alloc, pathlist);
- Node_Copy(from, newnode, alloc, unorderedpath);
- Node_Copy(from, newnode, alloc, cheapestpath); */
-#if 0 /* can't use Node_copy now. 2/95 -ay */
- Node_Copy(from, newnode, alloc, classlist);
- Node_Copy(from, newnode, alloc, indexkeys);
- Node_Copy(from, newnode, alloc, ordering);
+ (*to) = NULL;
+ return true;
+ }
+
+ /* COPY_NEW(c) */
+ newnode = (Rel) (*alloc) (classSize(Rel));
+ if (newnode == NULL)
+ {
+ return false;
+ }
+
+ /* ----------------
+ * copy node superclass fields
+ * ----------------
+ */
+ CopyNodeFields((Node) from, (Node) newnode, alloc);
+
+ /* ----------------
+ * copy remainder of node
+ * ----------------
+ */
+ Node_Copy(from, newnode, alloc, relids);
+
+ newnode->indexed = from->indexed;
+ newnode->pages = from->pages;
+ newnode->tuples = from->tuples;
+ newnode->size = from->size;
+ newnode->width = from->width;
+
+ Node_Copy(from, newnode, alloc, targetlist);
+
+ /*
+ * No!!!! Node_Copy(from, newnode, alloc, pathlist);
+ * Node_Copy(from, newnode, alloc, unorderedpath); Node_Copy(from,
+ * newnode, alloc, cheapestpath);
+ */
+#if 0 /* can't use Node_copy now. 2/95 -ay */
+ Node_Copy(from, newnode, alloc, classlist);
+ Node_Copy(from, newnode, alloc, indexkeys);
+ Node_Copy(from, newnode, alloc, ordering);
#endif
- Node_Copy(from, newnode, alloc, clauseinfo);
- Node_Copy(from, newnode, alloc, joininfo);
- Node_Copy(from, newnode, alloc, innerjoin);
- Node_Copy(from, newnode, alloc, superrels);
-
- (*to) = newnode;
- return true;
+ Node_Copy(from, newnode, alloc, clauseinfo);
+ Node_Copy(from, newnode, alloc, joininfo);
+ Node_Copy(from, newnode, alloc, innerjoin);
+ Node_Copy(from, newnode, alloc, superrels);
+
+ (*to) = newnode;
+ return true;
}
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 7637d15f200..bdceec18be3 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* createplan.c--
- * Routines to create the desired plan for processing a query
+ * Routines to create the desired plan for processing a query
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.11 1997/04/24 15:59:58 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.12 1997/09/07 04:43:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,766 +41,836 @@
#include "optimizer/internal.h"
-#define TEMP_SORT 1
+#define TEMP_SORT 1
#define TEMP_MATERIAL 2
-static List *switch_outer(List *clauses);
-static Scan *create_scan_node(Path *best_path, List *tlist);
-static Join *create_join_node(JoinPath *best_path, List *tlist);
-static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
- List *scan_clauses);
-static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
- List *scan_clauses);
-static NestLoop *create_nestloop_node(JoinPath *best_path, List *tlist,
- List *clauses, Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist,
- List *clauses, Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist,
- List *clauses, Plan *outer_node, List *outer_tlist,
- Plan *inner_node, List *inner_tlist);
-static Node *fix_indxqual_references(Node *clause, Path *index_path);
-static Temp *make_temp(List *tlist, List *keys, Oid *operators,
- Plan *plan_node, int temptype);
-static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
- List *indxid, List *indxqual);
-static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
- Plan *righttree);
-static HashJoin *make_hashjoin(List *tlist, List *qpqual,
- List *hashclauses, Plan *lefttree, Plan *righttree);
-static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
-static MergeJoin *make_mergesort(List * tlist, List *qpqual,
- List *mergeclauses, Oid opcode, Oid *rightorder,
- Oid *leftorder, Plan *righttree, Plan *lefttree);
-static Material *make_material(List *tlist, Oid tempid, Plan *lefttree,
- int keycount);
-
-/*
+static List *switch_outer(List * clauses);
+static Scan *create_scan_node(Path * best_path, List * tlist);
+static Join *create_join_node(JoinPath * best_path, List * tlist);
+static SeqScan *
+create_seqscan_node(Path * best_path, List * tlist,
+ List * scan_clauses);
+static IndexScan *
+create_indexscan_node(IndexPath * best_path, List * tlist,
+ List * scan_clauses);
+static NestLoop *
+create_nestloop_node(JoinPath * best_path, List * tlist,
+ List * clauses, Plan * outer_node, List * outer_tlist,
+ Plan * inner_node, List * inner_tlist);
+static MergeJoin *
+create_mergejoin_node(MergePath * best_path, List * tlist,
+ List * clauses, Plan * outer_node, List * outer_tlist,
+ Plan * inner_node, List * inner_tlist);
+static HashJoin *
+create_hashjoin_node(HashPath * best_path, List * tlist,
+ List * clauses, Plan * outer_node, List * outer_tlist,
+ Plan * inner_node, List * inner_tlist);
+static Node *fix_indxqual_references(Node * clause, Path * index_path);
+static Temp *
+make_temp(List * tlist, List * keys, Oid * operators,
+ Plan * plan_node, int temptype);
+static IndexScan *
+make_indexscan(List * qptlist, List * qpqual, Index scanrelid,
+ List * indxid, List * indxqual);
+static NestLoop *
+make_nestloop(List * qptlist, List * qpqual, Plan * lefttree,
+ Plan * righttree);
+static HashJoin *
+make_hashjoin(List * tlist, List * qpqual,
+ List * hashclauses, Plan * lefttree, Plan * righttree);
+static Hash *make_hash(List * tlist, Var * hashkey, Plan * lefttree);
+static MergeJoin *
+make_mergesort(List * tlist, List * qpqual,
+ List * mergeclauses, Oid opcode, Oid * rightorder,
+ Oid * leftorder, Plan * righttree, Plan * lefttree);
+static Material *
+make_material(List * tlist, Oid tempid, Plan * lefttree,
+ int keycount);
+
+/*
* create_plan--
- * Creates the access plan for a query by tracing backwards through the
- * desired chain of pathnodes, starting at the node 'best-path'. For
- * every pathnode found:
- * (1) Create a corresponding plan node containing appropriate id,
- * target list, and qualification information.
- * (2) Modify ALL clauses so that attributes are referenced using
- * relative values.
- * (3) Target lists are not modified, but will be in another routine.
- *
- * best-path is the best access path
+ * Creates the access plan for a query by tracing backwards through the
+ * desired chain of pathnodes, starting at the node 'best-path'. For
+ * every pathnode found:
+ * (1) Create a corresponding plan node containing appropriate id,
+ * target list, and qualification information.
+ * (2) Modify ALL clauses so that attributes are referenced using
+ * relative values.
+ * (3) Target lists are not modified, but will be in another routine.
+ *
+ * best-path is the best access path
*
- * Returns the optimal(?) access plan.
+ * Returns the optimal(?) access plan.
*/
-Plan *
-create_plan(Path *best_path)
+Plan *
+create_plan(Path * best_path)
{
- List *tlist;
- Plan *plan_node = (Plan*)NULL;
- Rel *parent_rel;
- int size;
- int width;
- int pages;
- int tuples;
-
- parent_rel = best_path->parent;
- tlist = get_actual_tlist(parent_rel->targetlist);
- size = parent_rel->size;
- width = parent_rel->width;
- pages = parent_rel->pages;
- tuples = parent_rel->tuples;
-
- switch(best_path->pathtype) {
- case T_IndexScan :
- case T_SeqScan :
- plan_node = (Plan*)create_scan_node(best_path, tlist);
- break;
- case T_HashJoin :
- case T_MergeJoin :
- case T_NestLoop:
- plan_node = (Plan*)create_join_node((JoinPath*)best_path, tlist);
- break;
- default:
- /* do nothing */
- break;
- }
-
- plan_node->plan_size = size;
- plan_node->plan_width = width;
- if (pages == 0) pages = 1;
- plan_node->plan_tupperpage = tuples/pages;
-
-#if 0 /* fix xfunc */
- /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
- if (XfuncMode != XFUNC_OFF)
+ List *tlist;
+ Plan *plan_node = (Plan *) NULL;
+ Rel *parent_rel;
+ int size;
+ int width;
+ int pages;
+ int tuples;
+
+ parent_rel = best_path->parent;
+ tlist = get_actual_tlist(parent_rel->targetlist);
+ size = parent_rel->size;
+ width = parent_rel->width;
+ pages = parent_rel->pages;
+ tuples = parent_rel->tuples;
+
+ switch (best_path->pathtype)
{
- set_qpqual((Plan) plan_node,
- lisp_qsort( get_qpqual((Plan) plan_node),
- xfunc_clause_compare));
- if (XfuncMode != XFUNC_NOR)
- /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
- xfunc_disjunct_sort(plan_node->qpqual);
+ case T_IndexScan:
+ case T_SeqScan:
+ plan_node = (Plan *) create_scan_node(best_path, tlist);
+ break;
+ case T_HashJoin:
+ case T_MergeJoin:
+ case T_NestLoop:
+ plan_node = (Plan *) create_join_node((JoinPath *) best_path, tlist);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+
+ plan_node->plan_size = size;
+ plan_node->plan_width = width;
+ if (pages == 0)
+ pages = 1;
+ plan_node->plan_tupperpage = tuples / pages;
+
+#if 0 /* fix xfunc */
+ /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */
+ if (XfuncMode != XFUNC_OFF)
+ {
+ set_qpqual((Plan) plan_node,
+ lisp_qsort(get_qpqual((Plan) plan_node),
+ xfunc_clause_compare));
+ if (XfuncMode != XFUNC_NOR)
+ /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */
+ xfunc_disjunct_sort(plan_node->qpqual);
}
#endif
-
- return(plan_node);
+
+ return (plan_node);
}
-/*
+/*
* create_scan_node--
- * Create a scan path for the parent relation of 'best-path'.
- *
- * tlist is the targetlist for the base relation scanned by 'best-path'
- *
- * Returns the scan node.
+ * Create a scan path for the parent relation of 'best-path'.
+ *
+ * tlist is the targetlist for the base relation scanned by 'best-path'
+ *
+ * Returns the scan node.
*/
-static Scan *
-create_scan_node(Path *best_path, List *tlist)
+static Scan *
+create_scan_node(Path * best_path, List * tlist)
{
- Scan *node = NULL ;
- List *scan_clauses;
-
- /*
- * Extract the relevant clauses from the parent relation and replace the
- * operator OIDs with the corresponding regproc ids.
- *
- * now that local predicate clauses are copied into paths in
- * find_rel_paths() and then (possibly) pulled up in xfunc_trypullup(),
- * we get the relevant clauses from the path itself, not its parent
- * relation. --- JMH, 6/15/92
- */
- scan_clauses = fix_opids(get_actual_clauses(best_path->locclauseinfo));
-
- switch(best_path->pathtype) {
- case T_SeqScan :
- node = (Scan*)create_seqscan_node(best_path, tlist, scan_clauses);
- break;
-
- case T_IndexScan:
- node = (Scan*)create_indexscan_node((IndexPath*)best_path,
- tlist,
- scan_clauses);
- break;
-
- default :
- elog(WARN, "create_scan_node: unknown node type",
- best_path->pathtype);
- break;
- }
-
- return node;
+ Scan *node = NULL;
+ List *scan_clauses;
+
+ /*
+ * Extract the relevant clauses from the parent relation and replace
+ * the operator OIDs with the corresponding regproc ids.
+ *
+ * now that local predicate clauses are copied into paths in
+ * find_rel_paths() and then (possibly) pulled up in
+ * xfunc_trypullup(), we get the relevant clauses from the path
+ * itself, not its parent relation. --- JMH, 6/15/92
+ */
+ scan_clauses = fix_opids(get_actual_clauses(best_path->locclauseinfo));
+
+ switch (best_path->pathtype)
+ {
+ case T_SeqScan:
+ node = (Scan *) create_seqscan_node(best_path, tlist, scan_clauses);
+ break;
+
+ case T_IndexScan:
+ node = (Scan *) create_indexscan_node((IndexPath *) best_path,
+ tlist,
+ scan_clauses);
+ break;
+
+ default:
+ elog(WARN, "create_scan_node: unknown node type",
+ best_path->pathtype);
+ break;
+ }
+
+ return node;
}
-/*
+/*
* create_join_node --
- * Create a join path for 'best-path' and(recursively) paths for its
- * inner and outer paths.
- *
- * 'tlist' is the targetlist for the join relation corresponding to
- * 'best-path'
- *
- * Returns the join node.
+ * Create a join path for 'best-path' and(recursively) paths for its
+ * inner and outer paths.
+ *
+ * 'tlist' is the targetlist for the join relation corresponding to
+ * 'best-path'
+ *
+ * Returns the join node.
*/
-static Join *
-create_join_node(JoinPath *best_path, List *tlist)
+static Join *
+create_join_node(JoinPath * best_path, List * tlist)
{
- Plan *outer_node;
- List *outer_tlist;
- Plan *inner_node;
- List *inner_tlist;
- List *clauses;
- Join *retval = NULL;
-
- outer_node = create_plan((Path*)best_path->outerjoinpath);
- outer_tlist = outer_node->targetlist;
-
- inner_node = create_plan((Path*)best_path->innerjoinpath);
- inner_tlist = inner_node->targetlist;
-
- clauses = get_actual_clauses(best_path->pathclauseinfo);
-
- switch(best_path->path.pathtype) {
- case T_MergeJoin:
- retval = (Join*)create_mergejoin_node((MergePath*)best_path,
- tlist,
- clauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
- break;
- case T_HashJoin:
- retval = (Join*)create_hashjoin_node((HashPath*)best_path,
- tlist,
- clauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
- break;
- case T_NestLoop:
- retval = (Join*)create_nestloop_node((JoinPath*)best_path,
- tlist,
- clauses,
- outer_node,
- outer_tlist,
- inner_node,
- inner_tlist);
- break;
- default:
- /* do nothing */
- elog(WARN, "create_join_node: unknown node type",
- best_path->path.pathtype);
- }
+ Plan *outer_node;
+ List *outer_tlist;
+ Plan *inner_node;
+ List *inner_tlist;
+ List *clauses;
+ Join *retval = NULL;
+
+ outer_node = create_plan((Path *) best_path->outerjoinpath);
+ outer_tlist = outer_node->targetlist;
+
+ inner_node = create_plan((Path *) best_path->innerjoinpath);
+ inner_tlist = inner_node->targetlist;
+
+ clauses = get_actual_clauses(best_path->pathclauseinfo);
+
+ switch (best_path->path.pathtype)
+ {
+ case T_MergeJoin:
+ retval = (Join *) create_mergejoin_node((MergePath *) best_path,
+ tlist,
+ clauses,
+ outer_node,
+ outer_tlist,
+ inner_node,
+ inner_tlist);
+ break;
+ case T_HashJoin:
+ retval = (Join *) create_hashjoin_node((HashPath *) best_path,
+ tlist,
+ clauses,
+ outer_node,
+ outer_tlist,
+ inner_node,
+ inner_tlist);
+ break;
+ case T_NestLoop:
+ retval = (Join *) create_nestloop_node((JoinPath *) best_path,
+ tlist,
+ clauses,
+ outer_node,
+ outer_tlist,
+ inner_node,
+ inner_tlist);
+ break;
+ default:
+ /* do nothing */
+ elog(WARN, "create_join_node: unknown node type",
+ best_path->path.pathtype);
+ }
#if 0
- /*
- ** Expensive function pullups may have pulled local predicates
- ** into this path node. Put them in the qpqual of the plan node.
- ** -- JMH, 6/15/92
- */
- if (get_locclauseinfo(best_path) != NIL)
- set_qpqual((Plan)retval,
- nconc(get_qpqual((Plan) retval),
- fix_opids(get_actual_clauses
- (get_locclauseinfo(best_path)))));
+
+ /*
+ * * Expensive function pullups may have pulled local predicates *
+ * into this path node. Put them in the qpqual of the plan node. *
+ * -- JMH, 6/15/92
+ */
+ if (get_locclauseinfo(best_path) != NIL)
+ set_qpqual((Plan) retval,
+ nconc(get_qpqual((Plan) retval),
+ fix_opids(get_actual_clauses
+ (get_locclauseinfo(best_path)))));
#endif
- return(retval);
+ return (retval);
}
/*****************************************************************************
*
- * BASE-RELATION SCAN METHODS
+ * BASE-RELATION SCAN METHODS
*
*****************************************************************************/
-
-/*
+
+/*
* create_seqscan_node--
- * Returns a seqscan node for the base relation scanned by 'best-path'
- * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
+ * Returns a seqscan node for the base relation scanned by 'best-path'
+ * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
*/
static SeqScan *
-create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
+create_seqscan_node(Path * best_path, List * tlist, List * scan_clauses)
{
- SeqScan *scan_node = (SeqScan*)NULL;
- Index scan_relid = -1;
- List *temp;
-
- temp = best_path->parent->relids;
- if(temp == NULL)
- elog(WARN,"scanrelid is empty");
- else
- scan_relid = (Index)lfirsti(temp); /* ??? who takes care of lnext? - ay */
- scan_node = make_seqscan(tlist,
- scan_clauses,
- scan_relid,
- (Plan*)NULL);
-
- scan_node->plan.cost = best_path->path_cost;
-
- return(scan_node);
+ SeqScan *scan_node = (SeqScan *) NULL;
+ Index scan_relid = -1;
+ List *temp;
+
+ temp = best_path->parent->relids;
+ if (temp == NULL)
+ elog(WARN, "scanrelid is empty");
+ else
+ scan_relid = (Index) lfirsti(temp); /* ??? who takes care of
+ * lnext? - ay */
+ scan_node = make_seqscan(tlist,
+ scan_clauses,
+ scan_relid,
+ (Plan *) NULL);
+
+ scan_node->plan.cost = best_path->path_cost;
+
+ return (scan_node);
}
-/*
+/*
* create_indexscan_node--
- * Returns a indexscan node for the base relation scanned by 'best-path'
- * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
+ * Returns a indexscan node for the base relation scanned by 'best-path'
+ * with restriction clauses 'scan-clauses' and targetlist 'tlist'.
*/
static IndexScan *
-create_indexscan_node(IndexPath *best_path,
- List *tlist,
- List *scan_clauses)
+create_indexscan_node(IndexPath * best_path,
+ List * tlist,
+ List * scan_clauses)
{
- /*
- * Extract the(first if conjunct, only if disjunct) clause from the
- * clauseinfo list.
- */
- Expr *index_clause = (Expr*)NULL;
- List *indxqual = NIL;
- List *qpqual = NIL;
- List *fixed_indxqual = NIL;
- List *ixid;
- IndexScan *scan_node = (IndexScan*)NULL;
- bool lossy = FALSE;
- HeapTuple indexTuple;
- IndexTupleForm index;
-
- /*
- * If an 'or' clause is to be used with this index, the indxqual
- * field will contain a list of the 'or' clause arguments, e.g., the
- * clause(OR a b c) will generate: ((a) (b) (c)). Otherwise, the
- * indxqual will simply contain one conjunctive qualification: ((a)).
- */
- if (best_path->indexqual != NULL)
- /* added call to fix_opids, JMH 6/23/92 */
- index_clause = (Expr*)
- lfirst(fix_opids(get_actual_clauses(best_path->indexqual)));
-
- if (or_clause((Node*)index_clause)) {
- List *temp = NIL;
-
- foreach(temp, index_clause->args)
- indxqual = lappend(indxqual, lcons(lfirst(temp), NIL));
- } else {
- indxqual = lcons(get_actual_clauses(best_path->indexqual),
- NIL);
- }
-
- /* check and see if any indices are lossy */
- foreach (ixid, best_path->indexid) {
- indexTuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(lfirsti(ixid)),
- 0,0,0);
- if (!HeapTupleIsValid(indexTuple))
- elog(WARN, "create_plan: index %d not found",
- lfirsti(ixid));
- index = (IndexTupleForm)GETSTRUCT(indexTuple);
- if (index->indislossy)
- lossy = TRUE;
- }
-
-
- /*
- * The qpqual field contains all restrictions not automatically handled
- * by the index. Note that for non-lossy indices, the predicates
- * in the indxqual are handled by the index, while for lossy indices
- * the indxqual predicates need to be double-checked after the
- * index fetches the best-guess tuples.
- */
- if(or_clause((Node*)index_clause)) {
- qpqual = set_difference(scan_clauses,
- lcons(index_clause,NIL));
-
- if (lossy)
- qpqual = nconc(qpqual,
- lcons((List *)copyObject(index_clause),NIL));
- }
- else {
- qpqual = set_difference(scan_clauses, lfirst(indxqual));
- if (lossy)
- qpqual = nconc(qpqual,
- (List *)copyObject(lfirst(indxqual)));
- }
-
- fixed_indxqual =
- (List*)fix_indxqual_references((Node*)indxqual,(Path*)best_path);
-
- scan_node =
- make_indexscan(tlist,
- qpqual,
- lfirsti(best_path->path.parent->relids),
- best_path->indexid,
- fixed_indxqual);
-
- scan_node->scan.plan.cost = best_path->path.path_cost;
-
- return(scan_node);
+
+ /*
+ * Extract the(first if conjunct, only if disjunct) clause from the
+ * clauseinfo list.
+ */
+ Expr *index_clause = (Expr *) NULL;
+ List *indxqual = NIL;
+ List *qpqual = NIL;
+ List *fixed_indxqual = NIL;
+ List *ixid;
+ IndexScan *scan_node = (IndexScan *) NULL;
+ bool lossy = FALSE;
+ HeapTuple indexTuple;
+ IndexTupleForm index;
+
+ /*
+ * If an 'or' clause is to be used with this index, the indxqual field
+ * will contain a list of the 'or' clause arguments, e.g., the
+ * clause(OR a b c) will generate: ((a) (b) (c)). Otherwise, the
+ * indxqual will simply contain one conjunctive qualification: ((a)).
+ */
+ if (best_path->indexqual != NULL)
+ /* added call to fix_opids, JMH 6/23/92 */
+ index_clause = (Expr *)
+ lfirst(fix_opids(get_actual_clauses(best_path->indexqual)));
+
+ if (or_clause((Node *) index_clause))
+ {
+ List *temp = NIL;
+
+ foreach(temp, index_clause->args)
+ indxqual = lappend(indxqual, lcons(lfirst(temp), NIL));
+ }
+ else
+ {
+ indxqual = lcons(get_actual_clauses(best_path->indexqual),
+ NIL);
+ }
+
+ /* check and see if any indices are lossy */
+ foreach(ixid, best_path->indexid)
+ {
+ indexTuple = SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(lfirsti(ixid)),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indexTuple))
+ elog(WARN, "create_plan: index %d not found",
+ lfirsti(ixid));
+ index = (IndexTupleForm) GETSTRUCT(indexTuple);
+ if (index->indislossy)
+ lossy = TRUE;
+ }
+
+
+ /*
+ * The qpqual field contains all restrictions not automatically
+ * handled by the index. Note that for non-lossy indices, the
+ * predicates in the indxqual are handled by the index, while for
+ * lossy indices the indxqual predicates need to be double-checked
+ * after the index fetches the best-guess tuples.
+ */
+ if (or_clause((Node *) index_clause))
+ {
+ qpqual = set_difference(scan_clauses,
+ lcons(index_clause, NIL));
+
+ if (lossy)
+ qpqual = nconc(qpqual,
+ lcons((List *) copyObject(index_clause), NIL));
+ }
+ else
+ {
+ qpqual = set_difference(scan_clauses, lfirst(indxqual));
+ if (lossy)
+ qpqual = nconc(qpqual,
+ (List *) copyObject(lfirst(indxqual)));
+ }
+
+ fixed_indxqual =
+ (List *) fix_indxqual_references((Node *) indxqual, (Path *) best_path);
+
+ scan_node =
+ make_indexscan(tlist,
+ qpqual,
+ lfirsti(best_path->path.parent->relids),
+ best_path->indexid,
+ fixed_indxqual);
+
+ scan_node->scan.plan.cost = best_path->path.path_cost;
+
+ return (scan_node);
}
/*****************************************************************************
*
- * JOIN METHODS
+ * JOIN METHODS
*
*****************************************************************************/
static NestLoop *
-create_nestloop_node(JoinPath *best_path,
- List *tlist,
- List *clauses,
- Plan *outer_node,
- List *outer_tlist,
- Plan *inner_node,
- List *inner_tlist)
+create_nestloop_node(JoinPath * best_path,
+ List * tlist,
+ List * clauses,
+ Plan * outer_node,
+ List * outer_tlist,
+ Plan * inner_node,
+ List * inner_tlist)
{
- NestLoop *join_node = (NestLoop*)NULL;
+ NestLoop *join_node = (NestLoop *) NULL;
- if (IsA(inner_node,IndexScan)) {
- /* An index is being used to reduce the number of tuples scanned in
- * the inner relation. There will never be more than one index used
- * in the inner scan path, so we need only consider the first set of
- * qualifications in indxqual.
- *
- * But there may be more than one clauses in this "first set"
- * in the case of multi-column indices. - vadim 03/18/97
- */
+ if (IsA(inner_node, IndexScan))
+ {
- List *inner_indxqual = lfirst(((IndexScan*)inner_node)->indxqual);
- List *inner_qual;
- bool found = false;
+ /*
+ * An index is being used to reduce the number of tuples scanned
+ * in the inner relation. There will never be more than one index
+ * used in the inner scan path, so we need only consider the first
+ * set of qualifications in indxqual.
+ *
+ * But there may be more than one clauses in this "first set" in the
+ * case of multi-column indices. - vadim 03/18/97
+ */
+
+ List *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual);
+ List *inner_qual;
+ bool found = false;
+
+ foreach(inner_qual, inner_indxqual)
+ {
+ if (!qual_clause_p((Node *) lfirst(inner_qual)))
+ {
+ found = true;
+ break;
+ }
+ }
- foreach (inner_qual, inner_indxqual)
- {
- if ( !qual_clause_p ((Node*)lfirst(inner_qual)) )
- {
- found = true;
- break;
- }
+ /*
+ * If we have in fact found a join index qualification, remove
+ * these index clauses from the nestloop's join clauses and reset
+ * the inner(index) scan's qualification so that the var nodes
+ * refer to the proper outer join relation attributes.
+ *
+ * XXX Re-moving index clauses doesn't work properly: 1.
+ * fix_indxqual_references may change varattno-s in
+ * inner_indxqual; 2. clauses may be commuted I havn't time to fix
+ * it at the moment. - vadim 04/24/97
+ */
+ if (found)
+ {
+ List *new_inner_qual = NIL;
+
+ clauses = set_difference(clauses, inner_indxqual); /* XXX */
+ new_inner_qual =
+ index_outerjoin_references(inner_indxqual,
+ outer_node->targetlist,
+ ((Scan *) inner_node)->scanrelid);
+ ((IndexScan *) inner_node)->indxqual =
+ lcons(new_inner_qual, NIL);
+ }
}
-
- /* If we have in fact found a join index qualification, remove these
- * index clauses from the nestloop's join clauses and reset the
- * inner(index) scan's qualification so that the var nodes refer to
- * the proper outer join relation attributes.
- *
- * XXX Re-moving index clauses doesn't work properly:
- * 1. fix_indxqual_references may change varattno-s in
- * inner_indxqual;
- * 2. clauses may be commuted
- * I havn't time to fix it at the moment. - vadim 04/24/97
- */
- if ( found )
+ else if (IsA_Join(inner_node))
{
- List *new_inner_qual = NIL;
-
- clauses = set_difference(clauses,inner_indxqual); /* XXX */
- new_inner_qual =
- index_outerjoin_references(inner_indxqual,
- outer_node->targetlist,
- ((Scan*)inner_node)->scanrelid);
- ((IndexScan*)inner_node)->indxqual =
- lcons(new_inner_qual,NIL);
+ inner_node = (Plan *) make_temp(inner_tlist,
+ NIL,
+ NULL,
+ inner_node,
+ TEMP_MATERIAL);
}
- }else if (IsA_Join(inner_node)) {
- inner_node = (Plan*)make_temp(inner_tlist,
- NIL,
- NULL,
- inner_node,
- TEMP_MATERIAL);
- }
-
- join_node = make_nestloop(tlist,
- join_references(clauses,
- outer_tlist,
- inner_tlist),
- outer_node,
- inner_node);
-
- join_node->join.cost = best_path->path.path_cost;
-
- return(join_node);
+
+ join_node = make_nestloop(tlist,
+ join_references(clauses,
+ outer_tlist,
+ inner_tlist),
+ outer_node,
+ inner_node);
+
+ join_node->join.cost = best_path->path.path_cost;
+
+ return (join_node);
}
static MergeJoin *
-create_mergejoin_node(MergePath *best_path,
- List *tlist,
- List *clauses,
- Plan *outer_node,
- List *outer_tlist,
- Plan *inner_node,
- List *inner_tlist)
+create_mergejoin_node(MergePath * best_path,
+ List * tlist,
+ List * clauses,
+ Plan * outer_node,
+ List * outer_tlist,
+ Plan * inner_node,
+ List * inner_tlist)
{
- List *qpqual, *mergeclauses;
- RegProcedure opcode;
- Oid *outer_order, *inner_order;
- MergeJoin *join_node;
-
-
- /* Separate the mergeclauses from the other join qualification
- * clauses and set those clauses to contain references to lower
- * attributes.
- */
- qpqual = join_references(set_difference(clauses,
- best_path->path_mergeclauses),
- outer_tlist,
- inner_tlist);
-
- /* Now set the references in the mergeclauses and rearrange them so
- * that the outer variable is always on the left.
- */
- mergeclauses = switch_outer(join_references(best_path->path_mergeclauses,
- outer_tlist,
- inner_tlist));
-
- opcode =
- get_opcode((best_path->jpath.path.p_ordering.ord.merge)->join_operator);
-
- outer_order = (Oid *)palloc(sizeof(Oid)*2);
- outer_order[0] =
- (best_path->jpath.path.p_ordering.ord.merge)->left_operator;
- outer_order[1] = 0;
-
- inner_order = (Oid *)palloc(sizeof(Oid)*2);
- inner_order[0] =
- (best_path->jpath.path.p_ordering.ord.merge)->right_operator;
- inner_order[1] = 0;
-
- /* Create explicit sort paths for the outer and inner join paths if
- * necessary. The sort cost was already accounted for in the path.
- */
- if (best_path->outersortkeys) {
- Temp *sorted_outer_node = make_temp(outer_tlist,
- best_path->outersortkeys,
- outer_order,
- outer_node,
- TEMP_SORT);
- sorted_outer_node->plan.cost = outer_node->cost;
- outer_node = (Plan*)sorted_outer_node;
- }
-
- if (best_path->innersortkeys) {
- Temp *sorted_inner_node = make_temp(inner_tlist,
- best_path->innersortkeys,
- inner_order,
- inner_node,
- TEMP_SORT);
- sorted_inner_node->plan.cost = outer_node->cost;
- inner_node = (Plan*)sorted_inner_node;
- }
-
- join_node = make_mergesort(tlist,
- qpqual,
- mergeclauses,
- opcode,
- inner_order,
- outer_order,
- inner_node,
- outer_node);
-
- join_node->join.cost = best_path->jpath.path.path_cost;
-
- return(join_node);
+ List *qpqual,
+ *mergeclauses;
+ RegProcedure opcode;
+ Oid *outer_order,
+ *inner_order;
+ MergeJoin *join_node;
+
+
+ /*
+ * Separate the mergeclauses from the other join qualification clauses
+ * and set those clauses to contain references to lower attributes.
+ */
+ qpqual = join_references(set_difference(clauses,
+ best_path->path_mergeclauses),
+ outer_tlist,
+ inner_tlist);
+
+ /*
+ * Now set the references in the mergeclauses and rearrange them so
+ * that the outer variable is always on the left.
+ */
+ mergeclauses = switch_outer(join_references(best_path->path_mergeclauses,
+ outer_tlist,
+ inner_tlist));
+
+ opcode =
+ get_opcode((best_path->jpath.path.p_ordering.ord.merge)->join_operator);
+
+ outer_order = (Oid *) palloc(sizeof(Oid) * 2);
+ outer_order[0] =
+ (best_path->jpath.path.p_ordering.ord.merge)->left_operator;
+ outer_order[1] = 0;
+
+ inner_order = (Oid *) palloc(sizeof(Oid) * 2);
+ inner_order[0] =
+ (best_path->jpath.path.p_ordering.ord.merge)->right_operator;
+ inner_order[1] = 0;
+
+ /*
+ * Create explicit sort paths for the outer and inner join paths if
+ * necessary. The sort cost was already accounted for in the path.
+ */
+ if (best_path->outersortkeys)
+ {
+ Temp *sorted_outer_node = make_temp(outer_tlist,
+ best_path->outersortkeys,
+ outer_order,
+ outer_node,
+ TEMP_SORT);
+
+ sorted_outer_node->plan.cost = outer_node->cost;
+ outer_node = (Plan *) sorted_outer_node;
+ }
+
+ if (best_path->innersortkeys)
+ {
+ Temp *sorted_inner_node = make_temp(inner_tlist,
+ best_path->innersortkeys,
+ inner_order,
+ inner_node,
+ TEMP_SORT);
+
+ sorted_inner_node->plan.cost = outer_node->cost;
+ inner_node = (Plan *) sorted_inner_node;
+ }
+
+ join_node = make_mergesort(tlist,
+ qpqual,
+ mergeclauses,
+ opcode,
+ inner_order,
+ outer_order,
+ inner_node,
+ outer_node);
+
+ join_node->join.cost = best_path->jpath.path.path_cost;
+
+ return (join_node);
}
-/*
- * create_hashjoin_node-- XXX HASH
- *
- * Returns a new hashjoin node.
- *
- * XXX hash join ops are totally bogus -- how the hell do we choose
- * these?? at runtime? what about a hash index?
+/*
+ * create_hashjoin_node-- XXX HASH
+ *
+ * Returns a new hashjoin node.
+ *
+ * XXX hash join ops are totally bogus -- how the hell do we choose
+ * these?? at runtime? what about a hash index?
*/
static HashJoin *
-create_hashjoin_node(HashPath *best_path,
- List *tlist,
- List *clauses,
- Plan *outer_node,
- List *outer_tlist,
- Plan *inner_node,
- List *inner_tlist)
+create_hashjoin_node(HashPath * best_path,
+ List * tlist,
+ List * clauses,
+ Plan * outer_node,
+ List * outer_tlist,
+ Plan * inner_node,
+ List * inner_tlist)
{
- List *qpqual;
- List *hashclauses;
- HashJoin *join_node;
- Hash *hash_node;
- Var *innerhashkey;
-
- /* Separate the hashclauses from the other join qualification clauses
- * and set those clauses to contain references to lower attributes.
- */
- qpqual =
- join_references(set_difference(clauses,
- best_path->path_hashclauses),
- outer_tlist,
- inner_tlist);
-
- /* Now set the references in the hashclauses and rearrange them so
- * that the outer variable is always on the left.
- */
- hashclauses =
- switch_outer(join_references(best_path->path_hashclauses,
- outer_tlist,
- inner_tlist));
-
- innerhashkey = get_rightop(lfirst(hashclauses));
-
- hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
- join_node = make_hashjoin(tlist,
- qpqual,
- hashclauses,
- outer_node,
- (Plan*)hash_node);
- join_node->join.cost = best_path->jpath.path.path_cost;
-
- return(join_node);
+ List *qpqual;
+ List *hashclauses;
+ HashJoin *join_node;
+ Hash *hash_node;
+ Var *innerhashkey;
+
+ /*
+ * Separate the hashclauses from the other join qualification clauses
+ * and set those clauses to contain references to lower attributes.
+ */
+ qpqual =
+ join_references(set_difference(clauses,
+ best_path->path_hashclauses),
+ outer_tlist,
+ inner_tlist);
+
+ /*
+ * Now set the references in the hashclauses and rearrange them so
+ * that the outer variable is always on the left.
+ */
+ hashclauses =
+ switch_outer(join_references(best_path->path_hashclauses,
+ outer_tlist,
+ inner_tlist));
+
+ innerhashkey = get_rightop(lfirst(hashclauses));
+
+ hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
+ join_node = make_hashjoin(tlist,
+ qpqual,
+ hashclauses,
+ outer_node,
+ (Plan *) hash_node);
+ join_node->join.cost = best_path->jpath.path.path_cost;
+
+ return (join_node);
}
/*****************************************************************************
*
- * SUPPORTING ROUTINES
+ * SUPPORTING ROUTINES
*
*****************************************************************************/
-static Node *
-fix_indxqual_references(Node *clause, Path *index_path)
+static Node *
+fix_indxqual_references(Node * clause, Path * index_path)
{
- Node *newclause;
-
- if (IsA(clause,Var)) {
- if (lfirsti(index_path->parent->relids) == ((Var*)clause)->varno) {
- int pos = 0;
- int varatt = ((Var*)clause)->varattno;
- int *indexkeys = ((IndexPath*)index_path)->indexkeys;
-
- if (indexkeys) {
- while (indexkeys[pos] != 0) {
- if(varatt == indexkeys[pos]) {
- break;
- }
- pos++;
+ Node *newclause;
+
+ if (IsA(clause, Var))
+ {
+ if (lfirsti(index_path->parent->relids) == ((Var *) clause)->varno)
+ {
+ int pos = 0;
+ int varatt = ((Var *) clause)->varattno;
+ int *indexkeys = ((IndexPath *) index_path)->indexkeys;
+
+ if (indexkeys)
+ {
+ while (indexkeys[pos] != 0)
+ {
+ if (varatt == indexkeys[pos])
+ {
+ break;
+ }
+ pos++;
+ }
+ }
+ newclause = copyObject((Node *) clause);
+ ((Var *) newclause)->varattno = pos + 1;
+ return (newclause);
+ }
+ else
+ {
+ return (clause);
}
- }
- newclause = copyObject((Node*)clause);
- ((Var*)newclause)->varattno = pos + 1;
- return (newclause);
- } else {
- return (clause);
}
- } else if(IsA(clause,Const)) {
- return(clause);
+ else if (IsA(clause, Const))
+ {
+ return (clause);
#ifdef INDEXSCAN_PATCH
- } else if(IsA(clause,Param)) {
- /* Function parameter used as index scan arg. DZ - 27-8-1996 */
- return(clause);
+ }
+ else if (IsA(clause, Param))
+ {
+ /* Function parameter used as index scan arg. DZ - 27-8-1996 */
+ return (clause);
#endif
- } else if(is_opclause(clause) &&
- is_funcclause((Node*)get_leftop((Expr*)clause)) &&
- ((Func*)((Expr*)get_leftop((Expr*)clause))->oper)->funcisindex){
- Var *newvar =
- makeVar((Index)lfirsti(index_path->parent->relids),
- 1, /* func indices have one key */
- ((Func*)((Expr*)clause)->oper)->functype,
- (Index)lfirsti(index_path->parent->relids),
- 0);
-
- return
- ((Node*)make_opclause((Oper*)((Expr*)clause)->oper,
- newvar,
- get_rightop((Expr*)clause)));
-
- } else if (IsA(clause,Expr)) {
- Expr *expr = (Expr*)clause;
- List *new_subclauses = NIL;
- Node *subclause = NULL;
- List *i = NIL;
-
- foreach(i, expr->args) {
- subclause = lfirst(i);
- if(subclause)
- new_subclauses =
- lappend(new_subclauses,
- fix_indxqual_references(subclause,
- index_path));
+ }
+ else if (is_opclause(clause) &&
+ is_funcclause((Node *) get_leftop((Expr *) clause)) &&
+ ((Func *) ((Expr *) get_leftop((Expr *) clause))->oper)->funcisindex)
+ {
+ Var *newvar =
+ makeVar((Index) lfirsti(index_path->parent->relids),
+ 1, /* func indices have one key */
+ ((Func *) ((Expr *) clause)->oper)->functype,
+ (Index) lfirsti(index_path->parent->relids),
+ 0);
+
+ return
+ ((Node *) make_opclause((Oper *) ((Expr *) clause)->oper,
+ newvar,
+ get_rightop((Expr *) clause)));
}
-
- /* XXX new_subclauses should be a list of the form:
- * ( (var var) (var const) ...) ?
- */
- if(new_subclauses) {
- return (Node*)
- make_clause(expr->opType, expr->oper, new_subclauses);
- } else {
- return(clause);
- }
- } else {
- List *oldclauses = (List*)clause;
- List *new_subclauses = NIL;
- Node *subclause = NULL;
- List *i = NIL;
-
- foreach(i, oldclauses) {
- subclause = lfirst(i);
- if(subclause)
- new_subclauses =
- lappend(new_subclauses,
- fix_indxqual_references(subclause,
- index_path));
+ else if (IsA(clause, Expr))
+ {
+ Expr *expr = (Expr *) clause;
+ List *new_subclauses = NIL;
+ Node *subclause = NULL;
+ List *i = NIL;
+
+ foreach(i, expr->args)
+ {
+ subclause = lfirst(i);
+ if (subclause)
+ new_subclauses =
+ lappend(new_subclauses,
+ fix_indxqual_references(subclause,
+ index_path));
+
+ }
+
+ /*
+ * XXX new_subclauses should be a list of the form: ( (var var)
+ * (var const) ...) ?
+ */
+ if (new_subclauses)
+ {
+ return (Node *)
+ make_clause(expr->opType, expr->oper, new_subclauses);
+ }
+ else
+ {
+ return (clause);
+ }
+ }
+ else
+ {
+ List *oldclauses = (List *) clause;
+ List *new_subclauses = NIL;
+ Node *subclause = NULL;
+ List *i = NIL;
+
+ foreach(i, oldclauses)
+ {
+ subclause = lfirst(i);
+ if (subclause)
+ new_subclauses =
+ lappend(new_subclauses,
+ fix_indxqual_references(subclause,
+ index_path));
+
+ }
+ /*
+ * XXX new_subclauses should be a list of the form: ( (var var)
+ * (var const) ...) ?
+ */
+ if (new_subclauses)
+ {
+ return (Node *) new_subclauses;
+ }
+ else
+ {
+ return (clause);
+ }
}
-
- /* XXX new_subclauses should be a list of the form:
- * ( (var var) (var const) ...) ?
- */
- if(new_subclauses) {
- return (Node*)new_subclauses;
- } else {
- return (clause);
- }
- }
}
-/*
+/*
* switch_outer--
- * Given a list of merge clauses, rearranges the elements within the
- * clauses so the outer join variable is on the left and the inner is on
- * the right.
- *
- * Returns the rearranged list ?
- *
- * XXX Shouldn't the operator be commuted?!
+ * Given a list of merge clauses, rearranges the elements within the
+ * clauses so the outer join variable is on the left and the inner is on
+ * the right.
+ *
+ * Returns the rearranged list ?
+ *
+ * XXX Shouldn't the operator be commuted?!
*/
-static List *
-switch_outer(List *clauses)
+static List *
+switch_outer(List * clauses)
{
- List *t_list = NIL;
- Expr *temp = NULL;
- List *i = NIL;
- Expr *clause;
- Node *op;
-
- foreach(i,clauses) {
- clause = lfirst(i);
- op = (Node*)get_rightop(clause);
- if ( IsA (op, ArrayRef) )
- op = ((ArrayRef*)op)->refexpr;
- Assert ( IsA (op, Var) );
- if ( var_is_outer ((Var*)op) )
+ List *t_list = NIL;
+ Expr *temp = NULL;
+ List *i = NIL;
+ Expr *clause;
+ Node *op;
+
+ foreach(i, clauses)
{
- temp = make_clause(clause->opType, clause->oper,
- lcons(get_rightop(clause),
- lcons(get_leftop(clause),
- NIL)));
- t_list = lappend(t_list,temp);
- }
- else
- t_list = lappend(t_list,clause);
- }
- return(t_list);
+ clause = lfirst(i);
+ op = (Node *) get_rightop(clause);
+ if (IsA(op, ArrayRef))
+ op = ((ArrayRef *) op)->refexpr;
+ Assert(IsA(op, Var));
+ if (var_is_outer((Var *) op))
+ {
+ temp = make_clause(clause->opType, clause->oper,
+ lcons(get_rightop(clause),
+ lcons(get_leftop(clause),
+ NIL)));
+ t_list = lappend(t_list, temp);
+ }
+ else
+ t_list = lappend(t_list, clause);
+ }
+ return (t_list);
}
-/*
+/*
* set-temp-tlist-operators--
- * Sets the key and keyop fields of resdom nodes in a target list.
- *
- * 'tlist' is the target list
- * 'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)),
- * corresponding to vars in the target list that are to
- * be sorted or hashed
- * 'operators' is the corresponding list of N sort or hash operators
- * 'keyno' is the first key number
- * XXX - keyno ? doesn't exist - jeff
- *
- * Returns the modified target list.
+ * Sets the key and keyop fields of resdom nodes in a target list.
+ *
+ * 'tlist' is the target list
+ * 'pathkeys' is a list of N keys in the form((key1) (key2)...(keyn)),
+ * corresponding to vars in the target list that are to
+ * be sorted or hashed
+ * 'operators' is the corresponding list of N sort or hash operators
+ * 'keyno' is the first key number
+ * XXX - keyno ? doesn't exist - jeff
+ *
+ * Returns the modified target list.
*/
-static List *
-set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators)
+static List *
+set_temp_tlist_operators(List * tlist, List * pathkeys, Oid * operators)
{
- Node *keys = NULL;
- int keyno = 1;
- Resdom *resdom = (Resdom*)NULL ;
- List *i = NIL;
-
- foreach(i, pathkeys) {
- keys = lfirst((List*)lfirst(i));
- resdom = tlist_member((Var*)keys, tlist);
- if (resdom) {
-
- /* Order the resdom keys and replace the operator OID for each
- * key with the regproc OID.
- *
- * XXX Note that the optimizer only generates merge joins
- * with 1 operator (see create_mergejoin_node) - ay 2/95
- */
- resdom->reskey = keyno;
- resdom->reskeyop = get_opcode(operators[0]);
+ Node *keys = NULL;
+ int keyno = 1;
+ Resdom *resdom = (Resdom *) NULL;
+ List *i = NIL;
+
+ foreach(i, pathkeys)
+ {
+ keys = lfirst((List *) lfirst(i));
+ resdom = tlist_member((Var *) keys, tlist);
+ if (resdom)
+ {
+
+ /*
+ * Order the resdom keys and replace the operator OID for each
+ * key with the regproc OID.
+ *
+ * XXX Note that the optimizer only generates merge joins with 1
+ * operator (see create_mergejoin_node) - ay 2/95
+ */
+ resdom->reskey = keyno;
+ resdom->reskeyop = get_opcode(operators[0]);
+ }
+ keyno += 1;
}
- keyno += 1;
- }
- return(tlist);
+ return (tlist);
}
/*****************************************************************************
@@ -808,355 +878,362 @@ set_temp_tlist_operators(List *tlist, List *pathkeys, Oid *operators)
*
*****************************************************************************/
-/*
+/*
* make_temp--
- * Create plan nodes to sort or materialize relations into temporaries. The
- * result returned for a sort will look like (SEQSCAN(SORT(plan-node)))
- * or (SEQSCAN(MATERIAL(plan-node)))
- *
- * 'tlist' is the target list of the scan to be sorted or hashed
- * 'keys' is the list of keys which the sort or hash will be done on
- * 'operators' is the operators with which the sort or hash is to be done
- * (a list of operator OIDs)
- * 'plan-node' is the node which yields tuples for the sort
- * 'temptype' indicates which operation(sort or hash) to perform
+ * Create plan nodes to sort or materialize relations into temporaries. The
+ * result returned for a sort will look like (SEQSCAN(SORT(plan-node)))
+ * or (SEQSCAN(MATERIAL(plan-node)))
+ *
+ * 'tlist' is the target list of the scan to be sorted or hashed
+ * 'keys' is the list of keys which the sort or hash will be done on
+ * 'operators' is the operators with which the sort or hash is to be done
+ * (a list of operator OIDs)
+ * 'plan-node' is the node which yields tuples for the sort
+ * 'temptype' indicates which operation(sort or hash) to perform
*/
-static Temp *
-make_temp(List *tlist,
- List *keys,
- Oid *operators,
- Plan *plan_node,
- int temptype)
+static Temp *
+make_temp(List * tlist,
+ List * keys,
+ Oid * operators,
+ Plan * plan_node,
+ int temptype)
{
- List *temp_tlist;
- Temp *retval = NULL;
-
- /* Create a new target list for the temporary, with keys set. */
- temp_tlist = set_temp_tlist_operators(new_unsorted_tlist(tlist),
- keys,
- operators);
- switch(temptype) {
- case TEMP_SORT :
- retval = (Temp*)make_seqscan(tlist,
- NIL,
- _TEMP_RELATION_ID_,
- (Plan*)make_sort(temp_tlist,
- _TEMP_RELATION_ID_,
- plan_node,
- length(keys)));
- break;
-
- case TEMP_MATERIAL :
- retval = (Temp*)make_seqscan(tlist,
- NIL,
- _TEMP_RELATION_ID_,
- (Plan*)make_material(temp_tlist,
- _TEMP_RELATION_ID_,
- plan_node,
- length(keys)));
- break;
-
- default:
- elog(WARN,"make_temp: unknown temp type %d", temptype);
-
- }
- return(retval);
+ List *temp_tlist;
+ Temp *retval = NULL;
+
+ /* Create a new target list for the temporary, with keys set. */
+ temp_tlist = set_temp_tlist_operators(new_unsorted_tlist(tlist),
+ keys,
+ operators);
+ switch (temptype)
+ {
+ case TEMP_SORT:
+ retval = (Temp *) make_seqscan(tlist,
+ NIL,
+ _TEMP_RELATION_ID_,
+ (Plan *) make_sort(temp_tlist,
+ _TEMP_RELATION_ID_,
+ plan_node,
+ length(keys)));
+ break;
+
+ case TEMP_MATERIAL:
+ retval = (Temp *) make_seqscan(tlist,
+ NIL,
+ _TEMP_RELATION_ID_,
+ (Plan *) make_material(temp_tlist,
+ _TEMP_RELATION_ID_,
+ plan_node,
+ length(keys)));
+ break;
+
+ default:
+ elog(WARN, "make_temp: unknown temp type %d", temptype);
+
+ }
+ return (retval);
}
-SeqScan *
-make_seqscan(List *qptlist,
- List *qpqual,
- Index scanrelid,
- Plan *lefttree)
+SeqScan *
+make_seqscan(List * qptlist,
+ List * qpqual,
+ Index scanrelid,
+ Plan * lefttree)
{
- SeqScan *node = makeNode(SeqScan);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = qptlist;
- plan->qual = qpqual;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->scanrelid = scanrelid;
- node->scanstate = (CommonScanState *)NULL;
-
- return(node);
+ SeqScan *node = makeNode(SeqScan);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->scanrelid = scanrelid;
+ node->scanstate = (CommonScanState *) NULL;
+
+ return (node);
}
static IndexScan *
-make_indexscan(List *qptlist,
- List *qpqual,
- Index scanrelid,
- List *indxid,
- List *indxqual)
+make_indexscan(List * qptlist,
+ List * qpqual,
+ Index scanrelid,
+ List * indxid,
+ List * indxqual)
{
- IndexScan *node = makeNode(IndexScan);
- Plan *plan = &node->scan.plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = qptlist;
- plan->qual = qpqual;
- plan->lefttree = NULL;
- plan->righttree = NULL;
- node->scan.scanrelid = scanrelid;
- node->indxid = indxid;
- node->indxqual = indxqual;
- node->scan.scanstate = (CommonScanState *)NULL;
-
- return(node);
+ IndexScan *node = makeNode(IndexScan);
+ Plan *plan = &node->scan.plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = NULL;
+ plan->righttree = NULL;
+ node->scan.scanrelid = scanrelid;
+ node->indxid = indxid;
+ node->indxqual = indxqual;
+ node->scan.scanstate = (CommonScanState *) NULL;
+
+ return (node);
}
static NestLoop *
-make_nestloop(List *qptlist,
- List *qpqual,
- Plan *lefttree,
- Plan *righttree)
+make_nestloop(List * qptlist,
+ List * qpqual,
+ Plan * lefttree,
+ Plan * righttree)
{
- NestLoop *node = makeNode(NestLoop);
- Plan *plan = &node->join;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = qptlist;
- plan->qual = qpqual;
- plan->lefttree = lefttree;
- plan->righttree = righttree;
- node->nlstate = (NestLoopState*)NULL;
-
- return(node);
+ NestLoop *node = makeNode(NestLoop);
+ Plan *plan = &node->join;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = qptlist;
+ plan->qual = qpqual;
+ plan->lefttree = lefttree;
+ plan->righttree = righttree;
+ node->nlstate = (NestLoopState *) NULL;
+
+ return (node);
}
static HashJoin *
-make_hashjoin(List *tlist,
- List *qpqual,
- List *hashclauses,
- Plan *lefttree,
- Plan *righttree)
+make_hashjoin(List * tlist,
+ List * qpqual,
+ List * hashclauses,
+ Plan * lefttree,
+ Plan * righttree)
{
- HashJoin *node = makeNode(HashJoin);
- Plan *plan = &node->join;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = qpqual;
- plan->lefttree = lefttree;
- plan->righttree = righttree;
- node->hashclauses = hashclauses;
- node->hashjointable = NULL;
- node->hashjointablekey = 0;
- node->hashjointablesize = 0;
- node->hashdone = false;
-
- return(node);
+ HashJoin *node = makeNode(HashJoin);
+ Plan *plan = &node->join;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = qpqual;
+ plan->lefttree = lefttree;
+ plan->righttree = righttree;
+ node->hashclauses = hashclauses;
+ node->hashjoin